cleanup usoSearchCache + tidy up db.js

This commit is contained in:
tophf 2020-10-07 10:47:51 +03:00
parent a01bd3cd61
commit b840d4897d
2 changed files with 77 additions and 114 deletions

View File

@ -1,5 +1,5 @@
/* global download prefs openURL FIREFOX CHROME /* global download prefs openURL FIREFOX CHROME
URLS ignoreChromeError usercssHelper URLS ignoreChromeError usercssHelper chromeLocal semverCompare
styleManager msg navigatorUtil workerUtil contentScripts sync styleManager msg navigatorUtil workerUtil contentScripts sync
findExistingTab activateTab isTabReplaceable getActiveTab findExistingTab activateTab isTabReplaceable getActiveTab
tabManager */ tabManager */
@ -139,7 +139,7 @@ if (chrome.commands) {
} }
// ************************************************************************* // *************************************************************************
chrome.runtime.onInstalled.addListener(({reason}) => { chrome.runtime.onInstalled.addListener(({reason, previousVersion}) => {
// save install type: "admin", "development", "normal", "sideload" or "other" // save install type: "admin", "development", "normal", "sideload" or "other"
// "normal" = addon installed from webstore // "normal" = addon installed from webstore
chrome.management.getSelf(info => { chrome.management.getSelf(info => {
@ -156,6 +156,14 @@ chrome.runtime.onInstalled.addListener(({reason}) => {
}); });
// themes may change // themes may change
delete localStorage.codeMirrorThemes; delete localStorage.codeMirrorThemes;
// inline search cache for USO is not needed anymore, TODO: remove this by the middle of 2021
if (semverCompare(previousVersion, '1.5.13') <= 0) {
setTimeout(async () => {
const del = Object.keys(await chromeLocal.get())
.filter(key => key.startsWith('usoSearchCache'));
if (del.length) chromeLocal.remove(del);
}, 15e3);
}
}); });
// ************************************************************************* // *************************************************************************

View File

@ -1,4 +1,4 @@
/* global chromeLocal ignoreChromeError workerUtil createChromeStorageDB */ /* global chromeLocal workerUtil createChromeStorageDB */
/* exported db */ /* exported db */
/* /*
Initialize a database. There are some problems using IndexedDB in Firefox: Initialize a database. There are some problems using IndexedDB in Firefox:
@ -10,29 +10,18 @@ https://www.reddit.com/r/firefox/comments/7ijuaq/firefox_59_webextensions_can_us
'use strict'; 'use strict';
const db = (() => { const db = (() => {
let exec; const DATABASE = 'stylish';
const preparing = prepare(); const STORE = 'styles';
return { const FALLBACK = 'dbInChromeStorage';
exec: (...args) => const dbApi = {
preparing.then(() => exec(...args)) async exec(...args) {
}; dbApi.exec = await tryUsingIndexedDB().catch(useChromeStorage);
return dbApi.exec(...args);
function prepare() {
return withPromise(shouldUseIndexedDB).then(
ok => {
if (ok) {
useIndexedDB();
} else {
useChromeStorage();
}
}, },
err => { };
useChromeStorage(err); return dbApi;
}
);
}
function shouldUseIndexedDB() { async function tryUsingIndexedDB() {
// we use chrome.storage.local fallback if IndexedDB doesn't save data, // we use chrome.storage.local fallback if IndexedDB doesn't save data,
// which, once detected on the first run, is remembered in chrome.storage.local // which, once detected on the first run, is remembered in chrome.storage.local
// for reliablility and in localStorage for fast synchronous access // for reliablility and in localStorage for fast synchronous access
@ -42,86 +31,53 @@ const db = (() => {
if (typeof indexedDB === 'undefined') { if (typeof indexedDB === 'undefined') {
throw new Error('indexedDB is undefined'); throw new Error('indexedDB is undefined');
} }
// test localStorage switch (await getFallback()) {
const fallbackSet = localStorage.dbInChromeStorage; case true: throw null;
if (fallbackSet === 'true') { case false: break;
return false; default: await testDB();
} }
if (fallbackSet === 'false') { return useIndexedDB();
return true;
}
// test storage.local
return chromeLocal.get('dbInChromeStorage')
.then(data => {
if (data && data.dbInChromeStorage) {
return false;
}
return testDBSize()
.then(ok => ok || testDBMutation());
});
} }
function withPromise(fn) { async function getFallback() {
try { return localStorage[FALLBACK] === 'true' ? true :
return Promise.resolve(fn()); localStorage[FALLBACK] === 'false' ? false :
} catch (err) { chromeLocal.getValue(FALLBACK);
return Promise.reject(err);
}
} }
function testDBSize() { async function testDB() {
return dbExecIndexedDB('getAllKeys', IDBKeyRange.lowerBound(1), 1) let e = await dbExecIndexedDB('getAllKeys', IDBKeyRange.lowerBound(1), 1);
.then(event => ( // throws if result is null
event.target.result && e = e.target.result[0];
event.target.result.length && const id = `${performance.now()}.${Math.random()}.${Date.now()}`;
event.target.result[0] await dbExecIndexedDB('put', {id});
)); e = await dbExecIndexedDB('get', id);
} // throws if result or id is null
await dbExecIndexedDB('delete', e.target.result.id);
function testDBMutation() {
return dbExecIndexedDB('put', {id: -1})
.then(() => dbExecIndexedDB('get', -1))
.then(event => {
if (!event.target.result) {
throw new Error('failed to get previously put item');
}
if (event.target.result.id !== -1) {
throw new Error('item id is wrong');
}
return dbExecIndexedDB('delete', -1);
})
.then(() => true);
} }
function useChromeStorage(err) { function useChromeStorage(err) {
exec = createChromeStorageDB().exec; chromeLocal.setValue(FALLBACK, true);
chromeLocal.set({dbInChromeStorage: true}, ignoreChromeError);
if (err) { if (err) {
chromeLocal.setValue('dbInChromeStorageReason', workerUtil.cloneError(err)); chromeLocal.setValue(FALLBACK + 'Reason', workerUtil.cloneError(err));
console.warn('Failed to access indexedDB. Switched to storage API.', err); console.warn('Failed to access indexedDB. Switched to storage API.', err);
} }
localStorage.dbInChromeStorage = 'true'; localStorage[FALLBACK] = 'true';
return createChromeStorageDB().exec;
} }
function useIndexedDB() { function useIndexedDB() {
exec = dbExecIndexedDB; chromeLocal.setValue(FALLBACK, false);
chromeLocal.set({dbInChromeStorage: false}, ignoreChromeError); localStorage[FALLBACK] = 'false';
localStorage.dbInChromeStorage = 'false'; return dbExecIndexedDB;
} }
function dbExecIndexedDB(method, ...args) { async function dbExecIndexedDB(method, ...args) {
return open().then(database => {
if (!method) {
return database;
}
if (method === 'putMany') {
return putMany(database, ...args);
}
const mode = method.startsWith('get') ? 'readonly' : 'readwrite'; const mode = method.startsWith('get') ? 'readonly' : 'readwrite';
const transaction = database.transaction(['styles'], mode); const store = (await open()).transaction([STORE], mode).objectStore(STORE);
const store = transaction.objectStore('styles'); const fn = method === 'putMany' ? putMany : storeRequest;
return storeRequest(store, method, ...args); return fn(store, method, ...args);
}); }
function storeRequest(store, method, ...args) { function storeRequest(store, method, ...args) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -131,26 +87,25 @@ const db = (() => {
}); });
} }
function putMany(store, _method, items) {
return Promise.all(items.map(item => storeRequest(store, 'put', item)));
}
function open() { function open() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = indexedDB.open('stylish', 2); const request = indexedDB.open(DATABASE, 2);
request.onsuccess = () => resolve(request.result); request.onsuccess = () => resolve(request.result);
request.onerror = reject; request.onerror = reject;
request.onupgradeneeded = event => { request.onupgradeneeded = create;
});
}
function create(event) {
if (event.oldVersion === 0) { if (event.oldVersion === 0) {
event.target.result.createObjectStore('styles', { event.target.result.createObjectStore(STORE, {
keyPath: 'id', keyPath: 'id',
autoIncrement: true, autoIncrement: true,
}); });
} }
};
});
}
function putMany(database, items) {
const transaction = database.transaction(['styles'], 'readwrite');
const store = transaction.objectStore('styles');
return Promise.all(items.map(item => storeRequest(store, 'put', item)));
}
} }
})(); })();