mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-02 00:40:07 +00:00
More BigBot Fixes (#2233)
* Add `.DS_Store` to `.gitignore` * Format and improve DX. * Add extra logging and fix gateway workers. * Deno fmt. * Be more explicit in `.env.example`. * Add a `watch-bot` task and format. * Deno FMT * Deno FMT (all `template/bigbot` files) Co-authored-by: ITOH <to@itoh.at>
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,4 +5,7 @@ debug.ts
|
||||
|
||||
# npm stuff
|
||||
.npmignore
|
||||
npm/
|
||||
npm/
|
||||
|
||||
# MacOS is weird
|
||||
.DS_Store
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
# Get this from https://discord.com/developers/applications/${applicationId}/bot
|
||||
DISCORD_TOKEN=
|
||||
MAX_SHARDS=0
|
||||
|
||||
# Sharding setup. This is largely dependant on your system specs.
|
||||
# For **development purposes** the defaults are fine.
|
||||
MAX_SHARDS=1
|
||||
FIRST_SHARD_ID=0
|
||||
LAST_SHARD_ID=0
|
||||
SHARDS_PER_CLUSTER=10
|
||||
MAX_CLUSTERS=
|
||||
URL_GATEWAY_PROXY_WILL_FORWARD_TO=
|
||||
GATEWAY_SECRET_KEY=
|
||||
REST_AUTHORIZATION_KEY=
|
||||
REST_PORT=
|
||||
GATEWAY_PORT=
|
||||
EVENT_HANDLER_PORT=
|
||||
EVENT_HANDLER_SECRET_KEY=
|
||||
EVENT_HANDLER_URL=
|
||||
MAX_CLUSTERS=10
|
||||
|
||||
# For the event handler process, change the key!
|
||||
# (url is fine unless hosted on a different machine)
|
||||
EVENT_HANDLER_PORT=1235
|
||||
EVENT_HANDLER_SECRET_KEY=secreteventhandlerkey
|
||||
EVENT_HANDLER_URL=localhost
|
||||
|
||||
# For the gateway process, change the key!
|
||||
REST_PORT=1236
|
||||
REST_AUTHORIZATION_KEY=secretrestkey
|
||||
|
||||
# For the gateway process, change the key!
|
||||
# (url is fine unless hosted on a different machine)
|
||||
GATEWAY_PORT=1237
|
||||
GATEWAY_SECRET_KEY=secretgatewaykey
|
||||
GATEWAY_PROXY_URL=localhost
|
||||
|
||||
# Change to false for production use
|
||||
DEVELOPMENT=true
|
||||
|
||||
# Optional, but very helpful for development.
|
||||
MISSING_TRANSLATION_WEBHOOK=
|
||||
DEV_GUILD_ID=
|
||||
DEV_GUILD_ID=
|
||||
|
||||
@@ -6,8 +6,7 @@ This template is designed for bots that aim or are already in millions of Discor
|
||||
|
||||
## Setup
|
||||
|
||||
- Use the template generator button to make your own copy.
|
||||
- Delete all the template folders except the `bigbot` folder.
|
||||
- Clone this repository can move this directory into your desired project location.
|
||||
- Move all files from the `bigbot` folder to the root of the project.
|
||||
- You may encounter an issue with .vscode but force move the files to the root of the project. We have setup special
|
||||
import maps in this template that should override the general .vscode folder already in the root folder.
|
||||
@@ -17,12 +16,16 @@ This template is designed for bots that aim or are already in millions of Discor
|
||||
|
||||
## Usage
|
||||
|
||||
- Always run the `rest` process first. `deno task rest`
|
||||
- Start the `bot` process next. `deno task bot`
|
||||
- Lastly, start the `gateway` process. `deno task gateway`
|
||||
> Note: Please install at least `deno@^1.22` on your system. (This is due to the requirement of the `Deno` namespace in
|
||||
> workers for the `gateway` process.)
|
||||
|
||||
Note: The `gateway` process and `rest` are designed not to be shut off. So once those are on, the only thing you should
|
||||
be doing is restarting your `bot` process.
|
||||
- Always run the `rest` process first with `deno task rest`.
|
||||
- Start the `bot` process next with `deno task bot`. (If you are developing a bot, use `deno task watch-bot` instead to
|
||||
auto reload any changes. This won't restart any other processes, just your bot.)
|
||||
- Lastly, start the `gateway` process with `deno task gateway`.
|
||||
|
||||
> Important: The `gateway` process and `rest` are designed not to be shut off. So once those are on, the only thing you
|
||||
> should be doing is restarting your `bot` process. This saves API requests
|
||||
|
||||
## Details
|
||||
|
||||
|
||||
@@ -36,15 +36,15 @@ export const SHARDS_PER_CLUSTER = env.SHARDS_PER_CLUSTER ? parseInt(env.SHARDS_P
|
||||
export const MAX_CLUSTERS = parseInt(env.MAX_CLUSTERS!, 10);
|
||||
if (!MAX_CLUSTERS) {
|
||||
throw new Error(
|
||||
"Please for the love of god, tell me how many clusters your machine can handle!",
|
||||
"How many clusters can you run on your machine (MAX_CLUSTERS)? Check your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const URL_GATEWAY_PROXY_WILL_FORWARD_TO = env
|
||||
.URL_GATEWAY_PROXY_WILL_FORWARD_TO!;
|
||||
if (!URL_GATEWAY_PROXY_WILL_FORWARD_TO) {
|
||||
export const GATEWAY_PROXY_URL = env
|
||||
.GATEWAY_PROXY_URL!;
|
||||
if (!GATEWAY_PROXY_URL) {
|
||||
throw new Error(
|
||||
"Don't you think you need to give a URL where you want your gateway proxy to send events to?",
|
||||
"Hmm, it seems like you don't have somewhere to send gateway events to (GATEWAY_PROXY_URL). Please check your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,34 +52,36 @@ export const EVENT_HANDLER_URL = env
|
||||
.EVENT_HANDLER_URL!;
|
||||
if (!EVENT_HANDLER_URL) {
|
||||
throw new Error(
|
||||
"Don't you think you need to give a URL where you want your events sent to?",
|
||||
"Hmm, it seems like you don't have somewhere to send events to (EVENT_HANDLER_URL). Please check your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const GATEWAY_SECRET_KEY = env.GATEWAY_SECRET_KEY!;
|
||||
if (!GATEWAY_SECRET_KEY) {
|
||||
throw new Error(
|
||||
"Do you want to be hacked? Add a secret authorization key that can be used to identify requests are from you.",
|
||||
"You need to add a GATEWAY_SECRET_KEY to your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const REST_AUTHORIZATION_KEY = env.REST_AUTHORIZATION_KEY!;
|
||||
if (!REST_AUTHORIZATION_KEY) {
|
||||
throw new Error(
|
||||
"Do you want to be hacked? Add a secret authorization key to make sure requests are only made by you.",
|
||||
"You need to add a REST_AUTHORIZATION_KEY to your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const EVENT_HANDLER_SECRET_KEY = env.EVENT_HANDLER_SECRET_KEY!;
|
||||
if (!EVENT_HANDLER_SECRET_KEY) {
|
||||
throw new Error(
|
||||
"Do you want to be hacked? Add a secret authorization key to make sure requests are only made by you.",
|
||||
"You need to add an EVENT_HANDLER_SECRET_KEY to your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const BOT_ID = BigInt(atob(env.DISCORD_TOKEN.split(".")[0]));
|
||||
if (!BOT_ID) {
|
||||
throw new Error("Please enter the BOT ID you want to run this with.");
|
||||
throw new Error(
|
||||
"Hmm, it seems like you didn't put in a valid DISCORD_TOKEN. Check your .env file!",
|
||||
);
|
||||
}
|
||||
|
||||
export const REST_PORT = env.REST_PORT ? parseInt(env.REST_PORT, 10) : 5000;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"tasks": {
|
||||
"rest": "deno run -A --unstable --import-map ./importMap.json ./src/rest/mod.ts",
|
||||
"bot": "deno run -A --unstable --import-map ./importMap.json ./src/bot/mod.ts",
|
||||
"watch-bot": "deno run --watch -A --unstable --import-map ./importMap.json ./src/bot/mod.ts",
|
||||
"gateway": "deno run -A --unstable --import-map ./importMap.json ./src/gateway/mod.ts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import log from "../../utils/logger.ts";
|
||||
import { logger } from "../../utils/logger.ts";
|
||||
import { decode, encode, Kwik, KwikTable } from "../../../deps.ts";
|
||||
|
||||
const log = logger({ name: "DB" });
|
||||
|
||||
log.info("Initializing KwikDB Database.");
|
||||
|
||||
interface CommandVersionsSchema {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { InteractionTypes, MessageComponentTypes } from "../../../../deps.ts";
|
||||
import { bot } from "../../mod.ts";
|
||||
import { executeSlashCommand } from "../interactions/executeSlashCommand.ts";
|
||||
import { logger, LogLevels } from "../../../utils/logger.ts";
|
||||
|
||||
const log = logger({ name: "InteractionHandler" });
|
||||
|
||||
export function setInteractionCreateEvent() {
|
||||
bot.events.interactionCreate = async function (_, interaction) {
|
||||
log.info("Adding `bot.events.interactionCreate` handler.");
|
||||
bot.events.interactionCreate = async (_, interaction) => {
|
||||
log.debug("New event fired:\n", interaction);
|
||||
// SLASH COMMAND
|
||||
if (interaction.type === InteractionTypes.ApplicationCommand) {
|
||||
log.debug("Slash Command Fired!");
|
||||
return await executeSlashCommand(bot, interaction);
|
||||
}
|
||||
|
||||
@@ -17,8 +23,10 @@ export function setInteractionCreateEvent() {
|
||||
interaction.data.componentType ===
|
||||
MessageComponentTypes.Button
|
||||
) {
|
||||
log.debug("Button Event!");
|
||||
// processButtonCollectors(bot, interaction)
|
||||
}
|
||||
}
|
||||
};
|
||||
log.debug("All handlers:\n", bot.events);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
sendPrivateInteractionResponse,
|
||||
white,
|
||||
} from "../../../../deps.ts";
|
||||
import logger from "../../../../src/utils/logger.ts";
|
||||
import { optionParser, translateOptionNames } from "../../../utils/options.ts";
|
||||
import { privateReplyToInteraction, replyToInteraction } from "../../../utils/replies.ts";
|
||||
import slashLogWebhook from "../../../utils/slashWebhook.ts";
|
||||
@@ -19,6 +18,9 @@ import { BotClient } from "../../botClient.ts";
|
||||
import { loadLanguage, serverLanguages, translate } from "../../languages/translate.ts";
|
||||
import { Command, ConvertArgumentDefinitionsToArgs } from "../../types/command.ts";
|
||||
import commands from "./mod.ts";
|
||||
import { logger, LogLevels } from "../../../utils/logger.ts";
|
||||
|
||||
const log = logger({ name: "CommandHandler" });
|
||||
|
||||
function logCommand(
|
||||
info: Interaction,
|
||||
@@ -40,13 +42,15 @@ function logCommand(
|
||||
black(`${info.guildId ? `Guild ID: (${info.guildId})` : "DM"}`),
|
||||
);
|
||||
|
||||
logger.info(`${command} by ${user} in ${guild} with MessageID: ${info.id}`);
|
||||
log.info(`${command} by ${user} in ${guild} with MessageID: ${info.id}`);
|
||||
}
|
||||
|
||||
export async function executeSlashCommand(
|
||||
bot: BotClient,
|
||||
interaction: Interaction,
|
||||
) {
|
||||
log.debug(`New interaction:\n`, interaction);
|
||||
|
||||
const data = interaction.data;
|
||||
const name = data?.name as keyof typeof commands;
|
||||
|
||||
@@ -55,17 +59,22 @@ export async function executeSlashCommand(
|
||||
|
||||
// Command could not be found
|
||||
if (!command?.execute) {
|
||||
return await sendPrivateInteractionResponse(bot, interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
content: translate(
|
||||
bot,
|
||||
interaction.guildId!,
|
||||
"EXECUTE_COMMAND_NOT_FOUND",
|
||||
),
|
||||
return await sendPrivateInteractionResponse(
|
||||
bot,
|
||||
interaction.id,
|
||||
interaction.token,
|
||||
{
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
content: translate(
|
||||
bot,
|
||||
interaction.guildId!,
|
||||
"EXECUTE_COMMAND_NOT_FOUND",
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch(logger.error);
|
||||
)
|
||||
.catch(log.error);
|
||||
}
|
||||
|
||||
// HAVE TO CONVERT OUTSIDE OF TRY SO IT CAN BE USED IN CATCH TOO
|
||||
@@ -107,11 +116,11 @@ export async function executeSlashCommand(
|
||||
);
|
||||
logCommand(interaction, "Success", name);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
log.error(error);
|
||||
logCommand(interaction, "Failure", name);
|
||||
await slashLogWebhook(bot, interaction, name).catch(logger.error);
|
||||
await slashLogWebhook(bot, interaction, name).catch(log.error);
|
||||
return await privateReplyToInteraction(bot, interaction, {
|
||||
content: translate(bot, interaction.id, "EXECUTE_COMMAND_ERROR"),
|
||||
}).catch(logger.error);
|
||||
}).catch(log.error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import { BotClient } from "../../../botClient.ts";
|
||||
import { usesLatestCommandVersion } from "../../../database/commandVersion.ts";
|
||||
import { commandVersions } from "../../../database/kwik.ts";
|
||||
|
||||
export async function setGuildCommands(bot: BotClient, data: DiscordGatewayPayload) {
|
||||
export async function setGuildCommands(
|
||||
bot: BotClient,
|
||||
data: DiscordGatewayPayload,
|
||||
) {
|
||||
if (!data.t) return;
|
||||
|
||||
if (data.t === "GUILD_DELETE") {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { setInteractionCreateEvent } from "./handlers/interactionCreate.ts";
|
||||
import { logger } from "../../utils/logger.ts";
|
||||
|
||||
const log = logger({ name: "EventHandlers" });
|
||||
|
||||
export function setupEventHandlers() {
|
||||
log.debug("Adding Event Handlers!");
|
||||
setInteractionCreateEvent();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ if (DEVELOPMENT) {
|
||||
// Start listening on localhost.
|
||||
const server = Deno.listen({ port: EVENT_HANDLER_PORT });
|
||||
logger.info(
|
||||
`HTTP webserver running. Access it at: http://localhost:${EVENT_HANDLER_PORT}/`,
|
||||
`HTTP webserver running. Access it at: http://localhost:${EVENT_HANDLER_PORT}/`,
|
||||
);
|
||||
|
||||
// Connections to the server will be yielded up as an async iterable.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Collection, createGatewayManager, createRestManager, endpoints } from "../../deps.ts";
|
||||
import { DISCORD_TOKEN, EVENT_HANDLER_SECRET_KEY, REST_AUTHORIZATION_KEY, REST_PORT } from "../../configs.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
|
||||
const log = logger({ name: "Gateway" });
|
||||
|
||||
// CREATE A SIMPLE MANAGER FOR REST
|
||||
const rest = createRestManager({
|
||||
@@ -14,23 +17,24 @@ const gateway = createGatewayManager({
|
||||
token: DISCORD_TOKEN,
|
||||
intents: ["GuildMessages", "Guilds"],
|
||||
// THIS WILL BASICALLY BE YOUR HANDLER FOR YOUR EVENTS.
|
||||
handleDiscordPayload: async function (_, data, shardId) {},
|
||||
handleDiscordPayload: async (_, data, shardId) => {},
|
||||
});
|
||||
|
||||
const workers = new Collection<number, Worker>();
|
||||
|
||||
async function startGateway() {
|
||||
// CALL THE REST PROCESS TO GET GATEWAY DATA
|
||||
const result = await rest.runMethod(rest, "get", endpoints.GATEWAY_BOT()).then((res) => ({
|
||||
url: res.url,
|
||||
shards: res.shards,
|
||||
sessionStartLimit: {
|
||||
total: res.session_start_limit.total,
|
||||
remaining: res.session_start_limit.remaining,
|
||||
resetAfter: res.session_start_limit.reset_after,
|
||||
maxConcurrency: res.session_start_limit.max_concurrency,
|
||||
},
|
||||
}));
|
||||
const result = await rest.runMethod(rest, "get", endpoints.GATEWAY_BOT())
|
||||
.then((res) => ({
|
||||
url: res.url,
|
||||
shards: res.shards,
|
||||
sessionStartLimit: {
|
||||
total: res.session_start_limit.total,
|
||||
remaining: res.session_start_limit.remaining,
|
||||
resetAfter: res.session_start_limit.reset_after,
|
||||
maxConcurrency: res.session_start_limit.max_concurrency,
|
||||
},
|
||||
}));
|
||||
|
||||
// LOAD DATA FROM DISCORDS RECOMMENDATIONS OR YOUR OWN CUSTOM ONES HERE
|
||||
gateway.shardsRecommended = result.shards;
|
||||
@@ -44,7 +48,12 @@ async function startGateway() {
|
||||
// PREPARE BUCKETS FOR IDENTIFYING
|
||||
gateway.prepareBuckets(gateway, 0, result.shards);
|
||||
|
||||
function startWorker(workerId: number, bucketId: number, firstShardId: number, lastShardId: number) {
|
||||
function startWorker(
|
||||
workerId: number,
|
||||
bucketId: number,
|
||||
firstShardId: number,
|
||||
lastShardId: number,
|
||||
) {
|
||||
const worker = workers.get(workerId);
|
||||
if (!worker) return;
|
||||
|
||||
@@ -82,7 +91,14 @@ async function startGateway() {
|
||||
const data = JSON.parse(message.data);
|
||||
if (data.type === "ALL_SHARDS_READY") {
|
||||
const queue = bucket.workers[i + 1];
|
||||
if (queue) startWorker(queue[0], bucketId, queue[1], queue[queue.length - 1]);
|
||||
if (queue) {
|
||||
startWorker(
|
||||
queue[0],
|
||||
bucketId,
|
||||
queue[1],
|
||||
queue[queue.length - 1],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.type === "RESHARDED") {
|
||||
@@ -125,16 +141,17 @@ startGateway();
|
||||
setInterval(async () => {
|
||||
console.log("GW DEBUG", "[Resharding] Checking if resharding is needed.");
|
||||
|
||||
const results = await rest.runMethod(rest, "get", endpoints.GATEWAY_BOT()).then((res) => ({
|
||||
url: res.url,
|
||||
shards: res.shards,
|
||||
sessionStartLimit: {
|
||||
total: res.session_start_limit.total,
|
||||
remaining: res.session_start_limit.remaining,
|
||||
resetAfter: res.session_start_limit.reset_after,
|
||||
maxConcurrency: res.session_start_limit.max_concurrency,
|
||||
},
|
||||
}));
|
||||
const results = await rest.runMethod(rest, "get", endpoints.GATEWAY_BOT())
|
||||
.then((res) => ({
|
||||
url: res.url,
|
||||
shards: res.shards,
|
||||
sessionStartLimit: {
|
||||
total: res.session_start_limit.total,
|
||||
remaining: res.session_start_limit.remaining,
|
||||
resetAfter: res.session_start_limit.reset_after,
|
||||
maxConcurrency: res.session_start_limit.max_concurrency,
|
||||
},
|
||||
}));
|
||||
const percentage = ((results.shards - gateway.maxShards) / gateway.maxShards) * 100;
|
||||
// Less than necessary% being used so do nothing
|
||||
if (percentage < gateway.reshardPercentage) return;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { DISCORD_TOKEN, EVENT_HANDLER_PORT, EVENT_HANDLER_SECRET_KEY, EVENT_HANDLER_URL } from "../../configs.ts";
|
||||
import {
|
||||
DEVELOPMENT,
|
||||
DISCORD_TOKEN,
|
||||
EVENT_HANDLER_PORT,
|
||||
EVENT_HANDLER_SECRET_KEY,
|
||||
EVENT_HANDLER_URL,
|
||||
} from "../../configs.ts";
|
||||
import { Collection, createGatewayManager, DiscordReady, GatewayManager, GetGatewayBot } from "../../deps.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
|
||||
let gateway: GatewayManager;
|
||||
// FOR RESHARDED
|
||||
@@ -7,7 +14,14 @@ let gatewayPendingClosing: GatewayManager;
|
||||
let workerId: number;
|
||||
|
||||
function spawnGateway(shardId: number, options: Partial<GatewayManager>) {
|
||||
console.log(`[Worker #${workerId}]`, "[Worker] Spawning the worker gateway.", shardId, options);
|
||||
const log = logger({
|
||||
name: `GatewayWorker: ${workerId}`,
|
||||
});
|
||||
|
||||
log.info(
|
||||
`Spawning the worker gateway for shard #${shardId}\n`,
|
||||
options,
|
||||
);
|
||||
gateway = createGatewayManager({
|
||||
// LOAD DATA FROM DISCORDS RECOMMENDATIONS OR YOUR OWN CUSTOM ONES HERE
|
||||
shardsRecommended: options.shardsRecommended,
|
||||
@@ -28,13 +42,16 @@ function spawnGateway(shardId: number, options: Partial<GatewayManager>) {
|
||||
// TRIGGER RAW EVENT
|
||||
if (!data.t) return;
|
||||
|
||||
const id = (data.t && ["GUILD_CREATE", "GUILD_DELETE", "GUILD_UPDATE"].includes(data.t)
|
||||
const id = (data.t &&
|
||||
["GUILD_CREATE", "GUILD_DELETE", "GUILD_UPDATE"].includes(data.t)
|
||||
? (data.d as any)?.id
|
||||
: (data.d as any)?.guild_id) ?? "000000000000000000";
|
||||
|
||||
// IF FINAL SHARD BECAME READY TRIGGER NEXT WORKER
|
||||
if (data.t === "READY") {
|
||||
console.log(`[Worker #${workerId}]`, `[Worker] Shard #${shardId} online`);
|
||||
log.info(
|
||||
`Shard online`,
|
||||
);
|
||||
|
||||
if (shardId === gateway.lastShardId) {
|
||||
// @ts-ignore
|
||||
@@ -47,11 +64,12 @@ function spawnGateway(shardId: number, options: Partial<GatewayManager>) {
|
||||
}
|
||||
|
||||
// DONT SEND THESE EVENTS USELESS TO BOT
|
||||
if (["GUILD_LOADED_DD"].includes(data.t)) {
|
||||
return;
|
||||
}
|
||||
if (["GUILD_LOADED_DD"].includes(data.t)) return;
|
||||
|
||||
await fetch(`${EVENT_HANDLER_URL}:${EVENT_HANDLER_PORT}`, {
|
||||
// Debug mode only
|
||||
log.debug(`New Event:\n`, data);
|
||||
|
||||
await fetch(`http://${EVENT_HANDLER_URL}:${EVENT_HANDLER_PORT}`, {
|
||||
headers: {
|
||||
Authorization: gateway.secretKey,
|
||||
"Content-Type": "application/json",
|
||||
@@ -62,11 +80,11 @@ function spawnGateway(shardId: number, options: Partial<GatewayManager>) {
|
||||
data,
|
||||
}),
|
||||
})
|
||||
// BELOW IS FOR DENO MEMORY LEAK
|
||||
.then((res) =>
|
||||
res.text()
|
||||
)
|
||||
.catch(() => null);
|
||||
.then((res) => {
|
||||
// BELOW IS FOR DENO MEMORY LEAK
|
||||
return res.text();
|
||||
})
|
||||
.catch((err) => log.error("Error Sending Event:\n", err));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -107,7 +125,16 @@ interface FullyReshardedPayload {
|
||||
|
||||
// @ts-ignore this should not be erroring
|
||||
self.onmessage = async function (message: MessageEvent<string>) {
|
||||
const data = JSON.parse(message.data) as IdentifyPayload | ReshardPayload | FullyReshardedPayload;
|
||||
const log = logger({
|
||||
name: `GatewayWorker${JSON.parse(message.data).workerId ? `: ${JSON.parse(message.data).workerId}` : undefined}`,
|
||||
});
|
||||
|
||||
log.debug(`New Message:\n`, message.data);
|
||||
|
||||
const data = JSON.parse(message.data) as
|
||||
| IdentifyPayload
|
||||
| ReshardPayload
|
||||
| FullyReshardedPayload;
|
||||
|
||||
if (data.type === "IDENTIFY") {
|
||||
workerId = data.workerId;
|
||||
@@ -125,12 +152,12 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
}
|
||||
|
||||
if (data.type === "RESHARDED-CLOSEOLD") {
|
||||
console.log(`[Worker #${workerId}]`, "[Resharding] Closing old gateways.");
|
||||
log.info("[Resharding] Closing old gateways.");
|
||||
await gateway.resharding.closeOldShards(gatewayPendingClosing);
|
||||
}
|
||||
|
||||
if (data.type === "RESHARD") {
|
||||
console.log(`[Worker #${workerId}]`, "[Worker] Resharding the worker.");
|
||||
log.info("[Worker] Resharding the worker.");
|
||||
gateway.resharding.isPending = async function (gateway: GatewayManager) {
|
||||
for (let i = gateway.firstShardId; i < gateway.lastShardId; i++) {
|
||||
const shard = gateway.shards.get(i);
|
||||
@@ -142,8 +169,14 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
return false;
|
||||
};
|
||||
|
||||
async function processResharding(oldGateway: GatewayManager, results: GetGatewayBot) {
|
||||
oldGateway.debug("GW DEBUG", "[Resharding] Starting the reshard process.");
|
||||
async function processResharding(
|
||||
oldGateway: GatewayManager,
|
||||
results: GetGatewayBot,
|
||||
) {
|
||||
oldGateway.debug(
|
||||
"GW DEBUG",
|
||||
"[Resharding] Starting the reshard process.",
|
||||
);
|
||||
|
||||
const gateway = createGatewayManager({
|
||||
...oldGateway,
|
||||
@@ -164,7 +197,9 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
gateway.handleDiscordPayload = async function (_, data, shardId) {
|
||||
if (data.t === "READY") {
|
||||
const payload = data.d as DiscordReady;
|
||||
console.log(`[Worker - ${workerId}] Shard #${payload.shard?.[0]} online`);
|
||||
log.info(
|
||||
`Shard #${payload.shard?.[0]} online`,
|
||||
);
|
||||
if (shardId === gateway.lastShardId) {
|
||||
// @ts-ignore
|
||||
postMessage(
|
||||
@@ -185,7 +220,12 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
}
|
||||
|
||||
// DON"T OVERRIDE THESE
|
||||
if (["cache", "shards", "loadingShards", "buckets", "utf8decoder"].includes(key)) continue;
|
||||
if (
|
||||
["cache", "shards", "loadingShards", "buckets", "utf8decoder"]
|
||||
.includes(key)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// USE ANY CUSTOMIZED OPTIONS FROM OLD GATEWAY
|
||||
// @ts-ignore silly ts error
|
||||
@@ -195,8 +235,13 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
// Begin resharding
|
||||
// If more than 100K servers, begin switching to 16x sharding
|
||||
if (gateway.useOptimalLargeBotSharding) {
|
||||
console.log(`[Worker - ${workerId}]`, "[Resharding] Using optimal large bot sharding solution.");
|
||||
gateway.maxShards = gateway.calculateMaxShards(results.shards, results.sessionStartLimit.maxConcurrency);
|
||||
log.info(
|
||||
"[Resharding] Using optimal large bot sharding solution.",
|
||||
);
|
||||
gateway.maxShards = gateway.calculateMaxShards(
|
||||
results.shards,
|
||||
results.sessionStartLimit.maxConcurrency,
|
||||
);
|
||||
} else {
|
||||
gateway.maxShards = results.shards;
|
||||
}
|
||||
@@ -216,7 +261,10 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
return new Promise((resolve) => {
|
||||
// TIMER TO KEEP CHECKING WHEN ALL SHARDS HAVE RESHARDED
|
||||
const timer = setInterval(async () => {
|
||||
const pending = await gateway.resharding.isPending(gateway, oldGateway);
|
||||
const pending = await gateway.resharding.isPending(
|
||||
gateway,
|
||||
oldGateway,
|
||||
);
|
||||
// STILL PENDING ON SOME SHARDS TO BE CREATED
|
||||
if (pending) return;
|
||||
|
||||
@@ -240,7 +288,7 @@ self.onmessage = async function (message: MessageEvent<string>) {
|
||||
}
|
||||
|
||||
gateway = await processResharding(gateway, data.results);
|
||||
console.log(`[Worker - ${workerId}] Resharded the worker.`);
|
||||
log.info(`Resharded the worker.`);
|
||||
// @ts-ignore this should not be erroring
|
||||
postMessage(
|
||||
JSON.stringify({
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// START FILE FOR REST PROCESS
|
||||
import { DISCORD_TOKEN, REST_AUTHORIZATION_KEY, REST_PORT } from "../../configs.ts";
|
||||
import { BASE_URL, createRestManager } from "../../deps.ts";
|
||||
import { log } from "../utils/logger.ts";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
|
||||
const log = logger({ name: "REST" });
|
||||
|
||||
// CREATES THE FUNCTIONALITY FOR MANAGING THE REST REQUESTS
|
||||
const rest = createRestManager({
|
||||
|
||||
@@ -98,5 +98,4 @@ export function logger({
|
||||
};
|
||||
}
|
||||
|
||||
export const log = logger();
|
||||
export default log;
|
||||
export default logger();
|
||||
|
||||
@@ -119,7 +119,11 @@ export async function updateGuildCommands(bot: BotClient, guildId: bigint) {
|
||||
|
||||
// ADVANCED VERSION WILL ALLOW TRANSLATION
|
||||
const translatedName = translate(bot, guildId, command.name);
|
||||
const translatedDescription = translate(bot, guildId, command.description);
|
||||
const translatedDescription = translate(
|
||||
bot,
|
||||
guildId,
|
||||
command.description,
|
||||
);
|
||||
|
||||
return {
|
||||
name: translatedName.toLowerCase(),
|
||||
@@ -144,7 +148,11 @@ export async function updateGuildCommands(bot: BotClient, guildId: bigint) {
|
||||
|
||||
// ADVANCED VERSION WILL ALLOW TRANSLATION
|
||||
const translatedName = translate(bot, guildId, command.name);
|
||||
const translatedDescription = translate(bot, guildId, command.description);
|
||||
const translatedDescription = translate(
|
||||
bot,
|
||||
guildId,
|
||||
command.description,
|
||||
);
|
||||
|
||||
return {
|
||||
name: (translatedName || name).toLowerCase(),
|
||||
|
||||
Reference in New Issue
Block a user