Compare commits
2 Commits
4f86b26890
...
23fe47f69f
| Author | SHA1 | Date | |
|---|---|---|---|
| 23fe47f69f | |||
| a9976ca624 |
@ -1,38 +1,33 @@
|
|||||||
import * as Comlink from 'comlink';
|
import * as Comlink from "comlink";
|
||||||
import type { NetworkBackend } from '../../workers/network.worker';
|
import type { NetworkBackend } from "../../workers/network.worker";
|
||||||
import Services from '../service'; // Attention à la dépendance circulaire, on va gérer ça
|
import Services from "../service";
|
||||||
|
|
||||||
export class NetworkService {
|
export class NetworkService {
|
||||||
private worker: Comlink.Remote<NetworkBackend>;
|
private worker: Comlink.Remote<NetworkBackend>;
|
||||||
private workerInstance: Worker;
|
private workerInstance: Worker;
|
||||||
|
|
||||||
// Cache local pour répondre instantanément aux demandes synchrones de l'UI
|
// Cache local
|
||||||
private localRelays: Record<string, string> = {};
|
private localRelays: Record<string, string> = {};
|
||||||
|
|
||||||
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),
|
||||||
{ type: 'module' }
|
{ type: "module" }
|
||||||
);
|
);
|
||||||
this.worker = Comlink.wrap<NetworkBackend>(this.workerInstance);
|
this.worker = Comlink.wrap<NetworkBackend>(this.workerInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialisation appelée par Services.ts
|
|
||||||
public async initRelays() {
|
public async initRelays() {
|
||||||
// 1. Setup des callbacks : Quand le worker reçoit un message, il appelle ici
|
|
||||||
await this.worker.setCallbacks(
|
await this.worker.setCallbacks(
|
||||||
Comlink.proxy(this.onMessageReceived.bind(this)),
|
Comlink.proxy(this.onMessageReceived.bind(this)),
|
||||||
Comlink.proxy(this.onStatusChange.bind(this))
|
Comlink.proxy(this.onStatusChange.bind(this))
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2. Lancer les connexions
|
|
||||||
for (const url of this.bootstrapUrls) {
|
for (const url of this.bootstrapUrls) {
|
||||||
this.addWebsocketConnection(url);
|
this.addWebsocketConnection(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MÉTHODES PUBLIQUES (API inchangée) ---
|
|
||||||
|
|
||||||
public async addWebsocketConnection(url: string) {
|
public async addWebsocketConnection(url: string) {
|
||||||
await this.worker.connect(url);
|
await this.worker.connect(url);
|
||||||
}
|
}
|
||||||
@ -44,14 +39,10 @@ export class NetworkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async sendMessage(flag: string, content: string) {
|
public async sendMessage(flag: string, content: string) {
|
||||||
// On transmet au worker
|
|
||||||
// Note: Le type 'any' est utilisé pour simplifier la compatibilité avec AnkFlag
|
|
||||||
await this.worker.sendMessage(flag as any, content);
|
await this.worker.sendMessage(flag as any, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateRelay(url: string, spAddress: string) {
|
public updateRelay(url: string, spAddress: string) {
|
||||||
// Cette méthode était utilisée pour update l'état local.
|
|
||||||
// Maintenant c'est le worker qui gère la vérité, mais on garde le cache local.
|
|
||||||
this.localRelays[url] = spAddress;
|
this.localRelays[url] = spAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,30 +50,46 @@ export class NetworkService {
|
|||||||
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> {
|
||||||
// On demande au worker qui a la "vraie" info temps réel
|
const maxRetries = 20; // 20 tentatives
|
||||||
const addr = await this.worker.getAvailableRelay();
|
const interval = 500; // toutes les 500ms = 10 secondes max
|
||||||
if (addr) return addr;
|
|
||||||
|
|
||||||
// Fallback ou attente...
|
for (let i = 0; i < maxRetries; i++) {
|
||||||
throw new Error('Aucun relais disponible (NetworkWorker)');
|
// On demande au worker
|
||||||
|
const addr = await this.worker.getAvailableRelay();
|
||||||
|
|
||||||
|
if (addr && addr !== "") {
|
||||||
|
return addr; // Trouvé !
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pas encore là ? On attend un peu...
|
||||||
|
if (i === 0)
|
||||||
|
console.log("[NetworkService] ⏳ Attente du Handshake relais...");
|
||||||
|
await new Promise((r) => setTimeout(r, interval));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
"Timeout: Aucun relais disponible après 10s (Handshake non reçu ?)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- INTERNES (CALLBACKS) ---
|
// --- INTERNES ---
|
||||||
|
|
||||||
private async onMessageReceived(flag: string, content: string, url: string) {
|
private async onMessageReceived(flag: string, content: string, url: string) {
|
||||||
// C'est ici qu'on fait le pont : NetworkWorker -> Main -> CoreWorker
|
|
||||||
// On passe par l'instance Singleton de Services pour atteindre le CoreWorker
|
|
||||||
const services = await Services.getInstance();
|
const services = await Services.getInstance();
|
||||||
await services.dispatchToWorker(flag, content, url);
|
await services.dispatchToWorker(flag, content, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onStatusChange(url: string, status: 'OPEN' | 'CLOSED', spAddress?: string) {
|
private onStatusChange(
|
||||||
if (status === 'OPEN' && spAddress) {
|
url: string,
|
||||||
|
status: "OPEN" | "CLOSED",
|
||||||
|
spAddress?: string
|
||||||
|
) {
|
||||||
|
if (status === "OPEN" && spAddress) {
|
||||||
this.localRelays[url] = spAddress;
|
this.localRelays[url] = spAddress;
|
||||||
} else if (status === 'CLOSED') {
|
} else if (status === "CLOSED") {
|
||||||
this.localRelays[url] = '';
|
this.localRelays[url] = "";
|
||||||
}
|
}
|
||||||
// On pourrait notifier l'UI ici de l'état de la connexion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Services from '../services/service';
|
import Services from "../services/service";
|
||||||
import { getCorrectDOM } from './html.utils';
|
import { getCorrectDOM } from "./html.utils";
|
||||||
import { addSubscription } from './subscription.utils';
|
import { addSubscription } from "./subscription.utils";
|
||||||
|
|
||||||
//Generate emojis list
|
//Generate emojis list
|
||||||
export function generateEmojiList(): string[] {
|
export function generateEmojiList(): string[] {
|
||||||
@ -30,7 +30,7 @@ export async function addressToEmoji(text: string): Promise<string> {
|
|||||||
//Adress to Hash
|
//Adress to Hash
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
const data = encoder.encode(text);
|
const data = encoder.encode(text);
|
||||||
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||||
|
|
||||||
const hash = new Uint8Array(hashBuffer);
|
const hash = new Uint8Array(hashBuffer);
|
||||||
const bytes = hash.slice(-4);
|
const bytes = hash.slice(-4);
|
||||||
@ -39,17 +39,19 @@ export async function addressToEmoji(text: string): Promise<string> {
|
|||||||
const emojiList = generateEmojiList();
|
const emojiList = generateEmojiList();
|
||||||
const emojis = Array.from(bytes)
|
const emojis = Array.from(bytes)
|
||||||
.map((byte) => emojiList[byte])
|
.map((byte) => emojiList[byte])
|
||||||
.join('');
|
.join("");
|
||||||
return emojis;
|
return emojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get emojis from other device
|
//Get emojis from other device
|
||||||
async function emojisPairingRequest() {
|
async function emojisPairingRequest() {
|
||||||
try {
|
try {
|
||||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
const container = getCorrectDOM("login-4nk-component") as HTMLElement;
|
||||||
|
|
||||||
const urlParams: URLSearchParams = new URLSearchParams(window.location.search);
|
const urlParams: URLSearchParams = new URLSearchParams(
|
||||||
const sp_adress: string | null = urlParams.get('sp_address');
|
window.location.search
|
||||||
|
);
|
||||||
|
const sp_adress: string | null = urlParams.get("sp_address");
|
||||||
|
|
||||||
if (!sp_adress) {
|
if (!sp_adress) {
|
||||||
// console.error("No 'sp_adress' parameter found in the URL.");
|
// console.error("No 'sp_adress' parameter found in the URL.");
|
||||||
@ -57,10 +59,10 @@ async function emojisPairingRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const emojis = await addressToEmoji(sp_adress);
|
const emojis = await addressToEmoji(sp_adress);
|
||||||
const emojiDisplay = container?.querySelector('.pairing-request');
|
const emojiDisplay = container?.querySelector(".pairing-request");
|
||||||
|
|
||||||
if (emojiDisplay) {
|
if (emojiDisplay) {
|
||||||
emojiDisplay.textContent = '(Request from: ' + emojis + ')';
|
emojiDisplay.textContent = "(Request from: " + emojis + ")";
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -69,11 +71,11 @@ async function emojisPairingRequest() {
|
|||||||
|
|
||||||
// Display address emojis and other device emojis
|
// Display address emojis and other device emojis
|
||||||
export async function displayEmojis(text: string) {
|
export async function displayEmojis(text: string) {
|
||||||
console.log('🚀 ~ Services ~ adressToEmoji');
|
console.log("🚀 ~ Services ~ adressToEmoji");
|
||||||
try {
|
try {
|
||||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
const container = getCorrectDOM("login-4nk-component") as HTMLElement;
|
||||||
const emojis = await addressToEmoji(text);
|
const emojis = await addressToEmoji(text);
|
||||||
const emojiDisplay = container?.querySelector('.emoji-display');
|
const emojiDisplay = container?.querySelector(".emoji-display");
|
||||||
|
|
||||||
if (emojiDisplay) {
|
if (emojiDisplay) {
|
||||||
emojiDisplay.textContent = emojis;
|
emojiDisplay.textContent = emojis;
|
||||||
@ -89,13 +91,19 @@ export async function displayEmojis(text: string) {
|
|||||||
|
|
||||||
// Verify Other address
|
// Verify Other address
|
||||||
export function initAddressInput() {
|
export function initAddressInput() {
|
||||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
const container = getCorrectDOM("login-4nk-component") as HTMLElement;
|
||||||
const addressInput = container.querySelector('#addressInput') as HTMLInputElement;
|
const addressInput = container.querySelector(
|
||||||
const emojiDisplay = container.querySelector('#emoji-display-2');
|
"#addressInput"
|
||||||
const okButton = container.querySelector('#okButton') as HTMLButtonElement;
|
) as HTMLInputElement;
|
||||||
const createButton = container.querySelector('#createButton') as HTMLButtonElement;
|
const emojiDisplay = container.querySelector("#emoji-display-2");
|
||||||
const actionButton = container.querySelector('#actionButton') as HTMLButtonElement;
|
const okButton = container.querySelector("#okButton") as HTMLButtonElement;
|
||||||
addSubscription(addressInput, 'input', async () => {
|
const createButton = container.querySelector(
|
||||||
|
"#createButton"
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
const actionButton = container.querySelector(
|
||||||
|
"#actionButton"
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
addSubscription(addressInput, "input", async () => {
|
||||||
let address = addressInput.value;
|
let address = addressInput.value;
|
||||||
|
|
||||||
// Vérifie si l'adresse est une URL
|
// Vérifie si l'adresse est une URL
|
||||||
@ -103,7 +111,7 @@ export function initAddressInput() {
|
|||||||
const url = new URL(address);
|
const url = new URL(address);
|
||||||
// Si c'est une URL valide, extraire le paramètre sp_address
|
// Si c'est une URL valide, extraire le paramètre sp_address
|
||||||
const urlParams = new URLSearchParams(url.search);
|
const urlParams = new URLSearchParams(url.search);
|
||||||
const extractedAddress = urlParams.get('sp_address') || ''; // Prend sp_address ou une chaîne vide
|
const extractedAddress = urlParams.get("sp_address") || ""; // Prend sp_address ou une chaîne vide
|
||||||
|
|
||||||
if (extractedAddress) {
|
if (extractedAddress) {
|
||||||
address = extractedAddress;
|
address = extractedAddress;
|
||||||
@ -119,20 +127,20 @@ export function initAddressInput() {
|
|||||||
emojiDisplay.textContent = emojis;
|
emojiDisplay.textContent = emojis;
|
||||||
}
|
}
|
||||||
if (okButton) {
|
if (okButton) {
|
||||||
okButton.style.display = 'inline-block';
|
okButton.style.display = "inline-block";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (emojiDisplay) {
|
if (emojiDisplay) {
|
||||||
emojiDisplay.textContent = '';
|
emojiDisplay.textContent = "";
|
||||||
}
|
}
|
||||||
if (okButton) {
|
if (okButton) {
|
||||||
okButton.style.display = 'none';
|
okButton.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (createButton) {
|
if (createButton) {
|
||||||
addSubscription(createButton, 'click', () => {
|
addSubscription(createButton, "click", () => {
|
||||||
onCreateButtonClick();
|
onCreateButtonClick();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -142,14 +150,14 @@ async function onCreateButtonClick() {
|
|||||||
try {
|
try {
|
||||||
await prepareAndSendPairingTx();
|
await prepareAndSendPairingTx();
|
||||||
// Don't call confirmPairing immediately - it will be called when the pairing process is complete
|
// Don't call confirmPairing immediately - it will be called when the pairing process is complete
|
||||||
console.log('Pairing process initiated. Waiting for completion...');
|
console.log("Pairing process initiated. Waiting for completion...");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`onCreateButtonClick error: ${e}`);
|
console.error(`onCreateButtonClick error: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Une constante est plus claire qu'une 'magic string' ("")
|
// Une constante est plus claire qu'une 'magic string' ("")
|
||||||
const DEFAULT_PAIRING_PAYLOAD = '';
|
const DEFAULT_PAIRING_PAYLOAD = "";
|
||||||
|
|
||||||
export async function prepareAndSendPairingTx(): Promise<void> {
|
export async function prepareAndSendPairingTx(): Promise<void> {
|
||||||
const service = await Services.getInstance();
|
const service = await Services.getInstance();
|
||||||
@ -157,18 +165,22 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
// 1. Création du processus d'appairage
|
// 1. Création du processus d'appairage
|
||||||
// const relayAddress = service.getAllRelays(); // <-- Cette variable n'était pas utilisée
|
// const relayAddress = service.getAllRelays(); // <-- Cette variable n'était pas utilisée
|
||||||
const createPairingProcessReturn = await service.createPairingProcess(DEFAULT_PAIRING_PAYLOAD, []);
|
const createPairingProcessReturn = await service.createPairingProcess(
|
||||||
|
DEFAULT_PAIRING_PAYLOAD,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
if (!createPairingProcessReturn.updated_process) {
|
if (!createPairingProcessReturn.updated_process) {
|
||||||
throw new Error('createPairingProcess returned an empty new process');
|
throw new Error("createPairingProcess returned an empty new process");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilisation du "destructuring" pour assigner les variables
|
// Utilisation du "destructuring" pour assigner les variables
|
||||||
const { process_id: pairingId, current_process: process } = createPairingProcessReturn.updated_process;
|
const { process_id: pairingId, current_process: process } =
|
||||||
|
createPairingProcessReturn.updated_process;
|
||||||
|
|
||||||
// Ajout d'une vérification pour éviter les erreurs si states est vide
|
// Ajout d'une vérification pour éviter les erreurs si states est vide
|
||||||
if (!process.states || process.states.length === 0) {
|
if (!process.states || process.states.length === 0) {
|
||||||
throw new Error('Le processus reçu ne contient aucun état (state)');
|
throw new Error("Le processus reçu ne contient aucun état (state)");
|
||||||
}
|
}
|
||||||
const stateId = process.states[0].state_id;
|
const stateId = process.states[0].state_id;
|
||||||
|
|
||||||
@ -176,11 +188,12 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
|||||||
await service.ensureConnections(process, stateId);
|
await service.ensureConnections(process, stateId);
|
||||||
|
|
||||||
// 3. Mettre à jour l'état du service
|
// 3. Mettre à jour l'état du service
|
||||||
service.setProcessId(pairingId);
|
await service.setProcessId(pairingId);
|
||||||
service.setStateId(stateId);
|
await service.setStateId(stateId);
|
||||||
|
|
||||||
// 4. Appairer le 'device'
|
// 4. Appairer le 'device'
|
||||||
service.pairDevice(pairingId, [service.getDeviceAddress()]);
|
const myAddress = await service.getDeviceAddress();
|
||||||
|
await service.pairDevice(pairingId, [myAddress]);
|
||||||
|
|
||||||
// 5. Mettre à jour la BDD
|
// 5. Mettre à jour la BDD
|
||||||
try {
|
try {
|
||||||
@ -190,13 +203,19 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
|||||||
await service.saveDeviceInDatabase(currentDevice);
|
await service.saveDeviceInDatabase(currentDevice);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Échec non-critique de la mise à jour BDD (pairing_process_commitment):', err);
|
console.error(
|
||||||
|
"Échec non-critique de la mise à jour BDD (pairing_process_commitment):",
|
||||||
|
err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Gérer les étapes suivantes du processus
|
// 6. Gérer les étapes suivantes du processus
|
||||||
await service.handleApiReturn(createPairingProcessReturn);
|
await service.handleApiReturn(createPairingProcessReturn);
|
||||||
|
|
||||||
const createPrdUpdateReturn = await service.createPrdUpdate(pairingId, stateId);
|
const createPrdUpdateReturn = await service.createPrdUpdate(
|
||||||
|
pairingId,
|
||||||
|
stateId
|
||||||
|
);
|
||||||
await service.handleApiReturn(createPrdUpdateReturn);
|
await service.handleApiReturn(createPrdUpdateReturn);
|
||||||
|
|
||||||
const approveChangeReturn = await service.approveChange(pairingId, stateId);
|
const approveChangeReturn = await service.approveChange(pairingId, stateId);
|
||||||
@ -212,13 +231,12 @@ export async function prepareAndSendPairingTx(): Promise<void> {
|
|||||||
export async function generateCreateBtn() {
|
export async function generateCreateBtn() {
|
||||||
try {
|
try {
|
||||||
// Generate CreateBtn
|
// Generate CreateBtn
|
||||||
const container = getCorrectDOM('login-4nk-component') as HTMLElement;
|
const container = getCorrectDOM("login-4nk-component") as HTMLElement;
|
||||||
const createBtn = container?.querySelector('.create-btn');
|
const createBtn = container?.querySelector(".create-btn");
|
||||||
if (createBtn) {
|
if (createBtn) {
|
||||||
createBtn.textContent = 'CREATE';
|
createBtn.textContent = "CREATE";
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user