From 464f367c8026c2fcf9d66944c72f2fb46fa58b37 Mon Sep 17 00:00:00 2001 From: Pihkaal Date: Thu, 4 Dec 2025 18:43:53 +0100 Subject: [PATCH] refactor(discord-bot): move differents modes in separate files --- apps/discord-bot/src/index.ts | 112 +++++------------------------ apps/discord-bot/src/modes/bot.ts | 61 ++++++++++++++++ apps/discord-bot/src/modes/user.ts | 34 +++++++++ apps/discord-bot/src/utils/cli.ts | 32 +++++++++ 4 files changed, 145 insertions(+), 94 deletions(-) create mode 100644 apps/discord-bot/src/modes/bot.ts create mode 100644 apps/discord-bot/src/modes/user.ts create mode 100644 apps/discord-bot/src/utils/cli.ts diff --git a/apps/discord-bot/src/index.ts b/apps/discord-bot/src/index.ts index c489b80..7cb1555 100644 --- a/apps/discord-bot/src/index.ts +++ b/apps/discord-bot/src/index.ts @@ -1,29 +1,12 @@ import { env } from "~/env"; -import { listTrackedPlayers, trackWovPlayer } from "~/services/tracking"; -import { checkForNewQuest } from "~/services/wov"; -import { createInfoEmbed } from "~/utils/discord"; -import { askForGrinders } from "~/utils/quest"; -import { commands } from "~/commands"; +import { Client, GatewayIntentBits, Partials } from "discord.js"; +import { setupBotMode } from "~/modes/bot"; +import { setupUserMode } from "~/modes/user"; +import { parseArgs } from "~/utils/cli"; -import { ChannelType, Client, GatewayIntentBits, Partials } from "discord.js"; -import * as readline from "node:readline"; +const mode = parseArgs(process.argv.slice(2)); -// user mode = write in console, send in channel -const flagIndex = process.argv.indexOf("--user"); -let userMode: { enabled: true; channelId: string } | { enabled: false } = { - enabled: false, -}; -if (flagIndex !== -1) { - const channelId = process.argv[flagIndex + 1]; - if (channelId === undefined) { - console.error("ERROR: --user expects channelId as a paramater"); - process.exit(1); - } - - userMode = { enabled: true, channelId }; -} - -console.log(`User mode: ${userMode.enabled ? "enabled" : "disabled"}`); +console.log(`Mode: ${mode.type}`); const client = new Client({ intents: [ @@ -35,81 +18,22 @@ const client = new Client({ partials: [Partials.Message, Partials.Channel], }); -const questCheckCron = async () => { - const quest = await checkForNewQuest(); - if (quest) { - await askForGrinders(quest, client); +switch (mode.type) { + case "user": { + setupUserMode(client, mode.channelId); + break; } -}; -const trackingCron = async () => { - const trackedPlayers = await listTrackedPlayers(); - for (const playerId of trackedPlayers) { - const res = await trackWovPlayer(playerId); - if (res.event !== "changed") return; - - const chan = client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL); - if (!chan?.isSendable()) throw "Invalid tracking channel"; - - const lastUsername = res.oldUsernames[res.oldUsernames.length - 1]; - - await chan.send( - createInfoEmbed( - `### [UPDATE] \`${lastUsername}\` -> \`${res.newUsername}\` [\`${playerId}\`]\n\n**Nouveau pseudo:** \`${res.newUsername}\`\n**Anciens pseudos:**\n${res.oldUsernames.map((x) => `- \`${x}\``).join("\n")}`, - ), - ); + case "bot": { + setupBotMode(client); + break; } -}; -client.on("ready", async (client) => { - console.log(`Logged in as ${client.user.username}`); - - if (userMode.enabled) { - const chan = client.channels.cache.get(userMode.channelId); - if (chan?.type !== ChannelType.GuildText) { - console.error("ERROR: invalid channel"); - process.exit(1); - } - - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - prompt: `${chan.name} ~ `, - }); - - rl.prompt(); - - rl.on("line", async (line) => { - await chan.send(line); - rl.prompt(); - }); - - rl.on("close", () => { - process.exit(0); - }); - } else { - await questCheckCron(); - setInterval(questCheckCron, env.WOV_FETCH_INTERVAL); - - await trackingCron(); - setInterval(trackingCron, env.WOV_TRACKING_INTERVAL); + default: { + // @ts-ignore + console.error(`ERROR: Not implemented: '${mode.type}'`); + process.exit(1); } -}); - -client.on("messageCreate", async (message) => { - if (message.author.bot || userMode.enabled) return; - - if (message.content.startsWith(`<@${client.user!.id}>`)) { - const [command, ...args] = message.content - .replace(`<@${client.user!.id}>`, "") - .trim() - .split(" "); - - const commandHandler = commands[command]; - if (commandHandler) { - await commandHandler(message, args); - } - } -}); +} await client.login(env.DISCORD_BOT_TOKEN); diff --git a/apps/discord-bot/src/modes/bot.ts b/apps/discord-bot/src/modes/bot.ts new file mode 100644 index 0000000..abf83a9 --- /dev/null +++ b/apps/discord-bot/src/modes/bot.ts @@ -0,0 +1,61 @@ +import type { Client } from "discord.js"; +import { env } from "~/env"; +import { listTrackedPlayers, trackWovPlayer } from "~/services/tracking"; +import { checkForNewQuest } from "~/services/wov"; +import { createInfoEmbed } from "~/utils/discord"; +import { askForGrinders } from "~/utils/quest"; +import { commands } from "~/commands"; + +const questCheckCron = async (client: Client) => { + const quest = await checkForNewQuest(); + if (quest) { + await askForGrinders(quest, client); + } +}; + +const trackingCron = async (client: Client) => { + const trackedPlayers = await listTrackedPlayers(); + for (const playerId of trackedPlayers) { + const res = await trackWovPlayer(playerId); + if (res.event !== "changed") return; + + const chan = client.channels.cache.get(env.DISCORD_TRACKING_CHANNEL); + if (!chan?.isSendable()) throw "Invalid tracking channel"; + + const lastUsername = res.oldUsernames[res.oldUsernames.length - 1]; + + await chan.send( + createInfoEmbed( + `### [UPDATE] \`${lastUsername}\` -> \`${res.newUsername}\` [\`${playerId}\`]\n\n**Nouveau pseudo:** \`${res.newUsername}\`\n**Anciens pseudos:**\n${res.oldUsernames.map((x) => `- \`${x}\``).join("\n")}`, + ), + ); + } +}; + +export const setupBotMode = (client: Client) => { + client.on("clientReady", async (client) => { + console.log(`Logged in as ${client.user.username}`); + + await questCheckCron(client); + setInterval(() => questCheckCron(client), env.WOV_FETCH_INTERVAL); + + await trackingCron(client); + setInterval(() => trackingCron(client), env.WOV_TRACKING_INTERVAL); + }); + + client.on("messageCreate", async (message) => { + if (message.author.bot) return; + + if (message.content.startsWith(`<@${client.user!.id}>`)) { + const [command, ...args] = message.content + .replace(`<@${client.user!.id}>`, "") + .trim() + .split(" "); + + const commandHandler = commands[command]; + if (commandHandler) { + await commandHandler(message, args); + } + } + }); +}; diff --git a/apps/discord-bot/src/modes/user.ts b/apps/discord-bot/src/modes/user.ts new file mode 100644 index 0000000..1ae4683 --- /dev/null +++ b/apps/discord-bot/src/modes/user.ts @@ -0,0 +1,34 @@ +import type { Client, TextChannel } from "discord.js"; +import { ChannelType } from "discord.js"; +import * as readline from "node:readline"; + +export const setupUserMode = (client: Client, channelId: string) => { + client.on("clientReady", (client) => { + console.log(`Logged in as ${client.user.username}`); + + const chan = client.channels.cache.get(channelId); + if (chan?.type !== ChannelType.GuildText) { + console.error("ERROR: invalid channel"); + process.exit(1); + } + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + prompt: `${chan.name} ~ `, + }); + + rl.prompt(); + + rl.on("line", async (line) => { + if (line.trim().length > 0) { + await (chan as TextChannel).send(line); + } + rl.prompt(); + }); + + rl.on("close", () => { + process.exit(0); + }); + }); +}; diff --git a/apps/discord-bot/src/utils/cli.ts b/apps/discord-bot/src/utils/cli.ts new file mode 100644 index 0000000..75cf869 --- /dev/null +++ b/apps/discord-bot/src/utils/cli.ts @@ -0,0 +1,32 @@ +type Mode = { type: "bot" } | { type: "user"; channelId: string }; + +export const parseArgs = (args: string[]): Mode => { + let mode: Mode = { type: "bot" }; + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + switch (arg) { + case "-u": + case "--as-user": { + const channelId = args[(i += 1)]; + + if (!channelId) { + console.error(`ERROR: ${arg} requires a channel ID`); + process.exit(1); + } + + mode = { type: "user", channelId }; + + break; + } + + default: { + console.error(`ERROR: Unrecognized argument: '${arg}'`); + process.exit(1); + } + } + } + + return mode; +};