Refactor database.service

This commit is contained in:
NicolasCantu 2025-02-26 09:29:36 +01:00
parent aa22b78121
commit b7a2f3a058

View File

@ -8,6 +8,7 @@ export class Database {
private serviceWorkerRegistration: ServiceWorkerRegistration | null = null;
private messageChannel: MessageChannel | null = null;
private messageChannelForGet: MessageChannel | null = null;
private serviceWorkerCheckIntervalId: number | null = null;
private storeDefinitions = {
AnkLabels: {
name: 'labels',
@ -81,12 +82,10 @@ export class Database {
});
};
request.onsuccess = () => {
setTimeout(() => {
request.onsuccess = async () => {
this.db = request.result;
this.initServiceWorker();
await this.initServiceWorker();
resolve();
}, 500);
};
request.onerror = () => {
@ -120,36 +119,36 @@ export class Database {
if (registrations.length === 0) {
// No existing workers: register a new one.
this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' });
console.log('Service Worker registered with scope:', registration.scope);
console.log('Service Worker registered with scope:', this.serviceWorkerRegistration.scope);
} else if (registrations.length === 1) {
// One existing worker: update it (restart it) without unregistering.
this.serviceWorkerRegistration = registrations[0];
await this.serviceWorkerRegistration.update();
console.log('Service worker updated');
console.log('Service Worker updated');
} else {
// More than one existing worker: unregister them all and register a new one.
console.log('Multiple Service Worker(s) detected. Unregistering all...');
await Promise.all(registrations.map(reg => reg.unregister()));
console.log('All previous Service Workers unregistered.');
this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' });
console.log('Service Worker registered with scope:', registration.scope);
console.log('Service Worker registered with scope:', this.serviceWorkerRegistration.scope);
}
await this.checkForUpdates();
// Set up the message channels
this.messageChannel = new MessageChannel();
this.messageChannelForGet = new MessageChannel();
this.messageChannel.port1.onmessage = this.handleAddObjectResponse;
this.messageChannelForGet.port1.onmessage = this.handleGetObjectResponse;
// Set up a global message listener for responses from the service worker.
navigator.serviceWorker.addEventListener('message', async (event) => {
console.log('Received message from service worker:', event.data);
await this.handleServiceWorkerMessage(event.data);
});
// Ensure the new service worker is activated before sending messages
// Set up a periodic check to ensure the service worker is active and to send a SYNC message.
this.serviceWorkerCheckIntervalId = window.setInterval(async () => {
const activeWorker = this.serviceWorkerRegistration.active || (await this.waitForServiceWorkerActivation(this.serviceWorkerRegistration));
activeWorker?.postMessage(
{ type: 'START' },
[this.messageChannel.port2],
);
const service = await Services.getInstance();
const payload = await service.getMyProcesses();
activeWorker?.postMessage({ type: 'SCAN', payload });
}, 5000);
} catch (error) {
console.error('Service Worker registration failed:', error);
}
@ -188,6 +187,46 @@ export class Database {
}
}
private async handleServiceWorkerMessage(message: any) {
switch (message.type) {
case 'TO_DOWNLOAD':
console.log('Received data to download:', message.data);
await this.handleDownloadList(message.data);
break;
default:
console.warn('Unknown message type received from service worker:', message);
}
}
private async handleDownloadList(downloadList: string[]): void {
// Download the missing data
let requestedStateId = [];
const service = await Services.getInstance();
for (const hash of downloadList) {
try {
const valueBytes = await service.fetchValueFromStorage(hash);
if (valueBytes) {
// Save data to db
const blob = new Blob([valueBytes], {type: "application/octet-stream"});
await service.saveBlobToDb(hash, blob);
} else {
// We first request the data from managers
console.log('Request data from managers of the process');
// get the diff from db
const diff = await service.getDiffByValue(hash);
const processId = diff.process_id;
const stateId = diff.state_id;
if (!requestedStateId.includes(stateId)) {
await service.requestDataFromPeers(processId, stateId);
requestedStateId.push(stateId);
}
}
} catch (e) {
console.error(e);
}
}
}
private handleAddObjectResponse = async (event: MessageEvent) => {
const data = event.data;
console.log('Received response from service worker (ADD_OBJECT):', data);
@ -195,6 +234,7 @@ export class Database {
if (data.type === 'NOTIFICATIONS') {
service.setNotifications(data.data);
} else if (data.type === 'TO_DOWNLOAD') {
console.log(`Received missing data ${data}`);
// Download the missing data
let requestedStateId = [];
for (const hash of data.data) {
@ -220,8 +260,6 @@ export class Database {
console.error(e);
}
}
// try to update list of my processes
await service.getMyProcesses();
}
};
@ -267,49 +305,6 @@ export class Database {
});
}
public updateMyProcesses(myProcessesId: string[]): Promise<void> {
if (myProcessesId.length === 0) {
return;
}
return new Promise(async (resolve, reject) => {
if (!this.serviceWorkerRegistration) {
// console.warn('Service worker registration is not ready. Waiting...');
this.serviceWorkerRegistration = await navigator.serviceWorker.ready;
}
const activeWorker = await this.waitForServiceWorkerActivation(this.serviceWorkerRegistration);
// Create a message channel for communication
const messageChannel = new MessageChannel();
// Handle the response from the service worker
messageChannel.port1.onmessage = (event) => {
if (event.data.status === 'success') {
resolve();
} else {
const error = event.data.message;
reject(new Error(error || 'Unknown error occurred while scanning our processes'));
}
};
try {
const payload = { myProcessesId };
console.log('Sending UPDATE_PROCESSES msg with payload', payload);
activeWorker?.postMessage(
{
type: 'UPDATE_PROCESSES',
payload,
},
[messageChannel.port2],
);
} catch (error) {
reject(new Error(`Failed to send message to service worker: ${error}`));
}
});
}
public async getObject(storeName: string, key: string): Promise<any | null> {
const db = await this.getDb();
const tx = db.transaction(storeName, 'readonly');