diff --git a/module/shard.ts b/module/shard.ts index 128f65a69..31c1c9731 100644 --- a/module/shard.ts +++ b/module/shard.ts @@ -80,6 +80,11 @@ const createShard = async ( break; case GatewayOpcode.Reconnect: case GatewayOpcode.InvalidSession: + // When d is false we need to reidentify + if (!data.d) { + createShard(botGatewayData, identifyPayload); + break; + } needToResume = true; resumeConnection(botGatewayData, identifyPayload); break; diff --git a/module/shardingManager.ts b/module/shardingManager.ts index 3ab37cc8d..147ea08c7 100644 --- a/module/shardingManager.ts +++ b/module/shardingManager.ts @@ -32,6 +32,7 @@ import { GuildRolePayload, UserPayload, FetchMembersOptions, + GuildRoleDeletePayload, } from "../types/guild.ts"; import { handleInternalGuildCreate, @@ -66,6 +67,7 @@ const fetchAllMembersProcessingRequests = new Map< FetchAllMembersRequest >(); const shards: Worker[] = []; +let createNextShard = true; export function createShardWorker(shardID?: number) { const path = new URL("./shard.ts", import.meta.url).toString(); @@ -76,6 +78,7 @@ export function createShardWorker(shardID?: number) { shardID || shardCounter++, botGatewayData.shards, ]; + shard.postMessage( { type: "CREATE_SHARD", @@ -95,13 +98,19 @@ export const spawnShards = async ( payload: unknown, id = 1, ) => { - createShardWorker(); - // 5 second delay per shard - await delay(5000); - if (id < data.shards) spawnShards(data, payload, id + 1); + if (id < data.shards) { + if (createNextShard) { + createNextShard = false; + createShardWorker(); + spawnShards(data, payload, id + 1); + } else { + await delay(1000); + spawnShards(data, payload, id); + } + } }; -function handleDiscordPayload(data: DiscordPayload) { +async function handleDiscordPayload(data: DiscordPayload) { eventHandlers.raw?.(data); switch (data.op) { @@ -109,7 +118,13 @@ function handleDiscordPayload(data: DiscordPayload) { // Incase the user wants to listen to heartbeat responses return eventHandlers.heartbeat?.(); case GatewayOpcode.Dispatch: - if (data.t === "READY") return eventHandlers.ready?.(); + if (data.t === "READY") { + // Triggered on each shard + eventHandlers.ready?.(); + // Wait 5 seconds to spawn next shard + await delay(5000); + createNextShard = true; + } if (data.t === "CHANNEL_CREATE") { return handleInternalChannelCreate(data.d as ChannelCreatePayload); @@ -290,9 +305,19 @@ function handleDiscordPayload(data: DiscordPayload) { } } + if (data.t === "GUILD_ROLE_DELETE") { + const options = data.d as GuildRoleDeletePayload; + const guild = cache.guilds.get(options.guild_id); + if (!guild) return; + + const cachedRole = guild.roles.get(options.role_id)!; + guild.roles.delete(options.role_id); + return eventHandlers.roleDelete?.(guild, cachedRole); + } + if ( data.t && - ["GUILD_ROLE_CREATE", "GUILD_ROLE_DELETE", "GUILD_ROLE_UPDATE"] + ["GUILD_ROLE_CREATE", "GUILD_ROLE_UPDATE"] .includes(data.t) ) { const options = data.d as GuildRolePayload; @@ -309,13 +334,6 @@ function handleDiscordPayload(data: DiscordPayload) { const cachedRole = guild.roles.get(options.role.id); if (!cachedRole) return; - if (data.t === "GUILD_ROLE_DELETE") { - const roles = guild.roles; - roles.delete(options.role.id); - guild.roles = roles; - return eventHandlers.roleDelete?.(guild, cachedRole); - } - if (data.t === "GUILD_ROLE_UPDATE") { const role = createRole(options.role); return eventHandlers.roleUpdate?.(guild, role, cachedRole); diff --git a/types/guild.ts b/types/guild.ts index a427c3a09..af31a86de 100644 --- a/types/guild.ts +++ b/types/guild.ts @@ -14,6 +14,13 @@ export interface GuildRolePayload { role: RoleData; } +export interface GuildRoleDeletePayload { + /** The id of the guild */ + guild_id: string; + /** The id of the role */ + role_id: string; +} + export interface GuildMemberChunkPayload { /** The id of the guild */ guild_id: string;