mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 17:41:56 +08:00
108 lines
2.9 KiB
TypeScript
108 lines
2.9 KiB
TypeScript
import { useState, useEffect, useRef, useCallback } from "react";
|
|
|
|
export interface WebSocketHook {
|
|
socket: WebSocket | null;
|
|
connected: boolean;
|
|
message: string | null;
|
|
sendMessage: (msg: string) => void;
|
|
}
|
|
|
|
export default function useWebSocket(url: string): WebSocketHook {
|
|
const [socket, setSocket] = useState<WebSocket | null>(null);
|
|
const [message, setMessage] = useState<string | null>(null);
|
|
const [connected, setConnected] = useState<boolean>(false);
|
|
const socketRef = useRef<WebSocket | null>(null);
|
|
const reconnectAttempts = useRef<number>(0);
|
|
const reconnectTimeout = useRef<NodeJS.Timeout | null>(null);
|
|
const isUnmounted = useRef<boolean>(false);
|
|
|
|
const connect = useCallback(() => {
|
|
if (isUnmounted.current) return;
|
|
|
|
console.log("Connecting to WebSocket...");
|
|
|
|
console.log("WebSocket URL:", url);
|
|
|
|
const ws = new WebSocket(url);
|
|
setSocket(ws);
|
|
socketRef.current = ws;
|
|
|
|
ws.onopen = () => {
|
|
setConnected(true);
|
|
reconnectAttempts.current = 0;
|
|
};
|
|
|
|
ws.onmessage = (event: MessageEvent) => {
|
|
setMessage(event.data);
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error("WebSocket Error:", error);
|
|
// 在错误发生时主动关闭连接,触发重连
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
ws.close();
|
|
}
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
setConnected(false);
|
|
// 清理当前的 socket
|
|
socketRef.current = null;
|
|
|
|
if (!isUnmounted.current) {
|
|
// 检查是否已经在重连中
|
|
if (reconnectTimeout.current) {
|
|
clearTimeout(reconnectTimeout.current);
|
|
}
|
|
|
|
// Attempt to reconnect with increased max attempts
|
|
if (reconnectAttempts.current < 10) {
|
|
const timeout = Math.min(
|
|
Math.pow(2, reconnectAttempts.current) * 1000,
|
|
30000,
|
|
); // 最大30秒
|
|
reconnectAttempts.current += 1;
|
|
console.log(
|
|
`Attempting to reconnect in ${timeout / 1000} seconds...`,
|
|
);
|
|
reconnectTimeout.current = setTimeout(() => {
|
|
connect();
|
|
}, timeout);
|
|
} else {
|
|
console.warn(
|
|
"Max reconnect attempts reached. Please refresh the page to try again.",
|
|
);
|
|
}
|
|
}
|
|
};
|
|
}, [url]);
|
|
|
|
useEffect(() => {
|
|
connect();
|
|
|
|
return () => {
|
|
isUnmounted.current = true;
|
|
if (socketRef.current) {
|
|
socketRef.current.close();
|
|
}
|
|
if (reconnectTimeout.current) {
|
|
clearTimeout(reconnectTimeout.current);
|
|
}
|
|
};
|
|
}, [connect]);
|
|
|
|
// Function to send messages
|
|
const sendMessage = useCallback((msg: string) => {
|
|
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) {
|
|
socketRef.current.send(msg);
|
|
} else {
|
|
console.warn(
|
|
"WebSocket is not open. Ready state:",
|
|
socketRef.current?.readyState,
|
|
);
|
|
}
|
|
}, []);
|
|
|
|
return { socket, message, sendMessage, connected };
|
|
}
|