class CachedFetch {
constructor() {
this.db = SQLiteDatabaseClient.open();
this.initialize();
}
async initialize() {
const cache = await this.db;
await cache.query(`
CREATE TABLE IF NOT EXISTS cache (
key text PRIMARY KEY,
value text
)`);
}
async importZip(file) {
const array = new Uint8Array(await file.arrayBuffer());
const f = fflate.gunzipSync(array);
this.db = await SQLiteDatabaseClient.open(f);
}
import(file) {
this.db = SQLiteDatabaseClient.open(file);
}
async export() {
const cache = await this.db;
return cache._db.export();
}
async download() {
return DOM.download(
async () => new Blob([await this.export()]),
"cache.db"
);
}
async downloadZip() {
const gzip = fflate.gzipSync(await this.export());
return DOM.download(
new Blob([gzip], { type: "application/gzip" }),
"cache.zip"
);
}
hashCode(str) {
let hash = 0;
for (let i = 0, len = str.length; i < len; i++) {
let chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0;
}
return hash;
}
generateKey(url, options) {
const request = new Request(url, options);
return this.hashCode(
JSON.stringify({
url: request.url,
body: options?.body?.toString(),
method: request.method,
headers: request.headers
})
);
}
async fetch(url, options) {
const cache = await this.db;
const key = this.generateKey(url, options);
console.log(key);
const cachedResponse = await cache.query(
"SELECT value FROM cache WHERE key = $1",
[key]
);
if (cachedResponse.length > 0) {
return JSON.parse(cachedResponse[0].value);
}
const response = await fetch(url, options);
const data = await response;
const value = {
body: await data.text()
};
await cache.query("INSERT INTO cache (key, value) VALUES ($1, $2)", [
key,
JSON.stringify(value)
]);
return value;
}
}