feat: initial Papo bot scaffold
This commit is contained in:
94
src/services/commandHandler.ts
Normal file
94
src/services/commandHandler.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { REST, Routes, Collection, Client, ChatInputCommandInteraction, GatewayIntentBits } from 'discord.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { SlashCommand } from '../utils/types.js';
|
||||
import { env } from '../config/env.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export class CommandHandler {
|
||||
private commands = new Collection<string, SlashCommand>();
|
||||
|
||||
constructor(private client: Client) {}
|
||||
|
||||
public async loadCommands() {
|
||||
const commandsPath = path.join(process.cwd(), 'src', 'commands');
|
||||
const commandFiles = this.getCommandFiles(commandsPath);
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const mod = await import(file);
|
||||
const command: SlashCommand = mod.default;
|
||||
if (command?.data && command?.execute) {
|
||||
this.commands.set(command.data.name, command);
|
||||
logger.info(`Loaded command ${command.data.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getCommandFiles(dir: string): string[] {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
const files: string[] = [];
|
||||
for (const entry of entries) {
|
||||
const res = path.resolve(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
files.push(...this.getCommandFiles(res));
|
||||
} else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.js'))) {
|
||||
files.push(res);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
public async registerSlashCommands() {
|
||||
const rest = new REST({ version: '10' }).setToken(env.token);
|
||||
const body = this.commands.map((command) => command.data.toJSON());
|
||||
|
||||
const guilds = env.guildIds.length ? env.guildIds : [];
|
||||
if (guilds.length) {
|
||||
for (const gid of guilds) {
|
||||
try {
|
||||
await rest.put(Routes.applicationGuildCommands(env.clientId, gid), { body });
|
||||
logger.info(`Registered ${body.length} slash commands for guild ${gid}`);
|
||||
} catch (err) {
|
||||
logger.error(`Failed to register slash commands for guild ${gid}`, err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
await rest.put(Routes.applicationCommands(env.clientId), { body });
|
||||
logger.info(`Registered ${body.length} global slash commands`);
|
||||
} catch (err) {
|
||||
logger.error('Failed to register global slash commands', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async registerGuildCommands(guildId: string) {
|
||||
const rest = new REST({ version: '10' }).setToken(env.token);
|
||||
const body = this.commands.map((command) => command.data.toJSON());
|
||||
try {
|
||||
await rest.put(Routes.applicationGuildCommands(env.clientId, guildId), { body });
|
||||
logger.info(`Registered ${body.length} slash commands for guild ${guildId}`);
|
||||
} catch (err) {
|
||||
logger.error(`Failed to register commands for guild ${guildId}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
public async handleInteraction(interaction: ChatInputCommandInteraction) {
|
||||
const command = this.commands.get(interaction.commandName);
|
||||
if (!command) return;
|
||||
if (command.guildOnly && !interaction.inGuild()) {
|
||||
await interaction.reply({ content: 'Dieser Befehl funktioniert nur auf Servern.', ephemeral: true });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await command.execute(interaction, this.client);
|
||||
} catch (err) {
|
||||
logger.error(`Command ${interaction.commandName} failed`, err);
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
await interaction.followUp({ content: 'Es ist ein Fehler aufgetreten.', ephemeral: true });
|
||||
} else {
|
||||
await interaction.reply({ content: 'Es ist ein Fehler aufgetreten.', ephemeral: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user