Files
Papo/src/services/commandHandler.ts

137 lines
4.9 KiB
TypeScript

import { REST, Routes, Collection, Client, ChatInputCommandInteraction, GatewayIntentBits } from 'discord.js';
import fs from 'fs';
import path from 'path';
import { SlashCommand } from '../utils/types';
import { env } from '../config/env';
import { logger } from '../utils/logger';
import { AdminService } from './adminService';
import { StatuspageService } from './statuspageService';
import { settingsStore } from '../config/state';
import { ModuleKey } from './moduleService';
export class CommandHandler {
private commands = new Collection<string, SlashCommand>();
private moduleMap: Record<string, ModuleKey> = {
// Tickets
ticket: 'ticketsEnabled',
ticketpanel: 'ticketsEnabled',
transcript: 'ticketsEnabled',
close: 'ticketsEnabled',
claim: 'ticketsEnabled',
// Music
play: 'musicEnabled',
skip: 'musicEnabled',
stop: 'musicEnabled',
pause: 'musicEnabled',
resume: 'musicEnabled',
loop: 'musicEnabled',
queue: 'musicEnabled',
// Level
rank: 'levelingEnabled',
// Statuspage
status: 'statuspageEnabled',
// Birthday
birthday: 'birthdayEnabled',
// Events
event: 'eventsEnabled',
events: 'eventsEnabled'
};
constructor(private client: Client, private admin?: AdminService, private statuspage?: StatuspageService) {}
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;
}
if (interaction.inGuild()) {
const moduleKey = this.moduleMap[interaction.commandName];
if (moduleKey) {
const cfg = settingsStore.get(interaction.guildId!);
const enabled = cfg?.[moduleKey];
if (enabled === false) {
await interaction.reply({ content: 'Dieses Modul ist fuer diese Guild deaktiviert.', ephemeral: true });
return;
}
}
}
try {
this.admin?.trackCommand(interaction.guildId);
if (interaction.guildId) this.admin?.trackGuildEvent(interaction.guildId, 'commands');
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 });
}
}
}
}