simplify uuidIndex and setOrder

This commit is contained in:
tophf 2022-01-24 03:27:18 +03:00
parent 264518a5c4
commit 95869d0337
2 changed files with 55 additions and 68 deletions

View File

@ -26,6 +26,7 @@ const styleMan = (() => {
Object.assign(styleUtil, { Object.assign(styleUtil, {
id2style, id2style,
handleSave, handleSave,
uuid2style,
}); });
//#region Declarations //#region Declarations
@ -66,16 +67,16 @@ const styleMan = (() => {
const DELETE_IF_NULL = ['id', 'customName', 'md5Url', 'originalMd5']; const DELETE_IF_NULL = ['id', 'customName', 'md5Url', 'originalMd5'];
const INJ_ORDER = 'injectionOrder'; const INJ_ORDER = 'injectionOrder';
const order = {main: {}, prio: {}}; const order = {main: {}, prio: {}};
const orderForDb = { const orderWrap = {
id: INJ_ORDER, id: INJ_ORDER,
value: mapObj(order, () => []),
_id: `${chrome.runtime.id}-${INJ_ORDER}`, _id: `${chrome.runtime.id}-${INJ_ORDER}`,
get value() { _rev: 0,
return mapObj(order, group => sortObjectKeysByValue(group, id2uuid));
},
set value(val) {
setOrderFromArray(val);
},
}; };
uuidIndex.custom = Object.defineProperty({}, INJ_ORDER, {
get: () => orderWrap,
set: setOrder,
});
/** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */ /** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */
let ready = init(); let ready = init();
@ -105,15 +106,21 @@ const styleMan = (() => {
if (ready.then) await ready; if (ready.then) await ready;
const {style, appliesTo} = dataMap.get(id); const {style, appliesTo} = dataMap.get(id);
const sync = reason !== 'sync'; const sync = reason !== 'sync';
const uuid = style._id;
db.styles.delete(id); db.styles.delete(id);
if (sync) API.sync.delete(style._id, Date.now()); if (sync) API.sync.delete(uuid, Date.now());
for (const url of appliesTo) { for (const url of appliesTo) {
const cache = cachedStyleForUrl.get(url); const cache = cachedStyleForUrl.get(url);
if (cache) delete cache.sections[id]; if (cache) delete cache.sections[id];
} }
dataMap.delete(id); dataMap.delete(id);
mapObj(order, val => delete val[id]); uuidIndex.delete(uuid);
setOrder(orderForDb.value, {sync}); mapObj(orderWrap.value, (group, type) => {
delete order[type][id];
const i = group.indexOf(uuid);
if (i >= 0) group.splice(i, 1);
});
setOrder(orderWrap, {calc: false});
if (style._usw && style._usw.token) { if (style._usw && style._usw.token) {
// Must be called after the style is deleted from dataMap // Must be called after the style is deleted from dataMap
API.usw.revoke(id); API.usw.revoke(id);
@ -155,7 +162,7 @@ const styleMan = (() => {
/** @returns {Promise<Object<string,StyleObj[]>>}>} */ /** @returns {Promise<Object<string,StyleObj[]>>}>} */
async getAllOrdered() { async getAllOrdered() {
if (ready.then) await ready; if (ready.then) await ready;
const res = mapObj(order, group => sortObjectKeysByValue(group, id2style)); const res = mapObj(orderWrap.value, group => group.map(uuid2style));
if (res.main.length + res.prio.length < dataMap.size) { if (res.main.length + res.prio.length < dataMap.size) {
for (const {style} of dataMap.values()) { for (const {style} of dataMap.values()) {
if (!(style.id in order.main) && !(style.id in order.prio)) { if (!(style.id in order.main) && !(style.id in order.prio)) {
@ -283,11 +290,9 @@ const styleMan = (() => {
save: saveStyle, save: saveStyle,
async setOrder(val) { async setOrder(value) {
if (ready.then) await ready; if (ready.then) await ready;
return val && return setOrder({value}, {broadcast: true, sync: true});
!deepEqual(val, order) &&
setOrder(val, {broadcast: true, sync: true});
}, },
/** @returns {Promise<number>} style id */ /** @returns {Promise<number>} style id */
@ -331,8 +336,8 @@ const styleMan = (() => {
} }
/** @returns {?string} */ /** @returns {?string} */
function id2uuid(id) { function uuid2style(uuid) {
return (id2style(id) || {})._id; return id2style(uuidIndex.get(uuid));
} }
/** @returns {StyleObj} */ /** @returns {StyleObj} */
@ -505,12 +510,8 @@ const styleMan = (() => {
if (updated.length) { if (updated.length) {
await db.styles.putMany(updated); await db.styles.putMany(updated);
} }
setOrder(await orderPromise, {store: false});
styles.forEach(storeInMap); styles.forEach(storeInMap);
Object.assign(orderForDb, await orderPromise);
API.sync.registerDoc(orderForDb, doc => {
Object.assign(orderForDb, doc);
setOrder();
});
ready = true; ready = true;
bgReady._resolveStyles(); bgReady._resolveStyles();
} }
@ -718,29 +719,29 @@ const styleMan = (() => {
return (num + 0x10000).toString(16).slice(-4) + (i >= 1 && i <= 4 ? '-' : ''); return (num + 0x10000).toString(16).slice(-4) + (i >= 1 && i <= 4 ? '-' : '');
} }
async function setOrder(val, {broadcast, store = true, sync} = {}) { async function setOrder(data, {broadcast, calc = true, store = true, sync} = {}) {
if (val) { if (!data || !data.value || deepEqual(data.value, orderWrap.value)) {
setOrderFromArray(val); return;
orderForDb._rev = Date.now(); }
Object.assign(orderWrap, data, sync && {_rev: Date.now()});
if (calc) {
for (const [type, group] of Object.entries(data.value)) {
const dst = order[type] = {};
group.forEach((uuid, i) => {
const id = uuidIndex.get(uuid);
if (id) dst[id] = i;
});
}
}
if (broadcast) {
msg.broadcast({method: 'styleSort', order});
}
if (store) {
await db.open(prefs.STORAGE_KEY).put(orderWrap);
}
if (sync) {
API.sync.putDoc(orderWrap);
} }
if (broadcast) msg.broadcast({method: 'styleSort', order});
if (store) await db.open(prefs.STORAGE_KEY).put(orderForDb);
if (sync) API.sync.putDoc(orderForDb);
}
function setOrderFromArray(newOrder) {
mapObj(order, (_, type) => {
const res = order[type] = {};
(newOrder && newOrder[type] || []).forEach((uid, i) => {
const id = uuidIndex.get(uid);
if (id) res[id] = i;
});
});
}
/** Since JS object's numeric keys are sorted in ascending order, we have to re-sort by value */
function sortObjectKeysByValue(obj, map) {
return Object.entries(obj).sort((a, b) => a[1] - b[1]).map(e => map(e[0]));
} }
//#endregion //#endregion

View File

@ -1,5 +1,5 @@
/* global API msg */// msg.js /* global API msg */// msg.js
/* global uuidIndex */// common.js /* global bgReady uuidIndex */// common.js
/* global chromeLocal chromeSync */// storage-util.js /* global chromeLocal chromeSync */// storage-util.js
/* global db */ /* global db */
/* global iconMan */ /* global iconMan */
@ -30,13 +30,12 @@ const syncMan = (() => {
errorMessage: null, errorMessage: null,
login: false, login: false,
}; };
const customDocs = {};
const compareRevision = (rev1, rev2) => rev1 - rev2; const compareRevision = (rev1, rev2) => rev1 - rev2;
let lastError = null; let lastError = null;
let ctrl; let ctrl;
let currentDrive; let currentDrive;
/** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */ /** @type {Promise|boolean} will be `true` to avoid wasting a microtask tick on each `await` */
let ready = prefs.ready.then(() => { let ready = bgReady.styles.then(() => {
ready = true; ready = true;
prefs.subscribe('sync.enabled', prefs.subscribe('sync.enabled',
(_, val) => val === 'none' (_, val) => val === 'none'
@ -58,7 +57,6 @@ const syncMan = (() => {
async delete(_id, rev) { async delete(_id, rev) {
if (ready.then) await ready; if (ready.then) await ready;
uuidIndex.delete(_id);
if (!currentDrive) return; if (!currentDrive) return;
schedule(); schedule();
return ctrl.delete(_id, rev); return ctrl.delete(_id, rev);
@ -84,22 +82,13 @@ const syncMan = (() => {
} }
}, },
async putDoc({id, _id, _rev}) { async putDoc({_id, _rev}) {
if (ready.then) await ready; if (ready.then) await ready;
uuidIndex.set(_id, id);
if (!currentDrive) return; if (!currentDrive) return;
schedule(); schedule();
return ctrl.put(_id, _rev); return ctrl.put(_id, _rev);
}, },
registerDoc(doc, setter) {
uuidIndex.set(doc._id, doc.id);
Object.defineProperty(customDocs, doc.id, {
get: () => doc,
set: setter,
});
},
async setDriveOptions(driveName, options) { async setDriveOptions(driveName, options) {
const key = `secure/sync/driveOptions/${driveName}`; const key = `secure/sync/driveOptions/${driveName}`;
await chromeSync.setValue(key, options); await chromeSync.setValue(key, options);
@ -192,19 +181,17 @@ const syncMan = (() => {
async function initController() { async function initController() {
await require(['/vendor/db-to-cloud/db-to-cloud.min']); /* global dbToCloud */ await require(['/vendor/db-to-cloud/db-to-cloud.min']); /* global dbToCloud */
ctrl = dbToCloud.dbToCloud({ ctrl = dbToCloud.dbToCloud({
onGet(uuid) { onGet: styleUtil.uuid2style,
return styleUtil.id2style(uuidIndex.get(uuid));
},
async onPut(doc) { async onPut(doc) {
const id = uuidIndex.get(doc._id); const id = uuidIndex.get(doc._id);
const oldCust = customDocs[id]; const oldCust = uuidIndex.custom[id];
const oldDoc = oldCust || styleUtil.id2style(id); const oldDoc = oldCust || styleUtil.id2style(id);
const diff = oldDoc ? compareRevision(oldDoc._rev, doc._rev) : -1; const diff = oldDoc ? compareRevision(oldDoc._rev, doc._rev) : -1;
if (!diff) return; if (!diff) return;
if (diff > 0) { if (diff > 0) {
syncMan.putDoc(oldDoc); syncMan.putDoc(oldDoc);
} else if (oldCust) { } else if (oldCust) {
customDocs[id] = doc; uuidIndex.custom[id] = doc;
} else { } else {
delete doc.id; delete doc.id;
if (id) doc.id = id; if (id) doc.id = id;
@ -215,13 +202,12 @@ const syncMan = (() => {
onDelete(_id, rev) { onDelete(_id, rev) {
const id = uuidIndex.get(_id); const id = uuidIndex.get(_id);
const oldDoc = styleUtil.id2style(id); const oldDoc = styleUtil.id2style(id);
if (oldDoc && compareRevision(oldDoc._rev, rev) <= 0) { return oldDoc &&
uuidIndex.delete(id); compareRevision(oldDoc._rev, rev) <= 0 &&
return API.styles.delete(id, 'sync'); API.styles.delete(id, 'sync');
}
}, },
async onFirstSync() { async onFirstSync() {
for (const i of Object.values(customDocs).concat(await API.styles.getAll())) { for (const i of Object.values(uuidIndex.custom).concat(await API.styles.getAll())) {
ctrl.put(i._id, i._rev); ctrl.put(i._id, i._rev);
} }
}, },