// SPDX-License-Identifier: GPL-3.0-or-later // Author: Sascha Nitsch https://contentnation.net/@grumpydevelop import { randomUUID, UUID } from 'crypto'; import { WebSocketServer } from 'ws'; import { WorldSim } from '../worldsim'; import WebSocket from 'ws'; interface MyWebSocket extends WebSocket { isAlive: boolean; websocketid: string; heartbeat(): void; closeHandler(this: WebSocket): void; } class RobotWS extends WebSocketServer { private idLookup: Map; private worldSim: WorldSim; constructor(options: any, worldsim: WorldSim) { super(options); this.worldSim = worldsim; this.idLookup = new Map(); const that = this; this.on('connection', function connection(ws: MyWebSocket) { ws.isAlive = true; ws.websocketid = randomUUID().toString(); worldsim.register(ws.websocketid); that.idLookup.set(ws.websocketid, ws); ws.heartbeat = function() { this.isAlive = true; } ws.closeHandler = function(this: WebSocket) { that.closeHandler(this); } ws.on('close', ws.closeHandler); ws.on('pong', ws.heartbeat); ws.on('message', function (this: WebSocket, data: Buffer, isBinary: boolean) { const t = this; t.heartbeat(); that.message(t, data, isBinary); }); }); const interval = setInterval(this.ping, 10000); this.on('close', function close() { //console.log("close", a); clearInterval(interval); }); } broadcast = (msg: string) => { if (this.clients === undefined) { return; } this.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(msg); } }) } closeHandler = (ws: MyWebSocket) => { this.worldSim.unregister(ws.websocketid); this.idLookup.delete(ws.websocketid); } message = (ws: MyWebSocket, data: Buffer, isBinary:boolean) => { const message = data.toString(); const uuid = ws.websocketid; const tokens = message.split(" "); if (tokens.length == 2) { switch(tokens[0]) { case 'cmd': this.worldSim.cmd(uuid, JSON.parse(tokens[1])); break; case 'model': this.worldSim.setModel(uuid, tokens[1]) break; case 'name': this.worldSim.setName(uuid, tokens[1]); break; default: console.log("unknown command", message); } } } ping = () => { if (this.clients === undefined) { return; } this.clients.forEach(function each(ws: WebSocket) { const mws = ws; if (mws.isAlive === false) { return mws.terminate(); } mws.isAlive = false; mws.ping(); }); } send(uuid: string, msg: string) { const ws = this.idLookup.get(uuid); ws?.send(msg); } } export { RobotWS }