mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 17:41:56 +08:00
refactor: websocket connect
This commit is contained in:
parent
6344064977
commit
a9186f1148
@ -56,9 +56,9 @@ export default function ServerDetailChart({
|
|||||||
}: {
|
}: {
|
||||||
server_id: string;
|
server_id: string;
|
||||||
}) {
|
}) {
|
||||||
const { lastMessage, readyState } = useWebSocketContext();
|
const { lastMessage, connected } = useWebSocketContext();
|
||||||
|
|
||||||
if (readyState !== 1) {
|
if (!connected) {
|
||||||
return <ServerDetailChartLoading />;
|
return <ServerDetailChartLoading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ export default function ServerDetailOverview({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { lastMessage, readyState } = useWebSocketContext();
|
const { lastMessage, connected } = useWebSocketContext();
|
||||||
|
|
||||||
if (readyState !== 1) {
|
if (!connected) {
|
||||||
return <ServerDetailLoading />;
|
return <ServerDetailLoading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +195,9 @@ export default function ServerDetailOverview({
|
|||||||
<p className="text-xs text-muted-foreground">{"Load"}</p>
|
<p className="text-xs text-muted-foreground">{"Load"}</p>
|
||||||
{server.state.load_1 ? (
|
{server.state.load_1 ? (
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{server.state.load_1} / {server.state.load_5} /{" "}
|
{server.state.load_1.toFixed(2)} /{" "}
|
||||||
{server.state.load_15}
|
{server.state.load_5.toFixed(2)} /{" "}
|
||||||
|
{server.state.load_15.toFixed(2)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-xs"> {t("serverDetail.unknown")}</div>
|
<div className="text-xs"> {t("serverDetail.unknown")}</div>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { createContext } from "react";
|
import { createContext } from "react";
|
||||||
|
|
||||||
export interface WebSocketContextType {
|
export interface WebSocketContextType {
|
||||||
sendMessage: (message: string) => void;
|
lastMessage: { data: string } | null;
|
||||||
lastMessage: MessageEvent | null;
|
connected: boolean;
|
||||||
readyState: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WebSocketContext = createContext<WebSocketContextType | undefined>(
|
export const WebSocketContext = createContext<WebSocketContextType>({
|
||||||
undefined,
|
lastMessage: null,
|
||||||
);
|
connected: false,
|
||||||
|
});
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import { WebSocketContext, WebSocketContextType } from "./websocket-context";
|
||||||
WebSocketContext,
|
|
||||||
type WebSocketContextType,
|
|
||||||
} from "./websocket-context";
|
|
||||||
import useWebSocket from "react-use-websocket";
|
|
||||||
|
|
||||||
interface WebSocketProviderProps {
|
interface WebSocketProviderProps {
|
||||||
url: string;
|
url: string;
|
||||||
@ -14,16 +10,67 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
|
|||||||
url,
|
url,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const { sendMessage, lastMessage, readyState } = useWebSocket(url, {
|
const [lastMessage, setLastMessage] = useState<{ data: string } | null>(null);
|
||||||
reconnectAttempts: 10,
|
const [connected, setConnected] = useState(false);
|
||||||
reconnectInterval: 3000,
|
const ws = useRef<WebSocket | null>(null);
|
||||||
shouldReconnect: () => true,
|
const reconnectTimeout = useRef<NodeJS.Timeout>();
|
||||||
});
|
const maxReconnectAttempts = 30;
|
||||||
|
const reconnectAttempts = useRef(0);
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
try {
|
||||||
|
const wsUrl = new URL(url, window.location.origin);
|
||||||
|
wsUrl.protocol = wsUrl.protocol.replace("http", "ws");
|
||||||
|
|
||||||
|
ws.current = new WebSocket(wsUrl.toString());
|
||||||
|
|
||||||
|
ws.current.onopen = () => {
|
||||||
|
console.log("WebSocket connected");
|
||||||
|
setConnected(true);
|
||||||
|
reconnectAttempts.current = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onclose = () => {
|
||||||
|
console.log("WebSocket disconnected");
|
||||||
|
setConnected(false);
|
||||||
|
|
||||||
|
// 重连逻辑
|
||||||
|
if (reconnectAttempts.current < maxReconnectAttempts) {
|
||||||
|
reconnectTimeout.current = setTimeout(() => {
|
||||||
|
reconnectAttempts.current++;
|
||||||
|
connect();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onmessage = (event) => {
|
||||||
|
setLastMessage({ data: event.data });
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onerror = (error) => {
|
||||||
|
console.error("WebSocket error:", error);
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("WebSocket connection error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
connect();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (ws.current) {
|
||||||
|
ws.current.close();
|
||||||
|
}
|
||||||
|
if (reconnectTimeout.current) {
|
||||||
|
clearTimeout(reconnectTimeout.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
const contextValue: WebSocketContextType = {
|
const contextValue: WebSocketContextType = {
|
||||||
sendMessage,
|
|
||||||
lastMessage,
|
lastMessage,
|
||||||
readyState,
|
connected,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -13,6 +13,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { ChartBarSquareIcon, ViewColumnsIcon } from "@heroicons/react/20/solid";
|
import { ChartBarSquareIcon, ViewColumnsIcon } from "@heroicons/react/20/solid";
|
||||||
import { ServiceTracker } from "@/components/ServiceTracker";
|
import { ServiceTracker } from "@/components/ServiceTracker";
|
||||||
import ServerCardInline from "@/components/ServerCardInline";
|
import ServerCardInline from "@/components/ServerCardInline";
|
||||||
|
import { Loader } from "@/components/loading/Loader";
|
||||||
|
|
||||||
export default function Servers() {
|
export default function Servers() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -20,7 +21,7 @@ export default function Servers() {
|
|||||||
queryKey: ["server-group"],
|
queryKey: ["server-group"],
|
||||||
queryFn: () => fetchServerGroup(),
|
queryFn: () => fetchServerGroup(),
|
||||||
});
|
});
|
||||||
const { lastMessage, readyState } = useWebSocketContext();
|
const { lastMessage, connected } = useWebSocketContext();
|
||||||
|
|
||||||
const [showServices, setShowServices] = useState<string>("0");
|
const [showServices, setShowServices] = useState<string>("0");
|
||||||
const [inline, setInline] = useState<string>("0");
|
const [inline, setInline] = useState<string>("0");
|
||||||
@ -47,16 +48,19 @@ export default function Servers() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hasShownToast = sessionStorage.getItem("websocket-connected-toast");
|
const hasShownToast = sessionStorage.getItem("websocket-connected-toast");
|
||||||
if (readyState == 1 && !hasShownToast) {
|
if (connected && !hasShownToast) {
|
||||||
toast.success(t("info.websocketConnected"));
|
toast.success(t("info.websocketConnected"));
|
||||||
sessionStorage.setItem("websocket-connected-toast", "true");
|
sessionStorage.setItem("websocket-connected-toast", "true");
|
||||||
}
|
}
|
||||||
}, [readyState]);
|
}, [connected]);
|
||||||
|
|
||||||
if (readyState !== 1) {
|
if (!connected) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center ">
|
<div className="flex flex-col items-center min-h-96 justify-center ">
|
||||||
<p className="font-semibold text-sm">{t("info.websocketConnecting")}</p>
|
<p className="font-semibold flex items-center gap-2 text-sm">
|
||||||
|
<Loader visible={true} />
|
||||||
|
{t("info.websocketConnecting")}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ export default defineConfig({
|
|||||||
"/api/v1/": {
|
"/api/v1/": {
|
||||||
target: "http://localhost:8008",
|
target: "http://localhost:8008",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user