Improved websocket to ensure the reconnection

This commit is contained in:
NicolasCantu 2025-11-25 09:58:14 +01:00
parent 8512b90d36
commit 225dd27c2c

View File

@ -1,36 +1,53 @@
import { AnkFlag } from 'pkg/sdk_client'; import { AnkFlag } from '../../pkg/sdk_client'; // Vérifie le chemin vers pkg
import Services from './service'; import Services from './service';
let ws: WebSocket; let ws: WebSocket | null = null;
let messageQueue: string[] = []; let messageQueue: string[] = [];
let reconnectInterval = 1000; // Délai initial de 1s avant reconnexion
const MAX_RECONNECT_INTERVAL = 30000; // Max 30s
let isConnecting = false;
let urlReference: string = '';
let pingIntervalId: any = null;
export async function initWebsocket(url: string) { export async function initWebsocket(url: string) {
ws = new WebSocket(url); urlReference = url;
connect();
}
if (ws !== null) { function connect() {
ws.onopen = async (event) => { if (isConnecting || (ws && ws.readyState === WebSocket.OPEN)) return;
console.log('WebSocket connection established'); isConnecting = true;
console.log(`[WS] 🔌 Tentative de connexion à ${urlReference}...`);
ws = new WebSocket(urlReference);
ws.onopen = async () => {
console.log('[WS] ✅ Connexion établie !');
isConnecting = false;
reconnectInterval = 1000; // Reset du délai
// Démarrer le Heartbeat (Ping pour garder la connexion vivante)
startHeartbeat();
// Vider la file d'attente (messages envoyés pendant la coupure)
while (messageQueue.length > 0) { while (messageQueue.length > 0) {
const message = messageQueue.shift(); const message = messageQueue.shift();
if (message) { if (message) ws?.send(message);
ws.send(message);
}
} }
}; };
// Listen for messages
ws.onmessage = (event) => { ws.onmessage = (event) => {
const msgData = event.data; const msgData = event.data;
// console.log("Received text message: ", msgData);
(async () => {
if (typeof msgData === 'string') { if (typeof msgData === 'string') {
(async () => {
try { try {
const parsedMessage = JSON.parse(msgData); const parsedMessage = JSON.parse(msgData);
const services = await Services.getInstance(); const services = await Services.getInstance();
// Gestion des messages
switch (parsedMessage.flag) { switch (parsedMessage.flag) {
case 'Handshake': case 'Handshake':
await services.handleHandshakeMsg(url, parsedMessage.content); await services.handleHandshakeMsg(urlReference, parsedMessage.content);
break; break;
case 'NewTx': case 'NewTx':
await services.parseNewTx(parsedMessage.content); await services.parseNewTx(parsedMessage.content);
@ -39,51 +56,80 @@ export async function initWebsocket(url: string) {
await services.parseCipher(parsedMessage.content); await services.parseCipher(parsedMessage.content);
break; break;
case 'Commit': case 'Commit':
// Basically if we see this it means we have an error
await services.handleCommitError(parsedMessage.content); await services.handleCommitError(parsedMessage.content);
break; break;
// Ajoute d'autres cas si nécessaire
default:
// console.log('[WS] Message reçu:', parsedMessage.flag);
} }
} catch (error) { } catch (error) {
console.error('Received an invalid message:', error); console.error('[WS] Erreur traitement message:', error);
}
} else {
console.error('Received a non-string message');
} }
})(); })();
};
// Listen for possible errors
ws.onerror = (event) => {
console.error('WebSocket error:', event);
};
// Listen for when the connection is closed
ws.onclose = (event) => {
console.log('WebSocket is closed now.');
};
} }
};
ws.onerror = (event) => {
console.error('[WS] 💥 Erreur:', event);
// Pas besoin de reconnecter ici, onclose sera appelé juste après
};
ws.onclose = (event) => {
isConnecting = false;
stopHeartbeat();
console.warn(`[WS] ⚠️ Déconnecté (Code: ${event.code}). Reconnexion dans ${reconnectInterval / 1000}s...`);
// Reconnexion exponentielle (1s, 1.5s, 2.25s...)
setTimeout(() => {
connect();
reconnectInterval = Math.min(reconnectInterval * 1.5, MAX_RECONNECT_INTERVAL);
}, reconnectInterval);
};
}
function startHeartbeat() {
stopHeartbeat();
// Envoie un ping toutes les 30 secondes pour éviter que le serveur ou le navigateur ne coupe la connexion
pingIntervalId = setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
// Adapter selon ce que ton serveur attend comme Ping, ou envoyer un message vide
// ws.send(JSON.stringify({ flag: 'Ping', content: '' }));
}
}, 30000);
}
function stopHeartbeat() {
if (pingIntervalId) clearInterval(pingIntervalId);
} }
// Method to send messages
export function sendMessage(flag: AnkFlag, message: string): void { export function sendMessage(flag: AnkFlag, message: string): void {
if (ws.readyState === WebSocket.OPEN) { if (ws && ws.readyState === WebSocket.OPEN) {
const networkMessage = { const networkMessage = {
flag: flag, flag: flag,
content: message, content: message,
}; };
console.log('Sending message of type:', flag);
ws.send(JSON.stringify(networkMessage)); ws.send(JSON.stringify(networkMessage));
} else { } else {
console.error('WebSocket is not open. ReadyState:', ws.readyState); console.warn(`[WS] Pas connecté. Message '${flag}' mis en file d'attente.`);
messageQueue.push(message); const networkMessage = {
flag: flag,
content: message,
};
messageQueue.push(JSON.stringify(networkMessage));
// Si on n'est pas déjà en train de se connecter, on force une tentative
if (!isConnecting) connect();
} }
} }
export function getUrl(): string { export function getUrl(): string {
return ws.url; return urlReference;
} }
// Method to close the WebSocket connection
export function close(): void { export function close(): void {
if (ws) {
ws.onclose = null; // On évite la reconnexion auto si fermeture volontaire
stopHeartbeat();
ws.close(); ws.close();
}
} }