Files
discordeno/src/handlers/misc/READY.ts
T
2021-03-29 23:47:31 +04:00

102 lines
3.0 KiB
TypeScript

import {
eventHandlers,
lastShardId,
setApplicationId,
setBotId,
} from "../../bot.ts";
import { cache, cacheHandlers } from "../../cache.ts";
import { initialMemberLoadQueue } from "../../structures/guild.ts";
import { structures } from "../../structures/mod.ts";
import { delay } from "../../util/utils.ts";
import { allowNextShard, basicShards } from "../../ws/mod.ts";
export async function handleReady(
data: DiscordGatewayPayload,
shardId: number,
) {
// The bot has already started, the last shard is resumed, however.
if (cache.isReady) return;
const payload = data.d as DiscordReady;
setBotId(payload.user.id);
setApplicationId(payload.application.id);
// Triggered on each shard
eventHandlers.shardReady?.(shardId);
// Save when the READY event was received to prevent infinite load loops
const now = Date.now();
const shard = basicShards.get(shardId);
if (!shard) return;
// Set ready to false just to go sure
shard.ready = false;
// All guilds are unavailable at first
shard.unavailableGuildIds = new Set(payload.guilds.map((g) => g.id));
// Start ready check in 2 seconds
setTimeout(() => checkReady(payload, shardId, now), 2000);
// Wait 5 seconds to spawn next shard
await delay(5000);
allowNextShard();
}
// Don't pass the shard itself because unavailableGuilds won't be updated by the GUILD_CREATE event
/** This function checks if the shard is fully loaded */
function checkReady(payload: DiscordReady, shardId: number, now: number) {
const shard = basicShards.get(shardId);
if (!shard) return;
// Check if all guilds were loaded
if (shard.unavailableGuildIds.size) {
if (Date.now() - now > 10000) {
eventHandlers.shardFailedToLoad?.(shardId, shard.unavailableGuildIds);
// Force execute the loaded function to prevent infinite loop
loaded(shardId);
} else {
// Not all guilds were loaded but 10 seconds haven't passed so check again
setTimeout(() => checkReady(payload, shardId, now), 2000);
}
} else {
// All guilds were loaded
loaded(shardId);
}
}
async function loaded(shardId: number) {
const shard = basicShards.get(shardId);
if (!shard) return;
shard.ready = true;
// If it is the last shard we can go full ready
if (shardId === lastShardId - 1) {
// Still some shards are loading so wait another 2 seconds for them
if (basicShards.some((shard) => !shard.ready)) {
setTimeout(() => loaded(shardId), 2000);
} else {
cache.isReady = true;
eventHandlers.ready?.();
// All the members that came in on guild creates should now be processed 1 by 1
for (const [guildId, members] of initialMemberLoadQueue.entries()) {
await Promise.allSettled(
members.map(async (member) => {
const memberStruct = await structures.createMemberStruct(
member,
guildId,
);
return cacheHandlers.set(
"members",
memberStruct.id,
memberStruct,
);
}),
);
}
}
}
}