// shared/api/websocket.service.ts import { useAgentStore } from "@/app/providers/layout/store/agent.store"; import { useWebSocket, type LogMessage } from "@/shared/hooks/useWebSocket"; import { useEffect, useRef, useCallback, useMemo } from "react"; interface WebSocketServiceProps { onLogMessage?: (message: LogMessage) => void; } export const useWebSocketService = ({ onLogMessage, }: WebSocketServiceProps = {}) => { const { agents } = useAgentStore(); const lastFilterRef = useRef<{ hosts: string[]; services: string[] }>({ hosts: [], services: [], }); // Токен для аутентификации const TOKEN = "H0AB91gb7427xswom0xalJHq7Ked0tLt6F0gOyqw5yMWPDrroOcX8CjPXeD8uzsU"; // Получаем выбранные агенты и сервисы синхронно const getSelectedServices = useCallback(() => { const selectedServices: string[] = []; const selectedHosts: string[] = []; // TODO: реализовать механизм выбора сервисов // Пока выбираем все agents.forEach((agent) => { agent.services.forEach((service) => { selectedServices.push(service); selectedHosts.push(agent.token); }); }); return { hosts: selectedHosts, services: selectedServices }; }, [agents]); // Формируем URL синхронно const wsUrl = useMemo(() => { const { hosts, services } = getSelectedServices(); const params = new URLSearchParams(); if (hosts.length === 0 && services.length === 0) { params.append("all", "true"); } else { hosts.forEach((host) => { params.append("hosts", host); }); services.forEach((service) => { params.append("services", service); }); } const queryString = params.toString(); const url = `${import.meta.env.VITE_WS_URL}/ws?${queryString}`; console.log("Generated WebSocket URL:", url); return url; }, [getSelectedServices]); const { isConnected, isAuthenticated, lastMessage, error, reconnect, connect: wsConnect, disconnect: wsDisconnect, updateFilter, } = useWebSocket({ url: wsUrl, token: TOKEN, autoConnect: false, // Отключаем авто-подключение, будем управлять вручную reconnectInterval: 3000, maxReconnectAttempts: 10, }); // Функция для подключения const connect = useCallback(() => { if (!isManualPausedRef.current) { wsConnect(); } }, [wsConnect]); // Функция для отключения const disconnect = useCallback(() => { wsDisconnect(); }, [wsDisconnect]); // Реф для отслеживания ручной паузы const isManualPausedRef = useRef(false); // Принудительно переподключаемся при изменении URL, если не на паузе useEffect(() => { if (wsUrl && !isManualPausedRef.current) { console.log("URL changed, reconnecting..."); setTimeout(() => { reconnect(); }, 100); } }, [wsUrl, reconnect]); // Обновляем фильтр при изменении выбранных сервисов useEffect(() => { const { hosts, services } = getSelectedServices(); const currentFilter = { hosts, services }; const hasChanged = JSON.stringify(currentFilter) !== JSON.stringify(lastFilterRef.current); if (hasChanged && isConnected && !isManualPausedRef.current) { console.log("Updating filter:", currentFilter); updateFilter(hosts, services); lastFilterRef.current = currentFilter; } }, [agents, isConnected, updateFilter, getSelectedServices]); // Передаем сообщения в callback useEffect(() => { if (lastMessage && onLogMessage) { onLogMessage(lastMessage); } }, [lastMessage, onLogMessage]); return { isConnected: isConnected && isAuthenticated, isAuthenticated, error, selectedCount: getSelectedServices().services.length, connect, disconnect, }; };