@krp-races/krp-node-wrapper
Version:
A node.js wrapper for a dedicated or challenge server in kart racing pro.
191 lines (188 loc) • 8 kB
JavaScript
var tslib_es6 = require('../tslib.es6-DGH0njpN.js');
var events = require('events');
var modules_SocketWrapper = require('./SocketWrapper.js');
var enums_ClientStatus = require('../enums/ClientStatus.js');
var utils_readStringLines = require('../utils/readStringLines.js');
var utils_writeStringLines = require('../utils/writeStringLines.js');
var utils_timeout = require('../utils/timeout.js');
var modules_LivetimingReader = require('./LivetimingReader.js');
require('dgram');
require('../enums/DataType.js');
require('../enums/Event/ChallengeType.js');
require('../enums/Event/EventType.js');
require('../enums/Session/Classification/KartStatus.js');
require('../enums/Session/Classification/RaceStatus.js');
require('../enums/Session/SessionEntry/DriverStatusReason.js');
require('../enums/Session/SessionEntry/DriverStatusState.js');
require('../enums/Session/SessionState.js');
require('../enums/Session/SessionType.js');
require('../utils/Vec2.js');
require('../utils/Vec3.js');
const defaultData = {
entries: new Map(),
sessions: new Map(),
contacts: [],
};
class LivetimingClient extends events.EventEmitter {
constructor(options) {
super();
this.data = defaultData;
this.enabled = false;
this.status = enums_ClientStatus.ClientStatus.NOT_CONNECTED;
this.options = options;
this.socket = new modules_SocketWrapper.SocketWrapper(options);
this.socket.on("message", this.handleMessage.bind(this));
this.socket.on("error", this.handleError.bind(this));
this.on("connected", this.handleKeepAlive.bind(this));
}
setEnabled(enabled) {
const prevEnabled = this.enabled;
this.enabled = enabled;
if (!prevEnabled && enabled)
this.handleReconnect();
if (prevEnabled && !enabled)
this.disconnect();
}
getEnabled() {
return this.enabled;
}
setStatus(status) {
this.status = status;
}
getStatus() {
return this.status;
}
connect() {
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
if (this.status === enums_ClientStatus.ClientStatus.CONNECTED)
return;
this.setStatus(enums_ClientStatus.ClientStatus.CONNECTING);
const data = utils_writeStringLines.writeStringLines(["CONNECT", this.options.password]);
this.socket.send(data);
const promise = new Promise((resolve, reject) => {
const listener = (msg) => {
const lines = utils_readStringLines.readStringLines(msg);
switch (lines[0]) {
case "OK":
if (lines[1] !== "krp") {
reject(new Error("Wrong game"));
this.setStatus(enums_ClientStatus.ClientStatus.NOT_CONNECTED);
this.socket.removeListener("message", listener);
break;
}
resolve(undefined);
this.setStatus(enums_ClientStatus.ClientStatus.CONNECTED);
this.socket.removeListener("message", listener);
break;
case "FULL":
reject(new Error("Server is full"));
this.setStatus(enums_ClientStatus.ClientStatus.NOT_CONNECTED);
this.socket.removeListener("message", listener);
break;
case "WRONGPASSWORD":
reject(new Error("Wrong password"));
this.setStatus(enums_ClientStatus.ClientStatus.NOT_CONNECTED);
this.socket.removeListener("message", listener);
break;
}
};
this.socket.on("message", listener);
});
return Promise.race([promise, utils_timeout.timeout(5000)]).catch((err) => this.handleError(err));
});
}
disconnect() {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
const data = utils_writeStringLines.writeStringLines(["DISCONNECT"]);
this.socket.send(data);
this.setStatus(enums_ClientStatus.ClientStatus.NOT_CONNECTED);
this.emit("disconnected");
}
keepAlive() {
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
const data = utils_writeStringLines.writeStringLines(["KEEPALIVE"]);
this.socket.send(data);
const promise = new Promise((resolve) => {
const listener = (msg) => {
const lines = utils_readStringLines.readStringLines(msg);
if (lines[0] === "ALIVE") {
resolve(undefined);
this.socket.removeListener("message", listener);
}
};
this.socket.on("message", listener);
});
return Promise.race([promise, utils_timeout.timeout(5000)]).catch((err) => this.handleError(err));
});
}
start(trackPositions, collisions) {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
const data = utils_writeStringLines.writeStringLines([
"START",
trackPositions.toFixed(0),
collisions.toFixed(0),
]);
this.socket.send(data);
}
acknowledge(messageId) {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
const data = utils_writeStringLines.writeStringLines(["ACK", messageId]);
this.socket.send(data);
}
handleReconnect() {
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
// If not enabled, do not attempt to reconnect
if (!this.enabled)
return;
yield this.connect().catch((err) => this.handleError(err));
// When connected to a server, do not attempt to reconnect
if (this.status === enums_ClientStatus.ClientStatus.CONNECTED) {
this.emit("connected");
this.start(this.options.trackPositions, this.options.collisions);
return;
}
// Attempt to reconnect in x milliseconds
setTimeout(this.handleReconnect.bind(this), 5000);
});
}
handleKeepAlive() {
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
yield this.keepAlive().catch((err) => this.handleError(err));
setTimeout(this.handleKeepAlive.bind(this), 15000);
});
}
handleMessage(msg) {
if (this.status !== enums_ClientStatus.ClientStatus.CONNECTED)
return;
const lines = utils_readStringLines.readStringLines(msg);
switch (lines[0]) {
case "MSG":
{
const reader = new modules_LivetimingReader.LivetimingReader(lines, this.data);
this.data = reader.read();
this.acknowledge(lines[1]);
this.emit("data", this.data);
}
break;
case "DATA":
{
const reader = new modules_LivetimingReader.LivetimingReader(lines, this.data, 1);
this.data = reader.read();
this.emit("data", this.data);
}
break;
}
}
handleError(err) {
this.emit("error", err);
this.disconnect();
}
}
exports.LivetimingClient = LivetimingClient;