refactor(network.service): implement event-driven mechanism for relay readiness, replacing polling with promise-based handling for improved efficiency and clarity

This commit is contained in:
NicolasCantu 2025-12-02 00:54:14 +01:00
parent 355d5ea18d
commit d78dc14a2b

View File

@ -9,6 +9,10 @@ export class NetworkService {
// Cache local // Cache local
private localRelays: Record<string, string> = {}; private localRelays: Record<string, string> = {};
// Mécanisme d'attente (Events)
private relayReadyResolver: ((addr: string) => void) | null = null;
private relayReadyPromise: Promise<string> | null = null;
constructor(private bootstrapUrls: string[]) { constructor(private bootstrapUrls: string[]) {
this.workerInstance = new Worker( this.workerInstance = new Worker(
new URL("../../workers/network.worker.ts", import.meta.url), new URL("../../workers/network.worker.ts", import.meta.url),
@ -42,36 +46,47 @@ export class NetworkService {
await this.worker.sendMessage(flag as any, content); await this.worker.sendMessage(flag as any, content);
} }
// Cette méthode est appelée par le Worker (via Services.ts) ou par onStatusChange
public updateRelay(url: string, spAddress: string) { public updateRelay(url: string, spAddress: string) {
this.localRelays[url] = spAddress; this.localRelays[url] = spAddress;
// ✨ EVENT TRIGGER : Si quelqu'un attendait un relais, on le débloque !
if (spAddress && spAddress !== "" && this.relayReadyResolver) {
this.relayReadyResolver(spAddress);
this.relayReadyResolver = null;
this.relayReadyPromise = null;
}
} }
public getAllRelays() { public getAllRelays() {
return this.localRelays; return this.localRelays;
} }
// 🔥 CORRECTION ICI : Ajout d'une boucle d'attente (Polling)
public async getAvailableRelayAddress(): Promise<string> { public async getAvailableRelayAddress(): Promise<string> {
const maxRetries = 20; // 20 tentatives // 1. Vérification immédiate (Fast path)
const interval = 500; // toutes les 500ms = 10 secondes max const existing = Object.values(this.localRelays).find(
(addr) => addr && addr !== ""
);
if (existing) return existing;
for (let i = 0; i < maxRetries; i++) { // 2. Si pas encore là, on crée une "barrière" (Promise)
// On demande au worker if (!this.relayReadyPromise) {
const addr = await this.worker.getAvailableRelay(); console.log("[NetworkService] ⏳ Attente d'un événement Handshake...");
this.relayReadyPromise = new Promise<string>((resolve, reject) => {
this.relayReadyResolver = resolve;
if (addr && addr !== "") { // Timeout de sécurité (10s) pour ne pas bloquer indéfiniment
return addr; // Trouvé ! setTimeout(() => {
} if (this.relayReadyResolver) {
reject(new Error("Timeout: Aucun relais reçu après 10s"));
// Pas encore là ? On attend un peu... this.relayReadyResolver = null;
if (i === 0) this.relayReadyPromise = null;
console.log("[NetworkService] ⏳ Attente du Handshake relais..."); }
await new Promise((r) => setTimeout(r, interval)); }, 10000);
});
} }
throw new Error( return this.relayReadyPromise;
"Timeout: Aucun relais disponible après 10s (Handshake non reçu ?)"
);
} }
// --- INTERNES --- // --- INTERNES ---
@ -87,7 +102,8 @@ export class NetworkService {
spAddress?: string spAddress?: string
) { ) {
if (status === "OPEN" && spAddress) { if (status === "OPEN" && spAddress) {
this.localRelays[url] = spAddress; // Met à jour et déclenche potentiellement le resolve()
this.updateRelay(url, spAddress);
} else if (status === "CLOSED") { } else if (status === "CLOSED") {
this.localRelays[url] = ""; this.localRelays[url] = "";
} }