import { useEffect, useRef, useState, } from 'react' interface WebSocketHandlers { onClose?: (event: CloseEvent) => void, onError?: (event: Event) => void, onMessage?: (data: T) => void, onOpen?: (event: Event) => void, } interface WebSocketOptions { allowConnection?: boolean, // Разрешено ли подключение autoReconnect?: boolean, // Автоматическое переподключение при ошибке handlers?: WebSocketHandlers, // Обработчики событий maxReconnectAttempts?: number, // Максимальное количество попыток переподключения reconnectInterval?: number, // Интервал между попытками переподключения url: string, // Url запроса } export const useWebSocket = ({ allowConnection = true, autoReconnect = false, handlers = {}, maxReconnectAttempts = 5, reconnectInterval = 5000, url, }: WebSocketOptions) => { const { onClose, onError, onMessage, onOpen, } = handlers const webSocketRef = useRef(null) const timeoutIdRef = useRef(null) const reconnectAttemptsRef = useRef(0) const onCloseRef = useRef(onClose) const onErrorRef = useRef(onError) const onMessageRef = useRef(onMessage) const onOpenRef = useRef(onOpen) const [webSocketState, setWebSocketState] = useState(WebSocket.CONNECTING) const sendMessage = (message: Record) => { if (webSocketRef.current?.readyState !== WebSocket.OPEN) return const body = JSON.stringify(message) webSocketRef.current?.send(body) } const closeConnection = () => { setWebSocketState(WebSocket.CLOSING) webSocketRef.current?.close() } useEffect(() => { onCloseRef.current = onClose onErrorRef.current = onError onMessageRef.current = onMessage onOpenRef.current = onOpen }, [onClose, onError, onMessage, onOpen]) useEffect(() => { const connect = () => { if (!allowConnection) return const ws = new WebSocket(url) ws.addEventListener('open', handleOpen) ws.addEventListener('message', handleMessage) ws.addEventListener('close', handleClose) ws.addEventListener('error', handleError) webSocketRef.current = ws setWebSocketState(WebSocket.CONNECTING) } const handleOpen = (event: Event) => { setWebSocketState(WebSocket.OPEN) onOpenRef.current?.(event) reconnectAttemptsRef.current = 0 } const handleMessage = (event: MessageEvent) => { const data = JSON.parse(event.data) onMessageRef.current?.(data) } const handleClose = (event: CloseEvent) => { setWebSocketState(WebSocket.CLOSED) onCloseRef.current?.(event) } const handleError = (event: Event) => { setWebSocketState(WebSocket.CLOSED) onErrorRef.current?.(event) if (autoReconnect && reconnectAttemptsRef.current < maxReconnectAttempts) { timeoutIdRef.current = setTimeout(connect, reconnectInterval) reconnectAttemptsRef.current++ } } connect() return () => { webSocketRef.current?.removeEventListener('open', handleOpen) webSocketRef.current?.removeEventListener('message', handleMessage) webSocketRef.current?.removeEventListener('close', handleClose) webSocketRef.current?.removeEventListener('error', handleError) webSocketRef.current?.close() timeoutIdRef.current && clearTimeout(timeoutIdRef.current) } }, [url, autoReconnect, reconnectInterval, maxReconnectAttempts, allowConnection]) return { closeConnection, sendMessage, webSocketState, } }