const express = require('express'); const { promisify } = require('util'); const { exec } = require('child_process'); const rateLimit = require('express-rate-limit'); const app = express(); const port = 3066; require('dotenv').config(); const execPromise = promisify(exec); // Custom key generator to support Cloudflare's CF-Connecting-IP header const getClientIp = (req) => { return req.headers['cf-connecting-ip'] || req.ip; }; // Rate limiter configuration: 1 request per second with exponential backoff const limiter = rateLimit({ windowMs: 1000, // 1 second max: 1, // 1 request per IP standardHeaders: true, // Return rate limit info in headers legacyHeaders: false, // Disable X-RateLimit headers keyGenerator: getClientIp, // Use CF-Connecting-IP or fallback to req.ip handler: (req, res) => { // Calculate backoff time (exponential, starting at 2 seconds) const retryAfter = Math.pow(2, Math.min(req.rateLimit.current - req.rateLimit.limit, 5)); res.setHeader('Retry-After', retryAfter); res.status(429).json({ error: 'Too many requests, please try again later.', retryAfter: retryAfter }); } }); // Apply rate limiting to API routes only app.use('/java', limiter); app.use('/bedrock', limiter); async function checkConnectionStatus(hostname, port) { try { const command = `${process.env.STATUS_CHECK_PATH} -host ${hostname} -port ${port}`; const { stdout, stderr } = await execPromise(command); if (stderr) { return { isOnline: false, error: stderr }; } const data = JSON.parse(stdout); return { isOnline: true, data }; } catch (error) { return { isOnline: false, error: error.message }; } } async function checkGeyserStatus(hostname, port) { try { const command = `${process.env.GEYSER_STATUS_CHECK_PATH} -host ${hostname} -port ${port}`; const { stdout, stderr } = await execPromise(command); if (stderr) { return { isOnline: false, error: stderr }; } const data = JSON.parse(stdout); return { isOnline: true, data }; } catch (error) { return { isOnline: false, error: error.message }; } } app.use(express.static('public')); app.get('/', (req, res) => { res.sendFile(__dirname + '/public/index.html'); }); app.get('/java/:host/:port', async (req, res) => { const { host, port } = req.params; try { const result = await checkConnectionStatus(host, port); res.json(result); } catch (error) { res.status(500).json({ isOnline: false, error: `Server error: ${error.message}` }); } }); app.get('/bedrock/:host/:port', async (req, res) => { const { host, port } = req.params; try { const result = await checkGeyserStatus(host, port); console.log(result); res.json(result); } catch (error) { res.status(500).json({ isOnline: false, error: `Server error: ${error.message}` }); } }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); });