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