import { LogType, type LogFunc } from '../interface/common'; import { SocketError, WS_MSG_TYPE } from '../interface/socket'; export default class HeartbeatManager { private _socket: WebSocket; private _log?: LogFunc; private _interval: number; private _heartbeatInterval?: NodeJS.Timeout; private _pingStack = 0; private readonly PING_MAX_COUNT: number = 3; // This can be moved to configuration constructor(private wsId: string, socket: WebSocket, interval = 5000, log?: LogFunc) { this._socket = socket; this._log = log; this._interval = interval; } public start(): void { this.clear(); this._heartbeatInterval = setInterval(this._ping.bind(this), this._interval); } public stop(): void { if (this._heartbeatInterval) { clearInterval(this._heartbeatInterval); this._heartbeatInterval = undefined; } this._pingStack = 0; } /** * socket 收到消息之后,清空堆栈 */ public clear(): void { this._pingStack = 0; } private _ping(): void { if (this._socket.readyState !== WebSocket.OPEN) { this._pingStack = 0; return; } if (this._pingStack >= this.PING_MAX_COUNT) { this._log?.(LogType.error, '[socket] Max ping attempts reached. Closing socket.'); this._socket.close(SocketError.PING_PONG_ERROR, 'ping pong error'); } else { this._pingStack++; this._socket.send(JSON.stringify({ type: WS_MSG_TYPE.ping, wsId: this.wsId })); } } }