importation JS to TS changed

This commit is contained in:
NicolasCantu 2025-02-19 16:30:34 +01:00
parent 60b49a65e5
commit c0f8cc537c
2 changed files with 110 additions and 65 deletions

View File

@ -1,24 +1,73 @@
let processesToScan = new Set(); declare var self: ServiceWorkerGlobalScope;
let toDownload = new Set();
self.addEventListener('install', (event) => { // Interfaces
event.waitUntil(self.skipWaiting()); // Activate worker immediately interface Process {
states: State[];
merkle_root: string;
key: string;
}
interface State {
state_id: string;
commited_in: string;
merkle_root: string;
pcd_commitment?: {
[key: string]: string;
};
}
interface Diff {
process_id: string;
state_id: string;
value_commitment: string;
field: string;
description: string | null;
previous_value: any;
new_value: any;
notify_user: boolean;
need_validation: boolean;
validation_status: string;
}
interface ProcessWithDiffs {
process: State[];
processId: string;
diffs: Diff[][];
}
interface MessagePayload {
myProcessesId?: string[];
storeName?: string;
object?: any;
key?: IDBValidKey;
}
interface MessageEvent {
type: string;
payload?: MessagePayload;
}
let processesToScan: Set<string> = new Set();
let toDownload: Set<string> = new Set();
self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(self.skipWaiting());
}); });
self.addEventListener('activate', (event) => { self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(self.clients.claim()); // Become available to all pages event.waitUntil(self.clients.claim());
}); });
// Event listener for messages from clients self.addEventListener('message', async (event: ExtendableMessageEvent) => {
self.addEventListener('message', async (event) => { const data = event.data as MessageEvent;
const data = event.data;
if (data.type === 'START') { if (data.type === 'START') {
const fetchNotifications = async () => { processesToScan.clear();
const fetchNotifications = async (): Promise<void> => {
const itemsWithFlag = await getAllDiffsNeedValidation(); const itemsWithFlag = await getAllDiffsNeedValidation();
// Process items with the specific flag
itemsWithFlag?.forEach((item) => { itemsWithFlag?.forEach((item) => {
console.log(item); // Do something with each flagged item console.log(item);
}); });
event.ports[0].postMessage({ event.ports[0].postMessage({
@ -26,28 +75,23 @@ self.addEventListener('message', async (event) => {
data: itemsWithFlag, data: itemsWithFlag,
}); });
}; };
const scanMissingData = async () => {
const scanMissingData = async (): Promise<void> => {
console.log('Scanning for missing data...'); console.log('Scanning for missing data...');
const myProcesses = await getProcesses(processesToScan); const myProcesses = await getProcesses(processesToScan);
// Iterate on each process if (myProcesses && myProcesses.length !== 0) {
if (myProcesses && myProcesses.length != 0) {
for (const process of myProcesses) { for (const process of myProcesses) {
// Iterate on states
const firstState = process.states[0]; const firstState = process.states[0];
const processId = firstState.commited_in; const processId = firstState.commited_in;
for (const state of process.states) { for (const state of process.states) {
if (!state.pcd_commitment) continue; if (!state.pcd_commitment) continue;
// iterate on pcd_commitment
for (const [field, hash] of Object.entries(state.pcd_commitment)) { for (const [field, hash] of Object.entries(state.pcd_commitment)) {
// Check if we have the data in db
const existingData = await getBlob(hash); const existingData = await getBlob(hash);
if (!existingData) { if (!existingData) {
toDownload.add(hash); toDownload.add(hash);
// We also add an entry in diff, in case it doesn't already exist await addDiff(processId, state.state_id, hash, field);
await addDiff(processId, state.state_id, hash, field)
} else { } else {
// We remove it if we have it in the set
if (toDownload.delete(hash)) { if (toDownload.delete(hash)) {
console.log(`Removing ${hash} from the set`); console.log(`Removing ${hash} from the set`);
} }
@ -57,13 +101,14 @@ self.addEventListener('message', async (event) => {
} }
} }
if (toDownload.size != 0) { if (toDownload.size !== 0) {
event.ports[0].postMessage({ event.ports[0].postMessage({
type: 'TO_DOWNLOAD', type: 'TO_DOWNLOAD',
data: Array.from(toDownload), data: Array.from(toDownload),
}); });
} }
} };
fetchNotifications(); fetchNotifications();
setInterval(fetchNotifications, 2 * 60 * 1000); setInterval(fetchNotifications, 2 * 60 * 1000);
scanMissingData(); scanMissingData();
@ -72,24 +117,26 @@ self.addEventListener('message', async (event) => {
if (data.type === 'UPDATE_PROCESSES') { if (data.type === 'UPDATE_PROCESSES') {
try { try {
const { myProcessesId } = data.payload; const { myProcessesId } = data.payload || {};
console.log(myProcessesId); console.log(myProcessesId);
if (myProcessesId && myProcessesId.length != 0) { if (myProcessesId && myProcessesId.length !== 0) {
for (const processId of myProcessesId) { for (const processId of myProcessesId) {
processesToScan.add(processId); processesToScan.add(processId);
} }
console.log(processesToScan); console.log(processesToScan);
} else { } else {
event.ports[0].postMessage({ status: 'error', message: 'Empty lists' }); event.ports[0].postMessage({ status: 'error', message: 'Empty lists' });
} }
} catch (error) { } catch (error) {
event.ports[0].postMessage({ status: 'error', message: error.message }); event.ports[0].postMessage({ status: 'error', message: (error as Error).message });
} }
} }
if (data.type === 'ADD_OBJECT') { if (data.type === 'ADD_OBJECT') {
try { try {
const { storeName, object, key } = data.payload; const { storeName, object, key } = data.payload || {};
if (!storeName) throw new Error('Store name is required');
const db = await openDatabase(); const db = await openDatabase();
const tx = db.transaction(storeName, 'readwrite'); const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName); const store = tx.objectStore(storeName);
@ -102,22 +149,25 @@ self.addEventListener('message', async (event) => {
event.ports[0].postMessage({ status: 'success', message: '' }); event.ports[0].postMessage({ status: 'success', message: '' });
} catch (error) { } catch (error) {
event.ports[0].postMessage({ status: 'error', message: error.message }); event.ports[0].postMessage({ status: 'error', message: (error as Error).message });
} }
} }
}); });
async function openDatabase() { async function openDatabase(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = indexedDB.open('4nk', 1); const request = indexedDB.open('4nk', 1);
request.onerror = (event) => {
request.onerror = () => {
reject(request.error); reject(request.error);
}; };
request.onsuccess = (event) => {
request.onsuccess = () => {
resolve(request.result); resolve(request.result);
}; };
request.onupgradeneeded = (event) => {
const db = event.target.result; request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains('wallet')) { if (!db.objectStoreNames.contains('wallet')) {
db.createObjectStore('wallet', { keyPath: 'pre_id' }); db.createObjectStore('wallet', { keyPath: 'pre_id' });
} }
@ -125,8 +175,7 @@ async function openDatabase() {
}); });
} }
// Function to get all processes because it is asynchronous async function getAllProcesses(): Promise<Process[]> {
async function getAllProcesses() {
const db = await openDatabase(); const db = await openDatabase();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!db) { if (!db) {
@ -145,10 +194,10 @@ async function getAllProcesses() {
reject(request.error); reject(request.error);
}; };
}); });
}; }
async function getProcesses(processIds) { async function getProcesses(processIds: Set<string>): Promise<Process[]> {
if (!processIds || processIds.length === 0) { if (!processIds || processIds.size === 0) {
return []; return [];
} }
@ -161,34 +210,33 @@ async function getProcesses(processIds) {
const store = tx.objectStore('processes'); const store = tx.objectStore('processes');
const requests = Array.from(processIds).map((processId) => { const requests = Array.from(processIds).map((processId) => {
return new Promise((resolve) => { return new Promise<Process | undefined>((resolve) => {
const request = store.get(processId); const request = store.get(processId);
request.onsuccess = () => resolve(request.result); request.onsuccess = () => resolve(request.result);
request.onerror = () => { request.onerror = () => {
console.error(`Error fetching process ${processId}:`, request.error); console.error(`Error fetching process ${processId}:`, request.error);
resolve(undefined); resolve(undefined);
}; };
}); });
}); });
const results = await Promise.all(requests); const results = await Promise.all(requests);
return results.filter(result => result !== undefined); return results.filter((result): result is Process => result !== undefined);
} }
async function getAllDiffsNeedValidation() { async function getAllDiffsNeedValidation(): Promise<ProcessWithDiffs[]> {
const db = await openDatabase(); const db = await openDatabase();
const allProcesses = await getAllProcesses(); const allProcesses = await getAllProcesses();
const tx = db.transaction('diffs', 'readonly'); const tx = db.transaction('diffs', 'readonly');
const store = tx.objectStore('diffs'); const store = tx.objectStore('diffs');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = store.getAll(); const request = store.getAll();
request.onsuccess = (event) => { request.onsuccess = (event: Event) => {
const allItems = event.target.result; const allItems = (event.target as IDBRequest).result as Diff[];
const itemsWithFlag = allItems.filter((item) => item.need_validation); const itemsWithFlag = allItems.filter((item) => item.need_validation);
const processMap = {}; const processMap: { [key: string]: { process: State[]; processId: string; diffs: Diff[]; } } = {};
for (const diff of itemsWithFlag) { for (const diff of itemsWithFlag) {
const currentProcess = allProcesses.find((item) => { const currentProcess = allProcesses.find((item) => {
@ -210,11 +258,11 @@ async function getAllDiffsNeedValidation() {
} }
const results = Object.values(processMap).map((entry) => { const results = Object.values(processMap).map((entry) => {
const diffs = [] const diffs: Diff[][] = [];
for(const state of entry.process) { for(const state of entry.process) {
const filteredDiff = entry.diffs.filter(diff => diff.new_state_merkle_root === state.merkle_root); const filteredDiff = entry.diffs.filter(diff => diff.new_state_merkle_root === state.merkle_root);
if(filteredDiff && filteredDiff.length) { if(filteredDiff && filteredDiff.length) {
diffs.push(filteredDiff) diffs.push(filteredDiff);
} }
} }
return { return {
@ -227,44 +275,43 @@ async function getAllDiffsNeedValidation() {
resolve(results); resolve(results);
}; };
request.onerror = (event) => { request.onerror = (event: Event) => {
reject(event.target.error); reject((event.target as IDBRequest).error);
}; };
}); });
} }
async function getBlob(hash) { async function getBlob(hash: string): Promise<any> {
const db = await openDatabase(); const db = await openDatabase();
const storeName = 'data'; const storeName = 'data';
const tx = db.transaction(storeName, 'readonly'); const tx = db.transaction(storeName, 'readonly');
const store = tx.objectStore(storeName); const store = tx.objectStore(storeName);
const result = await new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
const getRequest = store.get(hash); const getRequest = store.get(hash);
getRequest.onsuccess = () => resolve(getRequest.result); getRequest.onsuccess = () => resolve(getRequest.result);
getRequest.onerror = () => reject(getRequest.error); getRequest.onerror = () => reject(getRequest.error);
}); });
return result;
} }
async function addDiff(processId, stateId, hash) { async function addDiff(processId: string, stateId: string, hash: string, field: string): Promise<IDBValidKey> {
const db = await openDatabase(); const db = await openDatabase();
const storeName = 'diffs'; const storeName = 'diffs';
const tx = db.transaction(storeName, 'readwrite'); const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName); const store = tx.objectStore(storeName);
// Check if the diff already exists const existingDiff = await new Promise<Diff | undefined>((resolve, reject) => {
const existingDiff = await new Promise((resolve, reject) => {
const getRequest = store.get(hash); const getRequest = store.get(hash);
getRequest.onsuccess = () => resolve(getRequest.result); getRequest.onsuccess = () => resolve(getRequest.result);
getRequest.onerror = () => reject(getRequest.error); getRequest.onerror = () => reject(getRequest.error);
}); });
if (!existingDiff) { if (!existingDiff) {
const newDiff = { const newDiff: Diff = {
process_id: processId, process_id: processId,
state_id: stateId, state_id: stateId,
value_commitment: hash, value_commitment: hash,
field: '', field: field,
description: null, description: null,
previous_value: null, previous_value: null,
new_value: null, new_value: null,
@ -273,13 +320,11 @@ async function addDiff(processId, stateId, hash) {
validation_status: 'None' validation_status: 'None'
}; };
const insertResult = await new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const putRequest = store.put(newDiff); const putRequest = store.put(newDiff);
putRequest.onsuccess = () => resolve(putRequest.result); putRequest.onsuccess = () => resolve(putRequest.result);
putRequest.onerror = () => reject(putRequest.error); putRequest.onerror = () => reject(putRequest.error);
}); });
return insertResult;
} }
return existingDiff; return existingDiff;

View File

@ -119,7 +119,7 @@ export class Database {
const registrations = await navigator.serviceWorker.getRegistrations(); const registrations = await navigator.serviceWorker.getRegistrations();
if (registrations.length === 0) { if (registrations.length === 0) {
// No existing workers: register a new one. // No existing workers: register a new one.
this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' }); this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.ts', { type: 'module' });
console.log('Service Worker registered with scope:', registration.scope); console.log('Service Worker registered with scope:', registration.scope);
} else if (registrations.length === 1) { } else if (registrations.length === 1) {
// One existing worker: update it (restart it) without unregistering. // One existing worker: update it (restart it) without unregistering.
@ -131,7 +131,7 @@ export class Database {
console.log('Multiple Service Worker(s) detected. Unregistering all...'); console.log('Multiple Service Worker(s) detected. Unregistering all...');
await Promise.all(registrations.map(reg => reg.unregister())); await Promise.all(registrations.map(reg => reg.unregister()));
console.log('All previous Service Workers unregistered.'); console.log('All previous Service Workers unregistered.');
this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.js', { type: 'module' }); this.serviceWorkerRegistration = await navigator.serviceWorker.register('/src/service-workers/database.worker.ts', { type: 'module' });
console.log('Service Worker registered with scope:', registration.scope); console.log('Service Worker registered with scope:', registration.scope);
} }