Lumi/src/main.js
2026-06-17 05:11:30 +02:00

127 lines
3.9 KiB
JavaScript

const { migrate } = require("./services/db");
const { ensureDefaults, getSetting, setSetting } = require("./services/settings");
const { createWebServer } = require("./web/server");
const { startBot, stopBot } = require("./services/discord");
const { startTwitchBot, stopTwitchBot } = require("./services/twitch");
const { startYouTubeBot, stopYouTubeBot } = require("./services/youtube");
const pluginService = require("./services/plugins");
const { loadEnabled } = pluginService;
const stopPlugins =
typeof pluginService.stopPlugins === "function"
? pluginService.stopPlugins
: async () => {};
const { checkForUpdates, pullUpdates, requestRestart } = require("./services/updater");
const { createCommandRouter } = require("./services/command-router");
const { registerTopCommand } = require("./services/top");
const logger = require("./services/logger");
const { isPlatformEnabled } = require("./services/platforms");
const {
isSafeModeRequested,
markStartupVerification
} = require("./services/recovery-mode");
async function main() {
migrate();
ensureDefaults();
logger.hookConsole();
const safeModeRequested = isSafeModeRequested();
const startupMarker = markStartupVerification();
if (startupMarker?.status === "stale") {
console.warn("Recovery marker detected from incomplete update; start with LUMI_SAFE_MODE=1 for recovery tools.");
}
const settingsApi = { getSetting, setSetting };
const commandRouter = createCommandRouter({ settings: settingsApi });
registerTopCommand({ commandRouter, settings: settingsApi });
let discordClient = null;
let twitchClient = null;
let youtubeClient = null;
if (!safeModeRequested && isPlatformEnabled("discord")) {
try {
discordClient = await startBot({ commandRouter });
} catch (error) {
console.error("Discord bot failed to start", error);
}
}
if (!safeModeRequested && isPlatformEnabled("twitch")) {
try {
twitchClient = await startTwitchBot({ commandRouter });
} catch (error) {
console.error("Twitch bot failed to start", error);
}
}
if (!safeModeRequested && isPlatformEnabled("youtube")) {
try {
youtubeClient = await startYouTubeBot({ commandRouter });
} catch (error) {
console.error("YouTube bot failed to start", error);
}
}
const app = createWebServer({
discordClient,
loadPlugins: (appInstance, web, webhooks) => {
if (safeModeRequested) return;
loadEnabled({
app: appInstance,
discordClient,
twitchClient,
youtubeClient,
settings: settingsApi,
web,
webhooks,
commandRouter
});
}
});
const port = Number(process.env.PORT || 3000);
app.listen(port, () => {
console.log(`WebUI listening on http://localhost:${port}`);
});
const autoUpdateEnabled = getSetting("auto_update_enabled", false);
const intervalMinutes = getSetting("auto_update_interval_minutes", 60);
if (!safeModeRequested && autoUpdateEnabled) {
const intervalMs = Math.max(5, Number(intervalMinutes)) * 60 * 1000;
let autoUpdateRunning = false;
setInterval(async () => {
if (autoUpdateRunning) return;
autoUpdateRunning = true;
try {
const remote = getSetting("git_remote", "origin");
const branch = getSetting("git_branch", "main");
if (checkForUpdates(remote, branch)) {
await pullUpdates(remote, branch);
requestRestart();
}
} catch (error) {
console.error("Auto-update failed", error);
} finally {
autoUpdateRunning = false;
}
}, intervalMs);
}
let shuttingDown = false;
const shutdown = async () => {
if (shuttingDown) {
return;
}
shuttingDown = true;
await stopPlugins();
await stopBot();
await stopTwitchBot();
await stopYouTubeBot();
process.exit(0);
};
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
}
main();