-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathindex.js
More file actions
85 lines (76 loc) · 2.72 KB
/
Copy pathindex.js
File metadata and controls
85 lines (76 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { Client, GatewayIntentBits, Collection, ActivityType, Events } from 'discord.js';
import * as db from './src/db.js';
import log from './src/logger.js';
import { setup as setupCommands, register as registerCommands } from './src/commands.js';
import { setup as setupVoiceHandler } from './src/voiceHandler.js';
import { loadState, cleanStaleTextIDs } from './src/startup.js';
const token = process.env.DISCORD_TOKEN;
if (!token) {
console.error('DISCORD_TOKEN environment variable is required');
process.exit(1);
}
const config = {
categoryName: process.env.CATEGORY_NAME || 'Voice Chat🎤',
channelName: process.env.CHANNEL_NAME || '➕ Create Channel',
highBitrateGuilds: process.env.HIGH_BITRATE_GUILDS
? process.env.HIGH_BITRATE_GUILDS.split(',').map(s => s.trim()).filter(Boolean)
: [],
};
const textIDs = new Collection();
const createTextChannel = new Collection();
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
});
let resolveReady;
let rejectReady;
const ready = new Promise((resolve, reject) => {
resolveReady = resolve;
rejectReady = reject;
});
// Startup failures are logged below even when no event is waiting yet.
ready.catch(() => {});
setupCommands(client, createTextChannel, { ready });
setupVoiceHandler(client, config, textIDs, createTextChannel, { ready });
client.once(Events.ClientReady, async () => {
try {
await loadState(client, textIDs, createTextChannel);
await cleanStaleTextIDs(client, textIDs);
await registerCommands(client);
client.user.setActivity('for /text', { type: ActivityType.Watching });
resolveReady();
log.info('ready', `${client.user.tag} ready`, { guilds: client.guilds.cache.size });
} catch (err) {
rejectReady(err);
log.error('startup', 'Failed during initialization', { error: err.message });
await shutdown('startup failure', 1);
}
});
let stopping;
function shutdown(reason, exitCode = 0) {
if (stopping) return stopping;
stopping = (async () => {
log.info('shutdown', 'Shutting down', { reason });
client.destroy();
try {
await db.destroy();
} catch (err) {
log.error('shutdown', 'Failed to close database', { error: err.message });
exitCode = 1;
}
process.exit(exitCode);
})();
return stopping;
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('unhandledRejection', (err) => {
log.error('process', 'Unhandled promise rejection', { error: err?.message || String(err) });
});
try {
await db.init();
await client.login(token);
} catch (err) {
rejectReady(err);
log.error('startup', 'Failed to start bot', { error: err.message });
await shutdown('startup failure', 1);
}