Files
UptimeKuma-DiscordBot/Bot/index.js
2025-10-06 00:56:47 -04:00

196 lines
7.7 KiB
JavaScript

const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const axios = require('axios');
// Load configuration from environment variables or config.json
const config = {
token: process.env.DISCORD_TOKEN || require('./config.json').token,
guildID: process.env.GUILD_ID || require('./config.json').guildID,
channelID: process.env.CHANNEL_ID || require('./config.json').channelID,
clientID: process.env.CLIENT_ID || require('./config.json').clientID,
updatetime: parseInt(process.env.UPDATE_TIME) || require('./config.json').updatetime,
backendUrl: process.env.BACKEND_URL || '<YOUR_BACKEND_URL>',
uptimeKumaUrl: process.env.UPTIME_KUMA_URL || '<YOUR_UPTIMEKUMA_URL>'
};
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
let monitorMessages = {
'Web Services': null,
'Infrastructure': null,
'Network': null
};
client.once('ready', async () => {
console.log('Bot is online!');
const channel = await client.channels.fetch(config.channelID);
if (channel && channel.isTextBased()) {
await clearChannel(channel);
} else {
console.error(`Unable to find text channel with ID ${config.channelID}`);
}
// Call the function to update messages immediately
await updateMessages();
// Set interval to update messages every 30 seconds
setInterval(updateMessages, config.updatetime * 1000);
});
async function updateMessages() {
try {
const guild = await client.guilds.fetch(config.guildID);
if (!guild) {
console.error(`Unable to find guild with ID ${config.guildID}`);
return;
}
const channel = await guild.channels.fetch(config.channelID);
if (!channel || !channel.isTextBased()) {
console.error(`Unable to find text channel with ID ${config.channelID}`);
return;
}
console.log(`Fetching from backend: ${config.backendUrl}`);
const response = await axios.get(config.backendUrl);
const monitors = response.data;
console.log('Backend response status:', response.status);
console.log('Backend response data type:', typeof monitors);
console.log('Backend response data:', JSON.stringify(monitors).substring(0, 500) + '...');
// Check if the backend returned an error
if (monitors.error) {
console.error('Backend API error:', monitors.message);
return;
}
// Ensure monitors is an array
if (!Array.isArray(monitors)) {
console.error('Backend returned invalid data format:', typeof monitors);
console.error('Expected array, got:', monitors);
return;
}
console.log(`Fetched ${monitors.length} monitors from backend`);
console.log('Monitor names:', monitors.map(m => m.monitor_name));
const webServicesMonitors = monitors.filter(monitor => [
'Main Page', 'Pelican', 'Jellyfin', 'Proxmox', 'Jellyseerr',
'CPanel', 'WHMCS', 'Gitea', 'Nextcloud', 'Radarr', 'Sonarr',
'Prowlarr', 'Nginx Proxy Manager', 'Authentik', 'n8n', 'HA Proxy'
].includes(monitor.monitor_name));
const infrastructureMonitors = monitors.filter(monitor => [
'a01.pve.hrs', 'a05.pve.hrs', 'a07.pve.hrs', 'a08.pve.hrs', 'a09.pve.hrs',
'01.bw.hrs', '01.ga.hrs', '01.ha.hrs', '01.lh.hrs', '01.nc.hrs'
].includes(monitor.monitor_name));
const networkMonitors = monitors.filter(monitor => [
'01.sh.hrs', '01.rs.hrs', '01.pe.hrs', '01.pt.hrs', '01.rr.hrs',
'01.wn.hrs', '02.pe.hrs', '01.cp.hrs', '02.cp.hrs', 'a06'
].includes(monitor.monitor_name));
console.log(`Web Services: ${webServicesMonitors.length}, Infrastructure: ${infrastructureMonitors.length}, Network: ${networkMonitors.length}`);
await sendMonitorsMessage(channel, 'Web Services', webServicesMonitors);
// await sendMonitorsMessage(channel, 'Infrastructure', infrastructureMonitors);
//await sendMonitorsMessage(channel, 'Network', networkMonitors);
// Send a test message if no monitors found
if (webServicesMonitors.length === 0) {
console.log('No monitors found, sending test message');
await channel.send('🔧 Bot is running but no monitors found. Check backend configuration.');
}
} catch (error) {
console.error('Error updating messages:', error);
// If it's an axios error, log more details
if (error.response) {
console.error('Backend API error:', error.response.status, error.response.statusText);
console.error('Response data:', error.response.data);
} else if (error.request) {
console.error('No response from backend API:', error.request);
} else {
console.error('Request setup error:', error.message);
}
}
}
async function sendMonitorsMessage(channel, category, monitors) {
console.log(`Processing ${category}: ${monitors.length} monitors`);
let description = monitors.map(monitor => {
let statusEmoji = '';
switch (monitor.status) {
case 0:
statusEmoji = '🔴'; // Offline
break;
case 1:
statusEmoji = '🟢'; // Online
break;
case 2:
statusEmoji = '🟡'; // Warning
break;
case 3:
statusEmoji = '🔵'; // Maintenance
break;
default:
statusEmoji = '❓'; // Unknown
}
return `${statusEmoji} | ${monitor.monitor_name}`;
}).join('\n');
console.log(`Generated description for ${category}: "${description}"`);
// Ensure description is not empty (Discord.js validation requirement)
if (!description || description.trim() === '') {
description = `No ${category.toLowerCase()} monitors found.`;
console.log(`Empty description, using fallback: "${description}"`);
}
let embed = new EmbedBuilder()
.setTitle(`${category} Monitor`)
.setColor('#0099ff')
.setDescription(description)
.setFooter({ text: `Last updated: ${new Date().toLocaleString()}` })
.setURL(config.uptimeKumaUrl);
try {
if (monitorMessages[category]) {
const message = await channel.messages.fetch(monitorMessages[category]);
if (message) {
await message.edit({ embeds: [embed] });
console.log(`${new Date().toLocaleString()} | Updated ${category} monitors message`);
} else {
const newMessage = await channel.send({ embeds: [embed] });
monitorMessages[category] = newMessage.id;
console.log(`${new Date().toLocaleString()} | Sent new ${category} monitors message`);
}
} else {
const newMessage = await channel.send({ embeds: [embed] });
monitorMessages[category] = newMessage.id;
console.log(`${new Date().toLocaleString()} | Sent ${category} monitors message`);
}
} catch (error) {
console.error(`Failed to send/update ${category} monitors message:`, error);
}
}
async function clearChannel(channel) {
try {
const fetchedMessages = await channel.messages.fetch();
await channel.bulkDelete(fetchedMessages);
console.log('Cleared channel');
} catch (error) {
console.error('Error clearing channel:', error);
}
}
client.login(config.token).catch(error => {
console.error('Error logging in:', error);
});