Files
HellreigN/frontend/src/shared/api/websocket.service.ts
T
nikitaa_ts c6a9907822
ci-front / build (push) Successful in 2m26s
feat
2026-04-04 19:49:37 +03:00

137 lines
4.0 KiB
TypeScript

// 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,
};
};