/ proof-of-concept / cymplay
Sign in
proof-of-concept / cymplay
cymplay / src / cache.ts
59 lines · 1.9 KBBlameHistoryRaw
1// IndexedDB cache of computed modes files, keyed by a hash of the configuration and options.
3const DB = "cymplay", STORE = "modes";
5function open(): Promise<IDBDatabase> {
6 return new Promise((resolve, reject) => {
7 const req = indexedDB.open(DB, 1);
8 req.onupgradeneeded = () => req.result.createObjectStore(STORE);
9 req.onsuccess = () => resolve(req.result);
10 req.onerror = () => reject(req.error);
11 });
14export async function cacheKey(obj: unknown): Promise<string> {
15 const bytes = new TextEncoder().encode(JSON.stringify(obj));
16 const digest = await crypto.subtle.digest("SHA-256", bytes);
17 return Array.from(new Uint8Array(digest).slice(0, 16), (b) => b.toString(16).padStart(2, "0")).join("");
20export async function cacheGet(key: string): Promise<ArrayBuffer | null> {
21 try {
22 const db = await open();
23 return await new Promise((resolve, reject) => {
24 const req = db.transaction(STORE, "readonly").objectStore(STORE).get(key);
25 req.onsuccess = () => resolve((req.result as ArrayBuffer) ?? null);
26 req.onerror = () => reject(req.error);
27 });
28 } catch {
29 return null;
30 }
33export async function cachePut(key: string, buffer: ArrayBuffer): Promise<void> {
34 try {
35 const db = await open();
36 await new Promise<void>((resolve, reject) => {
37 const tx = db.transaction(STORE, "readwrite");
38 tx.objectStore(STORE).put(buffer, key);
39 tx.oncomplete = () => resolve();
40 tx.onerror = () => reject(tx.error);
41 });
42 } catch {
43 /* caching is best effort */
44 }
47export async function cacheClear(): Promise<void> {
48 try {
49 const db = await open();
50 await new Promise<void>((resolve, reject) => {
51 const tx = db.transaction(STORE, "readwrite");
52 tx.objectStore(STORE).clear();
53 tx.oncomplete = () => resolve();
54 tx.onerror = () => reject(tx.error);
55 });
56 } catch {
57 /* ignore */
58 }
↑↓ move↵openescclose