refactor(data.worker): optimize database access in service worker by implementing direct IndexedDB functions and enhancing message handling

This commit is contained in:
NicolasCantu 2025-11-28 00:13:42 +01:00
parent bbbca27009
commit 8a87fe38c5
2 changed files with 288 additions and 223 deletions

View File

@ -1,82 +1,75 @@
const EMPTY32BYTES = String('').padStart(64, '0'); // public/data.worker.js
const DB_NAME = "4nk";
const DB_VERSION = 1;
const EMPTY32BYTES = String("").padStart(64, "0");
// ============================================ // ============================================
// SERVICE WORKER LIFECYCLE // SERVICE WORKER LIFECYCLE
// ============================================ // ============================================
self.addEventListener('install', (event) => { self.addEventListener("install", (event) => {
event.waitUntil(self.skipWaiting()); event.waitUntil(self.skipWaiting());
}); });
self.addEventListener('activate', (event) => { self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim()); event.waitUntil(self.clients.claim());
}); });
// ============================================ // ============================================
// MESSAGE HANDLER // INDEXEDDB DIRECT ACCESS (READ-ONLY)
// ============================================ // ============================================
self.addEventListener('message', async (event) => { /**
const data = event.data; * Ouvre une connexion à la BDD directement depuis le Service Worker
console.log('[Service Worker] Message received:', data.type); */
function openDB() {
if (data.type === 'SCAN') {
try {
const myProcessesId = data.payload;
if (myProcessesId && myProcessesId.length != 0) {
const scanResult = await scanMissingData(myProcessesId, event.source);
if (scanResult.toDownload.length != 0) {
console.log('[Service Worker] Sending TO_DOWNLOAD message');
event.source.postMessage({ type: 'TO_DOWNLOAD', data: scanResult.toDownload });
}
if (scanResult.diffsToCreate.length > 0) {
console.log('[Service Worker] Sending DIFFS_TO_CREATE message');
event.source.postMessage({ type: 'DIFFS_TO_CREATE', data: scanResult.diffsToCreate });
}
} else {
event.source.postMessage({ status: 'error', message: 'Empty lists' });
}
} catch (error) {
console.error('[Service Worker] Scan error:', error);
event.source.postMessage({ status: 'error', message: error.message });
}
}
});
// ============================================
// DATABASE COMMUNICATION
// ============================================
async function requestFromMainThread(client, action, payload) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const messageId = `sw_${Date.now()}_${Math.random()}`; const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
const messageHandler = (event) => { /**
if (event.data.id === messageId) { * Récupère un objet spécifique (équivalent à GET_OBJECT)
self.removeEventListener('message', messageHandler); */
if (event.data.type === 'DB_RESPONSE') { function getObject(db, storeName, key) {
resolve(event.data.result); return new Promise((resolve, reject) => {
} else if (event.data.type === 'DB_ERROR') { const transaction = db.transaction(storeName, "readonly");
reject(new Error(event.data.error)); const store = transaction.objectStore(storeName);
} const request = store.get(key);
} request.onerror = () => reject(request.error);
}; request.onsuccess = () => resolve(request.result);
});
}
self.addEventListener('message', messageHandler); /**
* Récupère plusieurs objets d'un coup (équivalent à GET_MULTIPLE_OBJECTS)
* Optimisé pour utiliser une seule transaction.
*/
function getMultipleObjects(db, storeName, keys) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, "readonly");
const store = transaction.objectStore(storeName);
const results = [];
client.postMessage({ let completed = 0;
type: 'DB_REQUEST', if (keys.length === 0) resolve([]);
id: messageId,
action, keys.forEach((key) => {
payload const request = store.get(key);
request.onsuccess = () => {
if (request.result) results.push(request.result);
completed++;
if (completed === keys.length) resolve(results);
};
request.onerror = () => {
console.warn(`[SW] Erreur lecture clé ${key}`);
completed++;
if (completed === keys.length) resolve(results);
};
}); });
setTimeout(() => {
self.removeEventListener('message', messageHandler);
reject(new Error('Database request timeout'));
}, 10000);
}); });
} }
@ -84,39 +77,56 @@ async function requestFromMainThread(client, action, payload) {
// SCAN LOGIC // SCAN LOGIC
// ============================================ // ============================================
async function scanMissingData(processesToScan, client) { async function scanMissingData(processesToScan) {
console.log('[Service Worker] Scanning for missing data...'); console.log("[Service Worker] 🚀 Scanning with DIRECT DB ACCESS...");
const myProcesses = await requestFromMainThread(client, 'GET_MULTIPLE_OBJECTS', { let db;
storeName: 'processes', try {
keys: processesToScan db = await openDB();
}); } catch (e) {
console.error("[SW] Impossible d'ouvrir la BDD:", e);
return { toDownload: [], diffsToCreate: [] };
}
// 1. Récupération directe des processus
const myProcesses = await getMultipleObjects(
db,
"processes",
processesToScan
);
let toDownload = new Set(); let toDownload = new Set();
let diffsToCreate = []; let diffsToCreate = [];
if (myProcesses && myProcesses.length != 0) { if (myProcesses && myProcesses.length !== 0) {
for (const process of myProcesses) { for (const process of myProcesses) {
if (!process || !process.states) continue;
const firstState = process.states[0]; const firstState = process.states[0];
// Sécurisation : on vérifie que firstState existe
if (!firstState) continue;
const processId = firstState.commited_in; const processId = firstState.commited_in;
for (const state of process.states) { for (const state of process.states) {
if (state.state_id === EMPTY32BYTES) continue; if (state.state_id === EMPTY32BYTES) continue;
for (const [field, hash] of Object.entries(state.pcd_commitment)) { for (const [field, hash] of Object.entries(state.pcd_commitment)) {
if (state.public_data[field] !== undefined || field === 'roles') continue; // On ignore les données publiques ou les rôles
if (
(state.public_data && state.public_data[field] !== undefined) ||
field === "roles"
)
continue;
const existingData = await requestFromMainThread(client, 'GET_OBJECT', { // 2. Vérification directe dans 'data'
storeName: 'data', const existingData = await getObject(db, "data", hash);
key: hash
});
if (!existingData) { if (!existingData) {
toDownload.add(hash); toDownload.add(hash);
const existingDiff = await requestFromMainThread(client, 'GET_OBJECT', { // 3. Vérification directe dans 'diffs'
storeName: 'diffs', const existingDiff = await getObject(db, "diffs", hash);
key: hash
});
if (!existingDiff) { if (!existingDiff) {
diffsToCreate.push({ diffsToCreate.push({
@ -130,12 +140,13 @@ async function scanMissingData(processesToScan, client) {
new_value: null, new_value: null,
notify_user: false, notify_user: false,
need_validation: false, need_validation: false,
validation_status: 'None' validation_status: "None",
}); });
} }
} else { } else {
if (toDownload.delete(hash)) { // Si on a trouvé la donnée, on est sûr de ne pas avoir besoin de la télécharger
console.log(`[Service Worker] Removing ${hash} from the set`); if (toDownload.has(hash)) {
toDownload.delete(hash);
} }
} }
} }
@ -143,10 +154,50 @@ async function scanMissingData(processesToScan, client) {
} }
} }
console.log('[Service Worker] Scan complete:', { toDownload: toDownload.size, diffsToCreate: diffsToCreate.length }); // On ferme la connexion BDD pour libérer les ressources
db.close();
console.log("[Service Worker] Scan complete:", {
toDownload: toDownload.size,
diffsToCreate: diffsToCreate.length,
});
return { return {
toDownload: Array.from(toDownload), toDownload: Array.from(toDownload),
diffsToCreate: diffsToCreate diffsToCreate: diffsToCreate,
}; };
} }
// ============================================
// MESSAGE HANDLER
// ============================================
self.addEventListener("message", async (event) => {
const data = event.data;
if (data.type === "SCAN") {
try {
const myProcessesId = data.payload;
if (myProcessesId && myProcessesId.length !== 0) {
// Appel direct de la nouvelle fonction optimisée
const scanResult = await scanMissingData(myProcessesId);
if (scanResult.toDownload.length !== 0) {
event.source.postMessage({
type: "TO_DOWNLOAD",
data: scanResult.toDownload,
});
}
if (scanResult.diffsToCreate.length > 0) {
event.source.postMessage({
type: "DIFFS_TO_CREATE",
data: scanResult.diffsToCreate,
});
}
}
} catch (error) {
console.error("[Service Worker] Scan error:", error);
// On évite de spammer l'UI avec des erreurs internes du worker
}
}
});

View File

@ -1,4 +1,4 @@
import Services from './service'; import Services from "./service";
/** /**
* Database service managing IndexedDB operations via Web Worker and Service Worker * Database service managing IndexedDB operations via Web Worker and Service Worker
@ -13,7 +13,10 @@ export class Database {
private serviceWorkerCheckIntervalId: number | null = null; private serviceWorkerCheckIntervalId: number | null = null;
private indexedDBWorker: Worker | null = null; private indexedDBWorker: Worker | null = null;
private messageIdCounter: number = 0; private messageIdCounter: number = 0;
private pendingMessages: Map<number, { resolve: (value: any) => void; reject: (error: any) => void }> = new Map(); private pendingMessages: Map<
number,
{ resolve: (value: any) => void; reject: (error: any) => void }
> = new Map();
// ============================================ // ============================================
// INITIALIZATION & SINGLETON // INITIALIZATION & SINGLETON
@ -37,7 +40,10 @@ export class Database {
// ============================================ // ============================================
private initIndexedDBWorker(): void { private initIndexedDBWorker(): void {
this.indexedDBWorker = new Worker(new URL('../workers/database.worker.ts', import.meta.url), { type: 'module' }); this.indexedDBWorker = new Worker(
new URL("../workers/database.worker.ts", import.meta.url),
{ type: "module" }
);
this.indexedDBWorker.onmessage = (event) => { this.indexedDBWorker.onmessage = (event) => {
const { id, type, result, error } = event.data; const { id, type, result, error } = event.data;
@ -46,27 +52,27 @@ export class Database {
if (pending) { if (pending) {
this.pendingMessages.delete(id); this.pendingMessages.delete(id);
if (type === 'SUCCESS') { if (type === "SUCCESS") {
pending.resolve(result); pending.resolve(result);
} else if (type === 'ERROR') { } else if (type === "ERROR") {
pending.reject(new Error(error)); pending.reject(new Error(error));
} }
} }
}; };
this.indexedDBWorker.onerror = (error) => { this.indexedDBWorker.onerror = (error) => {
console.error('[Database] IndexedDB Worker error:', error); console.error("[Database] IndexedDB Worker error:", error);
}; };
} }
private async waitForWorkerReady(): Promise<void> { private async waitForWorkerReady(): Promise<void> {
return this.sendMessageToWorker('INIT', {}); return this.sendMessageToWorker("INIT", {});
} }
private sendMessageToWorker<T = any>(type: string, payload: any): Promise<T> { private sendMessageToWorker<T = any>(type: string, payload: any): Promise<T> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this.indexedDBWorker) { if (!this.indexedDBWorker) {
reject(new Error('IndexedDB Worker not initialized')); reject(new Error("IndexedDB Worker not initialized"));
return; return;
} }
@ -90,74 +96,93 @@ export class Database {
// ============================================ // ============================================
private initServiceWorker(): void { private initServiceWorker(): void {
this.registerServiceWorker('/data.worker.js'); this.registerServiceWorker("/data.worker.js");
} }
private async registerServiceWorker(path: string): Promise<void> { private async registerServiceWorker(path: string): Promise<void> {
if (!('serviceWorker' in navigator)) return; if (!("serviceWorker" in navigator)) return;
console.log('[Database] Initializing Service Worker:', path); console.log("[Database] Initializing Service Worker:", path);
try { try {
const registrations = await navigator.serviceWorker.getRegistrations(); const registrations = await navigator.serviceWorker.getRegistrations();
for (const registration of registrations) { for (const registration of registrations) {
const scriptURL = registration.active?.scriptURL || registration.installing?.scriptURL || registration.waiting?.scriptURL; const scriptURL =
registration.active?.scriptURL ||
registration.installing?.scriptURL ||
registration.waiting?.scriptURL;
const scope = registration.scope; const scope = registration.scope;
if (scope.includes('/src/service-workers/') || (scriptURL && scriptURL.includes('/src/service-workers/'))) { if (
scope.includes("/src/service-workers/") ||
(scriptURL && scriptURL.includes("/src/service-workers/"))
) {
console.warn(`[Database] Removing old Service Worker (${scope})`); console.warn(`[Database] Removing old Service Worker (${scope})`);
await registration.unregister(); await registration.unregister();
} }
} }
const existingValidWorker = registrations.find((r) => { const existingValidWorker = registrations.find((r) => {
const url = r.active?.scriptURL || r.installing?.scriptURL || r.waiting?.scriptURL; const url =
return url && url.endsWith(path.replace(/^\//,'')); r.active?.scriptURL ||
r.installing?.scriptURL ||
r.waiting?.scriptURL;
return url && url.endsWith(path.replace(/^\//, ""));
}); });
if (!existingValidWorker) { if (!existingValidWorker) {
console.log('[Database] Registering new Service Worker'); console.log("[Database] Registering new Service Worker");
this.serviceWorkerRegistration = await navigator.serviceWorker.register(path, { type: 'module', scope: '/' }); this.serviceWorkerRegistration = await navigator.serviceWorker.register(
path,
{ type: "module", scope: "/" }
);
} else { } else {
console.log('[Database] Service Worker already active'); console.log("[Database] Service Worker already active");
this.serviceWorkerRegistration = existingValidWorker; this.serviceWorkerRegistration = existingValidWorker;
await this.serviceWorkerRegistration.update(); await this.serviceWorkerRegistration.update();
} }
navigator.serviceWorker.addEventListener('message', async (event) => { navigator.serviceWorker.addEventListener("message", async (event) => {
if (event.data.type === 'DB_REQUEST') { // ✅ SIMPLIFICATION : Plus besoin de gérer les "DB_REQUEST"
await this.handleDatabaseRequest(event.data);
return;
}
await this.handleServiceWorkerMessage(event.data); await this.handleServiceWorkerMessage(event.data);
}); });
if (this.serviceWorkerCheckIntervalId) clearInterval(this.serviceWorkerCheckIntervalId); if (this.serviceWorkerCheckIntervalId)
clearInterval(this.serviceWorkerCheckIntervalId);
this.serviceWorkerCheckIntervalId = window.setInterval(async () => { this.serviceWorkerCheckIntervalId = window.setInterval(async () => {
const activeWorker = this.serviceWorkerRegistration?.active || (await this.waitForServiceWorkerActivation(this.serviceWorkerRegistration!)); const activeWorker =
this.serviceWorkerRegistration?.active ||
(await this.waitForServiceWorkerActivation(
this.serviceWorkerRegistration!
));
const service = await Services.getInstance(); const service = await Services.getInstance();
const payload = await service.getMyProcesses(); const payload = await service.getMyProcesses();
if (payload && payload.length != 0) { if (payload && payload.length != 0) {
activeWorker?.postMessage({ type: 'SCAN', payload }); activeWorker?.postMessage({ type: "SCAN", payload });
} }
}, 5000); }, 5000);
} catch (error) { } catch (error) {
console.error('[Database] Service Worker error:', error); console.error("[Database] Service Worker error:", error);
} }
} }
private async waitForServiceWorkerActivation(registration: ServiceWorkerRegistration): Promise<ServiceWorker | null> { private async waitForServiceWorkerActivation(
registration: ServiceWorkerRegistration
): Promise<ServiceWorker | null> {
return new Promise((resolve) => { return new Promise((resolve) => {
if (registration.active) { if (registration.active) {
resolve(registration.active); resolve(registration.active);
} else { } else {
const listener = () => { const listener = () => {
if (registration.active) { if (registration.active) {
navigator.serviceWorker.removeEventListener('controllerchange', listener); navigator.serviceWorker.removeEventListener(
"controllerchange",
listener
);
resolve(registration.active); resolve(registration.active);
} }
}; };
navigator.serviceWorker.addEventListener('controllerchange', listener); navigator.serviceWorker.addEventListener("controllerchange", listener);
} }
}); });
} }
@ -168,10 +193,12 @@ export class Database {
await this.serviceWorkerRegistration.update(); await this.serviceWorkerRegistration.update();
if (this.serviceWorkerRegistration.waiting) { if (this.serviceWorkerRegistration.waiting) {
this.serviceWorkerRegistration.waiting.postMessage({ type: 'SKIP_WAITING' }); this.serviceWorkerRegistration.waiting.postMessage({
type: "SKIP_WAITING",
});
} }
} catch (error) { } catch (error) {
console.error('Error checking for service worker updates:', error); console.error("Error checking for service worker updates:", error);
} }
} }
} }
@ -179,73 +206,34 @@ export class Database {
// ============================================ // ============================================
// SERVICE WORKER MESSAGE HANDLERS // SERVICE WORKER MESSAGE HANDLERS
// ============================================ // ============================================
private async handleDatabaseRequest(request: any): Promise<void> {
const { id, action, payload } = request;
try { // ✅ NETTOYAGE : handleDatabaseRequest() a été supprimé
let result;
switch (action) {
case 'GET_OBJECT':
result = await this.getObject(payload.storeName, payload.key);
break;
case 'GET_MULTIPLE_OBJECTS':
result = await this.sendMessageToWorker('GET_MULTIPLE_OBJECTS', payload);
break;
case 'GET_ALL_OBJECTS':
result = await this.sendMessageToWorker('GET_ALL_OBJECTS', payload);
break;
case 'GET_ALL_OBJECTS_WITH_FILTER':
result = await this.sendMessageToWorker('GET_ALL_OBJECTS_WITH_FILTER', payload);
break;
default:
throw new Error(`Unknown database action: ${action}`);
}
if (this.serviceWorkerRegistration?.active) {
this.serviceWorkerRegistration.active.postMessage({
type: 'DB_RESPONSE',
id,
result
});
}
} catch (error: any) {
console.error('[Database] Error handling database request:', error);
if (this.serviceWorkerRegistration?.active) {
this.serviceWorkerRegistration.active.postMessage({
type: 'DB_ERROR',
id,
error: error.message || String(error)
});
}
}
}
private async handleServiceWorkerMessage(message: any) { private async handleServiceWorkerMessage(message: any) {
switch (message.type) { switch (message.type) {
case 'TO_DOWNLOAD': case "TO_DOWNLOAD":
await this.handleDownloadList(message.data); await this.handleDownloadList(message.data);
break; break;
case 'DIFFS_TO_CREATE': case "DIFFS_TO_CREATE":
await this.handleDiffsToCreate(message.data); await this.handleDiffsToCreate(message.data);
break; break;
default: default:
console.warn('Unknown message type received from service worker:', message); console.warn(
"Unknown message type received from service worker:",
message
);
} }
} }
private async handleDiffsToCreate(diffs: any[]): Promise<void> { private async handleDiffsToCreate(diffs: any[]): Promise<void> {
console.log(`[Database] Creating ${diffs.length} diffs from Service Worker scan`); console.log(
`[Database] Creating ${diffs.length} diffs from Service Worker scan`
);
try { try {
await this.saveDiffs(diffs); await this.saveDiffs(diffs);
console.log('[Database] Diffs created successfully'); console.log("[Database] Diffs created successfully");
} catch (error) { } catch (error) {
console.error('[Database] Error creating diffs:', error); console.error("[Database] Error creating diffs:", error);
} }
} }
@ -264,15 +252,17 @@ export class Database {
try { try {
const valueBytes = await service.fetchValueFromStorage(hash); const valueBytes = await service.fetchValueFromStorage(hash);
if (valueBytes) { if (valueBytes) {
const blob = new Blob([valueBytes], { type: 'application/octet-stream' }); const blob = new Blob([valueBytes], {
type: "application/octet-stream",
});
await service.saveBlobToDb(hash, blob); await service.saveBlobToDb(hash, blob);
document.dispatchEvent( document.dispatchEvent(
new CustomEvent('newDataReceived', { new CustomEvent("newDataReceived", {
detail: { processId, stateId, hash }, detail: { processId, stateId, hash },
}), })
); );
} else { } else {
console.log('Request data from managers of the process'); console.log("Request data from managers of the process");
if (!requestedStateId.includes(stateId)) { if (!requestedStateId.includes(stateId)) {
await service.requestDataFromPeers(processId, [stateId], [roles]); await service.requestDataFromPeers(processId, [stateId], [roles]);
requestedStateId.push(stateId); requestedStateId.push(stateId);
@ -289,35 +279,50 @@ export class Database {
// ============================================ // ============================================
public async getStoreList(): Promise<{ [key: string]: string }> { public async getStoreList(): Promise<{ [key: string]: string }> {
return this.sendMessageToWorker('GET_STORE_LIST', {}); return this.sendMessageToWorker("GET_STORE_LIST", {});
} }
public async addObject(payload: { storeName: string; object: any; key: any }): Promise<void> { public async addObject(payload: {
await this.sendMessageToWorker('ADD_OBJECT', payload); storeName: string;
object: any;
key: any;
}): Promise<void> {
await this.sendMessageToWorker("ADD_OBJECT", payload);
} }
public async batchWriting(payload: { storeName: string; objects: { key: any; object: any }[] }): Promise<void> { public async batchWriting(payload: {
await this.sendMessageToWorker('BATCH_WRITING', payload); storeName: string;
objects: { key: any; object: any }[];
}): Promise<void> {
await this.sendMessageToWorker("BATCH_WRITING", payload);
} }
public async getObject(storeName: string, key: string): Promise<any | null> { public async getObject(storeName: string, key: string): Promise<any | null> {
return this.sendMessageToWorker('GET_OBJECT', { storeName, key }); return this.sendMessageToWorker("GET_OBJECT", { storeName, key });
} }
public async dumpStore(storeName: string): Promise<Record<string, any>> { public async dumpStore(storeName: string): Promise<Record<string, any>> {
return this.sendMessageToWorker('DUMP_STORE', { storeName }); return this.sendMessageToWorker("DUMP_STORE", { storeName });
} }
public async deleteObject(storeName: string, key: string): Promise<void> { public async deleteObject(storeName: string, key: string): Promise<void> {
await this.sendMessageToWorker('DELETE_OBJECT', { storeName, key }); await this.sendMessageToWorker("DELETE_OBJECT", { storeName, key });
} }
public async clearStore(storeName: string): Promise<void> { public async clearStore(storeName: string): Promise<void> {
await this.sendMessageToWorker('CLEAR_STORE', { storeName }); await this.sendMessageToWorker("CLEAR_STORE", { storeName });
} }
public async requestStoreByIndex(storeName: string, indexName: string, request: string): Promise<any[]> { public async requestStoreByIndex(
return this.sendMessageToWorker('REQUEST_STORE_BY_INDEX', { storeName, indexName, request }); storeName: string,
indexName: string,
request: string
): Promise<any[]> {
return this.sendMessageToWorker("REQUEST_STORE_BY_INDEX", {
storeName,
indexName,
request,
});
} }
public async clearMultipleStores(storeNames: string[]): Promise<void> { public async clearMultipleStores(storeNames: string[]): Promise<void> {
@ -332,24 +337,22 @@ export class Database {
public async saveDevice(device: any): Promise<void> { public async saveDevice(device: any): Promise<void> {
try { try {
const existing = await this.getObject('wallet', '1'); const existing = await this.getObject("wallet", "1");
if (existing) { if (existing) {
await this.deleteObject('wallet', '1'); await this.deleteObject("wallet", "1");
} }
} catch (e) {} } catch (e) {}
await this.addObject({ await this.addObject({
storeName: 'wallet', storeName: "wallet",
object: { pre_id: '1', device }, object: { pre_id: "1", device },
key: null, key: null,
}); });
} }
public async getDevice(): Promise<any | null> { public async getDevice(): Promise<any | null> {
const result = await this.getObject('wallet', '1'); const result = await this.getObject("wallet", "1");
console.log(result); return result ? result["device"] : null;
return result ? result['device'] : null;
} }
// ============================================ // ============================================
@ -358,27 +361,32 @@ export class Database {
public async saveProcess(processId: string, process: any): Promise<void> { public async saveProcess(processId: string, process: any): Promise<void> {
await this.addObject({ await this.addObject({
storeName: 'processes', storeName: "processes",
object: process, object: process,
key: processId, key: processId,
}); });
} }
public async saveProcessesBatch(processes: Record<string, any>): Promise<void> { public async saveProcessesBatch(
processes: Record<string, any>
): Promise<void> {
if (Object.keys(processes).length === 0) return; if (Object.keys(processes).length === 0) return;
await this.batchWriting({ await this.batchWriting({
storeName: 'processes', storeName: "processes",
objects: Object.entries(processes).map(([key, value]) => ({ key, object: value })), objects: Object.entries(processes).map(([key, value]) => ({
key,
object: value,
})),
}); });
} }
public async getProcess(processId: string): Promise<any | null> { public async getProcess(processId: string): Promise<any | null> {
return this.getObject('processes', processId); return this.getObject("processes", processId);
} }
public async getAllProcesses(): Promise<Record<string, any>> { public async getAllProcesses(): Promise<Record<string, any>> {
return this.dumpStore('processes'); return this.dumpStore("processes");
} }
// ============================================ // ============================================
@ -387,14 +395,14 @@ export class Database {
public async saveBlob(hash: string, data: Blob): Promise<void> { public async saveBlob(hash: string, data: Blob): Promise<void> {
await this.addObject({ await this.addObject({
storeName: 'data', storeName: "data",
object: data, object: data,
key: hash, key: hash,
}); });
} }
public async getBlob(hash: string): Promise<Blob | null> { public async getBlob(hash: string): Promise<Blob | null> {
return this.getObject('data', hash); return this.getObject("data", hash);
} }
// ============================================ // ============================================
@ -406,7 +414,7 @@ export class Database {
for (const diff of diffs) { for (const diff of diffs) {
await this.addObject({ await this.addObject({
storeName: 'diffs', storeName: "diffs",
object: diff, object: diff,
key: null, key: null,
}); });
@ -414,11 +422,11 @@ export class Database {
} }
public async getDiff(hash: string): Promise<any | null> { public async getDiff(hash: string): Promise<any | null> {
return this.getObject('diffs', hash); return this.getObject("diffs", hash);
} }
public async getAllDiffs(): Promise<Record<string, any>> { public async getAllDiffs(): Promise<Record<string, any>> {
return this.dumpStore('diffs'); return this.dumpStore("diffs");
} }
// ============================================ // ============================================
@ -426,14 +434,17 @@ export class Database {
// ============================================ // ============================================
public async getSharedSecret(address: string): Promise<string | null> { public async getSharedSecret(address: string): Promise<string | null> {
return this.getObject('shared_secrets', address); return this.getObject("shared_secrets", address);
} }
public async saveSecretsBatch(unconfirmedSecrets: any[], sharedSecrets: { key: string; value: any }[]): Promise<void> { public async saveSecretsBatch(
unconfirmedSecrets: any[],
sharedSecrets: { key: string; value: any }[]
): Promise<void> {
if (unconfirmedSecrets && unconfirmedSecrets.length > 0) { if (unconfirmedSecrets && unconfirmedSecrets.length > 0) {
for (const secret of unconfirmedSecrets) { for (const secret of unconfirmedSecrets) {
await this.addObject({ await this.addObject({
storeName: 'unconfirmed_secrets', storeName: "unconfirmed_secrets",
object: secret, object: secret,
key: null, key: null,
}); });
@ -443,7 +454,7 @@ export class Database {
if (sharedSecrets && sharedSecrets.length > 0) { if (sharedSecrets && sharedSecrets.length > 0) {
for (const { key, value } of sharedSecrets) { for (const { key, value } of sharedSecrets) {
await this.addObject({ await this.addObject({
storeName: 'shared_secrets', storeName: "shared_secrets",
object: value, object: value,
key: key, key: key,
}); });
@ -451,9 +462,12 @@ export class Database {
} }
} }
public async getAllSecrets(): Promise<{ shared_secrets: Record<string, any>; unconfirmed_secrets: any[] }> { public async getAllSecrets(): Promise<{
const sharedSecrets = await this.dumpStore('shared_secrets'); shared_secrets: Record<string, any>;
const unconfirmedSecrets = await this.dumpStore('unconfirmed_secrets'); unconfirmed_secrets: any[];
}> {
const sharedSecrets = await this.dumpStore("shared_secrets");
const unconfirmedSecrets = await this.dumpStore("unconfirmed_secrets");
return { return {
shared_secrets: sharedSecrets, shared_secrets: sharedSecrets,