summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-02-14 18:59:33 +0100
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-02-14 18:59:33 +0100
commitf5269ef39eee21a098679eab121fb3636f460a04 (patch)
treea116a8bd46a0caf783deb5aa9212a1793b53c3e8
parentsetup listeners (diff)
downloadserver-f5269ef39eee21a098679eab121fb3636f460a04.tar.xz
:sparkles: Event dispatching
-rw-r--r--package-lock.json10
-rw-r--r--src/listener/listener.ts171
-rw-r--r--src/opcodes/Identify.ts4
-rw-r--r--src/util/WebSocket.ts2
4 files changed, 167 insertions, 20 deletions
diff --git a/package-lock.json b/package-lock.json

index bc082ae9..3d6effdf 100644 --- a/package-lock.json +++ b/package-lock.json
@@ -540,12 +540,13 @@ }, "node_modules/fosscord-server-util": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#b2e3df59d3829d8a149b0bd0c0679ec967b76e8d", + "resolved": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#7363f243ad9936466b97266592037ee0a5290c54", "license": "ISC", "dependencies": { "jsonwebtoken": "^8.5.1", "lambert-db": "^1.1.7", - "missing-native-js-functions": "^1.2.2" + "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4" } }, "node_modules/fresh": { @@ -2201,12 +2202,13 @@ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, "fosscord-server-util": { - "version": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#b2e3df59d3829d8a149b0bd0c0679ec967b76e8d", + "version": "git+ssh://git@github.com/fosscord/fosscord-server-util.git#7363f243ad9936466b97266592037ee0a5290c54", "from": "fosscord-server-util@github:fosscord/fosscord-server-util", "requires": { "jsonwebtoken": "^8.5.1", "lambert-db": "^1.1.7", - "missing-native-js-functions": "^1.2.2" + "missing-native-js-functions": "^1.2.2", + "mongodb": "^3.6.4" } }, "fresh": { diff --git a/src/listener/listener.ts b/src/listener/listener.ts
index d9531290..caf0456d 100644 --- a/src/listener/listener.ts +++ b/src/listener/listener.ts
@@ -1,23 +1,164 @@ -import { db, User, Event } from "fosscord-server-util"; -import { MongodbProviderCache } from "lambert-db/dist/Mongodb"; +import { db, Event, MongooseCache, UserModel, getPermission, Permissions } from "fosscord-server-util"; import WebSocket from "../util/WebSocket"; +// TODO: bot sharding +// TODO: close connection on Invalidated Token +// TODO: check intent +// TODO: Guild Member Update is sent for current-user updates regardless of whether the GUILD_MEMBERS intent is set. +// ? How to resubscribe MongooseCache for new dm channel events? Maybe directly send them to the user_id regardless of the channel_id? -> max overhead of creating 10 events in database for dm user group. Or a new field in event -> recipient_ids? + export async function setupListener(this: WebSocket) { - // TODO: bot sharding - // TODO: close connection on Invalidated Token + const user = await UserModel.findOne({ id: this.userid }).exec(); - const user: User = await db.data.users({ id: this.userid }).get(); + const eventStream = new MongooseCache( + db.collection("events"), + [{ $match: { $or: [{ guild_id: { $in: user.guilds } }, { user_id: this.userid }] } }], + { onlyEvents: true } + ); + await eventStream.init(); + eventStream.on("insert", dispatch.bind(this)); - // * MongoDB specific $in query to get all guilds of the user - const eventStream: MongodbProviderCache = await db.data - .guilds({ $or: [{ guild_id: { $in: user.guilds } }, { user_id: this.userid }] }) - .cache({ onlyEvents: true }) - .init(); + this.once("close", () => eventStream.destroy()); +} - eventStream.on("insert", (document: Event) => { - console.log("event", document); - this.emit(document.event, document.data); - }); +export async function dispatch(this: WebSocket, document: Event) { + var permission = new Permissions("ADMINISTRATOR"); // default permission for dms - this.once("close", () => eventStream.destroy()); + if (document.guild_id) { + if (!this.intents.has("GUILDS")) return; + const channel_id = document.channel_id || document.data?.channel_id; + permission = new Permissions(await getPermission(this.userid, document.guild_id, channel_id)); + } + + console.log("event", document); + + // check intents: https://discord.com/developers/docs/topics/gateway#gateway-intents + switch (document.event) { + case "GUILD_CREATE": + case "GUILD_DELETE": + case "GUILD_UPDATE": + case "GUILD_ROLE_CREATE": + case "GUILD_ROLE_UPDATE": + case "GUILD_ROLE_DELETE": + case "CHANNEL_CREATE": + case "CHANNEL_DELETE": + case "CHANNEL_UPDATE": + // gets sent if GUILDS intent is set (already checked in if document.guild_id) + break; + case "GUILD_INTEGRATIONS_UPDATE": + if (!this.intents.has("GUILD_INTEGRATIONS")) return; + break; + case "WEBHOOKS_UPDATE": + if (!this.intents.has("GUILD_WEBHOOKS")) return; + break; + case "GUILD_EMOJI_UPDATE": + if (!this.intents.has("GUILD_EMOJIS")) return; + break; + // only send them, if the user subscribed for this part of the member list, or is a bot + case "GUILD_MEMBER_ADD": + case "GUILD_MEMBER_REMOVE": + case "GUILD_MEMBER_UPDATE": + if (!this.intents.has("GUILD_MEMBERS")) return; + break; + case "VOICE_STATE_UPDATE": + if (!this.intents.has("GUILD_VOICE_STATES")) return; + break; + case "GUILD_BAN_ADD": + case "GUILD_BAN_REMOVE": + if (!this.intents.has("GUILD_BANS")) return; + break; + case "INVITE_CREATE": + case "INVITE_DELETE": + if (!this.intents.has("GUILD_INVITES")) return; + case "PRESENCE_UPDATE": + if (!this.intents.has("GUILD_PRESENCES")) return; + break; + case "MESSAGE_CREATE": + case "MESSAGE_DELETE": + case "MESSAGE_DELETE_BULK": + case "MESSAGE_UPDATE": + case "CHANNEL_PINS_UPDATE": + if (!this.intents.has("GUILD_MESSAGES") && document.guild_id) return; + if (!this.intents.has("DIRECT_MESSAGES") && !document.guild_id) return; + break; + case "MESSAGE_REACTION_ADD": + case "MESSAGE_REACTION_REMOVE": + case "MESSAGE_REACTION_REMOVE_ALL": + case "MESSAGE_REACTION_REMOVE_EMOJI": + if (!this.intents.has("GUILD_MESSAGE_REACTIONS") && document.guild_id) return; + if (!this.intents.has("DIRECT_MESSAGE_REACTIONS") && !document.guild_id) return; + break; + + case "TYPING_START": + if (!this.intents.has("GUILD_MESSAGE_TYPING") && document.guild_id) return; + if (!this.intents.has("DIRECT_MESSAGE_TYPING") && !document.guild_id) return; + break; + case "READY": + case "USER_UPDATE": + case "APPLICATION_COMMAND_CREATE": + case "APPLICATION_COMMAND_DELETE": + case "APPLICATION_COMMAND_UPDATE": + default: + // Any events not defined in an intent are considered "passthrough" and will always be sent to you. + break; + } + + // check permissions + switch (document.event) { + case "GUILD_INTEGRATIONS_UPDATE": + if (!permission.has("MANAGE_GUILD")) return; + break; + case "WEBHOOKS_UPDATE": + if (!permission.has("MANAGE_WEBHOOKS")) return; + break; + case "GUILD_MEMBER_ADD": + case "GUILD_MEMBER_REMOVE": + case "GUILD_MEMBER_UPDATE": + // only send them, if the user subscribed for this part of the member list, or is a bot + break; + case "GUILD_BAN_ADD": + case "GUILD_BAN_REMOVE": + if (!permission.has("BAN_MEMBERS")) break; + break; + case "INVITE_CREATE": + case "INVITE_DELETE": + if (!permission.has("MANAGE_GUILD")) break; + case "PRESENCE_UPDATE": + break; + case "VOICE_STATE_UPDATE": + case "MESSAGE_CREATE": + case "MESSAGE_DELETE": + case "MESSAGE_DELETE_BULK": + case "MESSAGE_UPDATE": + case "CHANNEL_PINS_UPDATE": + case "MESSAGE_REACTION_ADD": + case "MESSAGE_REACTION_REMOVE": + case "MESSAGE_REACTION_REMOVE_ALL": + case "MESSAGE_REACTION_REMOVE_EMOJI": + case "TYPING_START": + // only gets send if the user is alowed to view the current channel + if (!permission.has("VIEW_CHANNEL")) return; + break; + case "GUILD_CREATE": + case "GUILD_DELETE": + case "GUILD_UPDATE": + case "GUILD_ROLE_CREATE": + case "GUILD_ROLE_UPDATE": + case "GUILD_ROLE_DELETE": + case "CHANNEL_CREATE": + case "CHANNEL_DELETE": + case "CHANNEL_UPDATE": + case "GUILD_EMOJI_UPDATE": + case "READY": + case "USER_UPDATE": + case "APPLICATION_COMMAND_CREATE": + case "APPLICATION_COMMAND_DELETE": + case "APPLICATION_COMMAND_UPDATE": + default: + // always gets sent + // Any events not defined in an intent are considered "passthrough" and will always be sent + break; + } + + return this.emit(document.event, document.data); } diff --git a/src/opcodes/Identify.ts b/src/opcodes/Identify.ts
index da993ec8..f62f66b0 100644 --- a/src/opcodes/Identify.ts +++ b/src/opcodes/Identify.ts
@@ -1,9 +1,10 @@ import { CLOSECODES, Payload } from "../util/Constants"; import WebSocket from "../util/WebSocket"; -import { checkToken } from "fosscord-server-util"; +import { checkToken, Intents } from "fosscord-server-util"; import { setupListener } from "../listener/listener"; import { instanceOf } from "lambert-server"; import { IdentifySchema } from "../schema/Identify"; +// TODO: check priviliged intents export async function onIdentify(this: WebSocket, data: Payload) { try { @@ -14,6 +15,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { var decoded = await checkToken(identify.token); this.userid = decoded.id; + this.intents = new Intents(identify.intents); await setupListener.call(this); } catch (error) { diff --git a/src/util/WebSocket.ts b/src/util/WebSocket.ts
index 41ce8851..10b8348f 100644 --- a/src/util/WebSocket.ts +++ b/src/util/WebSocket.ts
@@ -1,3 +1,4 @@ +import { Intents } from "fosscord-server-util"; import WS, { Server, Data } from "ws"; interface WebSocket extends WS { @@ -7,6 +8,7 @@ interface WebSocket extends WS { compress?: "zlib-stream"; heartbeatTimeout: NodeJS.Timeout; readyTimeout: NodeJS.Timeout; + intents: Intents; } export default WebSocket;