ihm_client/public/data.worker.js

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
}
}
});