From 25ee1137852f253d7448deb783fbff1e19793870 Mon Sep 17 00:00:00 2001 From: Noah Heague Date: Sat, 21 Aug 2021 12:19:42 +1000 Subject: [PATCH] Better slash command handling --- bot/.eslintrc.json | 4 ++ bot/src/config.ts | 3 +- bot/src/help/help.ts | 5 +++ bot/src/index.ts | 53 +++++++++++-------------- bot/src/slashCommands/register.ts | 64 +++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 bot/src/help/help.ts create mode 100644 bot/src/slashCommands/register.ts diff --git a/bot/.eslintrc.json b/bot/.eslintrc.json index 31be53b9b..1e9e45d15 100644 --- a/bot/.eslintrc.json +++ b/bot/.eslintrc.json @@ -31,6 +31,10 @@ "semi": [ "error", "always" + ], + "object-curly-spacing": [ + "error", + "always" ] } } diff --git a/bot/src/config.ts b/bot/src/config.ts index f320bfb46..f76fa5026 100644 --- a/bot/src/config.ts +++ b/bot/src/config.ts @@ -6,7 +6,8 @@ export const allowedChannels = [ export enum LoggerLayers { client = "client", songLink = "songLink", - embedGenerator = "embedGenerator" + embedGenerator = "embedGenerator", + slashCommands = "slashCommands" } export const platformRegex = [ diff --git a/bot/src/help/help.ts b/bot/src/help/help.ts new file mode 100644 index 000000000..f2151f795 --- /dev/null +++ b/bot/src/help/help.ts @@ -0,0 +1,5 @@ +import { CommandInteraction } from "discord.js"; + +export const help = async (interaction: CommandInteraction): Promise => { + await interaction.reply("Send a link to a streaming service and I will reply with a rich embed.\nPrepend youtube links with `?`\n\nGithub: https://github.com/Puffycheeses/music_linkr\nDiscord: https://discord.gg/a5a7NQV"); +}; diff --git a/bot/src/index.ts b/bot/src/index.ts index 4bf4a5878..06dbbb987 100644 --- a/bot/src/index.ts +++ b/bot/src/index.ts @@ -1,10 +1,8 @@ import { Client, Intents } from "discord.js"; -import { REST } from "@discordjs/rest"; -import { Routes } from "discord-api-types/v9"; -import { SlashCommandBuilder } from "@discordjs/builders"; import { LoggerLayers, platformRegex } from "./config"; import { createLinkReply } from "./createEmbed/createEmbed"; import { getSongLinkResponse } from "./getSongLink/getSongLink"; +import { registerSlashCommands, slashCommands, tidyGuildCommands, SlashCommand } from "./slashCommands/register"; import { createLayeredLogger } from "./utils/logger"; import { shouldReply } from "./utils/utils"; @@ -42,36 +40,29 @@ client.on("messageCreate", async (message) => { client.on("interactionCreate", async (interaction) => { if (!interaction.isCommand()) return; + try { + const command = slashCommands.find((command: SlashCommand) => { + return command.info.name === interaction.commandName; + }); - if (interaction.commandName === "help") { - /** @TODO Prettify this! */ - await interaction.reply("Send a link to a streaming service and I will reply with a rich embed.\nPrepend youtube links with `?`\n\nGithub: https://github.com/Puffycheeses/music_linkr\nDiscord: https://discord.gg/a5a7NQV"); + if (command && command.exec) { + logger.info(`Running ${command.info.name} interaction`); + command.exec(interaction); + } + } catch (e) { + logger.error("Failed to run interaction"); } }); -const rest = new REST({ version: "9" }).setToken(process.env.DISCORDTOKEN); -client.login(process.env.DISCORDTOKEN).then(() => { - logger.info("Logged in successfully \n"); -}).catch((err) => { - logger.error("Log in Failed:", err); -}).then(() => { - client.guilds.cache.map(async (guild) => { - try { - logger.info(`Registering Slash command with ${guild.id}`); - await rest.put( - Routes.applicationGuildCommands(client.application.id, guild.id), - { - body: [ - new SlashCommandBuilder() - .setName("help") - .setDescription("Shows information about Music Linkr") - .toJSON() - ] - } - ); - } catch (e) { - logger.error(`Error on Guild: ${guild.id}`, e); - } - }); -}); +(async () => { + try { + await client.login(process.env.DISCORDTOKEN); + logger.info(`Logged in successfully to ${client.guilds.cache.size} guilds`); + } catch (e) { + logger.error("Log in Failed:", e); + } finally { + await tidyGuildCommands(client); + await registerSlashCommands(client); + } +})(); diff --git a/bot/src/slashCommands/register.ts b/bot/src/slashCommands/register.ts new file mode 100644 index 000000000..7ef04e8ab --- /dev/null +++ b/bot/src/slashCommands/register.ts @@ -0,0 +1,64 @@ +import { SlashCommandBuilder } from "@discordjs/builders"; +import { REST } from "@discordjs/rest"; +import { APIApplicationCommandOption } from "discord-api-types"; +import { Routes } from "discord-api-types/v9"; +import { Client, CommandInteraction, Interaction } from "discord.js"; +import { LoggerLayers } from "../config"; +import { help } from "../help/help"; +import { createLayeredLogger } from "../utils/logger"; + +const logger = createLayeredLogger(LoggerLayers.slashCommands); + +export interface SlashCommand { + info: { + name: string; + description: string; + options: APIApplicationCommandOption[]; + }; + exec(interaction: CommandInteraction): Promise; +} + +export const slashCommands: SlashCommand[] = [ + { + info: new SlashCommandBuilder() + .setName("help") + .setDescription("Shows information about Music Linkr") + .toJSON(), + exec: async (interaction: CommandInteraction) => await help(interaction), + } +]; + +const rest = new REST({ version: "9" }).setToken(process.env.DISCORDTOKEN); +export const registerSlashCommands = async (client: Client): Promise => { + try { + logger.info("Registering slash commands"); + await rest.put( + Routes.applicationCommands(client.application.id), + { + body: slashCommands.map(command => command.info) + } + ); + } catch (e) { + logger.error("Failed to register slash commands", e); + } finally { + logger.info("Successfully registered slash commands"); + } +}; + +/** @deprecated Remove once no guilds have legacy commands */ +export const tidyGuildCommands = async (client: Client): Promise => { + try { + logger.info("Removing legacy slash commands"); + const guilds = client.guilds.cache; + guilds.forEach(guild => { + const commands = guild.commands.cache; + commands.forEach(command => { + command.delete(); + }); + }); + } catch (e) { + logger.error("Failed to remove legacy slash commands"); + } finally { + logger.info("Successfully removed legacy slash commands"); + } +};