forked from mirrors/cursor-free-vip
Big Change Update
This commit is contained in:
731
uBlock0.chromium/js/cachestorage.js
Normal file
731
uBlock0.chromium/js/cachestorage.js
Normal file
@@ -0,0 +1,731 @@
|
||||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a comprehensive, efficient content blocker
|
||||
Copyright (C) 2016-present The uBlock Origin authors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
import * as s14e from './s14e-serializer.js';
|
||||
|
||||
import { ubolog } from './console.js';
|
||||
import webext from './webext.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const STORAGE_NAME = 'uBlock0CacheStorage';
|
||||
const extensionStorage = webext.storage.local;
|
||||
const pendingWrite = new Map();
|
||||
|
||||
const keysFromGetArg = arg => {
|
||||
if ( arg === null || arg === undefined ) { return []; }
|
||||
const type = typeof arg;
|
||||
if ( type === 'string' ) { return [ arg ]; }
|
||||
if ( Array.isArray(arg) ) { return arg; }
|
||||
if ( type !== 'object' ) { return; }
|
||||
return Object.keys(arg);
|
||||
};
|
||||
|
||||
let fastCache = 'indexedDB';
|
||||
|
||||
// https://eslint.org/docs/latest/rules/no-prototype-builtins
|
||||
const hasOwnProperty = (o, p) =>
|
||||
Object.prototype.hasOwnProperty.call(o, p);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Extension storage
|
||||
*
|
||||
* Always available.
|
||||
*
|
||||
* */
|
||||
|
||||
const cacheStorage = (( ) => {
|
||||
|
||||
const exGet = async (api, wanted, outbin) => {
|
||||
ubolog('cacheStorage.get:', api.name || 'storage.local', wanted.join());
|
||||
const missing = [];
|
||||
for ( const key of wanted ) {
|
||||
if ( pendingWrite.has(key) ) {
|
||||
outbin[key] = pendingWrite.get(key);
|
||||
} else {
|
||||
missing.push(key);
|
||||
}
|
||||
}
|
||||
if ( missing.length === 0 ) { return; }
|
||||
return api.get(missing).then(inbin => {
|
||||
inbin = inbin || {};
|
||||
const found = Object.keys(inbin);
|
||||
Object.assign(outbin, inbin);
|
||||
if ( found.length === wanted.length ) { return; }
|
||||
const missing = [];
|
||||
for ( const key of wanted ) {
|
||||
if ( hasOwnProperty(outbin, key) ) { continue; }
|
||||
missing.push(key);
|
||||
}
|
||||
return missing;
|
||||
});
|
||||
};
|
||||
|
||||
const compress = async (bin, key, data) => {
|
||||
const µbhs = µb.hiddenSettings;
|
||||
const after = await s14e.serializeAsync(data, {
|
||||
compress: µbhs.cacheStorageCompression,
|
||||
compressThreshold: µbhs.cacheStorageCompressionThreshold,
|
||||
multithreaded: µbhs.cacheStorageMultithread,
|
||||
});
|
||||
bin[key] = after;
|
||||
};
|
||||
|
||||
const decompress = async (bin, key) => {
|
||||
const data = bin[key];
|
||||
if ( s14e.isSerialized(data) === false ) { return; }
|
||||
const µbhs = µb.hiddenSettings;
|
||||
const isLarge = data.length >= µbhs.cacheStorageCompressionThreshold;
|
||||
bin[key] = await s14e.deserializeAsync(data, {
|
||||
multithreaded: isLarge && µbhs.cacheStorageMultithread || 1,
|
||||
});
|
||||
};
|
||||
|
||||
const api = {
|
||||
get(argbin) {
|
||||
const outbin = {};
|
||||
return exGet(
|
||||
cacheAPIs[fastCache],
|
||||
keysFromGetArg(argbin),
|
||||
outbin
|
||||
).then(wanted => {
|
||||
if ( wanted === undefined ) { return; }
|
||||
return exGet(extensionStorage, wanted, outbin);
|
||||
}).then(wanted => {
|
||||
if ( wanted === undefined ) { return; }
|
||||
if ( argbin instanceof Object === false ) { return; }
|
||||
if ( Array.isArray(argbin) ) { return; }
|
||||
for ( const key of wanted ) {
|
||||
if ( hasOwnProperty(argbin, key) === false ) { continue; }
|
||||
outbin[key] = argbin[key];
|
||||
}
|
||||
}).then(( ) => {
|
||||
const promises = [];
|
||||
for ( const key of Object.keys(outbin) ) {
|
||||
promises.push(decompress(outbin, key));
|
||||
}
|
||||
return Promise.all(promises).then(( ) => outbin);
|
||||
}).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
async keys(regex) {
|
||||
const results = await Promise.all([
|
||||
cacheAPIs[fastCache].keys(regex),
|
||||
extensionStorage.get(null).catch(( ) => {}),
|
||||
]);
|
||||
const keys = new Set(results[0]);
|
||||
const bin = results[1] || {};
|
||||
for ( const key of Object.keys(bin) ) {
|
||||
if ( regex && regex.test(key) === false ) { continue; }
|
||||
keys.add(key);
|
||||
}
|
||||
return keys;
|
||||
},
|
||||
|
||||
async set(rawbin) {
|
||||
const keys = Object.keys(rawbin);
|
||||
if ( keys.length === 0 ) { return; }
|
||||
ubolog('cacheStorage.set:', keys.join());
|
||||
for ( const key of keys ) {
|
||||
pendingWrite.set(key, rawbin[key]);
|
||||
}
|
||||
try {
|
||||
const serializedbin = {};
|
||||
const promises = [];
|
||||
for ( const key of keys ) {
|
||||
promises.push(compress(serializedbin, key, rawbin[key]));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await Promise.all([
|
||||
cacheAPIs[fastCache].set(rawbin, serializedbin),
|
||||
extensionStorage.set(serializedbin),
|
||||
]);
|
||||
} catch(reason) {
|
||||
ubolog(reason);
|
||||
}
|
||||
for ( const key of keys ) {
|
||||
pendingWrite.delete(key);
|
||||
}
|
||||
},
|
||||
|
||||
remove(...args) {
|
||||
cacheAPIs[fastCache].remove(...args);
|
||||
return extensionStorage.remove(...args).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
clear(...args) {
|
||||
cacheAPIs[fastCache].clear(...args);
|
||||
return extensionStorage.clear(...args).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
select(api) {
|
||||
if ( hasOwnProperty(cacheAPIs, api) === false ) { return fastCache; }
|
||||
fastCache = api;
|
||||
for ( const k of Object.keys(cacheAPIs) ) {
|
||||
if ( k === api ) { continue; }
|
||||
cacheAPIs[k]['clear']();
|
||||
}
|
||||
return fastCache;
|
||||
},
|
||||
};
|
||||
|
||||
// Not all platforms support getBytesInUse
|
||||
if ( extensionStorage.getBytesInUse instanceof Function ) {
|
||||
api.getBytesInUse = function(...args) {
|
||||
return extensionStorage.getBytesInUse(...args).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return api;
|
||||
})();
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Cache API
|
||||
*
|
||||
* Purpose is to mirror cache-related items from extension storage, as its
|
||||
* read/write operations are faster. May not be available/populated in
|
||||
* private/incognito mode.
|
||||
*
|
||||
* */
|
||||
|
||||
const cacheAPI = (( ) => {
|
||||
const caches = globalThis.caches;
|
||||
let cacheStoragePromise;
|
||||
|
||||
const getAPI = ( ) => {
|
||||
if ( cacheStoragePromise !== undefined ) { return cacheStoragePromise; }
|
||||
cacheStoragePromise = new Promise(resolve => {
|
||||
if ( typeof caches !== 'object' || caches === null ) {
|
||||
ubolog('CacheStorage API not available');
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
resolve(caches.open(STORAGE_NAME));
|
||||
}).catch(reason => {
|
||||
ubolog(reason);
|
||||
return null;
|
||||
});
|
||||
return cacheStoragePromise;
|
||||
};
|
||||
|
||||
const urlPrefix = 'https://ublock0.invalid/';
|
||||
|
||||
const keyToURL = key =>
|
||||
`${urlPrefix}${encodeURIComponent(key)}`;
|
||||
|
||||
const urlToKey = url =>
|
||||
decodeURIComponent(url.slice(urlPrefix.length));
|
||||
|
||||
// Cache API is subject to quota so we will use it only for what is key
|
||||
// performance-wise
|
||||
const shouldCache = bin => {
|
||||
const out = {};
|
||||
for ( const key of Object.keys(bin) ) {
|
||||
if ( key.startsWith('cache/' ) ) {
|
||||
if ( /^cache\/(compiled|selfie)\//.test(key) === false ) { continue; }
|
||||
}
|
||||
out[key] = bin[key];
|
||||
}
|
||||
if ( Object.keys(out).length !== 0 ) { return out; }
|
||||
};
|
||||
|
||||
const getOne = async key => {
|
||||
const cache = await getAPI();
|
||||
if ( cache === null ) { return; }
|
||||
return cache.match(keyToURL(key)).then(response => {
|
||||
if ( response === undefined ) { return; }
|
||||
return response.text();
|
||||
}).then(text => {
|
||||
if ( text === undefined ) { return; }
|
||||
return { key, text };
|
||||
}).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
|
||||
const getAll = async ( ) => {
|
||||
const cache = await getAPI();
|
||||
if ( cache === null ) { return; }
|
||||
return cache.keys().then(requests => {
|
||||
const promises = [];
|
||||
for ( const request of requests ) {
|
||||
promises.push(getOne(urlToKey(request.url)));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}).then(responses => {
|
||||
const bin = {};
|
||||
for ( const response of responses ) {
|
||||
if ( response === undefined ) { continue; }
|
||||
bin[response.key] = response.text;
|
||||
}
|
||||
return bin;
|
||||
}).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
|
||||
const setOne = async (key, text) => {
|
||||
if ( text === undefined ) { return removeOne(key); }
|
||||
const blob = new Blob([ text ], { type: 'text/plain;charset=utf-8'});
|
||||
const cache = await getAPI();
|
||||
if ( cache === null ) { return; }
|
||||
return cache
|
||||
.put(keyToURL(key), new Response(blob))
|
||||
.catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
|
||||
const removeOne = async key => {
|
||||
const cache = await getAPI();
|
||||
if ( cache === null ) { return; }
|
||||
return cache.delete(keyToURL(key)).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'cacheAPI',
|
||||
async get(arg) {
|
||||
const keys = keysFromGetArg(arg);
|
||||
if ( keys === undefined ) { return; }
|
||||
if ( keys.length === 0 ) {
|
||||
return getAll();
|
||||
}
|
||||
const bin = {};
|
||||
const toFetch = keys.slice();
|
||||
const hasDefault = typeof arg === 'object' && Array.isArray(arg) === false;
|
||||
for ( let i = 0; i < toFetch.length; i++ ) {
|
||||
const key = toFetch[i];
|
||||
if ( hasDefault && arg[key] !== undefined ) {
|
||||
bin[key] = arg[key];
|
||||
}
|
||||
toFetch[i] = getOne(key);
|
||||
}
|
||||
const responses = await Promise.all(toFetch);
|
||||
for ( const response of responses ) {
|
||||
if ( response === undefined ) { continue; }
|
||||
const { key, text } = response;
|
||||
if ( typeof key !== 'string' ) { continue; }
|
||||
if ( typeof text !== 'string' ) { continue; }
|
||||
bin[key] = text;
|
||||
}
|
||||
if ( Object.keys(bin).length === 0 ) { return; }
|
||||
return bin;
|
||||
},
|
||||
|
||||
async keys(regex) {
|
||||
const cache = await getAPI();
|
||||
if ( cache === null ) { return []; }
|
||||
return cache.keys().then(requests =>
|
||||
requests.map(r => urlToKey(r.url))
|
||||
.filter(k => regex === undefined || regex.test(k))
|
||||
).catch(( ) => []);
|
||||
},
|
||||
|
||||
async set(rawbin, serializedbin) {
|
||||
const bin = shouldCache(serializedbin);
|
||||
if ( bin === undefined ) { return; }
|
||||
const keys = Object.keys(bin);
|
||||
const promises = [];
|
||||
for ( const key of keys ) {
|
||||
promises.push(setOne(key, bin[key]));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
remove(keys) {
|
||||
const toRemove = [];
|
||||
if ( typeof keys === 'string' ) {
|
||||
toRemove.push(removeOne(keys));
|
||||
} else if ( Array.isArray(keys) ) {
|
||||
for ( const key of keys ) {
|
||||
toRemove.push(removeOne(key));
|
||||
}
|
||||
}
|
||||
return Promise.all(toRemove);
|
||||
},
|
||||
|
||||
async clear() {
|
||||
if ( typeof caches !== 'object' || caches === null ) { return; }
|
||||
return globalThis.caches.delete(STORAGE_NAME).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
shutdown() {
|
||||
cacheStoragePromise = undefined;
|
||||
return this.clear();
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* In-memory storage
|
||||
*
|
||||
* */
|
||||
|
||||
const memoryStorage = (( ) => {
|
||||
|
||||
const sessionStorage = vAPI.sessionStorage;
|
||||
|
||||
// This should help speed up loading from suspended state in Firefox for
|
||||
// Android.
|
||||
// 20240228 Observation: Slows down loading from suspended state in
|
||||
// Firefox desktop. Could be different in Firefox for Android.
|
||||
const shouldCache = bin => {
|
||||
const out = {};
|
||||
for ( const key of Object.keys(bin) ) {
|
||||
if ( key.startsWith('cache/compiled/') ) { continue; }
|
||||
out[key] = bin[key];
|
||||
}
|
||||
if ( Object.keys(out).length !== 0 ) { return out; }
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'memoryStorage',
|
||||
get(...args) {
|
||||
return sessionStorage.get(...args).then(bin => {
|
||||
return bin;
|
||||
}).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
async keys(regex) {
|
||||
const bin = await this.get(null);
|
||||
const keys = [];
|
||||
for ( const key of Object.keys(bin || {}) ) {
|
||||
if ( regex && regex.test(key) === false ) { continue; }
|
||||
keys.push(key);
|
||||
}
|
||||
return keys;
|
||||
},
|
||||
|
||||
async set(rawbin, serializedbin) {
|
||||
const bin = shouldCache(serializedbin);
|
||||
if ( bin === undefined ) { return; }
|
||||
return sessionStorage.set(bin).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
remove(...args) {
|
||||
return sessionStorage.remove(...args).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
clear(...args) {
|
||||
return sessionStorage.clear(...args).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
},
|
||||
|
||||
shutdown() {
|
||||
return this.clear();
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* IndexedDB
|
||||
*
|
||||
* Deprecated, exists only for the purpose of migrating from older versions.
|
||||
*
|
||||
* */
|
||||
|
||||
const idbStorage = (( ) => {
|
||||
let dbPromise;
|
||||
|
||||
const getDb = function() {
|
||||
if ( dbPromise !== undefined ) { return dbPromise; }
|
||||
dbPromise = new Promise(resolve => {
|
||||
const req = indexedDB.open(STORAGE_NAME, 1);
|
||||
req.onupgradeneeded = ev => {
|
||||
if ( ev.oldVersion === 1 ) { return; }
|
||||
try {
|
||||
const db = ev.target.result;
|
||||
db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
||||
} catch(ex) {
|
||||
req.onerror();
|
||||
}
|
||||
};
|
||||
req.onsuccess = ev => {
|
||||
if ( resolve === undefined ) { return; }
|
||||
resolve(ev.target.result || null);
|
||||
resolve = undefined;
|
||||
};
|
||||
req.onerror = req.onblocked = ( ) => {
|
||||
if ( resolve === undefined ) { return; }
|
||||
ubolog(req.error);
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
};
|
||||
vAPI.defer.once(10000).then(( ) => {
|
||||
if ( resolve === undefined ) { return; }
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
});
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / getDb() failed: ${reason}`);
|
||||
return null;
|
||||
});
|
||||
return dbPromise;
|
||||
};
|
||||
|
||||
// Cache API is subject to quota so we will use it only for what is key
|
||||
// performance-wise
|
||||
const shouldCache = key => {
|
||||
if ( key.startsWith('cache/') === false ) { return true; }
|
||||
return /^cache\/(compiled|selfie)\//.test(key);
|
||||
};
|
||||
|
||||
const getAllEntries = async function() {
|
||||
const db = await getDb();
|
||||
if ( db === null ) { return []; }
|
||||
return new Promise(resolve => {
|
||||
const entries = [];
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
resolve(Promise.all(entries));
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
const req = table.openCursor();
|
||||
req.onsuccess = ev => {
|
||||
const cursor = ev.target && ev.target.result;
|
||||
if ( !cursor ) { return; }
|
||||
const { key, value } = cursor.value;
|
||||
if ( value instanceof Blob === false ) {
|
||||
entries.push({ key, value });
|
||||
}
|
||||
cursor.continue();
|
||||
};
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / getAllEntries() failed: ${reason}`);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
const getAllKeys = async function(regex) {
|
||||
const db = await getDb();
|
||||
if ( db === null ) { return []; }
|
||||
return new Promise(resolve => {
|
||||
const keys = [];
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
resolve(keys);
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
const req = table.openCursor();
|
||||
req.onsuccess = ev => {
|
||||
const cursor = ev.target && ev.target.result;
|
||||
if ( !cursor ) { return; }
|
||||
if ( regex && regex.test(cursor.key) === false ) { return; }
|
||||
keys.push(cursor.key);
|
||||
cursor.continue();
|
||||
};
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / getAllKeys() failed: ${reason}`);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
const getEntries = async function(keys) {
|
||||
const db = await getDb();
|
||||
if ( db === null ) { return []; }
|
||||
return new Promise(resolve => {
|
||||
const entries = [];
|
||||
const gotOne = ev => {
|
||||
const { result } = ev.target;
|
||||
if ( typeof result !== 'object' ) { return; }
|
||||
if ( result === null ) { return; }
|
||||
const { key, value } = result;
|
||||
if ( value instanceof Blob ) { return; }
|
||||
entries.push({ key, value });
|
||||
};
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
resolve(Promise.all(entries));
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const key of keys ) {
|
||||
const req = table.get(key);
|
||||
req.onsuccess = gotOne;
|
||||
req.onerror = ( ) => { };
|
||||
}
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / getEntries() failed: ${reason}`);
|
||||
return [];
|
||||
});
|
||||
};
|
||||
|
||||
const getAll = async ( ) => {
|
||||
const entries = await getAllEntries();
|
||||
const outbin = {};
|
||||
for ( const { key, value } of entries ) {
|
||||
outbin[key] = value;
|
||||
}
|
||||
return outbin;
|
||||
};
|
||||
|
||||
const setEntries = async inbin => {
|
||||
const keys = Object.keys(inbin);
|
||||
if ( keys.length === 0 ) { return; }
|
||||
const db = await getDb();
|
||||
if ( db === null ) { return; }
|
||||
return new Promise(resolve => {
|
||||
const entries = [];
|
||||
for ( const key of keys ) {
|
||||
entries.push({ key, value: inbin[key] });
|
||||
}
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
resolve();
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const entry of entries ) {
|
||||
table.put(entry);
|
||||
}
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / setEntries() failed: ${reason}`);
|
||||
});
|
||||
};
|
||||
|
||||
const deleteEntries = async arg => {
|
||||
const keys = Array.isArray(arg) ? arg.slice() : [ arg ];
|
||||
if ( keys.length === 0 ) { return; }
|
||||
const db = await getDb();
|
||||
if ( db === null ) { return; }
|
||||
return new Promise(resolve => {
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
resolve();
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const key of keys ) {
|
||||
table.delete(key);
|
||||
}
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage() / deleteEntries() failed: ${reason}`);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'idbStorage',
|
||||
async get(argbin) {
|
||||
const keys = keysFromGetArg(argbin);
|
||||
if ( keys === undefined ) { return; }
|
||||
if ( keys.length === 0 ) { return getAll(); }
|
||||
const entries = await getEntries(keys);
|
||||
const outbin = {};
|
||||
const toRemove = [];
|
||||
for ( const { key, value } of entries ) {
|
||||
if ( shouldCache(key) === false ) {
|
||||
toRemove.push(key);
|
||||
continue;
|
||||
}
|
||||
outbin[key] = value;
|
||||
}
|
||||
if ( argbin instanceof Object && Array.isArray(argbin) === false ) {
|
||||
for ( const key of keys ) {
|
||||
if ( hasOwnProperty(outbin, key) ) { continue; }
|
||||
outbin[key] = argbin[key];
|
||||
}
|
||||
}
|
||||
if ( toRemove.length !== 0 ) {
|
||||
deleteEntries(toRemove);
|
||||
}
|
||||
return outbin;
|
||||
},
|
||||
|
||||
async set(rawbin) {
|
||||
const bin = {};
|
||||
for ( const key of Object.keys(rawbin) ) {
|
||||
if ( shouldCache(key) === false ) { continue; }
|
||||
bin[key] = rawbin[key];
|
||||
}
|
||||
return setEntries(bin);
|
||||
},
|
||||
|
||||
keys(...args) {
|
||||
return getAllKeys(...args);
|
||||
},
|
||||
|
||||
remove(...args) {
|
||||
return deleteEntries(...args);
|
||||
},
|
||||
|
||||
clear() {
|
||||
return getDb().then(db => {
|
||||
if ( db === null ) { return; }
|
||||
db.close();
|
||||
indexedDB.deleteDatabase(STORAGE_NAME);
|
||||
}).catch(reason => {
|
||||
ubolog(`idbStorage.clear() failed: ${reason}`);
|
||||
});
|
||||
},
|
||||
|
||||
async shutdown() {
|
||||
await this.clear();
|
||||
dbPromise = undefined;
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const cacheAPIs = {
|
||||
'indexedDB': idbStorage,
|
||||
'cacheAPI': cacheAPI,
|
||||
'browser.storage.session': memoryStorage,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export default cacheStorage;
|
||||
|
||||
/******************************************************************************/
|
||||
Reference in New Issue
Block a user