gitscope
← marzneshin / v0.6.1 / dashboard/src/modules/nodes/services/logs.socket.ts
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/modules/nodes/services/logs.socket.ts · TypeScript
Blame Raw
 1import { NodeType } from "@marzneshin/modules/nodes";
 2import useWebSocket, { ReadyState } from "react-use-websocket";
 3import { useAuth } from "@marzneshin/features/auth";
 4import { joinPaths } from "@tanstack/react-router";
 5import { useCallback, useEffect, useRef, useState } from "react";
 6
 7export const MAX_NUMBER_OF_LOGS = 500;
 8
 9export const getStatus = (status: string) => {
10  return {
11    [ReadyState.CONNECTING]: "connecting",
12    [ReadyState.OPEN]: "connected",
13    [ReadyState.CLOSING]: "closed",
14    [ReadyState.CLOSED]: "closed",
15    [ReadyState.UNINSTANTIATED]: "closed",
16  }[status];
17};
18
19export const getWebsocketUrl = (nodeId: number, backend: string) => {
20  try {
21    const baseURL = new URL(
22      import.meta.env.VITE_BASE_API.startsWith("/")
23        ? window.location.origin + import.meta.env.VITE_BASE_API
24        : import.meta.env.VITE_BASE_API,
25    );
26    const protocol = baseURL.protocol === "https:" ? "wss://" : "ws://";
27    return `${protocol}${joinPaths([baseURL.host + baseURL.pathname, `/nodes/${nodeId}/${backend}/logs`])}?interval=1&token=${useAuth.getState().getAuthToken()}`;
28  } catch (e) {
29    console.error("Unable to generate websocket url");
30    console.error(e);
31    return null;
32  }
33};
34
35export const useNodesLog = (node: NodeType, backend: string) => {
36  const [logs, setLogs] = useState<string[]>([]);
37  const logsDiv = useRef<HTMLDivElement | null>(null);
38  const scrollShouldStayOnEnd = useRef(true);
39
40  const updateLogs = useCallback(
41    (callback: (prevLogs: string[]) => string[]) => {
42      setLogs((prevLogs) => {
43        const newLogs = callback(prevLogs);
44        return newLogs.length > MAX_NUMBER_OF_LOGS
45          ? newLogs.slice(-MAX_NUMBER_OF_LOGS)
46          : newLogs;
47      });
48    },
49    [],
50  );
51
52  const { readyState } = useWebSocket(
53    node?.id ? getWebsocketUrl(node.id, backend) : "",
54    {
55      onMessage: (e: any) => {
56        updateLogs((prevLogs) => [...prevLogs, e.data]);
57      },
58      shouldReconnect: () => true,
59      reconnectAttempts: 10,
60      reconnectInterval: 1000,
61    },
62  );
63
64  useEffect(() => {
65    if (logsDiv.current && scrollShouldStayOnEnd.current) {
66      logsDiv.current.scrollTop = logsDiv.current.scrollHeight;
67    }
68  }, [logs]);
69
70  useEffect(() => {
71    return () => {
72      // Cleanup
73      setLogs([]);
74    };
75  }, []);
76
77  const status = getStatus(readyState.toString());
78
79  return { status, readyState, logs, logsDiv };
80};