mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-12 04:06:37 +08:00
节点监控离线延迟去抖
This commit is contained in:
@@ -88,6 +88,8 @@ export default function NodePage() {
|
|||||||
const [nodeList, setNodeList] = useState<Node[]>([]);
|
const [nodeList, setNodeList] = useState<Node[]>([]);
|
||||||
const [nodeOrder, setNodeOrder] = useState<number[]>([]);
|
const [nodeOrder, setNodeOrder] = useState<number[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [wsConnected, setWsConnected] = useState(false);
|
||||||
|
const [wsConnecting, setWsConnecting] = useState(false);
|
||||||
const [dialogVisible, setDialogVisible] = useState(false);
|
const [dialogVisible, setDialogVisible] = useState(false);
|
||||||
const [dialogTitle, setDialogTitle] = useState('');
|
const [dialogTitle, setDialogTitle] = useState('');
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
@@ -122,6 +124,31 @@ export default function NodePage() {
|
|||||||
const reconnectTimerRef = useRef<NodeJS.Timeout | null>(null);
|
const reconnectTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const reconnectAttemptsRef = useRef(0);
|
const reconnectAttemptsRef = useRef(0);
|
||||||
const maxReconnectAttempts = 5;
|
const maxReconnectAttempts = 5;
|
||||||
|
const offlineTimersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());
|
||||||
|
const offlineDelayMs = 3000;
|
||||||
|
|
||||||
|
const clearOfflineTimer = (nodeId: number) => {
|
||||||
|
const timer = offlineTimersRef.current.get(nodeId);
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
offlineTimersRef.current.delete(nodeId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleNodeOffline = (nodeId: number) => {
|
||||||
|
if (offlineTimersRef.current.has(nodeId)) return;
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
offlineTimersRef.current.delete(nodeId);
|
||||||
|
setNodeList((prev) =>
|
||||||
|
prev.map((node) => {
|
||||||
|
if (node.id !== nodeId) return node;
|
||||||
|
if (node.connectionStatus === 'offline' && node.systemInfo === null) return node;
|
||||||
|
return { ...node, connectionStatus: 'offline', systemInfo: null };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, offlineDelayMs);
|
||||||
|
offlineTimersRef.current.set(nodeId, timer);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadNodes();
|
loadNodes();
|
||||||
@@ -208,10 +235,13 @@ export default function NodePage() {
|
|||||||
const wsUrl = baseUrl.replace(/^http/, 'ws').replace(/\/api\/v1\/$/, '') + `/system-info?type=0&secret=${localStorage.getItem('token')}`;
|
const wsUrl = baseUrl.replace(/^http/, 'ws').replace(/\/api\/v1\/$/, '') + `/system-info?type=0&secret=${localStorage.getItem('token')}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setWsConnecting(true);
|
||||||
websocketRef.current = new WebSocket(wsUrl);
|
websocketRef.current = new WebSocket(wsUrl);
|
||||||
|
|
||||||
websocketRef.current.onopen = () => {
|
websocketRef.current.onopen = () => {
|
||||||
reconnectAttemptsRef.current = 0;
|
reconnectAttemptsRef.current = 0;
|
||||||
|
setWsConnected(true);
|
||||||
|
setWsConnecting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
websocketRef.current.onmessage = (event) => {
|
websocketRef.current.onmessage = (event) => {
|
||||||
@@ -229,9 +259,13 @@ export default function NodePage() {
|
|||||||
|
|
||||||
websocketRef.current.onclose = () => {
|
websocketRef.current.onclose = () => {
|
||||||
websocketRef.current = null;
|
websocketRef.current = null;
|
||||||
|
setWsConnected(false);
|
||||||
|
setWsConnecting(false);
|
||||||
attemptReconnect();
|
attemptReconnect();
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
setWsConnected(false);
|
||||||
|
setWsConnecting(false);
|
||||||
attemptReconnect();
|
attemptReconnect();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -239,21 +273,27 @@ export default function NodePage() {
|
|||||||
// 处理WebSocket消息
|
// 处理WebSocket消息
|
||||||
const handleWebSocketMessage = (data: any) => {
|
const handleWebSocketMessage = (data: any) => {
|
||||||
const { id, type, data: messageData } = data;
|
const { id, type, data: messageData } = data;
|
||||||
|
const nodeId = Number(id);
|
||||||
|
if (Number.isNaN(nodeId)) return;
|
||||||
|
|
||||||
if (type === 'status') {
|
if (type === 'status') {
|
||||||
setNodeList(prev => prev.map(node => {
|
if (messageData === 1) {
|
||||||
if (node.id == id) {
|
clearOfflineTimer(nodeId);
|
||||||
return {
|
setNodeList((prev) =>
|
||||||
...node,
|
prev.map((node) => {
|
||||||
connectionStatus: messageData === 1 ? 'online' : 'offline',
|
if (node.id !== nodeId) return node;
|
||||||
systemInfo: messageData === 0 ? null : node.systemInfo
|
if (node.connectionStatus === 'online') return node;
|
||||||
};
|
return { ...node, connectionStatus: 'online' };
|
||||||
}
|
})
|
||||||
return node;
|
);
|
||||||
}));
|
} else {
|
||||||
|
// 离线事件做延迟处理,避免短抖动导致频繁闪烁
|
||||||
|
scheduleNodeOffline(nodeId);
|
||||||
|
}
|
||||||
} else if (type === 'info') {
|
} else if (type === 'info') {
|
||||||
|
clearOfflineTimer(nodeId);
|
||||||
setNodeList(prev => prev.map(node => {
|
setNodeList(prev => prev.map(node => {
|
||||||
if (node.id == id) {
|
if (node.id === nodeId) {
|
||||||
try {
|
try {
|
||||||
let systemInfo;
|
let systemInfo;
|
||||||
if (typeof messageData === 'string') {
|
if (typeof messageData === 'string') {
|
||||||
@@ -316,10 +356,12 @@ export default function NodePage() {
|
|||||||
|
|
||||||
// 尝试重新连接
|
// 尝试重新连接
|
||||||
const attemptReconnect = () => {
|
const attemptReconnect = () => {
|
||||||
|
if (reconnectTimerRef.current) return;
|
||||||
if (reconnectAttemptsRef.current < maxReconnectAttempts) {
|
if (reconnectAttemptsRef.current < maxReconnectAttempts) {
|
||||||
reconnectAttemptsRef.current++;
|
reconnectAttemptsRef.current++;
|
||||||
|
|
||||||
reconnectTimerRef.current = setTimeout(() => {
|
reconnectTimerRef.current = setTimeout(() => {
|
||||||
|
reconnectTimerRef.current = null;
|
||||||
initWebSocket();
|
initWebSocket();
|
||||||
}, 3000 * reconnectAttemptsRef.current);
|
}, 3000 * reconnectAttemptsRef.current);
|
||||||
}
|
}
|
||||||
@@ -332,7 +374,12 @@ export default function NodePage() {
|
|||||||
reconnectTimerRef.current = null;
|
reconnectTimerRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offlineTimersRef.current.forEach((timer) => clearTimeout(timer));
|
||||||
|
offlineTimersRef.current.clear();
|
||||||
|
|
||||||
reconnectAttemptsRef.current = 0;
|
reconnectAttemptsRef.current = 0;
|
||||||
|
setWsConnected(false);
|
||||||
|
setWsConnecting(false);
|
||||||
|
|
||||||
if (websocketRef.current) {
|
if (websocketRef.current) {
|
||||||
websocketRef.current.onopen = null;
|
websocketRef.current.onopen = null;
|
||||||
@@ -347,12 +394,6 @@ export default function NodePage() {
|
|||||||
|
|
||||||
websocketRef.current = null;
|
websocketRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setNodeList(prev => prev.map(node => ({
|
|
||||||
...node,
|
|
||||||
connectionStatus: 'offline',
|
|
||||||
systemInfo: null
|
|
||||||
})));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -823,6 +864,15 @@ export default function NodePage() {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!wsConnected && (
|
||||||
|
<Alert
|
||||||
|
color="warning"
|
||||||
|
variant="flat"
|
||||||
|
description={wsConnecting ? '监控连接中...' : '监控连接已断开,正在重连...'}
|
||||||
|
className="mb-4"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 节点列表 */}
|
{/* 节点列表 */}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center h-64">
|
<div className="flex items-center justify-center h-64">
|
||||||
|
|||||||
Reference in New Issue
Block a user