Skip to content

Commit 9ddd85d

Browse files
committed
✨ Add updated CachedXMLHttpRequest and CachedXHRExtensions
1 parent 62eee37 commit 9ddd85d

13 files changed

Lines changed: 305 additions & 32 deletions

Assets/Plugins/WebGLCachedXHRExtensions.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using UnityEngine;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Kongregate {
5+
public class CacheEntryQuery : CustomYieldInstruction {
6+
private readonly string Url;
7+
private int Status = 0;
8+
9+
public CacheEntryQuery(string url) {
10+
Url = url;
11+
CachedXHRExtensions_SearchCache(url);
12+
}
13+
14+
public override bool keepWaiting {
15+
get {
16+
Status = CachedXHRExtensions_CheckStatus(Url);
17+
return Status == 0;
18+
}
19+
}
20+
21+
public bool IsCached {
22+
get {
23+
if (Status == 0) {
24+
Debug.Log("CacheEntryQuery: returning IsCached=false since query is pending");
25+
return false;
26+
}
27+
28+
return Status == 1;
29+
}
30+
}
31+
32+
#if UNITY_WEBGL && !UNITY_EDITOR
33+
[DllImport("__Internal")]
34+
private static extern void CachedXHRExtensions_SearchCache(string url);
35+
36+
[DllImport("__Internal")]
37+
private static extern int CachedXHRExtensions_CheckStatus(string url);
38+
#else
39+
private static void CachedXHRExtensions_SearchCache(string url) { }
40+
private static int CachedXHRExtensions_CheckStatus(string url) { return -1; }
41+
#endif
42+
}
43+
44+
public class CachedXHRExtensions {
45+
public static void CleanCache() {
46+
CachedXHRExtensions_CleanCache();
47+
}
48+
49+
#if UNITY_WEBGL && !UNITY_EDITOR
50+
[DllImport("__Internal")]
51+
static extern int CachedXHRExtensions_CleanCache();
52+
#else
53+
static void CachedXHRExtensions_CleanCache() {}
54+
#endif
55+
}
56+
}

Assets/Plugins/WebGLCachedXHRExtensions/CachedXHRExtensions.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mergeInto(LibraryManager.library, {
2+
CachedXHRExtensions_SearchCache: function(url) { CachedXHRExtensions.searchCache(url); },
3+
CachedXHRExtensions_CheckStatus: function(url) { return CachedXHRExtensions.checkStatus(url); },
4+
CachedXHRExtensions_CleanCache: function() {
5+
try {
6+
var self = CachedXMLHttpRequest.cache;
7+
self.db.transaction([self.store], "readwrite").objectStore(self.store).clear().onerror = function(){
8+
e.preventDefault();
9+
};
10+
} catch(e) {}
11+
}
12+
});

Assets/Plugins/WebGLCachedXHRExtensions/CachedXHRExtensions.jslib.meta

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
setTimeout(function(){
2+
var enabled = typeof CachedXMLHttpRequest !== "undefined" && !!CachedXMLHttpRequest.cache;
3+
console.log("CachedXHRExtensions initialized, enabled=" + enabled);
4+
var CachedXHRExtensions = function() {
5+
this._cacheStates = {};
6+
};
7+
8+
CachedXHRExtensions.prototype.searchCache = function(url) {
9+
if (!enabled) return;
10+
var self = this;
11+
url = typeof url === "string" ? url : Pointer_stringify(url);
12+
delete this._cacheStates[url];
13+
14+
CachedXMLHttpRequest.cache.get(url, function(err, result) {
15+
if (err || !result || !result.meta) {
16+
self._cacheStates[url] = false;
17+
} else {
18+
self._cacheStates[url] = true;
19+
}
20+
});
21+
};
22+
23+
CachedXHRExtensions.prototype.checkStatus = function(url) {
24+
if (!enabled) return -1;
25+
26+
url = typeof url === "string" ? url : Pointer_stringify(url);
27+
if (this._cacheStates[url] === undefined) return 0;
28+
return this._cacheStates[url] ? 1 : -1;
29+
};
30+
31+
window.CachedXHRExtensions = new CachedXHRExtensions();
32+
}, 0);

Assets/Plugins/WebGLCachedXHRExtensions/CachedXHRExtensions.jspre.meta

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This plugin provides additional functionality on top of the CachedXMLHttpRequest
2+
addon. The classes referred to below are in the Kongregate namespace.
3+
4+
* Clearing the cache by calling CachedXHRExtensions.CleanCache()
5+
* Asynchronously querying the cache to determine if an item exists:
6+
IEnumerator CheckIfAssetExists() {
7+
var query = new CacheEntryQuery("https://whatever.io/file.xml");
8+
yield return query;
9+
if (query.IsCached) {
10+
Debug.Log("Asset exists in cache!");
11+
}
12+
}

