'use strict'; const { GameDig } = require('gamedig'); const http = require('http'); const fs = require('fs'); const path = require('path'); // ─── Konfiguration ──────────────────────────────────────────────────────────── const CONFIG_PATH = path.join('/home/container', 'config.json'); const PORT = parseInt(process.env.SERVER_PORT || '3000', 10); const INTERVAL_SEC = parseInt(process.env.QUERY_INTERVAL || '60', 10); const API_KEY = process.env.API_KEY || ''; // ─── Config laden ───────────────────────────────────────────────────────────── let config; try { config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')); console.log(`[INIT] config.json geladen – ${config.servers.length} Server konfiguriert.`); } catch (e) { console.error(`[FEHLER] config.json konnte nicht gelesen werden: ${e.message}`); console.error(`[FEHLER] Bitte config.json im Pterodactyl-Dateimanager anlegen.`); process.exit(1); } // ─── Cache ──────────────────────────────────────────────────────────────────── let cache = { updated: null, interval_seconds: INTERVAL_SEC, servers: [] }; // ─── Server-Abfrage ─────────────────────────────────────────────────────────── async function queryAll() { const start = Date.now(); console.log(`[QUERY] Starte Abfragen (${config.servers.length} Server)...`); const results = await Promise.all( config.servers.map(async (s) => { try { const state = await GameDig.query({ type: s.type, host: s.host, port: s.port, requestRules: s.type === 'dayz', socketTimeout: 5000, }); console.log(` ✓ [${s.label}] online – ${state.numplayers}/${state.maxplayers} Spieler`); return { label: s.label, type: s.type, address: `${s.host}:${s.port}`, image: s.image || null, status: 'online', players: state.numplayers, maxPlayers: state.maxplayers, map: state.map || null, name: state.name || null, ping: state.ping || null, connect: state.connect || null, }; } catch (err) { console.log(` ✗ [${s.label}] offline – ${err.message}`); return { label: s.label, type: s.type, address: `${s.host}:${s.port}`, image: s.image || null, status: 'offline', error: err.message, }; } }) ); cache = { updated: new Date().toISOString(), interval_seconds: INTERVAL_SEC, servers: results, }; console.log(`[QUERY] Abgeschlossen in ${Date.now() - start}ms.`); } // ─── Auth-Prüfung ───────────────────────────────────────────────────────────── function checkAuth(req) { if (!API_KEY) return true; const headerKey = req.headers['x-api-key']; if (headerKey && headerKey === API_KEY) return true; const url = new URL(req.url, `http://localhost`); const queryKey = url.searchParams.get('key'); if (queryKey && queryKey === API_KEY) return true; return false; } // ─── HTTP Server ────────────────────────────────────────────────────────────── const server = http.createServer((req, res) => { const url = new URL(req.url, `http://localhost`); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Content-Type', 'application/json'); // Health-Endpoint (kein Auth erforderlich) if (url.pathname === '/health') { res.writeHead(200); res.end(JSON.stringify({ status: 'ok', updated: cache.updated })); return; } // API-Endpoint if (url.pathname === '/api/servers') { if (!checkAuth(req)) { res.writeHead(401); res.end(JSON.stringify({ error: 'Unauthorized', hint: 'X-API-Key Header oder ?key= Parameter erforderlich.' })); return; } if (!cache.updated) { res.writeHead(503); res.end(JSON.stringify({ error: 'Noch keine Daten verfügbar. Bitte kurz warten.' })); return; } res.writeHead(200); res.end(JSON.stringify(cache, null, 2)); return; } // 404 res.writeHead(404); res.end(JSON.stringify({ error: 'Nicht gefunden.', endpoints: ['/api/servers', '/health'] })); }); // ─── Start ──────────────────────────────────────────────────────────────────── server.listen(PORT, () => { console.log(''); console.log('╔══════════════════════════════════════════╗'); console.log('║ GameDig Server Status API ║'); console.log('╠══════════════════════════════════════════╣'); console.log(`║ Port: ${String(PORT).padEnd(29)}║`); console.log(`║ Interval: ${String(INTERVAL_SEC + 's').padEnd(29)}║`); console.log(`║ API-Key: ${(API_KEY ? 'aktiv' : 'deaktiviert').padEnd(29)}║`); console.log(`║ GET /api/servers${' '.repeat(24)}║`); console.log(`║ GET /health${' '.repeat(29)}║`); console.log('╚══════════════════════════════════════════╝'); console.log(''); queryAll(); setInterval(queryAll, INTERVAL_SEC * 1000); }); // ─── Graceful Shutdown ──────────────────────────────────────────────────────── process.on('SIGTERM', () => { console.log('[INFO] SIGTERM empfangen, Server wird beendet...'); server.close(() => process.exit(0)); });