add session counters and presence (brainlet-react presence is locked behind an experiment flag, just enable it with an override at the moment)

This commit is contained in:
hippoz 2021-06-10 14:02:31 +03:00
parent 76f041e75e
commit 3a53d585ff
Signed by: hippoz
GPG key ID: 7C52899193467641
3 changed files with 61 additions and 13 deletions

View file

@ -6,7 +6,7 @@ const werift = require("werift");
const { experiments } = require("../../../experiments");
const User = require("../../../models/User");
const Channel = require("../../../models/Channel");
const { parseMessage, opcodeSeparator, getOpcodeByName } = require("./messageparser");
const { parseMessage, packet } = require("./messageparser");
const { checkToken } = require("../../../common/auth/authfunctions");
const pingCheckDelay = 10000;
@ -43,6 +43,7 @@ class GatewayServer extends EventEmitter {
constructor({ server }) {
super();
this.wss = new websockets.Server({ server: server, path: "/gateway" });
this.sessionCounters = {};
this.pingInterval = setInterval(() => {
this.wss.clients.forEach((client) => {
@ -61,7 +62,7 @@ class GatewayServer extends EventEmitter {
this.wss.on("connection", (ws) => {
// Send HELLO message as soon as the client connects
ws.send(this.packet("HELLO", {}));
ws.send(packet("HELLO", {}));
ws.session = {
authenticated: false,
user: null,
@ -73,6 +74,21 @@ class GatewayServer extends EventEmitter {
ws.alive = true;
});
ws.on("close", async () => {
if (this.sessionCounters[ws.session.user._id] <= 1) {
this.inChannel(ws.channels[0], (client) => {
console.log(client.session);
client.send(packet("EVENT_CHANNEL_MEMBERS", {
[ws.session.user._id]: {
_id: ws.session.user._id,
username: ws.session.user.username,
status: 0,
status_text: "Now offline"
}
}));
});
}
this.sessionCounters[ws.session.user._id]--;
if (ws.rtc) await ws.rtc.connection.close();
});
ws.on("message", async (data) => {
@ -87,6 +103,12 @@ class GatewayServer extends EventEmitter {
ws.session.user = user;
ws.session.authenticated = true;
if (!this.sessionCounters[user._id]) this.sessionCounters[user._id] = 0;
this.sessionCounters[user._id]++;
if (this.sessionCounters[user._id] > 5) {
return ws.close(4006, "Too many sessions.");
}
// The user is now successfully authenticated, send the YOO_ACK packet
// TODO: This is probably not efficient
@ -96,7 +118,30 @@ class GatewayServer extends EventEmitter {
ws.channels = channels.map(x => x._id);
ws.send(this.packet("YOO_ACK", { session_id: ws.session.sessionId, channels, user: { username: user.username, _id: user._id }, __global_experiments: experiments }));
ws.send(packet("YOO_ACK", { session_id: ws.session.sessionId, channels, user: { username: user.username, _id: user._id }, __global_experiments: experiments }));
let presence = {};
const channel = channels[0];
this.inChannel(channel._id, (client) => {
presence[client.session.user._id] = {
_id: client.session.user._id,
username: client.session.user.username,
status: 1,
status_text: "Online"
};
if (client.session.sessionId !== ws.session.sessionId) client.send(packet("EVENT_CHANNEL_MEMBERS", {
[ws.session.user._id]: {
_id: ws.session.user._id,
username: ws.session.user.username,
status: 1,
status_text: "Online"
}
}));
});
ws.send(packet("EVENT_CHANNEL_MEMBERS", presence));
console.log(`gateway: user ${user.username}: handshake complete`);
} catch (e) {
console.log("gateway:", e);
@ -116,7 +161,7 @@ class GatewayServer extends EventEmitter {
// Check if the user is in that channel before broadcasting the message
if (!ws.channels.includes(message.data.channel._id)) return ws.close(4008, "Not authorized to perform action.");
this.broadcast(message.data.channel._id, this.packet("EVENT_CREATE_MESSAGE", {
this.broadcast(message.data.channel._id, packet("EVENT_CREATE_MESSAGE", {
content: messageContent,
channel: {
_id: message.data.channel._id
@ -133,7 +178,7 @@ class GatewayServer extends EventEmitter {
case "ACTION_VOICE_REQUEST_SESSION": {
if (!experiments.voiceSFUTesting) return;
// just send ourselves as the voice server lol
ws.send(this.packet("EVENT_VOICE_ASSIGN_SERVER", {
ws.send(packet("EVENT_VOICE_ASSIGN_SERVER", {
reportTo: "/gateway",
channel: message.data.channel
}));
@ -168,7 +213,7 @@ class GatewayServer extends EventEmitter {
});
}
ws.send(this.packet("EVENT_VOICE_CONNECTION_ANSWER", {
ws.send(packet("EVENT_VOICE_CONNECTION_ANSWER", {
answer: await ws.rtc.answer(offer)
}));
@ -225,9 +270,4 @@ GatewayServer.prototype.authMessage = function(ws) {
return true;
};
GatewayServer.prototype.packet = function(op, data) {
if (typeof op === "string") op = getOpcodeByName(op);
return `${op}${opcodeSeparator}${JSON.stringify(data)}`;
};
module.exports = GatewayServer;

View file

@ -4,6 +4,9 @@ const opcodes = {
2: { name: "YOO_ACK", data: "JSON" },
3: { name: "ACTION_CREATE_MESSAGE", data: "JSON" },
4: { name: "EVENT_CREATE_MESSAGE", data: "JSON" },
5: { name: "ACTION_UPDATE_STATUS", data: "JSON" },
6: { name: "EVENT_CHANNEL_MEMBERS", data: "JSON" },
7: { name: "EVENT_CHANNEL_MEMBER_UPDATE", data: "JSON" },
21: { name: "ACTION_VOICE_REQUEST_SESSION", data: "JSON" },
22: { name: "EVENT_VOICE_ASSIGN_SERVER", data: "JSON" },
23: { name: "ACTION_VOICE_CONNECTION_REQUEST", data: "JSON" },
@ -45,4 +48,9 @@ const getOpcodeByName = (name) => {
for (const [key, value] of Object.entries(opcodes)) if (value.name === name) return key;
};
module.exports = { opcodes, parseMessage, opcodeSeparator, getOpcodeByName };
const packet = (op, data) => {
if (typeof op === "string") op = getOpcodeByName(op);
return `${op}${opcodeSeparator}${JSON.stringify(data)}`;
};
module.exports = { opcodes, parseMessage, opcodeSeparator, getOpcodeByName, packet };

View file

@ -1,6 +1,6 @@
module.exports = {
experiments: {
voiceSFUTesting: false,
userListTest: true
userListTest: false
}
};