Assets/Plugins/WebGLCachedXHRExtensions/Readme.txt.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Plugins/WebGLCachedXMLHttpRequest/WebGLCachedXMLHttpRequest.jspre

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function CachedXMLHttpRequest() {
1515
meta.size = xhr.response.byteLength;
1616
CachedXMLHttpRequest.cache.put(cache.requestURL, meta, xhr.response, function (err) {
1717
CachedXMLHttpRequest.log("'" + cache.requestURL + "' downloaded successfully (" + xhr.response.byteLength + " bytes) " +
18-
(err ? "but not stored in indexedDB cache due to error." : "and stored in indexedDB cache."));
18+
(err ? "but not stored in indexedDB cache due to error: " + err.message : "and stored in indexedDB cache."));
1919
if (onload)
2020
onload(e);
2121
});
@@ -27,22 +27,28 @@ function CachedXMLHttpRequest() {
2727
if (onload)
2828
onload(e);
2929
}
30-
}
30+
};
3131
return xhr.send.apply(xhr, arguments);
3232
}
3333

34-
function revalidateCrossOriginRequest(meta, self, sendArguments) {
35-
var headXHR = new CachedXMLHttpRequest.XMLHttpRequest();
36-
headXHR.open("HEAD", meta.requestURL, false);
37-
headXHR.send();
38-
cache.override = meta.lastModified ? meta.lastModified == headXHR.getResponseHeader("Last-Modified") : meta.eTag && meta.eTag == headXHR.getResponseHeader("ETag");
39-
if (!cache.override)
40-
return send.apply(self, sendArguments);
34+
function loadComplete() {
4135
CachedXMLHttpRequest.log("'" + cache.requestURL + "' served from indexedDB cache (" + cache.response.byteLength + " bytes).");
4236
if (xhr.onload)
4337
xhr.onload();
4438
}
4539

40+
function revalidateCrossOriginRequest(meta, self, sendArguments) {
41+
var headXHR = new CachedXMLHttpRequest.XMLHttpRequest();
42+
headXHR.open("HEAD", meta.requestURL, cache.async);
43+
headXHR.onload = function() {
44+
cache.override = meta.lastModified ? meta.lastModified == headXHR.getResponseHeader("Last-Modified") : meta.eTag && meta.eTag == getETag(headXHR);
45+
if (!cache.override)
46+
return send.apply(self, sendArguments);
47+
loadComplete();
48+
};
49+
headXHR.send();
50+
}
51+
4652
Object.defineProperty(self, "open", { value: function (method, url, async) {
4753
cache = { method: method, requestURL: CachedXMLHttpRequest.cache.requestURL(url), async: async };
4854
return xhr.open.apply(xhr, arguments);
@@ -65,6 +71,12 @@ function CachedXMLHttpRequest() {
6571
cache.statusText = "OK";
6672
cache.response = result.response;
6773
cache.responseURL = result.meta.responseURL;
74+
75+
if (CachedXMLHttpRequest.checkBlacklist(Module.CachedXMLHttpRequestRevalidateBlacklist, cache.requestURL)) {
76+
cache.override = true;
77+
return loadComplete();
78+
}
79+
6880
if (window.location.href.lastIndexOf(absoluteUrlMatch[0], 0))
6981
return revalidateCrossOriginRequest(result.meta, self, sendArguments);
7082
if (result.meta.lastModified)
@@ -97,6 +109,17 @@ CachedXMLHttpRequest.log = function (message) {
97109
console.log("[CachedXMLHttpRequest] " + message);
98110
};
99111

112+
CachedXMLHttpRequest.checkBlacklist = function(list, url) {
113+
list = list || [];
114+
list = Array.isArray(list) ? list : [list];
115+
for (var i = 0; i < list.length; i++) {
116+
var regexp = list[i];
117+
if (typeof regexp === "string") regexp = new RegExp(regexp);
118+
if (regexp instanceof RegExp && regexp.test(url)) return true;
119+
}
120+
return false;
121+
};
122+
100123
CachedXMLHttpRequest.cache = {
101124
database: "CachedXMLHttpRequest",
102125
version: 1,
@@ -115,19 +138,24 @@ CachedXMLHttpRequest.cache = {
115138
queue: [],
116139
processQueue: function () {
117140
var self = this;
118-
self.queue.forEach(function (queued) { self[queued.action].apply(self, queued.arguments) });
141+
self.queue.forEach(function (queued) { self[queued.action].apply(self, queued.arguments); });
119142
self.queue = [];
120143

121144
},
122145
init: function () {
123-
var self = this;
146+
var self = this, onError = function(e) {
147+
CachedXMLHttpRequest.log("can not open indexedDB database: " + e.message);
148+
self.indexedDB = null;
149+
self.processQueue();
150+
if (e.preventDefault) e.preventDefault();
151+
};
124152
if (!self.indexedDB)
125153
return CachedXMLHttpRequest.log("indexedDB is not available");
126154
var openDB;
127155
try {
128156
openDB = indexedDB.open(self.database, self.version);
129157
} catch(e) {
130-
return CachedXMLHttpRequest.log("indexedDB access denied");
158+
return onError(new Error("indexedDB access denied"));
131159
}
132160
openDB.onupgradeneeded = function (e) {
133161
var db = e.target.result;
@@ -140,56 +168,57 @@ CachedXMLHttpRequest.cache = {
140168
objectStore.createIndex("meta", "meta", {unique: false});
141169
}
142170
objectStore.clear();
143-
}
144-
openDB.onerror = function (e) {
145-
CachedXMLHttpRequest.log("can not open indexedDB database");
146-
self.indexedDB = null;
147-
self.processQueue();
148-
}
171+
};
172+
openDB.onerror = onError;
149173
openDB.onsuccess = function (e) {
150174
self.db = e.target.result;
151175
self.processQueue();
152-
}
176+
};
153177

154178
},
155179
put: function (requestURL, meta, response, callback) {
180+
if (CachedXMLHttpRequest.checkBlacklist(Module.CachedXMLHttpRequestBlacklist, requestURL))
181+
return callback(new Error("requestURL was on the cache blacklist"));
182+
156183
var self = this;
157184
if (!self.indexedDB)
158185
return callback(new Error("indexedDB is not available"));
159186
if (!self.db)
160187
return self.queue.push({action: "put", arguments: arguments});
161188
meta.version = self.version;
162189
var putDB = self.db.transaction([self.store], "readwrite").objectStore(self.store).put({id: self.id(requestURL), meta: meta, response: response});
163-
putDB.onerror = function (e) { callback(new Error("failed to put request into indexedDB cache")); }
164-
putDB.onsuccess = function (e) { callback(null); }
190+
putDB.onerror = function (e) { e.preventDefault(); callback(new Error("failed to put request into indexedDB cache")); };
191+
putDB.onsuccess = function () { callback(null); };
165192

166193
},
167194
get: function (requestURL, callback) {
195+
if (CachedXMLHttpRequest.checkBlacklist(Module.CachedXMLHttpRequestBlacklist, requestURL))
196+
return callback(new Error("requestURL was on the cache blacklist"));
197+
168198
var self = this;
169199
if (!self.indexedDB)
170200
return callback(new Error("indexedDB is not available"));
171201
if (!self.db)
172202
return self.queue.push({action: "get", arguments: arguments});
173203
var getDB = self.db.transaction([self.store], "readonly").objectStore(self.store).get(self.id(requestURL));
174-
getDB.onerror = function (e) { callback(new Error("failed to get request from indexedDB cache")); }
175-
getDB.onsuccess = function (e) { callback(null, e.target.result); }
176-
177-
},
204+
getDB.onerror = function (e) { e.preventDefault(); callback(new Error("failed to get request from indexedDB cache")); };
205+
getDB.onsuccess = function (e) { callback(null, e.target.result); };
206+
}
178207
};
179208

180209
CachedXMLHttpRequest.cache.init();
181210

182211
CachedXMLHttpRequest.wrap = function (func) {
183212
return function () {
184-
var realXMLHttpRequest = XMLHttpRequest;
185-
XMLHttpRequest = CachedXMLHttpRequest;
213+
var realXMLHttpRequest = XMLHttpRequest, result;
214+
window.XMLHttpRequest = CachedXMLHttpRequest;
186215
try {
187-
var result = func.apply(this, arguments);
216+
result = func.apply(this, arguments);
188217
} catch (e) {
189-
XMLHttpRequest = realXMLHttpRequest;
218+
window.XMLHttpRequest = realXMLHttpRequest;
190219
throw e;
191220
}
192-
XMLHttpRequest = realXMLHttpRequest;
221+
window.XMLHttpRequest = realXMLHttpRequest;
193222
return result;
194223
};
195224
};

0 commit comments

Comments
 (0)