fix(service): Remplacer le polling des clés par un listener pour éviter une race condition
This commit is contained in:
parent
f610a1bfa6
commit
95e7044e0a
@ -36,6 +36,7 @@ export default class Services {
|
||||
private relayReadyResolver: (() => void) | null = null;
|
||||
private relayReadyPromise: Promise<void> | null = null;
|
||||
private secretsAreCompromised: boolean = false;
|
||||
private pendingKeyRequests: Map<string, (key: string) => void> = new Map();
|
||||
// Private constructor to prevent direct instantiation from outside
|
||||
private constructor() {}
|
||||
|
||||
@ -1138,10 +1139,44 @@ export default class Services {
|
||||
}
|
||||
}
|
||||
|
||||
this._resolvePendingKeyRequests(updatedProcess.current_process);
|
||||
|
||||
// Vérifier la logique métier spécifique au pairing
|
||||
await this.checkAndConfirmPairing(processId, updatedProcess);
|
||||
}
|
||||
|
||||
private _resolvePendingKeyRequests(process: Process) {
|
||||
if (this.pendingKeyRequests.size === 0) {
|
||||
return; // Optimisation : ne rien faire si personne n'attend
|
||||
}
|
||||
|
||||
console.log(`[Services:KeyResolver] 🔍 Vérification de ${this.pendingKeyRequests.size} requête(s) de clé en attente...`);
|
||||
|
||||
for (const state of process.states) {
|
||||
if (!state.keys || Object.keys(state.keys).length === 0) {
|
||||
continue; // Pas de clés dans cet état
|
||||
}
|
||||
|
||||
for (const [attributeName, key] of Object.entries(state.keys)) {
|
||||
const requestId = `${process.process_id}_${state.state_id}_${attributeName}`;
|
||||
|
||||
// Avons-nous une requête en attente pour CETTE clé ?
|
||||
if (this.pendingKeyRequests.has(requestId)) {
|
||||
console.log(`[Services:KeyResolver] ✅ Résolution de la requête pour ${requestId}`);
|
||||
|
||||
// Récupérer la fonction "resolve" et l'appeler avec la clé
|
||||
const resolveCallback = this.pendingKeyRequests.get(requestId);
|
||||
if (resolveCallback) {
|
||||
resolveCallback(key as string);
|
||||
}
|
||||
|
||||
// Nettoyer la requête
|
||||
this.pendingKeyRequests.delete(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async saveEncryptedData(encryptedData: Record<string, string>) {
|
||||
console.log(`[Services:saveEncryptedData] 💾 Sauvegarde de ${Object.keys(encryptedData).length} blob(s) chiffré(s)...`);
|
||||
for (const [hash, cipher] of Object.entries(encryptedData)) {
|
||||
@ -1906,11 +1941,11 @@ export default class Services {
|
||||
}
|
||||
|
||||
/**
|
||||
* NOUVELLE MÉTHODE PRIVÉE
|
||||
* Gère la logique complexe de demande aux pairs et la boucle de retentative.
|
||||
* NOUVELLE MÉTHODE PRIVÉE (MODIFIÉE)
|
||||
* Gère la logique de demande aux pairs en utilisant un système de Promise au lieu de polling.
|
||||
*/
|
||||
private async _fetchMissingKey(processId: string, state: ProcessState, attribute: string): Promise<{ hash: string | null; key: string | null }> {
|
||||
console.group(`🔐 Gestion de la clé manquante pour '${attribute}'`);
|
||||
console.group(`🔐 Gestion de la clé manquante pour '${attribute}' (via Promise)`);
|
||||
|
||||
try {
|
||||
const process = await this.getProcess(processId);
|
||||
@ -1919,53 +1954,42 @@ export default class Services {
|
||||
return { hash: null, key: null };
|
||||
}
|
||||
|
||||
// 1. Demander les connexions et envoyer la requête (comme avant)
|
||||
await this.ensureConnections(process);
|
||||
console.log(`🗣️ Demande de données aux pairs...`);
|
||||
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
||||
|
||||
// Boucle de retentative
|
||||
const maxRetries = 5;
|
||||
const retryDelay = 500;
|
||||
let retries = 0;
|
||||
let hash: string | null = null;
|
||||
let key: string | null = null;
|
||||
// 2. CRÉER LA PROMISE D'ATTENTE
|
||||
const requestId = `${processId}_${state.state_id}_${attribute}`;
|
||||
const keyRequestPromise = new Promise<string>((resolve, reject) => {
|
||||
// Sécurité : Définir un timeout (ex: 15 secondes)
|
||||
const timeout = setTimeout(() => {
|
||||
console.warn(`⌛ Timeout: La clé pour '${attribute}' n'est jamais arrivée.`);
|
||||
this.pendingKeyRequests.delete(requestId); // Nettoyer
|
||||
reject(new Error(`Timeout waiting for key: ${attribute}`));
|
||||
}, 15000); // 15 secondes
|
||||
|
||||
console.groupCollapsed(`⏳ Boucle d'attente de la clé (max ${maxRetries} tentatives)`);
|
||||
try {
|
||||
while (retries < maxRetries) {
|
||||
console.log(`(Tentative ${retries + 1}/${maxRetries})...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||
// Enregistrer le "resolve" pour qu'il soit appelé de l'extérieur
|
||||
this.pendingKeyRequests.set(requestId, (key: string) => {
|
||||
clearTimeout(timeout); // Annuler le timeout
|
||||
console.log(`✅ Clé reçue via listener pour '${attribute}'!`);
|
||||
resolve(key);
|
||||
});
|
||||
});
|
||||
|
||||
// On rafraîchit les données depuis la source
|
||||
const updatedProcess = await this.getProcess(processId);
|
||||
const updatedState = this.getStateFromId(updatedProcess, state.state_id);
|
||||
// 3. Attendre la clé
|
||||
const receivedKey = await keyRequestPromise;
|
||||
|
||||
if (updatedState) {
|
||||
hash = updatedState.pcd_commitment[attribute];
|
||||
key = updatedState.keys[attribute];
|
||||
// 4. Re-vérifier l'état (le hash a pu changer)
|
||||
const updatedProcess = await this.getProcess(processId);
|
||||
const updatedState = this.getStateFromId(updatedProcess, state.state_id);
|
||||
const updatedHash = updatedState ? updatedState.pcd_commitment[attribute] : state.pcd_commitment[attribute];
|
||||
|
||||
if (hash && key) {
|
||||
console.log('✅ Clé et hash reçus !');
|
||||
break; // Sortir de la boucle while
|
||||
}
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
} finally {
|
||||
// Garantit la fermeture du groupe de la boucle
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
if (!hash || !key) {
|
||||
console.warn(`⌛ Clé ou hash toujours manquant après ${maxRetries} tentatives.`);
|
||||
}
|
||||
|
||||
return { hash, key };
|
||||
return { hash: updatedHash, key: receivedKey };
|
||||
} catch (e) {
|
||||
console.error(`💥 Erreur durant _fetchMissingKey: ${e}`);
|
||||
return { hash: null, key: null };
|
||||
} finally {
|
||||
// Garantit la fermeture du groupe de gestion de clé
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user