robotank/server-nodejs/websockets/robot.ts
Sascha Nitsch 51f0415617 initial im
2025-03-03 02:17:50 +01:00

106 lines
2.8 KiB
TypeScript

// 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<String, WebSocket>;
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(<MyWebSocket>this);
}
ws.on('close', ws.closeHandler);
ws.on('pong', ws.heartbeat);
ws.on('message', function (this: WebSocket, data: Buffer, isBinary: boolean) {
const t = <MyWebSocket>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 = <MyWebSocket>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 }