mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
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:
co-authored by
Skillz4Killz
parent
5cb8388f91
commit
8be759f30e
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import language from "./language.js";
|
||||
import ping from "./ping.js";
|
||||
|
||||
export const COMMANDS = {
|
||||
language,
|
||||
ping,
|
||||
};
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user