'use strict'; const http = require('http'); const fs = require('fs'); const path = require('path'); // ── GameDig v4+ benötigt destructured import ────────────────────────────────── const { GameDig } = require('gamedig'); // ── Konfiguration ───────────────────────────────────────────────────────────── const CONFIG_PATH = path.join('/home/container', 'config.json'); const PORT = parseInt(process.env.SERVER_PORT || process.env.PORT || 21337, 10); const QUERY_INTERVAL = Math.max(10, parseInt(process.env.QUERY_INTERVAL || '60', 10)) * 1000; const API_KEY = process.env.API_KEY || ''; // ── Config laden ────────────────────────────────────────────────────────────── let servers = []; try { const raw = fs.readFileSync(CONFIG_PATH, 'utf8'); const cfg = JSON.parse(raw); servers = cfg.servers || []; console.log(`[INIT] config.json geladen – ${servers.length} Server konfiguriert.`); } catch (e) { console.error(`[FEHLER] config.json konnte nicht geladen werden: ${e.message}`); process.exit(1); } // ── Status-Cache ────────────────────────────────────────────────────────────── let cache = { updated: null, interval_seconds: QUERY_INTERVAL / 1000, servers: servers.map(s => ({ label: s.label, type: s.type, address: `${s.host}:${s.port}`, image: s.image || '', status: 'pending', players: 0, maxPlayers: 0, map: '', ping: 0 })) }; // ── GameDig Abfrage ─────────────────────────────────────────────────────────── async function queryServer(srv) { try { const opts = { type: srv.type, host: srv.host, port: srv.port, }; // DayZ: query port ist game port + 24714 if (srv.type === 'dayz' && !srv.queryPort) { opts.port = srv.queryPort || (srv.port + 24714); } if (srv.queryPort) { opts.port = srv.queryPort; } const state = await GameDig.query(opts); return { status: 'online', players: state.players ? state.players.length : 0, maxPlayers: state.maxplayers || 0, map: state.map || '', ping: state.ping || 0 }; } catch (err) { return { status: 'offline', error: err.message, players: 0, maxPlayers: 0, map: '', ping: 0 }; } } async function runQueries() { console.log(`[QUERY] Starte Abfragen (${servers.length} Server)...`); const start = Date.now(); const results = await Promise.all(servers.map(srv => queryServer(srv))); results.forEach((res, i) => { const srv = servers[i]; cache.servers[i] = { label: srv.label, type: srv.type, address: `${srv.host}:${srv.port}`, image: srv.image || '', ...res }; const icon = res.status === 'online' ? '✓' : '✗'; const info = res.status === 'online' ? `${res.players}/${res.maxPlayers} Spieler, ${res.ping}ms` : res.error || 'offline'; console.log(` ${icon} [${srv.label}] ${res.status} – ${info}`); }); cache.updated = new Date().toISOString(); console.log(`[QUERY] Abgeschlossen in ${Date.now() - start}ms.`); } // ── HTTP Server ─────────────────────────────────────────────────────────────── function checkAuth(req) { if (!API_KEY) return true; const headerKey = req.headers['x-api-key']; const urlKey = new URL(req.url, `http://localhost`).searchParams.get('key'); return headerKey === API_KEY || urlKey === API_KEY; } const server = http.createServer((req, res) => { const url = req.url.split('?')[0]; if (url === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', uptime: process.uptime() })); return; } if (url === '/api/servers') { if (!checkAuth(req)) { res.writeHead(401, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Unauthorized' })); return; } res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify(cache, null, 2)); return; } res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); }); server.listen(PORT, () => { console.log('╔══════════════════════════════════════════╗'); console.log('║ GameDig Server Status API ║'); console.log('╠══════════════════════════════════════════╣'); console.log(`║ Port: ${String(PORT).padEnd(29)}║`); console.log(`║ Interval: ${String(QUERY_INTERVAL/1000+'s').padEnd(29)}║`); console.log(`║ API-Key: ${(API_KEY ? 'aktiv' : 'deaktiviert').padEnd(29)}║`); console.log('║ GET /api/servers ║'); console.log('║ GET /health ║'); console.log('╚══════════════════════════════════════════╝'); // Erste Abfrage sofort, dann im Intervall runQueries(); setInterval(runQueries, QUERY_INTERVAL); });