// SPDX-License-Identifier: GPL-3.0-or-later // Author: Sascha Nitsch https://contentnation.net/@grumpydevelop import WebSocket from 'ws'; import { RobotCmd } from './robotcmd'; import { RobotStatus } from './robotstatus'; abstract class RoboBase { private pingTimeout: NodeJS.Timeout; private socket: WebSocket; private name: string; private model: string; protected cmd: RobotCmd; protected width: number; protected height: number; private lastUpdate: number; protected deltaTime: number; constructor(name: string, model:string) { this.name = name; this.model = model; this.cmd = new RobotCmd(); this.width = 0; this.height = 0; this.lastUpdate = 0; this.deltaTime = 0; } connect() { this.socket = new WebSocket('ws://127.0.0.1:3000/robot', undefined, { perMessageDeflate: false, autoPong: true }); this.socket.addEventListener('error', this.error); this.socket.addEventListener('open', () => { this.open(); this.heartbeat(); }); this.socket.addEventListener('ping', this.heartbeat); this.socket.addEventListener('message', this.message); this.socket.addEventListener('close', () => { clearTimeout(this.pingTimeout); }); } disconnect() { this.socket.close(); } error(...param) { console.error(param); } private heartbeat = () => { clearTimeout(this.pingTimeout); this.pingTimeout = setTimeout(() => { this.socket.terminate(); }, 30000 + 1000); } message = (event: MessageEvent) => { this.heartbeat(); const msgtext = event.data.toString(); const tokens = msgtext.split(' '); if (tokens.length == 1) { switch (tokens[0]) { case 'lost': this.lost(); break; case 'ready': this.ready(); break; case 'start': this.start(); break; case 'won': this.won(); break; default: console.log('msg', tokens[0]) } } else if (tokens.length == 2) { switch (tokens[0]) { case 'specs': const specs = JSON.parse(tokens[1]); this.width = specs['width']; this.height = specs['height']; break; case 'status': const status:RobotStatus = JSON.parse(tokens[1]); this.deltaTime = status.simulationTime - this.lastUpdate; this.lastUpdate = status.simulationTime; this.statusReady(status); break; default: console.log('unknown command tk2 ', msgtext); } } else { console.log('unknown command tk3', msgtext); } } open() { this.socket.send('name ' + this.name); this.socket.send('model ' + this.model); } sendCmd() { this.socket.send('cmd ' + JSON.stringify(this.cmd.toObject())); this.cmd.fire = false; } abstract lost(): void; abstract ready(): void; abstract start(): void; abstract statusReady(status: RobotStatus): void; abstract won(): void; } export { RoboBase }