120 lines
3 KiB
TypeScript
120 lines
3 KiB
TypeScript
// 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 }
|