Nix Krystik
2026-05-30 16:38:48 +08:00
parent 8c6d535f97
commit 0985712a1d
6 changed files with 171 additions and 171 deletions
+161 -161
View File
@@ -1,161 +1,161 @@
import { Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js'; import { Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js';
import { config } from './config'; import { config } from './config';
import { handleAuditLogCreate, handleBanRemove, handleBulkMessageDelete, handleGuildCreate, handleMemberJoin, handleMessageCreate, handleMessageDelete, handleMessageUpdate, handleThreadCreate, handleVoiceStateUpdate } from './events'; import { handleAuditLogCreate, handleBanRemove, handleBulkMessageDelete, handleGuildCreate, handleMemberJoin, handleMessageCreate, handleMessageDelete, handleMessageUpdate, handleThreadCreate, handleVoiceStateUpdate } from './events';
import { ScheduledTasks, Scheduler } from './scheduler'; import { ScheduledTasks, Scheduler } from './scheduler';
import { Database } from './shared/Database'; import { Database } from './shared/Database';
import { openRedisClient } from './shared/RedisClient'; import { openRedisClient } from './shared/RedisClient';
import { Handler } from './types'; import { Handler } from './types';
import { initIfNecessary, loadHandlersFrom, refreshCommands } from './utils'; import { initIfNecessary, loadHandlersFrom, refreshCommands } from './utils';
import { initializeWebserver } from './webserver'; import { initializeWebserver } from './webserver';
let ready = false; let ready = false;
console.log('Starting...'); console.log('Starting...');
const client = new DiscordClient({ const client = new DiscordClient({
intents: [ intents: [
GatewayIntentBits.Guilds, GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildModeration, GatewayIntentBits.GuildModeration,
GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.MessageContent GatewayIntentBits.MessageContent
], ],
partials: [Partials.Message, Partials.GuildMember, Partials.User, Partials.Channel], partials: [Partials.Message, Partials.GuildMember, Partials.User, Partials.Channel],
rest: { timeout: 30000 }, rest: { timeout: 30000 },
allowedMentions: { allowedMentions: {
parse: [], parse: [],
repliedUser: false repliedUser: false
} }
}); });
const scheduler: Scheduler = new Scheduler(client); const scheduler: Scheduler = new Scheduler(client);
const commands: Handler[] = []; const commands: Handler[] = [];
const contextMenus: Handler[] = []; const contextMenus: Handler[] = [];
const buttons: Handler[] = []; const buttons: Handler[] = [];
const modals: Handler[] = []; const modals: Handler[] = [];
const menus: Handler[] = []; const menus: Handler[] = [];
loadHandlersFrom('commands', commands); loadHandlersFrom('commands', commands);
loadHandlersFrom('context-menus', contextMenus); loadHandlersFrom('context-menus', contextMenus);
loadHandlersFrom('buttons', buttons); loadHandlersFrom('buttons', buttons);
loadHandlersFrom('modals', modals); loadHandlersFrom('modals', modals);
loadHandlersFrom('menus', menus); loadHandlersFrom('menus', menus);
// Due to their reliance on each other, these two events (interactionCreate, and ready) have to stay here. // Due to their reliance on each other, these two events (interactionCreate, and ready) have to stay here.
// Alternatively, they can move to another single file. Or use static classes. // Alternatively, they can move to another single file. Or use static classes.
client.on('interactionCreate', async (interaction) => { client.on('interactionCreate', async (interaction) => {
if (!ready) { if (!ready) {
if ( if (
interaction.isChatInputCommand() interaction.isChatInputCommand()
|| interaction.isContextMenuCommand() || interaction.isContextMenuCommand()
|| interaction.isButton() || interaction.isButton()
|| interaction.isModalSubmit() || interaction.isModalSubmit()
|| interaction.isAnySelectMenu() || interaction.isAnySelectMenu()
) )
interaction.reply({ interaction.reply({
content: 'Bot is still starting up. Please wait a few seconds.', content: 'Bot is still starting up. Please wait a few seconds.',
flags: [MessageFlags.Ephemeral], flags: [MessageFlags.Ephemeral],
}); });
return; return;
} }
if (interaction.isChatInputCommand()) { if (interaction.isChatInputCommand()) {
// Handle chat // Handle chat
for (const command of commands) { for (const command of commands) {
if (interaction.commandName == command.name) { if (interaction.commandName == command.name) {
command.handler(client, interaction); command.handler(client, interaction);
return; return;
} }
} }
} else if (interaction.isContextMenuCommand()) { } else if (interaction.isContextMenuCommand()) {
// Handle context menu commands. // Handle context menu commands.
for (const command of contextMenus) { for (const command of contextMenus) {
if (interaction.commandName == command.name) { if (interaction.commandName == command.name) {
command.handler(client, interaction); command.handler(client, interaction);
return; return;
} }
} }
} else if (interaction.isAutocomplete()) { } else if (interaction.isAutocomplete()) {
// Handle autocomplete requests. // Handle autocomplete requests.
for (const command of commands) { for (const command of commands) {
if (interaction.commandName == command.name) { if (interaction.commandName == command.name) {
if (command.autoComplete) { if (command.autoComplete) {
command command
.autoComplete(client, interaction) .autoComplete(client, interaction)
.catch(e => console.error(e)); .catch(e => console.error(e));
} }
return; return;
} }
} }
} else if (interaction.isButton()) { } else if (interaction.isButton()) {
// Handle button presses. // Handle button presses.
const id = interaction.customId.split('_')[0]; const id = interaction.customId.split('_')[0];
for (const button of buttons) { for (const button of buttons) {
if (id == button.name) { if (id == button.name) {
button.handler(client, interaction, ...interaction.customId.split('_').slice(1)); button.handler(client, interaction, ...interaction.customId.split('_').slice(1));
return; return;
} }
} }
} else if (interaction.isModalSubmit()) { } else if (interaction.isModalSubmit()) {
// Handle modal submissions. // Handle modal submissions.
const id = interaction.customId.split('_')[0]; const id = interaction.customId.split('_')[0];
for (const modal of modals) { for (const modal of modals) {
if (id == modal.name) { if (id == modal.name) {
modal.handler(client, interaction, ...interaction.customId.split('_').slice(1)); modal.handler(client, interaction, ...interaction.customId.split('_').slice(1));
return; return;
} }
} }
} else if (interaction.isAnySelectMenu()) { } else if (interaction.isAnySelectMenu()) {
// Handle menu selections. // Handle menu selections.
const id = interaction.customId.split('_')[0]; const id = interaction.customId.split('_')[0];
for (const menu of menus) { for (const menu of menus) {
if (id == menu.name) { if (id == menu.name) {
menu.handler(client, interaction, ...interaction.customId.split('_').slice(1)); menu.handler(client, interaction, ...interaction.customId.split('_').slice(1));
return; return;
} }
} }
} }
}); });
client.on('clientReady', async () => { client.on('clientReady', async () => {
console.log(`Logged in as ${client.user!.tag}!`); console.log(`Logged in as ${client.user!.tag}!`);
await refreshCommands(client); await refreshCommands(client);
await initIfNecessary(client, commands); await initIfNecessary(client, commands);
await initIfNecessary(client, buttons); await initIfNecessary(client, buttons);
await initIfNecessary(client, modals); await initIfNecessary(client, modals);
await initIfNecessary(client, menus); await initIfNecessary(client, menus);
await Database.open('./data/discord-main.db'); await Database.open('./data/discord-main.db');
await openRedisClient(config.REDIS_URL!, client); await openRedisClient(config.REDIS_URL!, client);
await initializeWebserver(client); await initializeWebserver(client);
ScheduledTasks.forEach((task) => scheduler.add(task)); ScheduledTasks.forEach((task) => scheduler.add(task));
ready = true; ready = true;
console.log('Ready'); console.log('Ready');
}); });
client.on('guildAuditLogEntryCreate', handleAuditLogCreate); client.on('guildAuditLogEntryCreate', handleAuditLogCreate);
client.on('guildBanRemove', handleBanRemove); client.on('guildBanRemove', handleBanRemove);
client.on('guildCreate', handleGuildCreate); client.on('guildCreate', handleGuildCreate);
client.on('guildMemberAdd', handleMemberJoin); client.on('guildMemberAdd', handleMemberJoin);
client.on('messageCreate', handleMessageCreate); client.on('messageCreate', handleMessageCreate);
client.on('messageDelete', handleMessageDelete); client.on('messageDelete', handleMessageDelete);
client.on('messageDeleteBulk', handleBulkMessageDelete); client.on('messageDeleteBulk', handleBulkMessageDelete);
client.on('messageUpdate', handleMessageUpdate); client.on('messageUpdate', handleMessageUpdate);
client.on('threadCreate', handleThreadCreate); client.on('threadCreate', handleThreadCreate);
client.on('voiceStateUpdate', handleVoiceStateUpdate); client.on('voiceStateUpdate', handleVoiceStateUpdate);
client.on('error', console.error); client.on('error', console.error);
process.on('uncaughtException', console.error); process.on('uncaughtException', console.error);
client.login(config.DISCORD_TOKEN); client.login(config.DISCORD_TOKEN);
@@ -11,4 +11,4 @@ class CheckExpiredBansTask implements Task {
} }
} }
export default new CheckExpiredBansTask(); export default new CheckExpiredBansTask();
@@ -11,4 +11,4 @@ class CloseStaleTicketsTask implements Task {
} }
} }
export default new CloseStaleTicketsTask(); export default new CloseStaleTicketsTask();
+1 -1
View File
@@ -4,4 +4,4 @@ import closeStaleTicketsTask from './close-stale-tickets-task';
export default [ export default [
closeStaleTicketsTask, closeStaleTicketsTask,
checkExpiredBansTask, checkExpiredBansTask,
]; ];
+6 -6
View File
@@ -1,6 +1,6 @@
export * from './command.d'; export * from './command.d';
export * from './database-types.d'; export * from './database-types.d';
export * from './e621-types.d'; export * from './e621-types.d';
export * from './handler.d'; export * from './handler.d';
export * from './helper-types.d'; export * from './helper-types.d';
export * from './scheduler.d'; export * from './scheduler.d';
+1 -1
View File
@@ -5,4 +5,4 @@ export interface Task {
firstRun: boolean; firstRun: boolean;
handle(context: Client): Promise<void>; handle(context: Client): Promise<void>;
}; };