refactor: websocket connect

This commit is contained in:
hamster1963 2024-12-02 02:15:46 +08:00
parent 6344064977
commit a9186f1148
6 changed files with 83 additions and 32 deletions

View File

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

View File

@ -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>

View File

@ -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,
});

View File

@ -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 (

View File

@ -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>
); );
} }

View File

@ -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,
}, },
}, },
}, },