refactor(data.worker): optimize database access in service worker by implementing direct IndexedDB functions and enhancing message handling
This commit is contained in:
parent
bbbca27009
commit
8a87fe38c5
@ -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);
|
||||||
const messageHandler = (event) => {
|
request.onsuccess = () => resolve(request.result);
|
||||||
if (event.data.id === messageId) {
|
});
|
||||||
self.removeEventListener('message', messageHandler);
|
}
|
||||||
if (event.data.type === 'DB_RESPONSE') {
|
|
||||||
resolve(event.data.result);
|
/**
|
||||||
} else if (event.data.type === 'DB_ERROR') {
|
* Récupère un objet spécifique (équivalent à GET_OBJECT)
|
||||||
reject(new Error(event.data.error));
|
*/
|
||||||
}
|
function getObject(db, storeName, key) {
|
||||||
}
|
return new Promise((resolve, reject) => {
|
||||||
};
|
const transaction = db.transaction(storeName, "readonly");
|
||||||
|
const store = transaction.objectStore(storeName);
|
||||||
self.addEventListener('message', messageHandler);
|
const request = store.get(key);
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
client.postMessage({
|
request.onsuccess = () => resolve(request.result);
|
||||||
type: 'DB_REQUEST',
|
});
|
||||||
id: messageId,
|
}
|
||||||
action,
|
|
||||||
payload
|
/**
|
||||||
|
* 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 = [];
|
||||||
|
|
||||||
|
let completed = 0;
|
||||||
|
if (keys.length === 0) resolve([]);
|
||||||
|
|
||||||
|
keys.forEach((key) => {
|
||||||
|
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,40 +77,57 @@ 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 (
|
||||||
const existingData = await requestFromMainThread(client, 'GET_OBJECT', {
|
(state.public_data && state.public_data[field] !== undefined) ||
|
||||||
storeName: 'data',
|
field === "roles"
|
||||||
key: hash
|
)
|
||||||
});
|
continue;
|
||||||
|
|
||||||
|
// 2. Vérification directe dans 'data'
|
||||||
|
const existingData = await getObject(db, "data", 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({
|
||||||
process_id: processId,
|
process_id: processId,
|
||||||
@ -130,23 +140,64 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@ -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
|
||||||
@ -7,13 +7,16 @@ export class Database {
|
|||||||
// ============================================
|
// ============================================
|
||||||
// PRIVATE PROPERTIES
|
// PRIVATE PROPERTIES
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
private static instance: Database;
|
private static instance: Database;
|
||||||
private serviceWorkerRegistration: ServiceWorkerRegistration | null = null;
|
private serviceWorkerRegistration: ServiceWorkerRegistration | null = null;
|
||||||
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,36 +40,39 @@ 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;
|
||||||
const pending = this.pendingMessages.get(id);
|
const pending = this.pendingMessages.get(id);
|
||||||
|
|
||||||
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;
|
// ✅ NETTOYAGE : handleDatabaseRequest() a été supprimé
|
||||||
|
|
||||||
try {
|
|
||||||
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,10 +462,13 @@ 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,
|
||||||
unconfirmed_secrets: Object.values(unconfirmedSecrets),
|
unconfirmed_secrets: Object.values(unconfirmedSecrets),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user