UNPKG

@cks-systems/manifest-sdk

Version:
103 lines (102 loc) 3.62 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketManager = void 0; const ws_1 = __importDefault(require("ws")); /** * Manages WebSocket server with client heartbeat functionality */ class WebSocketManager { wss; clientHeartbeats = new Map(); heartbeatInterval; constructor(port, heartbeatInterval = 30000) { this.heartbeatInterval = heartbeatInterval; this.wss = new ws_1.default.Server({ port }); this.wss.on('connection', (ws) => { console.log('New client connected'); // Start heartbeat for this client this.startClientHeartbeat(ws); ws.on('message', (message) => { console.log(`Received message: ${message}`); }); ws.on('pong', () => { // Client is still alive, reset the heartbeat timer this.resetClientHeartbeat(ws); }); ws.on('close', () => { console.log('Client disconnected'); this.stopClientHeartbeat(ws); }); ws.on('error', (error) => { console.error('WebSocket error:', error); this.stopClientHeartbeat(ws); }); }); } /** * Broadcast a message to all connected clients */ broadcast(message) { this.wss.clients.forEach((client) => { if (client.readyState === ws_1.default.OPEN) { client.send(message); } }); } /** * Close the WebSocket server and clean up */ close() { // Clean up all heartbeats before closing this.clientHeartbeats.forEach((timeout, ws) => { clearTimeout(timeout); ws.close(); }); this.clientHeartbeats.clear(); this.wss.close(); } startClientHeartbeat(ws) { const timeout = setTimeout(() => { console.log('Client heartbeat timeout, closing connection'); ws.terminate(); this.clientHeartbeats.delete(ws); }, this.heartbeatInterval * 2); // Wait for 2x heartbeat interval before considering dead this.clientHeartbeats.set(ws, timeout); // Send initial ping if (ws.readyState === ws_1.default.OPEN) { ws.ping(); } } resetClientHeartbeat(ws) { // Clear existing timeout const existingTimeout = this.clientHeartbeats.get(ws); if (existingTimeout) { clearTimeout(existingTimeout); } // Set new timeout and send next ping const timeout = setTimeout(() => { if (ws.readyState === ws_1.default.OPEN) { ws.ping(); // Set another timeout for the pong response const pongTimeout = setTimeout(() => { console.log('Client pong timeout, closing connection'); ws.terminate(); this.clientHeartbeats.delete(ws); }, this.heartbeatInterval); this.clientHeartbeats.set(ws, pongTimeout); } }, this.heartbeatInterval); this.clientHeartbeats.set(ws, timeout); } stopClientHeartbeat(ws) { const timeout = this.clientHeartbeats.get(ws); if (timeout) { clearTimeout(timeout); this.clientHeartbeats.delete(ws); } } } exports.WebSocketManager = WebSocketManager;