added stats to server and simple channel -> client map

This commit is contained in:
Steffen 2020-11-29 21:34:05 +01:00
parent e19b617df4
commit 805e16ad63
1 changed files with 40 additions and 13 deletions

View File

@ -10,17 +10,22 @@ const wss = new WebSocket.Server({
...(process.env.NODE_ENV === "development" ? { port: 8081 } : { server }), ...(process.env.NODE_ENV === "development" ? { port: 8081 } : { server }),
verifyClient: info => verifyClient: info =>
!!info.origin.match( !!info.origin.match(
/^https?:\/\/(bra1n\.github\.io|localhost|eddbra1nprivatetownsquare\.xyz)/i /^https?:\/\/([^.]+\.github\.io|localhost|live\.clocktower\.online|eddbra1nprivatetownsquare\.xyz)/i
) )
}); });
function noop() {} function noop() {}
// calculate latency on heartbeat
function heartbeat() { function heartbeat() {
this.latency = Math.round((new Date().getTime() - this.pingStart) / 2); this.latency = Math.round((new Date().getTime() - this.pingStart) / 2);
this.isAlive = true; this.isAlive = true;
} }
// map of channels currently in use
const channels = {};
// a new client connects
wss.on("connection", function connection(ws, req) { wss.on("connection", function connection(ws, req) {
ws.channel = req.url ws.channel = req.url
.split("/") .split("/")
@ -31,12 +36,10 @@ wss.on("connection", function connection(ws, req) {
ws.channel = ws.channel.substr(0, ws.channel.length - 5); ws.channel = ws.channel.substr(0, ws.channel.length - 5);
// check for another host on this channel // check for another host on this channel
if ( if (
Array.from(wss.clients).some( channels[ws.channel] &&
channels[ws.channel].some(
client => client =>
client !== ws && client !== ws && client.readyState === WebSocket.OPEN && client.isHost
client.readyState === WebSocket.OPEN &&
client.channel === ws.channel &&
client.isHost
) )
) { ) {
console.log(ws.channel, "duplicate host"); console.log(ws.channel, "duplicate host");
@ -46,19 +49,30 @@ wss.on("connection", function connection(ws, req) {
} }
ws.isAlive = true; ws.isAlive = true;
ws.pingStart = new Date().getTime(); ws.pingStart = new Date().getTime();
// add channel to list
if (!channels[ws.channel]) {
channels[ws.channel] = [];
}
channels[ws.channel].push(ws);
// start ping pong
ws.ping(noop); ws.ping(noop);
ws.on("pong", heartbeat); ws.on("pong", heartbeat);
// remove client from channels on close
ws.on("close", () => {
const index = channels[ws.channel].indexOf(ws);
if (index >= 0) {
channels[ws.channel].splice(index, 1);
}
if (!channels[ws.channel].length) delete channels[ws.channel];
});
// handle message
ws.on("message", function incoming(data) { ws.on("message", function incoming(data) {
const isPing = data.match(/^\["ping/i); const isPing = data.match(/^\["ping/i);
if (!isPing) { if (!isPing) {
console.log(new Date(), wss.clients.size, ws.channel, data); console.log(new Date(), wss.clients.size, ws.channel, data);
} }
wss.clients.forEach(function each(client) { channels[ws.channel].forEach(function each(client) {
if ( if (client !== ws && client.readyState === WebSocket.OPEN) {
client !== ws &&
client.readyState === WebSocket.OPEN &&
client.channel === ws.channel
) {
// inject latency between both clients if ping message // inject latency between both clients if ping message
if (isPing && client.latency && ws.latency) { if (isPing && client.latency && ws.latency) {
client.send(data.replace(/latency/, client.latency + ws.latency)); client.send(data.replace(/latency/, client.latency + ws.latency));
@ -70,6 +84,7 @@ wss.on("connection", function connection(ws, req) {
}); });
}); });
// start ping interval timer
const interval = setInterval(function ping() { const interval = setInterval(function ping() {
wss.clients.forEach(function each(ws) { wss.clients.forEach(function each(ws) {
if (ws.isAlive === false) return ws.terminate(); if (ws.isAlive === false) return ws.terminate();
@ -77,12 +92,24 @@ const interval = setInterval(function ping() {
ws.pingStart = new Date().getTime(); ws.pingStart = new Date().getTime();
ws.ping(noop); ws.ping(noop);
}); });
}, 30000); }, 30000); // 30 second pings
// handle server shutdown
wss.on("close", function close() { wss.on("close", function close() {
clearInterval(interval); clearInterval(interval);
}); });
// prod mode with stats API
if (process.env.NODE_ENV !== "development") { if (process.env.NODE_ENV !== "development") {
console.log("server starting");
server.listen(8080); server.listen(8080);
server.on("request", (req, res) => {
res.writeHead(200);
res.end(
JSON.stringify({
players: wss.clients.size,
channels: Object.keys(channels).length
})
);
});
} }