204 lines
6.0 KiB
JavaScript
204 lines
6.0 KiB
JavaScript
// public/data.worker.js
|
|
|
|
const DB_NAME = "4nk";
|
|
const DB_VERSION = 1;
|
|
const EMPTY32BYTES = String("").padStart(64, "0");
|
|
|
|
// ============================================
|
|
// SERVICE WORKER LIFECYCLE
|
|
// ============================================
|
|
|
|
self.addEventListener("install", (event) => {
|
|
event.waitUntil(self.skipWaiting());
|
|
});
|
|
|
|
self.addEventListener("activate", (event) => {
|
|
event.waitUntil(self.clients.claim());
|
|
});
|
|
|
|
// ============================================
|
|
// INDEXEDDB DIRECT ACCESS (READ-ONLY)
|
|
// ============================================
|
|
|
|
/**
|
|
* Ouvre une connexion à la BDD directement depuis le Service Worker
|
|
*/
|
|
function openDB() {
|
|
return new Promise((resolve, reject) => {
|
|
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
request.onerror = () => reject(request.error);
|
|
request.onsuccess = () => resolve(request.result);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Récupère un objet spécifique (équivalent à GET_OBJECT)
|
|
*/
|
|
function getObject(db, storeName, key) {
|
|
return new Promise((resolve, reject) => {
|
|
const transaction = db.transaction(storeName, "readonly");
|
|
const store = transaction.objectStore(storeName);
|
|
const request = store.get(key);
|
|
request.onerror = () => reject(request.error);
|
|
request.onsuccess = () => resolve(request.result);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
};
|
|
});
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// SCAN LOGIC
|
|
// ============================================
|
|
|
|
async function scanMissingData(processesToScan) {
|
|
console.log("[Service Worker] 🚀 Scanning with DIRECT DB ACCESS...");
|
|
|
|
let db;
|
|
try {
|
|
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 diffsToCreate = [];
|
|
|
|
if (myProcesses && myProcesses.length !== 0) {
|
|
for (const process of myProcesses) {
|
|
if (!process || !process.states) continue;
|
|
|
|
const firstState = process.states[0];
|
|
// Sécurisation : on vérifie que firstState existe
|
|
if (!firstState) continue;
|
|
|
|
const processId = firstState.commited_in;
|
|
|
|
for (const state of process.states) {
|
|
if (state.state_id === EMPTY32BYTES) continue;
|
|
|
|
for (const [field, hash] of Object.entries(state.pcd_commitment)) {
|
|
// On ignore les données publiques ou les rôles
|
|
if (
|
|
(state.public_data && state.public_data[field] !== undefined) ||
|
|
field === "roles"
|
|
)
|
|
continue;
|
|
|
|
// 2. Vérification directe dans 'data'
|
|
const existingData = await getObject(db, "data", hash);
|
|
|
|
if (!existingData) {
|
|
toDownload.add(hash);
|
|
|
|
// 3. Vérification directe dans 'diffs'
|
|
const existingDiff = await getObject(db, "diffs", hash);
|
|
|
|
if (!existingDiff) {
|
|
diffsToCreate.push({
|
|
process_id: processId,
|
|
state_id: state.state_id,
|
|
value_commitment: hash,
|
|
roles: state.roles,
|
|
field: field,
|
|
description: null,
|
|
previous_value: null,
|
|
new_value: null,
|
|
notify_user: false,
|
|
need_validation: false,
|
|
validation_status: "None",
|
|
});
|
|
}
|
|
} else {
|
|
// Si on a trouvé la donnée, on est sûr de ne pas avoir besoin de la télécharger
|
|
if (toDownload.has(hash)) {
|
|
toDownload.delete(hash);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
toDownload: Array.from(toDownload),
|
|
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
|
|
}
|
|
}
|
|
});
|