diff --git a/plugins/_lib/Caches/TrackInfoCache.ts b/plugins/_lib/Caches/TrackInfoCache.ts index b4e4d70..d7f68ac 100644 --- a/plugins/_lib/Caches/TrackInfoCache.ts +++ b/plugins/_lib/Caches/TrackInfoCache.ts @@ -7,6 +7,9 @@ import { ManifestMimeType } from "../trackBytes/getPlaybackInfo"; import { SharedObjectStore } from "../sharedStorage"; +import { Tracer } from "../trace"; +const tracer = Tracer("TrackInfoCache"); + const { parseStream } = <{ parseStream: typeof ParseStreamType }>require("music-metadata/lib/core"); export type TrackInfo = { @@ -23,25 +26,23 @@ export type TrackInfo = { const WEEK = 7 * 24 * 60 * 60 * 1000; export class TrackInfoCache { private static readonly _listeners: Map<[TrackInfo["trackId"], AudioQuality], ((trackInfo: TrackInfo) => void)[]> = new Map(); - private static readonly _store: SharedObjectStore<[TrackInfo["trackId"], TrackInfo["audioQuality"]], TrackInfo> = new SharedObjectStore("TrackInfoCache", { keyPath: ["trackId", "audioQuality"] }); - public static get(trackId: TrackInfo["trackId"], audioQuality: AudioQuality): Promise { - return this._store.get([trackId, audioQuality]); - } - - public static test() { - this._store.getAll().then(console.log); + private static readonly _store: SharedObjectStore<[TrackInfo["trackId"], TrackInfo["audioQuality"]], TrackInfo> = new SharedObjectStore("TrackInfoCache", { + keyPath: ["trackId", "audioQuality"], + }); + public static async get(trackId: TrackInfo["trackId"], audioQuality: AudioQuality): Promise { + return this._store.getCache([trackId, audioQuality], tracer.err.withContext("get")); } public static async register(trackId: TrackInfo["trackId"], audioQuality: AudioQuality, onTrackInfo: (trackInfoP: TrackInfo) => void): Promise { const listeners = this._listeners.get([trackId, audioQuality]); if (listeners !== undefined) listeners.push(onTrackInfo); else this._listeners.set([trackId, audioQuality], [onTrackInfo]); - const trackInfo = await this._store.get([trackId, audioQuality]); + const trackInfo = await this._store.getCache([trackId, audioQuality], tracer.err.withContext("register")); if (trackInfo !== undefined) onTrackInfo(trackInfo); } private static put(trackInfo: TrackInfo): void { - this._store.put(trackInfo); + this._store.putCache(trackInfo, [trackInfo.trackId, trackInfo.audioQuality], tracer.err.withContext("put")); for (const listener of TrackInfoCache._listeners.get([trackInfo.trackId, trackInfo.audioQuality]) || []) listener(trackInfo); } diff --git a/plugins/_lib/api/requestCache.ts b/plugins/_lib/api/requestCache.ts index c92602e..8f0a3f8 100644 --- a/plugins/_lib/api/requestCache.ts +++ b/plugins/_lib/api/requestCache.ts @@ -1,13 +1,16 @@ import { rejectNotOk, RequestOptionsWithBody, requestStream, toJson } from "../fetch"; import { SharedObjectStore } from "../sharedStorage"; +import { Tracer } from "../trace"; +const trace = Tracer("[requestCache]"); + export const requestCache = new SharedObjectStore("requestCache"); export const requestCached = async (url: string, options?: RequestOptionsWithBody): Promise => { - let apiRes = await requestCache.get(url); + let apiRes = await requestCache.getCache(url, trace.err.withContext("get")); if (apiRes !== undefined) return apiRes; apiRes = await requestStream(url, options) .then(rejectNotOk) .then(toJson); - await requestCache.put(apiRes, url); + await requestCache.putCache(apiRes, url, trace.err.withContext("put")); return apiRes; }; diff --git a/plugins/_lib/sharedStorage.ts b/plugins/_lib/sharedStorage.ts index adbca7f..31f7985 100644 --- a/plugins/_lib/sharedStorage.ts +++ b/plugins/_lib/sharedStorage.ts @@ -33,34 +33,50 @@ export class SharedObjectStore { return this.db.then((db) => db.close()); } - constructor(private readonly storeName: string, storeSchema?: IDBObjectStoreParameters) { + private readonly _memCache = new Map(); + constructor(private readonly storeName: string, private readonly storeSchema?: IDBObjectStoreParameters) { SharedObjectStore.openDB(storeName, storeSchema); } - async add(value: V, key?: K) { - return (await SharedObjectStore.db).add(this.storeName, value, key); + add(value: V, key?: K) { + return SharedObjectStore.db.then((db) => db.add(this.storeName, value, key)); } - async clear() { - return (await SharedObjectStore.db).clear(this.storeName); + clear() { + return SharedObjectStore.db.then((db) => db.clear(this.storeName)); } - async count(key?: K | null) { - return (await SharedObjectStore.db).count(this.storeName, key); + count(key?: K | null) { + return SharedObjectStore.db.then((db) => db.count(this.storeName, key)); } - async delete(key: K) { - return (await SharedObjectStore.db).delete(this.storeName, key); + delete(key: K) { + return SharedObjectStore.db.then((db) => db.delete(this.storeName, key)); } - async get(query: K) { - return (await SharedObjectStore.db).get(this.storeName, query); + getCache(query: K, errorHandler: (err?: Error) => void) { + const value = SharedObjectStore.db + .then((db) => db.get(this.storeName, query)) + .then((value) => { + this._memCache.set(query, value); + return value; + }) + .catch(errorHandler); + const memValue = this._memCache.get(query); + return memValue ?? value; } - async getAll(query?: K | null, count?: number) { - return (await SharedObjectStore.db).getAll(this.storeName, query, count); + get(query: K) { + return SharedObjectStore.db.then((db) => db.get(this.storeName, query)); } - async getAllKeys(query?: K | null, count?: number) { - return (await SharedObjectStore.db).getAllKeys(this.storeName, query, count); + getAll(query?: K | null, count?: number) { + return SharedObjectStore.db.then((db) => db.getAll(this.storeName, query, count)); } - async getKey(query: K) { - return (await SharedObjectStore.db).getKey(this.storeName, query); + getAllKeys(query?: K | null, count?: number) { + return SharedObjectStore.db.then((db) => db.getAllKeys(this.storeName, query, count)); } - async put(value: V, key?: K) { - return (await SharedObjectStore.db).put(this.storeName, value, key); + getKey(query: K) { + return SharedObjectStore.db.then((db) => db.getKey(this.storeName, query)); + } + putCache(value: V, key: K, errorHandler: (err?: Error) => void) { + this._memCache.set(key, value); + SharedObjectStore.db.then((db) => db.put(this.storeName, value, this.storeSchema?.keyPath !== undefined ? undefined : key)).catch(errorHandler); + } + put(value: V, key?: K) { + return SharedObjectStore.db.then((db) => db.put(this.storeName, value, key)); } }