mudb
Version:
Real-time database for multiplayer games
189 lines • 7.18 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const socket_1 = require("../socket");
const util_1 = require("./util");
const system_1 = require("../../scheduler/system");
function noop() { }
class MuNetSocketClient {
constructor(sessionId, reliableSocket, unreliableSocket, remotePort, remoteAddr, scheduler, removeConnection) {
this._state = socket_1.MuSocketState.INIT;
this._pendingMessages = [];
this.onmessage = noop;
this._onclose = noop;
this.sessionId = sessionId;
this._reliableSocket = reliableSocket;
this._unreliableSocket = unreliableSocket;
this._remotePort = remotePort;
this._remoteAddr = remoteAddr;
this.scheduler = scheduler;
this._reliableSocket.on('message', (msg) => {
if (util_1.isJSON(msg)) {
this._pendingMessages.push(msg.toString());
}
else {
this._pendingMessages.push(new Uint8Array(msg).slice(0));
}
});
this._reliableSocket.on('close', (hadError) => {
this._state = socket_1.MuSocketState.CLOSED;
this._onclose();
removeConnection();
if (hadError) {
console.error('mudb/net-socket: socket was closed due to a transmission error');
}
});
}
state() {
return this._state;
}
open(spec) {
if (this._state !== socket_1.MuSocketState.INIT) {
throw new Error('mudb/net-socket: socket was already opened');
}
this.scheduler.setTimeout(() => {
const onmessage = this.onmessage = spec.message;
this._onclose = spec.close;
this._state = socket_1.MuSocketState.OPEN;
spec.ready();
this._reliableSocket.on('message', (msg) => {
if (this._state !== socket_1.MuSocketState.OPEN) {
return;
}
if (util_1.isJSON(msg)) {
onmessage(msg.toString(), false);
}
else {
onmessage(new Uint8Array(msg), false);
}
});
for (let i = 0; i < this._pendingMessages.length; ++i) {
onmessage(this._pendingMessages[i], false);
}
this._pendingMessages.length = 0;
}, 0);
}
send(data, unreliable) {
if (this._state !== socket_1.MuSocketState.OPEN) {
return;
}
if (unreliable) {
const buf = Buffer.from(data);
this._unreliableSocket.send(buf, 0, buf.length, this._remotePort, this._remoteAddr);
}
else {
this._reliableSocket.write(data);
}
}
close() {
if (this._state === socket_1.MuSocketState.CLOSED) {
return;
}
this._state = socket_1.MuSocketState.CLOSED;
this._reliableSocket.end();
}
reliableBufferedAmount() {
return 0;
}
unreliableBufferedAmount() {
return 0;
}
}
class MuNetSocketServer {
constructor(spec) {
this._state = socket_1.MuSocketServerState.INIT;
this.clients = [];
this._unreliableMsgHandlers = {};
this._onclose = noop;
this._tcpServer = spec.tcpServer;
this._udpServer = spec.udpServer;
this.scheduler = spec.scheduler || system_1.MuSystemScheduler;
}
state() {
return this._state;
}
start(spec) {
if (this._state !== socket_1.MuSocketServerState.INIT) {
throw new Error('mudb/net-socket: server was already started');
}
this._tcpServer.on('connection', (socket) => {
socket.setNoDelay(true);
util_1.messagify(socket);
socket.on('error', (err) => {
console.error(err.stack);
});
socket.once('message', (message) => {
try {
const clientInfo = JSON.parse(message.toString());
if (typeof clientInfo.i !== 'string' ||
typeof clientInfo.p !== 'number' ||
typeof clientInfo.a !== 'string') {
throw new Error('bad client info');
}
const udpServerInfo = this._udpServer.address();
if (typeof udpServerInfo === 'string') {
socket.write(JSON.stringify({
p: '',
a: '' + udpServerInfo,
}));
}
else {
socket.write(JSON.stringify({
p: udpServerInfo.port,
a: udpServerInfo.address,
}));
}
const url = `${clientInfo.a}:${clientInfo.p}`;
const client = new MuNetSocketClient(clientInfo.i, socket, this._udpServer, clientInfo.p, clientInfo.a, this.scheduler, () => {
this.clients.splice(this.clients.indexOf(client), 1);
delete this._unreliableMsgHandlers[url];
});
this.clients.push(client);
this._unreliableMsgHandlers[url] = function (msg) {
if (client.state() !== socket_1.MuSocketState.OPEN) {
return;
}
if (util_1.isJSON(msg)) {
client.onmessage(msg.toString(), true);
}
else {
client.onmessage(new Uint8Array(msg), true);
}
};
spec.connection(client);
}
catch (e) {
console.error(`mudb/net-socket: destroying socket due to ${e}`);
socket.destroy();
}
});
});
this._udpServer.on('listening', () => {
let addr = this._udpServer.address();
if (typeof addr !== 'string') {
addr = addr.address;
}
if (addr === '0.0.0.0' || addr === '::') {
console.warn(`mudb/net-socket: UDP server is bound to ${addr}. Are you sure?`);
}
});
this._udpServer.on('message', (msg, client) => {
const onmessage = this._unreliableMsgHandlers[`${client.address}:${client.port}`];
if (typeof onmessage === 'function') {
onmessage(msg);
}
});
this._onclose = spec.close;
this._state = socket_1.MuSocketServerState.RUNNING;
spec.ready();
}
close() {
if (this._state === socket_1.MuSocketServerState.SHUTDOWN) {
return;
}
this._state = socket_1.MuSocketServerState.SHUTDOWN;
this._tcpServer.close(this._onclose);
this._udpServer.close();
}
}
exports.MuNetSocketServer = MuNetSocketServer;
//# sourceMappingURL=server.js.map