feat: handle and dispatch commands

This commit is contained in:
2026-01-10 10:26:35 -03:00
parent efe2cb7458
commit f424336eba
+127 -1
View File
@@ -3,20 +3,26 @@ import path from 'path';
import {
AutocompleteInteraction,
BaseInteraction,
ChatInputCommandInteraction,
GuildMember,
Interaction,
Message,
MessageFlags,
PermissionFlagsBits,
REST,
Routes,
SlashCommandOptionsOnlyBuilder,
VoiceState
} from 'discord.js';
import { Logger } from './utils/log';
import { Bot } from './bot';
import { config } from './utils/config';
import { Bot } from './bot';
export interface Command {
name?: string;
requiresAdmin: boolean;
ownerOnly?: boolean;
execute?: (interaction: ChatInputCommandInteraction) => Promise<void>;
autocomplete?: (interaction: AutocompleteInteraction) => Promise<void>;
messageListener?: (msg: Message) => Promise<void>;
@@ -58,6 +64,18 @@ export class CommandManager {
this.initialized = true;
await this.populateCommands();
this.registerSlashCommands();
const bot = Bot.get;
bot.on('interactionCreate', (interaction: Interaction) => {
this.onInteraction(interaction);
});
bot.on('messageCreate', (message: Message) => {
this.onMessage(message);
});
bot.on('voiceStateUpdate', (oldState: VoiceState, newState: VoiceState) => {
this.onVoiceStateUpdate(oldState, newState);
});
}
public getCategories(): Array<CommandCategory> {
@@ -194,4 +212,112 @@ export class CommandManager {
);
}
}
/*
interaction handling
*/
private async executeCommandInteraction(
interaction: ChatInputCommandInteraction
): Promise<void> {
const cmdName = interaction.commandName;
const command = this.get(cmdName);
if (!command)
return this.log.error(
'Attempted to execute non-existing command (%s)',
cmdName
);
if (command.requiresAdmin) {
const member = interaction.member as GuildMember;
if (!member.permissions.has(PermissionFlagsBits.Administrator)) {
await interaction.reply({
content:
"You don't have the permissions required to execute this command.",
flags: MessageFlags.Ephemeral
});
return;
}
}
if (command.ownerOnly) {
const member = interaction.member as GuildMember;
if (member.id != config.owner_id) {
await interaction.reply({
content: 'This command is restricted.',
flags: MessageFlags.Ephemeral
});
return;
}
}
if (command.execute) {
try {
await command.execute(interaction);
} catch (error) {
this.log.error(
'Error occurred while executing command %s: %s',
cmdName,
error
);
}
} else this.log.error('Command is missing execute method: %s', cmdName);
}
private async autocompleteCommandInteraction(
interaction: AutocompleteInteraction
): Promise<void> {
const cmdName = interaction.commandName;
const command = this.get(cmdName);
if (!command)
return this.log.error(
'Attempted to execute unexisting command (%s)',
cmdName
);
if (command.autocomplete) {
try {
await command.autocomplete(interaction);
} catch (error) {
this.log.error(
'Error occurred while autocompleting command %s: %s',
cmdName,
error
);
}
} else
this.log.error('Command is missing autocomplete method: %s', cmdName);
}
/*
event listeners
*/
private async onInteraction(interaction: BaseInteraction): Promise<void> {
/*
cmd execution
*/
if (interaction.isChatInputCommand())
return this.executeCommandInteraction(interaction);
if (interaction.isAutocomplete())
return this.autocompleteCommandInteraction(interaction);
return;
}
private async onMessage(message: Message<boolean>): Promise<void> {
if (message.author.bot) return;
for (const cmd of this.getAll())
if (cmd.messageListener) await cmd.messageListener(message);
}
private async onVoiceStateUpdate(
oldState: VoiceState,
newState: VoiceState
): Promise<void> {
for (const cmd of this.getAll())
if (cmd.voiceStateListener)
await cmd.voiceStateListener(oldState, newState);
}
}