-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
161 lines (136 loc) · 4.41 KB
/
main.js
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"use_strict";
import config from "./config.json" assert { type: "json" };
import { SlashCommandBuilder } from '@discordjs/builders';
import { ShardingManager } from 'discord.js';
import { stamp_console, client_id, sleep } from './shared.js';
import { REST } from '@discordjs/rest';
import { Routes } from 'discord-api-types/v9';
import { request } from 'https';
import { readdirSync } from 'node:fs';
stamp_console('MAIN');
const commands = [];
const commandFiles = readdirSync('./commands').filter(file => file.endsWith('.js'));
const rest = new REST({ version: '9' }).setToken(config.token);
// In production mode, commands are loaded via a different script
if (config.testing_mode) {
(async () => {
for (const file of commandFiles) {
const command = await import("./commands/" + file);
if (config.testing_mode || !command.testing) {
commands.push(command.data.toJSON());
}
}
commands.push(new SlashCommandBuilder().setName('commands').setDescription('Displays a list of commands!'));
try {
console.log('Started refreshing slash commands.');
await rest.put(
Routes.applicationGuildCommands(client_id, config.testing_guild),
{ body: commands },
);
console.log('Successfully reloaded slash commands.');
} catch (error) {
console.error(error);
}
})();
}
async function update_topgg() {
let options = {
hostname: "top.gg",
port: 443,
path: "/api/bots/" + client_id + "/stats",
method: "POST",
headers: {
'Authorization': config.topgg_token,
'Content-Type': 'application/json'
}
};
while (true) {
// Get server number by adding the value from each shard
let servers = (await manager.fetchClientValues("guilds.cache.size")).reduce((acc, guildCount) => acc + guildCount, 0);
// Set up request content (JSON object with server count)
let content = '{"server_count":' + servers.toString() + '}';
options.headers['Content-Length'] = content.length;
let req = request(options, (res) => {
// Callback for once our response is received
console.log('Status:', res.statusCode);
// If we didn't have a successful response, debugging
if (res.statusCode !== 200) {
console.warn('Headers:', res.headers);
console.warn('Data:');
// Print the request data
res.on('data', (data) => {
// If we don't check for errors inside the callback, the app will crash
// This slowly causes all the shards to fail and not be restarted
try {
process.stdout.write(data);
} catch (error) {
console.warn("Could not write response data.");
}
});
}
});
// No error checking here because we would be using
// the console.warn function anyway, and if it doesn't
// work for this, it wouldn't work for our error
req.on('error', console.warn);
// Write server count to request
req.write(content);
// Send it off
req.end();
console.log("Tog.gg statistics uploaded, awaiting response...");
await sleep(1000 * 3600);
}
}
const manager = new ShardingManager('./bot.js', {
token: config.token
});
manager.on("shardCreate", shard => {
console.log(`Launched shard ${shard.id}`);
// Give the client their shard
shard.on("ready", () => {
shard.send({type: "shard_id", data: shard.id});
});
});
// Make sure we have some shards to test
if (config.testing_mode) {
manager.totalShards = 2;
}
// When all shards are up
manager.spawn().then(shards => {
if (!config.testing_mode) {
update_topgg().catch(e => {
console.log("Top.gg update failed:");
console.log(e);
});
}
for (const [i, shard] of shards) {
shard.send({type: "loaded"});
}
});
async function onExit() {
// Stop automatically respawning new shards
manager.respawn = false;
for (const [i, shard] of manager.shards) {
// Send a message to each of the shards to exit
shard.send({type: "exit"});
}
// In production mode, commands are unloaded via a different script
if (config.testing_mode) {
let registered = await rest.get(Routes.applicationGuildCommands(client_id, config.testing_guild));
for (const command of registered) {
await rest.delete(Routes.applicationGuildCommand(client_id, config.testing_guild, command.id));
console.log(`- Unregistered '${command.name}'.`);
}
console.log("Unregistered all commands; Exitting now.");
}
}
process.on("SIGINT", () => {
onExit().then(() => {
console.log("Bot exited.");
process.exit();
}).catch(error => {
console.log(error);
console.log("Bot exited with errors.");
process.exit();
});
});