Fix BigBot Template (#2498)

* fix: bigbot template

* Apply suggestions from code review

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>
This commit is contained in:
Awesome Stickz
2022-10-03 15:27:22 -05:00
committed by GitHub
co-authored by Skillz4Killz
parent 5cb8388f91
commit 8be759f30e
10 changed files with 91 additions and 55 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import { InfluxDB } from "@influxdata/influxdb-client";
import { INFLUX_BUCKET, INFLUX_ORG, INFLUX_TOKEN, INFLUX_URL } from "./configs.js";
export const influxDB = new InfluxDB({ url: INFLUX_URL, token: INFLUX_TOKEN });
export const Influx = influxDB.getWriteApi(INFLUX_ORG, INFLUX_BUCKET);
export const influxDB = INFLUX_URL && INFLUX_TOKEN ? new InfluxDB({ url: INFLUX_URL, token: INFLUX_TOKEN }) : undefined;
export const Influx = influxDB?.getWriteApi(INFLUX_ORG, INFLUX_BUCKET);
+10 -4
View File
@@ -2,14 +2,17 @@ import { Bot, Collection, createBot, createRestManager } from "discordeno";
import enableHelpersPlugin from "discordeno/helpers-plugin";
import { createLogger } from "discordeno/logger";
import { DISCORD_TOKEN, INTENTS, REST_AUTHORIZATION, REST_URL } from "../configs.js";
import { setupEventHandlers } from "./events/mod.js";
import { MessageCollector } from "./utils/collectors.js";
import { customizeInternals } from "./utils/internals/mod.js";
export const bot = enableHelpersPlugin(
customizeBot(createBot({
token: DISCORD_TOKEN,
intents: INTENTS,
})),
customizeBot(
createBot({
token: DISCORD_TOKEN,
intents: INTENTS,
}),
),
);
/** Add custom props to your `bot` here */
@@ -42,6 +45,9 @@ export type BotWithCustomProps<B extends Bot = Bot> = B & {
// Example of how to customize internal discordeno stuff easily.
customizeInternals(bot);
// Setup event handlers.
setupEventHandlers();
bot.rest = createRestManager({
token: DISCORD_TOKEN,
secretKey: REST_AUTHORIZATION,
+2
View File
@@ -1,6 +1,8 @@
import language from "./language.js";
import ping from "./ping.js";
export const COMMANDS = {
language,
ping,
};
+3 -5
View File
@@ -5,11 +5,9 @@ export default createCommand({
name: "PING_NAME",
description: "PING_DESCRIPTION",
execute: async function (_, interaction) {
return await interaction.reply(translate(
interaction.guildId!,
"PING_RESPONSE_WITH_TIME",
Date.now() - snowflakeToTimestamp(interaction.id),
));
return await interaction.reply(
translate(interaction.guildId!, "PING_RESPONSE_WITH_TIME", Date.now() - snowflakeToTimestamp(interaction.id)),
);
},
});
@@ -14,7 +14,7 @@ import {
} from "discordeno";
import { bot, BotWithCustomProps } from "../../bot.js";
import COMMANDS from "../../commands/mod.js";
import { getLanguage, loadLanguage, serverLanguages, translate } from "../../languages/translate.js";
import { getLanguage, loadLanguage, serverLanguages, translate, translationKeys } from "../../languages/translate.js";
import { Command, ConvertArgumentDefinitionsToArgs } from "../../utils/slash/createCommand.js";
function logCommand(
@@ -44,9 +44,9 @@ export async function executeSlashCommand(bot: BotWithCustomProps, interaction:
// Command could not be found
if (!command?.execute) {
return await interaction.reply(translate(interaction.guildId!, "EXECUTE_COMMAND_NOT_FOUND")).catch(
bot.logger.error,
);
return await interaction
.reply(translate(interaction.guildId!, "EXECUTE_COMMAND_NOT_FOUND"))
.catch(bot.logger.error);
}
// HAVE TO CONVERT OUTSIDE OF TRY SO IT CAN BE USED IN CATCH TOO
@@ -124,13 +124,9 @@ export function translateOptionNames(
// TRANSLATE ALL OPTIONS
let translated: Record<string, string> = {};
for (const option of options) {
// TODO: fix this ignore
// @ts-ignore
translated[translate(bot, guildId, option.name).toLowerCase()] = translate(
bot,
translated[translate(guildId, option.name as translationKeys).toLowerCase()] = translate(
"english",
// @ts-ignore
option.name,
option.name as translationKeys,
);
if (option.options) {
translated = {
+12 -15
View File
@@ -33,10 +33,8 @@ process
.setTimestamp()
.setFooter("Unhandled Rejection Error Occurred");
// SEND ERROR TO THE LOG CHANNEL ON THE GAMER DEV SERVER
return bot.helpers
.sendWebhookMessage(bot.transformers.snowflake(id), token, { embeds })
.catch(console.error);
// SEND ERROR TO THE LOG CHANNEL ON THE DEV SERVER
return bot.helpers.sendWebhookMessage(bot.transformers.snowflake(id), token, { embeds }).catch(console.error);
})
.on("uncaughtException", async (error) => {
const { id, token } = webhookURLToIDAndToken(BUGS_ERRORS_REPORT_WEBHOOK);
@@ -57,10 +55,8 @@ process
.setTimestamp()
.setFooter("Unhandled Exception Error Occurred");
// SEND ERROR TO THE LOG CHANNEL ON THE GAMER DEV SERVER
await bot.helpers
.sendWebhookMessage(bot.transformers.snowflake(id), token, { embeds })
.catch(console.error);
// SEND ERROR TO THE LOG CHANNEL ON THE DEV SERVER
await bot.helpers.sendWebhookMessage(bot.transformers.snowflake(id), token, { embeds }).catch(console.error);
process.exit(1);
});
@@ -107,19 +103,20 @@ async function handleRequest(req: express.Request, res: express.Response) {
}
const json = req.body as {
data: DiscordGatewayPayload;
message: DiscordGatewayPayload;
shardId: number;
};
// EMITS RAW EVENT
bot.events.raw(bot, json.data, json.shardId);
if (json.data.t && json.data.t !== "RESUMED") {
// EMITS RAW EVENT
bot.events.raw(bot, json.message, json.shardId);
if (json.message.t && json.message.t !== "RESUMED") {
// When a guild or something isnt in cache this will fetch it before doing anything else
if (json.data.t !== "READY") {
await bot.events.dispatchRequirements(bot, json.data, json.shardId);
if (!["READY", "GUILD_LOADED_DD"].includes(json.message.t)) {
await bot.events.dispatchRequirements(bot, json.message, json.shardId);
}
bot.handlers[json.data.t]?.(bot, json.data, json.shardId);
bot.handlers[json.message.t]?.(bot, json.message, json.shardId);
}
res.status(200).json({ success: true });
+3 -3
View File
@@ -27,7 +27,7 @@ export const EVENT_HANDLER_PORT = 8081;
/** The url where the bot code(event handler) will run. This is where the gateway will send its messages to. */
// SETUP-DD-TEMP: Set the bot's url here.
export const EVENT_HANDLER_URL = "http://localhost:8080";
export const EVENT_HANDLER_URL = `http://localhost:${EVENT_HANDLER_PORT}`;
/** The full webhook url where the bot can send errors to alert you that the bot is missing translations. */
// SETUP-DD-TEMP: Set a full discord webhook url here.
@@ -86,9 +86,9 @@ export const TOTAL_WORKERS: number = 4;
// SETUP-DD-TEMP: Add a secret passcode here.
export const GATEWAY_AUTHORIZATION = "";
/** The url where the gateway will run. */
/** The host where the gateway will run. Must follow https://nodejs.org/api/net.html#serverlistenoptions-callback. */
// SETUP-DD-TEMP: Set the gateways's host here.
export const GATEWAY_HOST = "http://localhost";
export const GATEWAY_HOST = "localhost";
/** The port where the gateway will run. This is where the bot will send its messages to the gateway. */
// SETUP-DD-TEMP: Set the gateways's port here.
+2 -2
View File
@@ -76,12 +76,12 @@ async function main() {
token: DISCORD_TOKEN,
handlerUrls: [EVENT_HANDLER_URL],
handlerAuthorization: EVENT_HANDLER_AUTHORIZATION,
path: `${__dirname}/worker.ts`,
path: "./worker.ts",
totalShards: gateway.manager.totalShards,
workerId,
};
const worker = new Worker(`${__dirname}/worker.js`, {
const worker = new Worker("./worker.js", {
workerData,
});
+45 -3
View File
@@ -1,4 +1,13 @@
import { createShardManager, DiscordUnavailableGuild, Shard, ShardSocketRequest, ShardState } from "discordeno";
import {
createShardManager,
DiscordGuild,
DiscordReady,
DiscordUnavailableGuild,
GatewayEventNames,
Shard,
ShardSocketRequest,
ShardState,
} from "discordeno";
import { createLogger } from "discordeno/logger";
import { parentPort, workerData } from "worker_threads";
import { ManagerMessage } from "./index.js";
@@ -13,6 +22,10 @@ const log = createLogger({ name: `[WORKER #${script.workerId}]` });
const identifyPromises = new Map<number, () => void>();
// Store guild ids, loading guild ids to change GUILD_CREATE event to GUILD_LOADED_DD if needed.
const guildIds: Set<bigint> = new Set();
const loadingGuildIds: Set<bigint> = new Set();
const manager = createShardManager({
gatewayConfig: {
intents: script.intents,
@@ -24,14 +37,43 @@ const manager = createShardManager({
const url = script.handlerUrls[shard.id % script.handlerUrls.length];
if (!url) return console.log("ERROR: NO URL FOUND TO SEND MESSAGE");
// MUST HANDLE GUILD_DELETE EVENTS FOR UNAVAILABLE
if (message.t === "GUILD_DELETE" && (message.d as DiscordUnavailableGuild).unavailable) return;
if (message.t === "READY") {
// Marks which guilds the bot in when initial loading in cache.
(message.d as DiscordReady).guilds.forEach((g) => loadingGuildIds.add(BigInt(g.id)));
}
// If GUILD_CREATE event came from a shard loaded event, change event to GUILD_LOADED_DD.
if (message.t === "GUILD_CREATE") {
const guild = message.d as DiscordGuild;
const id = BigInt(guild.id);
const existing = guildIds.has(id);
if (existing) return;
if (loadingGuildIds.has(id)) {
(message.t as GatewayEventNames | "GUILD_LOADED_DD") = "GUILD_LOADED_DD";
loadingGuildIds.delete(id);
}
guildIds.add(id);
}
// Delete guild id from cache so GUILD_CREATE from the same guild later works properly.
if (message.t === "GUILD_DELETE") {
const guild = message.d as DiscordUnavailableGuild;
if (guild.unavailable) return;
guildIds.delete(BigInt(guild.id));
}
await fetch(url, {
method: "POST",
body: JSON.stringify({ message, shardId: shard.id }),
headers: { "Content-Type": "application/json", Authorization: script.handlerAuthorization },
}).catch((error) => log.error(error));
log.debug({ shardId: shard.id, message });
},
requestIdentify: async function (shardId: number): Promise<void> {
+6 -11
View File
@@ -3,7 +3,7 @@ import { BASE_URL, createRestManager } from "discordeno";
import express, { Request, Response } from "express";
import { Influx } from "../analytics.js";
import { DISCORD_TOKEN, INFLUX_TOKEN, REST_AUTHORIZATION, REST_PORT, REST_URL } from "../configs.js";
import { DISCORD_TOKEN, REST_AUTHORIZATION, REST_PORT, REST_URL } from "../configs.js";
const rest = createRestManager({
token: DISCORD_TOKEN,
@@ -13,9 +13,9 @@ const rest = createRestManager({
});
// If influxdb data is provided, enable analytics in this proxy.
if (INFLUX_TOKEN) {
if (Influx) {
rest.fetching = function (options) {
Influx.writePoint(
Influx?.writePoint(
new Point("restEvents")
// MARK THE TIME WHEN EVENT ARRIVED
.timestamp(new Date())
@@ -28,7 +28,7 @@ if (INFLUX_TOKEN) {
};
rest.fetched = function (options, response) {
Influx.writePoint(
Influx?.writePoint(
new Point("restEvents")
// MARK THE TIME WHEN EVENT ARRIVED
.timestamp(new Date())
@@ -44,7 +44,7 @@ if (INFLUX_TOKEN) {
setInterval(() => {
console.log(`[Influx - REST] Saving events...`);
Influx.flush()
Influx?.flush()
.then(() => {
console.log(`[Influx - REST] Saved events!`);
})
@@ -96,12 +96,7 @@ async function handleRequest(req: Request, res: Response) {
}
try {
const result = await rest.runMethod(
rest,
req.method as any,
`${BASE_URL}${req.url}`,
req.body,
);
const result = await rest.runMethod(rest, req.method as any, `${BASE_URL}${req.url}`, req.body);
if (result) {
res.status(200).json(result);