140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
require("dotenv").config();
|
|
const { Client, GatewayIntentBits, EmbedBuilder } = require("discord.js");
|
|
const UptimeKuma = require("uptimekuma-api");
|
|
const cron = require("node-cron");
|
|
const subs = require("./subs.json");
|
|
|
|
const KUMA_BASE_URL = process.env.KUMA_BASE_URL;
|
|
const DISCORD_TOKEN = process.env.TOKEN;
|
|
const CRON_SCHEDULE = "*/5 * * * *";
|
|
|
|
const STATUS_EMOJIS = {
|
|
online: "<:online:1307359583785713744>",
|
|
offline: "<:offline:1307359600592424971>",
|
|
degraded: "<:degraded:1307359619491954778>",
|
|
};
|
|
|
|
const STATUS_INFO = {
|
|
operational: {
|
|
text: "All Systems Operational",
|
|
color: 0x43b581, // Green
|
|
emoji: STATUS_EMOJIS.online,
|
|
},
|
|
degraded: {
|
|
text: "Degraded Service",
|
|
color: 0xfaa61a, // Orange
|
|
emoji: STATUS_EMOJIS.degraded,
|
|
},
|
|
outage: {
|
|
text: "Full Outage",
|
|
color: 0xf04747, // Red
|
|
emoji: STATUS_EMOJIS.offline,
|
|
},
|
|
};
|
|
|
|
const kuma = new UptimeKuma(KUMA_BASE_URL);
|
|
const client = new Client({
|
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
|
|
});
|
|
|
|
async function createStatusEmbed(statusPageSlug) {
|
|
try {
|
|
const statusData = await kuma.status(statusPageSlug);
|
|
const embed = new EmbedBuilder()
|
|
.setTitle(statusData.info.title)
|
|
.setThumbnail(statusData.info.icon);
|
|
|
|
let totalMonitors = 0;
|
|
let offlineMonitors = 0;
|
|
|
|
for (const category of statusData.status) {
|
|
let fieldText = "";
|
|
for (const monitor of category.monitors) {
|
|
totalMonitors++;
|
|
const isOnline = monitor.heartbeats[0]?.status === 1;
|
|
if (!isOnline) {
|
|
offlineMonitors++;
|
|
}
|
|
const emoji = isOnline ? STATUS_EMOJIS.online : STATUS_EMOJIS.offline;
|
|
fieldText += `${emoji} ${monitor.name}\n`;
|
|
}
|
|
|
|
// Discord embed fields have a 1024 character limit.
|
|
// This splits the text into multiple fields if necessary.
|
|
const fieldChunks = fieldText.match(/[\s\S]{1,1024}/g) || [];
|
|
fieldChunks.forEach((chunk, index) => {
|
|
embed.addFields({
|
|
name: index === 0 ? category.name : `${category.name} (cont.)`,
|
|
value: chunk,
|
|
});
|
|
});
|
|
}
|
|
|
|
const status = determineOverallStatus(offlineMonitors, totalMonitors);
|
|
const description = statusData.info.description
|
|
? `${statusData.info.description}\n\n${status.emoji} ${status.text}`
|
|
: `${status.emoji} ${status.text}`;
|
|
|
|
embed
|
|
.setDescription(description)
|
|
.setColor(status.color)
|
|
.setTimestamp(new Date());
|
|
|
|
return embed;
|
|
} catch (error) {
|
|
console.error(`Error fetching status for "${statusPageSlug}":`, error);
|
|
return new EmbedBuilder()
|
|
.setColor(STATUS_INFO.outage.color)
|
|
.setDescription("An error occurred while fetching status data.");
|
|
}
|
|
}
|
|
|
|
function determineOverallStatus(offlineCount, totalCount) {
|
|
if (offlineCount === 0) {
|
|
return STATUS_INFO.operational;
|
|
}
|
|
if (offlineCount === totalCount) {
|
|
return STATUS_INFO.outage;
|
|
}
|
|
return STATUS_INFO.degraded;
|
|
}
|
|
|
|
async function findOrCreateStatusMessage(channel) {
|
|
const messages = await channel.messages.fetch({ limit: 25 });
|
|
let message = messages.find((msg) => msg.author.id === client.user.id);
|
|
|
|
if (!message) {
|
|
const loadingEmbed = new EmbedBuilder().setDescription("Initializing status panel...");
|
|
message = await channel.send({ embeds: [loadingEmbed] });
|
|
}
|
|
return message;
|
|
}
|
|
|
|
async function updateAllStatusMessages() {
|
|
console.log("Updating all status messages...");
|
|
for (const [channelId, slug] of Object.entries(subs)) {
|
|
try {
|
|
const channel = await client.channels.fetch(channelId);
|
|
if (!channel || !channel.isTextBased()) {
|
|
console.warn(`Channel ${channelId} not found or is not a text channel.`);
|
|
continue;
|
|
}
|
|
|
|
const message = await findOrCreateStatusMessage(channel);
|
|
const embed = await createStatusEmbed(slug);
|
|
await message.edit({ embeds: [embed] });
|
|
} catch (error) {
|
|
console.error(`Failed to update status for channel ${channelId}:`, error);
|
|
}
|
|
}
|
|
console.log("Finished updating status messages.");
|
|
}
|
|
|
|
client.once("ready", async () => {
|
|
console.log(`Logged in as ${client.user.tag}`);
|
|
await updateAllStatusMessages(); // Initial update on startup
|
|
cron.schedule(CRON_SCHEDULE, updateAllStatusMessages);
|
|
console.log(`Scheduled status updates with cron schedule: ${CRON_SCHEDULE}`);
|
|
});
|
|
|
|
client.login(DISCORD_TOKEN); |