fix: 同步 WebSocket ping/pong 心跳

This commit is contained in:
疯狂的狮子Li 2026-10-27 11:23:07 +08:00
parent 85e45a76d4
commit 238ddbbe56

View File

@ -12,6 +12,8 @@ import { parsePushMessage, resolveNoticeGroup, resolveNoticeTitle, shouldAppendN
let eventSource: EventSource | undefined; let eventSource: EventSource | undefined;
let webSocket: WebSocket | undefined; let webSocket: WebSocket | undefined;
let reconnectTimer: number | undefined; let reconnectTimer: number | undefined;
let heartbeatTimer: number | undefined;
let pongTimer: number | undefined;
let reconnectAttempts = 0; let reconnectAttempts = 0;
let pushClosed = true; let pushClosed = true;
const KICKED_MESSAGE = 'kicked'; const KICKED_MESSAGE = 'kicked';
@ -103,6 +105,13 @@ function clearReconnectTimer() {
} }
} }
function clearHeartbeatTimers() {
if (heartbeatTimer) window.clearInterval(heartbeatTimer);
if (pongTimer) window.clearTimeout(pongTimer);
heartbeatTimer = undefined;
pongTimer = undefined;
}
function scheduleReconnect(connect: () => void, maxRetries: number, delay: number) { function scheduleReconnect(connect: () => void, maxRetries: number, delay: number) {
if (pushClosed) return; if (pushClosed) return;
if (reconnectAttempts >= maxRetries) return; if (reconnectAttempts >= maxRetries) return;
@ -133,16 +142,30 @@ function initSsePush(path: string) {
function initWsPush(path: string) { function initWsPush(path: string) {
const connect = () => { const connect = () => {
if (pushClosed) return; if (pushClosed) return;
clearHeartbeatTimers();
webSocket?.close(); webSocket?.close();
webSocket = new WebSocket(buildWsUrl(path)); const socket = new WebSocket(buildWsUrl(path));
webSocket.onopen = () => { webSocket = socket;
socket.onopen = () => {
reconnectAttempts = 0; reconnectAttempts = 0;
heartbeatTimer = window.setInterval(() => {
if (socket.readyState !== WebSocket.OPEN) return;
socket.send('ping');
pongTimer = window.setTimeout(() => socket.close(), 2000);
}, 10000);
}; };
webSocket.onmessage = event => { socket.onmessage = event => {
if (String(event.data) === 'pong') return; if (String(event.data) === 'pong') {
if (pongTimer) window.clearTimeout(pongTimer);
pongTimer = undefined;
return;
}
handlePushMessage(String(event.data)); handlePushMessage(String(event.data));
}; };
webSocket.onclose = () => scheduleReconnect(connect, 3, 1000); socket.onclose = () => {
clearHeartbeatTimers();
scheduleReconnect(connect, 3, 1000);
};
}; };
connect(); connect();
} }
@ -177,6 +200,7 @@ export function initPush() {
export function closePush() { export function closePush() {
pushClosed = true; pushClosed = true;
clearReconnectTimer(); clearReconnectTimer();
clearHeartbeatTimers();
if (webSocket) { if (webSocket) {
webSocket.onopen = null; webSocket.onopen = null;
webSocket.onmessage = null; webSocket.onmessage = null;