diff --git a/src/bot.ts b/src/bot.ts index b3b8d82b6..a90dafccb 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -72,6 +72,7 @@ import { tellClusterToIdentify, sendShardMessage, DiscordenoShard, + processGatewayQueue, } from "./ws/mod.ts"; import { validateLength } from "./util/validate_length.ts"; import { delay, validateComponents, validateSlashOptionChoices, validateSlashOptions } from "./util/utils.ts"; @@ -295,6 +296,7 @@ import { import { DiscordenoEmoji, transformEmoji } from "./transformers/emoji.ts"; import { transformActivity } from "./transformers/activity.ts"; import { DiscordenoPresence, transformPresence } from "./transformers/presence.ts"; +import { DiscordReady } from "./types/gateway/ready.ts"; export function createBot(options: CreateBotOptions) { return { @@ -435,6 +437,7 @@ export function createEventHandlers(events: Partial): EventHandle return { debug: events.debug ?? ignore, + ready: events.ready ?? ignore, dispatchRequirements: events.dispatchRequirements ?? ignore, integrationCreate: events.integrationCreate ?? ignore, integrationDelete: events.integrationDelete ?? ignore, @@ -545,6 +548,8 @@ export async function startBot(bot: Bot) { // START WS bot.gateway = createGatewayManager({ + token: bot.token, + intents: bot.intents, urlWSS: bot.botGatewayData.url, shardsRecommended: bot.botGatewayData.shards, sessionStartLimitTotal: bot.botGatewayData.sessionStartLimit.total, @@ -565,7 +570,7 @@ export async function startBot(bot: Bot) { }, }); - bot.gateway.spawnShards(bot.gateway) + bot.gateway.spawnShards(bot.gateway); } export function createUtils(options: Partial) { @@ -639,7 +644,7 @@ export function createGatewayManager( reshard: options.reshard ?? true, reshardPercentage: options.reshardPercentage ?? 80, spawnShardDelay: options.spawnShardDelay ?? 2600, - maxShards: options.maxShards ?? 0, + maxShards: options.maxShards ?? options.shardsRecommended ?? 0, useOptimalLargeBotSharding: options.useOptimalLargeBotSharding ?? true, shardsPerCluster: options.shardsPerCluster ?? 25, maxClusters: options.maxClusters ?? 4, @@ -651,7 +656,7 @@ export function createGatewayManager( $browser: options.$browser ?? "Discordeno", $device: options.$device ?? "Discordeno", intents: options.intents ?? 0, - shard: options.shard ?? [0, 0], + shard: options.shard ?? [0, options.shardsRecommended ?? 1], urlWSS: options.urlWSS ?? "wss://gateway.discord.gg/?v=9&encoding=json", shardsRecommended: options.shardsRecommended ?? 1, sessionStartLimitTotal: options.sessionStartLimitTotal ?? 1000, @@ -672,7 +677,7 @@ export function createGatewayManager( log, resharder, handleOnMessage, - processQueue, + processGatewayQueue, closeWS, sendShardMessage, resume, @@ -1165,7 +1170,7 @@ export interface GatewayManager { /** Handles the message events from websocket. */ handleOnMessage: typeof handleOnMessage; /** Handles processing queue of requests send to this shard. */ - processQueue: typeof processQueue; + processGatewayQueue: typeof processGatewayQueue; /** Closes shard WebSocket connection properly. */ closeWS: typeof closeWS; /** Properly adds a message to the shards queue. */ @@ -1176,6 +1181,19 @@ export interface GatewayManager { export interface EventHandlers { debug: (text: string) => unknown; + ready: ( + bot: Bot, + payload: { + shardId: number; + v: number; + user: DiscordenoUser; + guilds: bigint[]; + sessionId: string; + shard?: number[]; + applicationId: bigint; + }, + rawPayload: DiscordReady + ) => any; interactionCreate: (bot: Bot, interaction: DiscordenoInteraction) => any; integrationCreate: (bot: Bot, integration: DiscordenoIntegration) => any; integrationDelete: (bot: Bot, payload: { id: bigint; guildId: bigint; applicationId?: bigint }) => any; diff --git a/src/ws/heartbeat.ts b/src/ws/heartbeat.ts index 0f7ab8c45..1968a2220 100644 --- a/src/ws/heartbeat.ts +++ b/src/ws/heartbeat.ts @@ -13,9 +13,9 @@ export async function heartbeat(gateway: GatewayManager, shardId: number, interv // The first heartbeat is special so we send it without setInterval: https://discord.com/developers/docs/topics/gateway#heartbeating await delay(Math.floor(shard.heartbeat.interval * Math.random())); - if (shard.gateway.readyState !== WebSocket.OPEN) return; + if (shard.ws.readyState !== WebSocket.OPEN) return; - shard.gateway.send( + shard.ws.send( JSON.stringify({ op: DiscordGatewayOpcodes.Heartbeat, d: shard.previousSequenceNumber, @@ -34,7 +34,7 @@ export async function heartbeat(gateway: GatewayManager, shardId: number, interv gateway.log("HEARTBEATING", { shardId, shard: currentShard }); - if (currentShard.gateway.readyState === WebSocket.CLOSED || !currentShard.heartbeat.keepAlive) { + if (currentShard.ws.readyState === WebSocket.CLOSED || !currentShard.heartbeat.keepAlive) { gateway.log("HEARTBEATING_CLOSED", { shardId, shard: currentShard }); // STOP THE HEARTBEAT @@ -42,15 +42,15 @@ export async function heartbeat(gateway: GatewayManager, shardId: number, interv } if (!currentShard.heartbeat.acknowledged) { - gateway.closeWS(currentShard.gateway, 3066, "Did not receive an ACK in time."); + gateway.closeWS(currentShard.ws, 3066, "Did not receive an ACK in time."); return await gateway.identify(gateway, shardId, gateway.maxShards); } - if (currentShard.gateway.readyState !== WebSocket.OPEN) return; + if (currentShard.ws.readyState !== WebSocket.OPEN) return; currentShard.heartbeat.acknowledged = false; - currentShard.gateway.send( + currentShard.ws.send( JSON.stringify({ op: DiscordGatewayOpcodes.Heartbeat, d: currentShard.previousSequenceNumber, diff --git a/src/ws/identify.ts b/src/ws/identify.ts index e5010fc23..080bab013 100644 --- a/src/ws/identify.ts +++ b/src/ws/identify.ts @@ -39,6 +39,20 @@ export function identify(gateway: GatewayManager, shardId: number, maxShards: nu }); socket.onopen = () => { + console.log({ + op: DiscordGatewayOpcodes.Identify, + d: { + token: gateway.token, + compress: gateway.compress, + properties: { + $os: gateway.$os, + $browser: gateway.$browser, + $device: gateway.$device, + }, + intents: gateway.intents, + shard: [shardId, maxShards], + }, + },) gateway.sendShardMessage( gateway, shardId, diff --git a/src/ws/mod.ts b/src/ws/mod.ts index 78bd39c14..146bdc424 100644 --- a/src/ws/mod.ts +++ b/src/ws/mod.ts @@ -4,6 +4,7 @@ export * from "./events.ts"; export * from "./handle_on_message.ts"; export * from "./heartbeat.ts"; export * from "./identify.ts"; +export * from './process_gateway_queue.ts' export * from "./resharder.ts"; export * from "./resume.ts"; export * from "./spawn_shards.ts"; diff --git a/src/ws/process_queue.ts b/src/ws/process_gateway_queue.ts similarity index 86% rename from src/ws/process_queue.ts rename to src/ws/process_gateway_queue.ts index 1a9165662..934270027 100644 --- a/src/ws/process_queue.ts +++ b/src/ws/process_gateway_queue.ts @@ -1,7 +1,7 @@ import { delay } from "../util/utils.ts"; import { GatewayManager } from "../bot.ts"; -export async function processQueue(gateway: GatewayManager, id: number) { +export async function processGatewayQueue(gateway: GatewayManager, id: number) { const shard = gateway.shards.get(id); // If no items or its already processing then exit if (!shard?.queue.length || shard.processingQueue) return; @@ -9,7 +9,7 @@ export async function processQueue(gateway: GatewayManager, id: number) { shard.processingQueue = true; while (shard.queue.length) { - if (shard.gateway.readyState !== WebSocket.OPEN) { + if (shard.ws.readyState !== WebSocket.OPEN) { shard.processingQueue = false; return; } @@ -26,7 +26,7 @@ export async function processQueue(gateway: GatewayManager, id: number) { gateway.log("RAW_SEND", shard.id, request); - shard.gateway.send(JSON.stringify(request)); + shard.ws.send(JSON.stringify(request)); // Counter is useful for preventing 120/m requests. shard.queueCounter++; diff --git a/src/ws/send_shard_message.ts b/src/ws/send_shard_message.ts index 5e99bc537..c9ed15b57 100644 --- a/src/ws/send_shard_message.ts +++ b/src/ws/send_shard_message.ts @@ -16,5 +16,5 @@ export function sendShardMessage( shard.queue.unshift(message); } - gateway.processQueue(gateway, shard.id); + gateway.processGatewayQueue(gateway, shard.id); } diff --git a/tests/mod.ts b/tests/mod.ts index 4c542d7da..deaf056a0 100644 --- a/tests/mod.ts +++ b/tests/mod.ts @@ -4,7 +4,7 @@ import { Bot, createBot, createEventHandlers, startBot } from "../mod.ts"; Deno.test("[Bot] - Starting Tests", async (t) => { const bot = createBot({ token: TOKEN || Deno.env.get("DISCORD_TOKEN"), - botId: 0n, + botId: 675412054529540107n, events: createEventHandlers({ raw: console.log, }),