diff --git a/src/index.ts b/src/index.ts index d23298d..3d18ebc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,10 +2,11 @@ import Revolt from 'revolt.js'; import Discord from 'discord.js'; import Express from 'express'; import { config } from 'dotenv'; +import { exec } from 'child_process'; config(); -const { DISCORD_TOKEN, REVOLT_TOKEN, DISCORD_CHANNEL, REVOLT_CHANNEL, PORT } = process.env; +const { DISCORD_TOKEN, REVOLT_TOKEN, DISCORD_CHANNEL, REVOLT_CHANNEL, PORT, RESTART_COMMAND_BOT, RESTART_COMMAND_BRIDGE } = process.env; if (!DISCORD_TOKEN) throw '$DISCORD_TOKEN not set'; if (!REVOLT_TOKEN) throw '$REVOLT_TOKEN not set'; @@ -20,6 +21,9 @@ const clients = { revolt: new Revolt.Client({ autoReconnect: true, pongTimeout: 30, onPongTimeout: 'RECONNECT' }), } +let currentValue: Awaited>|null = null; +let restarting = { bot: false, bridge: false }; + const app = Express(); app.listen(PORT, () => console.log('Listening on :' + PORT)); @@ -30,15 +34,32 @@ clients.discord.on('ready', () => console.log('Discord ready')); clients.revolt.on('ready', () => console.log('Revolt ready')); app.get('/healthcheck', async (req: Express.Request, res: Express.Response) => { + console.log('Health check request received'); + + if (!currentValue) { + console.log('No health check result stored yet, running checks'); + await periodicCheck(); + } + + res.status(currentValue!.status).send(currentValue); +}); + +const periodicCheck = async () => { + console.log('Running periodic check'); + const now = new Date().toISOString(); const [ botStatus, bridgeStatusDiscord, bridgeStatusRevolt ] = await Promise.all([ retry(checkBot, 3), retry(checkBridgeDiscord, 3), retry(checkBridgeRevolt, 3), ]); - let statusCode = (botStatus && bridgeStatusDiscord && bridgeStatusRevolt) ? 200 : 503; - let response = { + if (botStatus) restarting.bot = false; + if (bridgeStatusDiscord && bridgeStatusRevolt) restarting.bridge = false; + + const statusCode = (botStatus && bridgeStatusDiscord && bridgeStatusRevolt) ? 200 : 503; + const response = { status: statusCode, + checkedOn: now, ready: { discord: !!clients.discord.readyAt, revolt: !!clients.revolt.websocket.ready, @@ -50,8 +71,43 @@ app.get('/healthcheck', async (req: Express.Request, res: Express.Response) => { }, }; - res.status(statusCode).send(response); -}); + currentValue = response; + runRestarts(response).catch(e => console.log(e)); // Explicitly do not await this + return response; +} + +const runRestarts = async (status: Awaited>) => { + if (!status.watchdog.bot && !restarting.bot && RESTART_COMMAND_BOT) { + console.log('Restarting bot'); + try { + restarting.bot = true; + const result = exec(RESTART_COMMAND_BOT!); + result.stdout?.on('data', data => console.log(data)); + result.stderr?.on('data', data => console.log(data)); + } catch(e) { + console.log(e); + } + } + + if ((!status.watchdog.bridgeDiscord || !status.watchdog.bridgeRevolt) && !restarting.bridge && RESTART_COMMAND_BRIDGE) { + console.log('Restarting bridge'); + try { + restarting.bridge = true; + const result = exec(RESTART_COMMAND_BRIDGE!); + result.stdout?.on('data', data => console.log(data)); + result.stderr?.on('data', data => console.log(data)); + } catch(e) { + console.log(e); + } + } +} + +setInterval(async () => { + if (clients.discord.readyAt && clients.revolt.user) { + await periodicCheck(); + } + else console.log('Cannot run periodic check as clients aren\'t ready yet'); +}, 30000); const checkBot = (): Promise => new Promise(async (resolve, _reject) => { const id = Math.round(Math.random() * 1000000);