From cdbb2fa26a0e84469a18f20c952cd3ad5e45aac4 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 12 Oct 2024 10:55:02 +1300 Subject: [PATCH 1/6] Add IDB custom store wrapper --- .../homebrew/utils/customIDBStoreWrapper.js | 54 +++++++++++++++++++ client/homebrew/utils/versionHistory.js | 24 ++++----- 2 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 client/homebrew/utils/customIDBStoreWrapper.js diff --git a/client/homebrew/utils/customIDBStoreWrapper.js b/client/homebrew/utils/customIDBStoreWrapper.js new file mode 100644 index 000000000..c82ff858a --- /dev/null +++ b/client/homebrew/utils/customIDBStoreWrapper.js @@ -0,0 +1,54 @@ +import * as IDB from 'idb-keyval/dist/index.js'; + +export function initCustomStore(db, store){ + const createCustomStore = async ()=>{ + return await IDB.createStore(db, store); + }; + return { + entries : async ()=>{ + // Return all entries : [[key1, value1], [key2, value2], ... [keyN, valueN] ] + return await IDB.entries(await createCustomStore()); + }, + keys : async ()=>{ + // Return all keys : [ key1, key2, ... keyN ] + return await IDB.keys(await createCustomStore()); + }, + values : async ()=>{ + // Return all values : [ value1, value2, ... valueN ] + return await IDB.values(await createCustomStore()); + }, + clear : async ()=>{ + // Delete all keys and values + return await IDB.clear(await createCustomStore); + }, + get : async (key)=>{ + // Get a value by its key + return await IDB.get(key, await createCustomStore()); + }, + getMany : async (keys)=>{ + // Get multiple values at once + return await IDB.getMany(keys, await createCustomStore()); + }, + set : async (key, value)=>{ + // Set a value in the store by the key + return await IDB.set(key, value, await createCustomStore()); + }, + setMany : async (entries)=>{ + // Set multiple values at once + // `entries` is in the form : [ [key1, value1], [key2, value2], ... [keyN, valueN] ] + return await IDB.setMany(entries, await createCustomStore()); + }, + update : async (key, updateFn)=>{ + // Update a value in a single atomic action + return await IDB.update(key, updateFn, await createCustomStore()); + }, + del : async (key)=>{ + // Delete a single key and associated value from the store + return await IDB.del(key, await createCustomStore()); + }, + delMany : async (keys)=>{ + // Delete multiple keys at once + return await IDB.delMany(keys, await createCustomStore()); + } + }; +}; \ No newline at end of file diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index a23af844a..23f9e03bc 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -1,4 +1,4 @@ -import * as IDB from 'idb-keyval/dist/index.js'; +import { initCustomStore } from './customIDBStoreWrapper'; export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY'; export const HISTORY_SLOTS = 5; @@ -21,13 +21,15 @@ const HISTORY_SAVE_DELAYS = { // '5' : 5 // }; -const HB_DB = 'HOMEBREWERY-DB'; -const HB_STORE = 'HISTORY'; - const GARBAGE_COLLECT_DELAY = 28 * 24 * 60; // const GARBAGE_COLLECT_DELAY = 10; +const HB_DB = 'HOMEBREWERY-DB'; +const HB_STORE = 'HISTORY'; + +const IDB = initCustomStore(HB_DB, HB_STORE); + function getKeyBySlot(brew, slot){ // Return a string representing the key for this brew and history slot return `${HISTORY_PREFIX}-${brew.shareId}-${slot}`; @@ -53,11 +55,6 @@ function parseBrewForStorage(brew, slot = 0) { return [key, archiveBrew]; } -// Create a custom IDB store -async function createHBStore(){ - return await IDB.createStore(HB_DB, HB_STORE); -} - export async function loadHistory(brew){ const DEFAULT_HISTORY_ITEM = { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true }; @@ -69,7 +66,7 @@ export async function loadHistory(brew){ }; // Load all keys from IDB at once - const dataArray = await IDB.getMany(historyKeys, await createHBStore()); + const dataArray = await IDB.getMany(historyKeys); return dataArray.map((data)=>{ return data ?? DEFAULT_HISTORY_ITEM; }); } @@ -97,7 +94,7 @@ export async function updateHistory(brew) { // Update the most recent brew historyUpdate.push(parseBrewForStorage(brew, 1)); - await IDB.setMany(historyUpdate, await createHBStore()); + await IDB.setMany(historyUpdate); // Break out of data checks because we found an expired value break; @@ -106,14 +103,13 @@ export async function updateHistory(brew) { }; export async function versionHistoryGarbageCollection(){ - - const entries = await IDB.entries(await createHBStore()); + const entries = await IDB.entries(); for (const [key, value] of entries){ const expireAt = new Date(value.savedAt); expireAt.setMinutes(expireAt.getMinutes() + GARBAGE_COLLECT_DELAY); if(new Date() > expireAt){ - await IDB.del(key, await createHBStore()); + await IDB.del(key); }; }; }; \ No newline at end of file From f64e7d3fd7a423829d976f7d345c432eaec92563 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 12 Oct 2024 10:57:01 +1300 Subject: [PATCH 2/6] Shift grabage collection to use delMany instead of a looped del --- client/homebrew/utils/versionHistory.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index 23f9e03bc..2468a48dc 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -105,11 +105,15 @@ export async function updateHistory(brew) { export async function versionHistoryGarbageCollection(){ const entries = await IDB.entries(); + const expiredKeys = []; for (const [key, value] of entries){ const expireAt = new Date(value.savedAt); expireAt.setMinutes(expireAt.getMinutes() + GARBAGE_COLLECT_DELAY); if(new Date() > expireAt){ - await IDB.del(key); + expiredKeys.push(key); }; }; + if(expiredKeys.length > 0){ + await IDB.delMany(expiredKeys); + } }; \ No newline at end of file From eb852b8045e0e97bb980e15c07929e20d882da51 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 26 Oct 2024 09:50:07 +1300 Subject: [PATCH 3/6] Add IDB Proxy --- .../homebrew/utils/customIDBStoreWrapper.js | 35 +++++++++++++++++++ client/homebrew/utils/versionHistory.js | 4 +-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/homebrew/utils/customIDBStoreWrapper.js b/client/homebrew/utils/customIDBStoreWrapper.js index c82ff858a..aa18beda1 100644 --- a/client/homebrew/utils/customIDBStoreWrapper.js +++ b/client/homebrew/utils/customIDBStoreWrapper.js @@ -1,5 +1,40 @@ import * as IDB from 'idb-keyval/dist/index.js'; +// The Proxy and the Wrapper _should_ be equivalent + +// IndexedDB Proxy + +export function initIDBProxy(db, store) { + + const PROP_LIST = [ + 'entries', + 'keys', + 'values', + 'clear', + 'get', + 'getMany', + 'set', + 'setMany', + 'update', + 'del', + 'delMany' + ]; + + const IDBHandler = { + get : (target, prop)=>{ + if(!PROP_LIST.includes(prop)){ return target[prop]; } + return function (...args) { + return target[prop].apply(target, [...args, target.createStore(db, store)]); + }; + } + }; + + return new Proxy(IDB, IDBHandler); +} + + +// IndexedDB Wrapper + export function initCustomStore(db, store){ const createCustomStore = async ()=>{ return await IDB.createStore(db, store); diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index 2468a48dc..4da4b29f1 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -1,4 +1,4 @@ -import { initCustomStore } from './customIDBStoreWrapper'; +import { initIDBProxy } from './customIDBStoreWrapper'; export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY'; export const HISTORY_SLOTS = 5; @@ -28,7 +28,7 @@ const GARBAGE_COLLECT_DELAY = 28 * 24 * 60; const HB_DB = 'HOMEBREWERY-DB'; const HB_STORE = 'HISTORY'; -const IDB = initCustomStore(HB_DB, HB_STORE); +const IDB = initIDBProxy(HB_DB, HB_STORE); function getKeyBySlot(brew, slot){ // Return a string representing the key for this brew and history slot From 478a541d62cec0767fae558a4ba095da8204e5bd Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sat, 26 Oct 2024 09:58:09 +1300 Subject: [PATCH 4/6] Remove wrapper from file name --- .../utils/{customIDBStoreWrapper.js => customIDBStore.js} | 0 client/homebrew/utils/versionHistory.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename client/homebrew/utils/{customIDBStoreWrapper.js => customIDBStore.js} (100%) diff --git a/client/homebrew/utils/customIDBStoreWrapper.js b/client/homebrew/utils/customIDBStore.js similarity index 100% rename from client/homebrew/utils/customIDBStoreWrapper.js rename to client/homebrew/utils/customIDBStore.js diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index 4da4b29f1..d9a70c11d 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -1,4 +1,4 @@ -import { initIDBProxy } from './customIDBStoreWrapper'; +import { initIDBProxy } from './customIDBStore.js'; export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY'; export const HISTORY_SLOTS = 5; From 6fed42198d81e0aeccdb0c67f6068c11be5973e5 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 29 Oct 2024 19:30:22 +1300 Subject: [PATCH 5/6] Simplify initCustomStore --- client/homebrew/utils/customIDBStore.js | 61 ++++++------------------- 1 file changed, 13 insertions(+), 48 deletions(-) diff --git a/client/homebrew/utils/customIDBStore.js b/client/homebrew/utils/customIDBStore.js index aa18beda1..ed65769a6 100644 --- a/client/homebrew/utils/customIDBStore.js +++ b/client/homebrew/utils/customIDBStore.js @@ -36,54 +36,19 @@ export function initIDBProxy(db, store) { // IndexedDB Wrapper export function initCustomStore(db, store){ - const createCustomStore = async ()=>{ - return await IDB.createStore(db, store); - }; + const createCustomStore = async ()=>IDB.createStore(db, store); + return { - entries : async ()=>{ - // Return all entries : [[key1, value1], [key2, value2], ... [keyN, valueN] ] - return await IDB.entries(await createCustomStore()); - }, - keys : async ()=>{ - // Return all keys : [ key1, key2, ... keyN ] - return await IDB.keys(await createCustomStore()); - }, - values : async ()=>{ - // Return all values : [ value1, value2, ... valueN ] - return await IDB.values(await createCustomStore()); - }, - clear : async ()=>{ - // Delete all keys and values - return await IDB.clear(await createCustomStore); - }, - get : async (key)=>{ - // Get a value by its key - return await IDB.get(key, await createCustomStore()); - }, - getMany : async (keys)=>{ - // Get multiple values at once - return await IDB.getMany(keys, await createCustomStore()); - }, - set : async (key, value)=>{ - // Set a value in the store by the key - return await IDB.set(key, value, await createCustomStore()); - }, - setMany : async (entries)=>{ - // Set multiple values at once - // `entries` is in the form : [ [key1, value1], [key2, value2], ... [keyN, valueN] ] - return await IDB.setMany(entries, await createCustomStore()); - }, - update : async (key, updateFn)=>{ - // Update a value in a single atomic action - return await IDB.update(key, updateFn, await createCustomStore()); - }, - del : async (key)=>{ - // Delete a single key and associated value from the store - return await IDB.del(key, await createCustomStore()); - }, - delMany : async (keys)=>{ - // Delete multiple keys at once - return await IDB.delMany(keys, await createCustomStore()); - } + entries : async ()=>IDB.entries(await createCustomStore()), + keys : async ()=>IDB.keys(await createCustomStore()), + values : async ()=>IDB.values(await createCustomStore()), + clear : async ()=>IDB.clear(await createCustomStore), + get : async (key)=>IDB.get(key, await createCustomStore()), + getMany : async (keys)=>IDB.getMany(keys, await createCustomStore()), + set : async (key, value)=>IDB.set(key, value, await createCustomStore()), + setMany : async (entries)=>IDB.setMany(entries, await createCustomStore()), + update : async (key, updateFn)=>IDB.update(key, updateFn, await createCustomStore()), + del : async (key)=>IDB.del(key, await createCustomStore()), + delMany : async (keys)=>IDB.delMany(keys, await createCustomStore()) }; }; \ No newline at end of file From ebf900ba240bc8bf7279e1ebea169a77da3cc75a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Wed, 30 Oct 2024 08:21:51 +1300 Subject: [PATCH 6/6] Remove Proxy version --- client/homebrew/utils/customIDBStore.js | 35 ------------------------- client/homebrew/utils/versionHistory.js | 4 +-- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/client/homebrew/utils/customIDBStore.js b/client/homebrew/utils/customIDBStore.js index ed65769a6..6a3c84400 100644 --- a/client/homebrew/utils/customIDBStore.js +++ b/client/homebrew/utils/customIDBStore.js @@ -1,40 +1,5 @@ import * as IDB from 'idb-keyval/dist/index.js'; -// The Proxy and the Wrapper _should_ be equivalent - -// IndexedDB Proxy - -export function initIDBProxy(db, store) { - - const PROP_LIST = [ - 'entries', - 'keys', - 'values', - 'clear', - 'get', - 'getMany', - 'set', - 'setMany', - 'update', - 'del', - 'delMany' - ]; - - const IDBHandler = { - get : (target, prop)=>{ - if(!PROP_LIST.includes(prop)){ return target[prop]; } - return function (...args) { - return target[prop].apply(target, [...args, target.createStore(db, store)]); - }; - } - }; - - return new Proxy(IDB, IDBHandler); -} - - -// IndexedDB Wrapper - export function initCustomStore(db, store){ const createCustomStore = async ()=>IDB.createStore(db, store); diff --git a/client/homebrew/utils/versionHistory.js b/client/homebrew/utils/versionHistory.js index d9a70c11d..ec3bd74e1 100644 --- a/client/homebrew/utils/versionHistory.js +++ b/client/homebrew/utils/versionHistory.js @@ -1,4 +1,4 @@ -import { initIDBProxy } from './customIDBStore.js'; +import { initCustomStore } from './customIDBStore.js'; export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY'; export const HISTORY_SLOTS = 5; @@ -28,7 +28,7 @@ const GARBAGE_COLLECT_DELAY = 28 * 24 * 60; const HB_DB = 'HOMEBREWERY-DB'; const HB_STORE = 'HISTORY'; -const IDB = initIDBProxy(HB_DB, HB_STORE); +const IDB = initCustomStore(HB_DB, HB_STORE); function getKeyBySlot(brew, slot){ // Return a string representing the key for this brew and history slot