IDKHowToCodeFr/tinyml-backend
1
1import { useEffect, useRef, useState } from "react";2 3export type ConnectionStatus = 'connected' | 'reconnecting' | 'disconnected';4 5export function useResilientSocket(url: string, onMessage: (msg: any) => void) {6 const [status, setStatus] = useState<ConnectionStatus>('disconnected');7 const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);8 const reconnectAttemptRef = useRef(0);9 const savedCallback = useRef(onMessage);10 11 useEffect(() => {12 savedCallback.current = onMessage;13 }, [onMessage]);14 15 useEffect(() => {16 let ws: WebSocket;17 let isComponentMounted = true;18 19 const connect = () => {20 ws = new WebSocket(url);21 22 ws.onopen = () => {23 if (!isComponentMounted) return;24 setStatus('connected');25 reconnectAttemptRef.current = 0; // Reset attempts26 };27 28 ws.onmessage = (event) => {29 if (!isComponentMounted) return;30 const msg = JSON.parse(event.data);31 savedCallback.current(msg);32 };33 34 ws.onclose = () => {35 if (!isComponentMounted) return;36 setStatus('reconnecting');37 const timeout = Math.min(1000 * (2 ** reconnectAttemptRef.current), 30000); // Max 30s38 reconnectAttemptRef.current += 1;39 40 reconnectTimeoutRef.current = setTimeout(connect, timeout);41 };42 43 ws.onerror = () => {44 if (!isComponentMounted) return;45 ws.close(); // Force trigger onclose46 };47 };48 49 connect();50 51 return () => {52 isComponentMounted = false;53 if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);54 if (ws) ws.close();55 };56 }, [url]);57 58 return status;59}60 