diff --git a/background/background.js b/background/background.js index c8481c9c..407e944d 100644 --- a/background/background.js +++ b/background/background.js @@ -38,11 +38,7 @@ addAPI(/** @namespace API */ { }, }))(), - /** @type IDBObjectStore */ - drafts: new Proxy({}, { - get: (_, cmd) => (...args) => db.exec.call('drafts', cmd, ...args), - }), - + drafts: db.open('drafts'), styles: styleMan, sync: syncMan, updater: updateMan, diff --git a/background/db-chrome-storage.js b/background/db-chrome-storage.js index 685f0905..416e9c09 100644 --- a/background/db-chrome-storage.js +++ b/background/db-chrome-storage.js @@ -4,6 +4,8 @@ /* exported createChromeStorageDB */ function createChromeStorageDB(PREFIX) { let INC; + const isMain = !PREFIX; + if (!PREFIX) PREFIX = 'style-'; return { @@ -19,7 +21,9 @@ function createChromeStorageDB(PREFIX) { const all = await chromeLocal.get(); if (!INC) prepareInc(all); return Object.entries(all) - .map(([key, val]) => key.startsWith(PREFIX) && Number(key.slice(PREFIX.length)) && val) + .map(([key, val]) => key.startsWith(PREFIX) && + (!isMain || Number(key.slice(PREFIX.length))) && + val) .filter(Boolean); }, diff --git a/background/db.js b/background/db.js index 51d74cde..32f405f1 100644 --- a/background/db.js +++ b/background/db.js @@ -11,16 +11,28 @@ /* exported db */ const db = (() => { - const DATABASE = 'stylish'; - const STORE = 'styles'; + let exec = async (...args) => ( + exec = await tryUsingIndexedDB().catch(useChromeStorage) + )(...args); + const DB = 'stylish'; const FALLBACK = 'dbInChromeStorage'; - const dbApi = { - async exec(...args) { - dbApi.exec = await tryUsingIndexedDB().catch(useChromeStorage); - return dbApi.exec(...args); - }, + const proxies = {}; + const proxyHandler = { + get: ({dbName}, cmd) => (...args) => exec(dbName, cmd, ...args), + }; + const getProxy = (dbName = DB) => + /** @type {IDBObjectStore | {putMany: function(items:?[]):Promise}} */ + proxies[dbName] || ( + proxies[dbName] = new Proxy({dbName}, proxyHandler) + ); + const getStoreName = dbName => + dbName === DB + ? 'styles' + : 'data'; + return { + styles: getProxy(), + open: getProxy, }; - return dbApi; async function tryUsingIndexedDB() { // we use chrome.storage.local fallback if IndexedDB doesn't save data, @@ -40,9 +52,9 @@ const db = (() => { async function testDB() { const id = `${performance.now()}.${Math.random()}.${Date.now()}`; - await dbExecIndexedDB('put', {id}); - const e = await dbExecIndexedDB('get', id); - await dbExecIndexedDB('delete', e.id); // throws if `e` or id is null + await dbExecIndexedDB(DB, 'put', {id}); + const e = await dbExecIndexedDB(DB, 'get', id); + await dbExecIndexedDB(DB, 'delete', e.id); // throws if `e` or id is null } async function useChromeStorage(err) { @@ -53,17 +65,17 @@ const db = (() => { } await require(['/background/db-chrome-storage']); /* global createChromeStorageDB */ const BASES = {}; - return function dbExecChromeStorage(method, ...args) { - const prefix = Object(this) instanceof String ? `${this}-` : 'style-'; - const baseApi = BASES[prefix] || (BASES[prefix] = createChromeStorageDB(prefix)); - return baseApi[method](...args); - }; + return (dbName, method, ...args) => ( + BASES[dbName] || ( + BASES[dbName] = createChromeStorageDB(dbName !== DB && `${dbName}-`) + ) + )[method](...args); } - async function dbExecIndexedDB(method, ...args) { + async function dbExecIndexedDB(dbName, method, ...args) { const mode = method.startsWith('get') ? 'readonly' : 'readwrite'; - const dbName = Object(this) instanceof String ? `${this}` : DATABASE; - const store = (await open(dbName)).transaction([STORE], mode).objectStore(STORE); + const storeName = getStoreName(dbName); + const store = (await open(dbName)).transaction([storeName], mode).objectStore(storeName); const fn = method === 'putMany' ? putMany : storeRequest; return fn(store, method, ...args); } @@ -92,7 +104,8 @@ const db = (() => { function create(event) { if (event.oldVersion === 0) { - event.target.result.createObjectStore(STORE, { + const idb = event.target.result; + idb.createObjectStore(getStoreName(idb.name), { keyPath: 'id', autoIncrement: true, }); diff --git a/background/style-manager.js b/background/style-manager.js index bece32ad..8b85d813 100644 --- a/background/style-manager.js +++ b/background/style-manager.js @@ -105,7 +105,7 @@ const styleMan = (() => { if (ready.then) await ready; const data = id2data(id); const {style, appliesTo} = data; - await db.exec('delete', id); + db.styles.delete(id); if (reason !== 'sync') { API.sync.delete(style._id, Date.now()); } @@ -251,7 +251,7 @@ const styleMan = (() => { await usercssMan.buildCode(style); } } - const events = await db.exec('putMany', items); + const events = await db.styles.putMany(items); return Promise.all(items.map((item, i) => handleSave(item, {reason: 'import'}, events[i]) )); @@ -437,7 +437,7 @@ const styleMan = (() => { async function saveStyle(style, handlingOptions) { beforeSave(style); - const newId = await db.exec('put', style); + const newId = await db.styles.put(style); return handleSave(style, handlingOptions, newId); } @@ -477,10 +477,10 @@ const styleMan = (() => { } async function init() { - const styles = await db.exec('getAll') || []; + const styles = await db.styles.getAll() || []; const updated = await Promise.all(styles.map(fixKnownProblems).filter(Boolean)); if (updated.length) { - await db.exec('putMany', updated); + await db.styles.putMany(updated); } styles.forEach(storeInMap); ready = true; diff --git a/background/sync-manager.js b/background/sync-manager.js index 5ce5be4c..1d448d8c 100644 --- a/background/sync-manager.js +++ b/background/sync-manager.js @@ -209,7 +209,7 @@ const syncMan = (() => { } } if (diff < 0) { - doc.id = await db.exec('put', doc); + doc.id = await db.styles.put(doc); uuidIndex.set(doc._id, doc.id); return styleUtil.handleSave(doc, {reason: 'sync'}); } diff --git a/background/update-manager.js b/background/update-manager.js index 0796e4af..2e1261d2 100644 --- a/background/update-manager.js +++ b/background/update-manager.js @@ -234,7 +234,7 @@ const updateMan = (() => { if (err && etag && !style.etag) { // first check of ETAG, gonna write it directly to DB as it's too trivial to sync or announce style.etag = etag; - await db.exec('put', style); + await db.styles.put(style); } return err ? Promise.reject(err)