From 32b378f539062eae3498180004aa7d10fbe701f3 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Apr 2026 15:41:57 +0000 Subject: [PATCH] fix: Use Pterodactyl API directly instead of servers-api Worker Worker was returning HTML error page. Now queries Pterodactyl panel directly using PTERO_CLIENT_KEY from .env. Chronicler #75 --- .../src/services/serverStatusPoller.js | 76 +++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/services/arbiter-3.0/src/services/serverStatusPoller.js b/services/arbiter-3.0/src/services/serverStatusPoller.js index b780fe1..8d0aaa9 100644 --- a/services/arbiter-3.0/src/services/serverStatusPoller.js +++ b/services/arbiter-3.0/src/services/serverStatusPoller.js @@ -14,8 +14,9 @@ const db = require('../database'); const DISCORD_API = 'https://discord.com/api/v10'; const DISCORD_TOKEN = process.env.DISCORD_BOT_TOKEN; -// Servers API (Cloudflare Worker that proxies Pterodactyl) -const SERVERS_API = 'https://servers-api.firefrostgaming.workers.dev'; +// Pterodactyl API (direct, not via Worker) +const PTERO_URL = process.env.PTERO_PANEL_URL || 'https://panel.firefrostgaming.com'; +const PTERO_KEY = process.env.PTERO_CLIENT_KEY; // Map server names to their status channel IDs // Key: lowercase server name (from Pterodactyl) @@ -172,6 +173,72 @@ function findChannelForServer(serverName) { return null; } +/** + * Fetch servers from Pterodactyl API + */ +async function fetchServers() { + if (!PTERO_KEY) { + console.error('[StatusPoller] PTERO_CLIENT_KEY not set'); + return []; + } + + try { + // Get server list + const listResponse = await axios.get(`${PTERO_URL}/api/client`, { + headers: { + 'Authorization': `Bearer ${PTERO_KEY}`, + 'Accept': 'application/json' + } + }); + + const serverList = listResponse.data.data || []; + const servers = []; + + // Get status for each server + for (const server of serverList) { + const id = server.attributes.identifier; + const name = server.attributes.name; + + try { + const statsResponse = await axios.get( + `${PTERO_URL}/api/client/servers/${id}/resources`, + { + headers: { + 'Authorization': `Bearer ${PTERO_KEY}`, + 'Accept': 'application/json' + } + } + ); + + const isRunning = statsResponse.data.attributes?.current_state === 'running'; + + servers.push({ + id: id, + name: name, + status: isRunning ? 'Online' : 'Offline', + players: isRunning ? (statsResponse.data.attributes?.resources?.players || 0) : 0 + }); + } catch (err) { + // Server might be inaccessible + servers.push({ + id: id, + name: name, + status: 'Unknown', + players: 0 + }); + } + + // Rate limiting + await new Promise(resolve => setTimeout(resolve, 200)); + } + + return servers; + } catch (err) { + console.error('[StatusPoller] Pterodactyl API error:', err.message); + return []; + } +} + /** * Poll all servers and update Discord status messages */ @@ -179,9 +246,7 @@ async function pollAndUpdate() { console.log('[StatusPoller] Polling server status...'); try { - // Fetch server status from Cloudflare Worker - const response = await axios.get(SERVERS_API); - const servers = response.data.servers || []; + const servers = await fetchServers(); console.log(`[StatusPoller] Got ${servers.length} servers`); @@ -230,6 +295,7 @@ function start(intervalMinutes = 5) { module.exports = { init, + fetchServers, pollAndUpdate, start, findChannelForServer,