151 lines
3.9 KiB
JavaScript
151 lines
3.9 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
const configStore = require("./ConfigStore.js");
|
|
const { getPrimaryGuild } = require("./GuildManager.js");
|
|
const {
|
|
applyPresence,
|
|
runBotReady,
|
|
logSlashCommandsRegistered,
|
|
} = require("./BotStartup.js");
|
|
|
|
function walk(dir, ext = ".js", fileList = []) {
|
|
if (!fs.existsSync(dir)) return fileList;
|
|
for (const file of fs.readdirSync(dir)) {
|
|
const full = path.join(dir, file);
|
|
if (fs.statSync(full).isDirectory()) {
|
|
walk(full, ext, fileList);
|
|
} else if (file.endsWith(ext)) {
|
|
fileList.push(full.replace(/\\/g, "/"));
|
|
}
|
|
}
|
|
return fileList;
|
|
}
|
|
|
|
async function refreshSlashCommands(client) {
|
|
if (!client?.application) return { count: 0 };
|
|
|
|
const cmdconfig = configStore.commands;
|
|
const commandFiles = walk("./Commands");
|
|
client.commands.clear();
|
|
|
|
for (const file of commandFiles) {
|
|
const resolved = path.resolve(file);
|
|
if (require.cache[resolved]) {
|
|
delete require.cache[resolved];
|
|
}
|
|
}
|
|
|
|
let count = 0;
|
|
for (const file of commandFiles) {
|
|
const command = require(path.resolve(file));
|
|
const matchingConfig = Object.values(cmdconfig).find(
|
|
(entry) =>
|
|
entry &&
|
|
typeof entry === "object" &&
|
|
entry.Command &&
|
|
String(entry.Command).toLowerCase() ===
|
|
String(command.name).toLowerCase(),
|
|
);
|
|
|
|
if (matchingConfig && matchingConfig.Enabled === false) {
|
|
continue;
|
|
}
|
|
|
|
client.commands.set(command.name, command);
|
|
count++;
|
|
}
|
|
|
|
const payload = client.commands.map((cmd) => cmd.data ?? cmd);
|
|
for (const guild of client.guilds.cache.values()) {
|
|
await guild.commands.set(payload);
|
|
}
|
|
|
|
return { count };
|
|
}
|
|
|
|
async function reloadBot(client, options = {}) {
|
|
const { fileKey, refreshCommands = true } = options;
|
|
|
|
let reloaded;
|
|
if (fileKey) {
|
|
configStore.reloadFile(fileKey);
|
|
reloaded = [fileKey];
|
|
} else {
|
|
reloaded = configStore.reloadBotConfigs();
|
|
}
|
|
|
|
applyPresence(client);
|
|
|
|
let commands = null;
|
|
if (refreshCommands && (!fileKey || fileKey === "commands")) {
|
|
commands = await refreshSlashCommands(client);
|
|
}
|
|
|
|
return {
|
|
reloaded,
|
|
commands,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Reload configs from disk, reconnect the Discord session, and refresh presence/commands.
|
|
* API and dashboard keep running on the same process.
|
|
*/
|
|
async function restartDiscordBot(client) {
|
|
if (!client) {
|
|
const err = new Error("Bot client not available");
|
|
err.code = "NO_CLIENT";
|
|
throw err;
|
|
}
|
|
|
|
const reloaded = configStore.reloadBotConfigs();
|
|
const token = configStore.supportbot?.General?.Token;
|
|
|
|
if (!token || String(token).trim() === "" || token === "BOT_TOKEN") {
|
|
const err = new Error("Invalid or missing bot token in supportbot.yml");
|
|
err.code = "INVALID_TOKEN";
|
|
throw err;
|
|
}
|
|
|
|
console.log("[BotReload] Restarting Discord bot after config change…");
|
|
client.__restarting = true;
|
|
|
|
if (client.user) {
|
|
try {
|
|
await client.destroy();
|
|
} catch (destroyErr) {
|
|
console.warn("[BotReload] destroy:", destroyErr.message);
|
|
}
|
|
}
|
|
|
|
client.__explicitStartup = true;
|
|
try {
|
|
try {
|
|
await client.login(token);
|
|
} catch (loginErr) {
|
|
console.error("[BotReload] login failed:", loginErr.message);
|
|
const err = new Error(`Could not start bot: ${loginErr.message}`);
|
|
err.code = "LOGIN_FAILED";
|
|
throw err;
|
|
}
|
|
|
|
// clientReady does not fire again after destroy()+login() — run startup explicitly
|
|
await runBotReady(client, { clearConsole: true, logCommands: false });
|
|
const commands = await refreshSlashCommands(client);
|
|
logSlashCommandsRegistered(client);
|
|
|
|
console.log("[BotReload] Bot restarted successfully");
|
|
return { restarted: true, reloaded, commands };
|
|
} finally {
|
|
client.__explicitStartup = false;
|
|
client.__restarting = false;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
applyPresence,
|
|
refreshSlashCommands,
|
|
reloadBot,
|
|
restartDiscordBot,
|
|
};
|