From 92db42113d89299f3a67cf96f08727bc96d967aa Mon Sep 17 00:00:00 2001 From: Markov Date: Thu, 26 Feb 2026 10:21:33 +0100 Subject: [PATCH] Add WS heartbeat every 30s to keep connection alive --- src/lib/ws.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/lib/ws.ts b/src/lib/ws.ts index b1cf871..840a027 100644 --- a/src/lib/ws.ts +++ b/src/lib/ws.ts @@ -9,6 +9,7 @@ class WSClient { private ws: WebSocket | null = null; private handlers: Map> = new Map(); private reconnectTimer: ReturnType | null = null; + private heartbeatTimer: ReturnType | null = null; private pendingQueue: any[] = []; private authenticated = false; private _lobbyId: string | null = null; @@ -38,7 +39,7 @@ class WSClient { const msg = JSON.parse(event.data); const type = msg.type; - // Handle auth.ok — flush pending queue + // Handle auth.ok — flush pending queue + start heartbeat if (type === "auth.ok") { this._lobbyId = msg.data?.lobby_chat_id || null; this._projects = msg.data?.projects || []; @@ -49,6 +50,8 @@ class WSClient { this.ws!.send(JSON.stringify(queued)); } this.pendingQueue = []; + // Start heartbeat every 30s to keep connection alive + this.startHeartbeat(); } // Auth error → force re-login @@ -73,6 +76,7 @@ class WSClient { this.ws.onclose = () => { this.authenticated = false; + this.stopHeartbeat(); this.reconnectTimer = setTimeout(() => this.connect(), 3000); }; @@ -81,12 +85,27 @@ class WSClient { disconnect() { if (this.reconnectTimer) clearTimeout(this.reconnectTimer); + this.stopHeartbeat(); this.ws?.close(); this.ws = null; this.authenticated = false; this.pendingQueue = []; } + private startHeartbeat() { + this.stopHeartbeat(); + this.heartbeatTimer = setInterval(() => { + this.heartbeat(); + }, 30_000); + } + + private stopHeartbeat() { + if (this.heartbeatTimer) { + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + } + on(type: string, handler: MessageHandler) { if (!this.handlers.has(type)) this.handlers.set(type, new Set()); this.handlers.get(type)!.add(handler);