gitscope
← marzneshin / v0.7.4 / dashboard/src/modules/nodes/api/logs.socket.ts
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/modules/nodes/api/logs.socket.ts · TypeScript
Blame Raw
 1import { NodeType } from "@marzneshin/modules/nodes";
 2import useWebSocket, { ReadyState } from "react-use-websocket";
 3import { useAuth } from "@marzneshin/modules/auth";
 4import { joinPaths } from "@tanstack/react-router";
 5import { useCallback, useEffect, useRef, useState } from "react";
 6
 7export const MAX_NUMBER_OF_LOGS = 200;
 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            setLogs([]);
73        };
74    }, []);
75
76    const status = getStatus(readyState.toString());
77
78    return { status, readyState, logs, logsDiv };
79};