diff --git a/src/events/Connection.ts b/src/events/Connection.ts
index 34274d9c..96c7c441 100644
--- a/src/events/Connection.ts
+++ b/src/events/Connection.ts
@@ -9,6 +9,7 @@ import { createDeflate } from "zlib";
// TODO: check rate limit
// TODO: specify rate limit in config
+// TODO: check msg max size
export async function Connection(this: Server, socket: WebSocket, request: IncomingMessage) {
try {
diff --git a/src/listener/listener.ts b/src/listener/listener.ts
index 82e6fa85..988a791a 100644
--- a/src/listener/listener.ts
+++ b/src/listener/listener.ts
@@ -8,12 +8,28 @@ import WebSocket from "../util/WebSocket";
// 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?
+// Sharding: calculate if the current shard id matches the formula: shard_id = (guild_id >> 22) % num_shards
+// https://discord.com/developers/docs/topics/gateway#sharding
+
export async function setupListener(this: WebSocket) {
const user = await UserModel.findOne({ id: this.user_id }).lean().exec();
+ var guilds = user.guilds;
+ const shard_count = 10n;
+ const shard_id = 0n;
+
+ if (shard_count) {
+ guilds = user.guilds.filter((x) => (BigInt(x) >> 22n) % shard_count === shard_id);
+ }
const eventStream = new MongooseCache(
db.collection("events"),
- [{ $match: { $or: [{ "fullDocument.guild_id": { $in: user.guilds } }, { "fullDocument.user_id": this.user_id }] } }],
+ [
+ {
+ $match: {
+ $or: [{ "fullDocument.guild_id": { $in: guilds } }, { "fullDocument.user_id": this.user_id }],
+ },
+ },
+ ],
{ onlyEvents: true }
);
await eventStream.init();
diff --git a/src/opcodes/Identify.ts b/src/opcodes/Identify.ts
index 1fa75ec1..584965af 100644
--- a/src/opcodes/Identify.ts
+++ b/src/opcodes/Identify.ts
@@ -38,6 +38,19 @@ export async function onIdentify(this: WebSocket, data: Payload) {
this.user_id = decoded.id;
if (!identify.intents) identify.intents = 0b11111111111111n;
this.intents = new Intents(identify.intents);
+ if (identify.shard) {
+ this.shard_id = identify.shard[0];
+ this.shard_count = identify.shard[1];
+ if (
+ !this.shard_count ||
+ !this.shard_id ||
+ this.shard_id >= this.shard_count ||
+ this.shard_id < 0 ||
+ this.shard_count <= 0
+ ) {
+ return this.close(CLOSECODES.Invalid_shard);
+ }
+ }
const members = toObject(await MemberModel.find({ id: this.user_id }).exec());
const merged_members = members.map((x: any) => {
@@ -48,8 +61,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
}) as MemberDocument[][];
const user_guild_settings_entries = members.map((x) => x.settings);
- const channels = await ChannelModel.find({ recipients: this.user_id }).lean().exec();
- const user = await UserModel.findOne({ id: this.user_id }).lean().exec();
+ const channels = await ChannelModel.find({ recipients: this.user_id }).exec();
+ const user = await UserModel.findOne({ id: this.user_id }).exec();
if (!user) return this.close(CLOSECODES.Authentication_failed);
const public_user = {
@@ -113,7 +126,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
partial: false, // TODO partial
version: 642,
},
- private_channels: channels,
+ // @ts-ignore
+ private_channels: toObject(channels),
session_id: "", // TODO
analytics_token: "", // TODO
connected_accounts: [], // TODO
diff --git a/src/schema/Identify.ts b/src/schema/Identify.ts
index 3e153fbe..dac5d9cc 100644
--- a/src/schema/Identify.ts
+++ b/src/schema/Identify.ts
@@ -25,7 +25,7 @@ export const IdentifySchema = {
$presence: ActivitySchema,
$compress: Boolean,
$large_threshold: Number,
- $shard: [Number],
+ $shard: [BigInt, BigInt],
$guild_subscriptions: Boolean,
$capabilities: Number,
$client_state: {
@@ -61,7 +61,7 @@ export interface IdentifySchema {
presence?: ActivitySchema;
compress?: boolean;
large_threshold?: number;
- shard?: [number];
+ shard?: [bigint, bigint];
guild_subscriptions?: boolean;
capabilities?: number;
client_state?: {
diff --git a/src/util/WebSocket.ts b/src/util/WebSocket.ts
index 566fc3aa..4aad85d0 100644
--- a/src/util/WebSocket.ts
+++ b/src/util/WebSocket.ts
@@ -7,6 +7,8 @@ interface WebSocket extends WS {
user_id: string;
encoding: "etf" | "json";
compress?: "zlib-stream";
+ shard_count?: bigint;
+ shard_id?: bigint;
deflate?: Deflate;
heartbeatTimeout: NodeJS.Timeout;
readyTimeout: NodeJS.Timeout;
|