Buckets:

knoxius/storage / webconsole.js
Nodiw52992's picture
download
raw
6.12 kB
'use strict';
const http = require('http');
const fs = require('fs');
const path = require('path');
const { spawn, exec } = require('child_process');
const httpProxy = require('http-proxy');
const LOG_FILE = path.join(__dirname, 'logs', 'latest.log');
const MC_PORT = 25566; // EaglerXServer internal WS port
const WEB_PORT = 7860; // Exposed port
// ── Banner ────────────────────────────────────────────────────────────────────
console.log('=========================================');
console.log(' Eaglercraft Server + Web Console ');
console.log('=========================================');
// ── Start Minecraft ───────────────────────────────────────────────────────────
const mcProcess = spawn('java', [
'-Xms2G', '-Xmx2G',
'-XX:+UseG1GC',
'-jar', 'server.jar', 'nogui'
], { cwd: __dirname });
const logStream = fs.createWriteStream(LOG_FILE, { flags: 'w' });
mcProcess.stdout.pipe(logStream, { end: false });
mcProcess.stderr.pipe(logStream, { end: false });
mcProcess.stdout.pipe(process.stdout);
mcProcess.stderr.pipe(process.stderr);
mcProcess.on('exit', (code) => {
console.log(`[MC] Server process exited with code ${code}`);
logStream.end();
});
// ── WebSocket Proxy ───────────────────────────────────────────────────────────
const proxy = httpProxy.createProxyServer({
target: `ws://127.0.0.1:${MC_PORT}`,
ws: true
});
proxy.on('error', (err, req, socket) => {
console.warn('[Proxy] Routing error (server may still be booting):', err.message);
if (socket && socket.writable) socket.destroy();
});
// ── HTML Page ─────────────────────────────────────────────────────────────────
const PAGE_HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Eaglercraft Console</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #1e1e1e; color: #d4d4d4;
font-family: 'Consolas', monospace;
display: flex; flex-direction: column;
height: 100vh; padding: 16px; gap: 12px;
}
h2 { color: #569cd6; font-size: 1.1rem; }
#logs {
flex: 1; overflow-y: auto; white-space: pre-wrap; word-break: break-all;
background: #0d0d0d; padding: 12px;
border: 1px solid #333; border-radius: 4px;
font-size: 0.82rem; line-height: 1.45;
}
form { display: flex; gap: 8px; }
input[type=text] {
flex: 1; padding: 9px 12px;
background: #2d2d2d; color: #fff;
border: 1px solid #444; border-radius: 4px; font-family: inherit;
}
button {
padding: 9px 20px; background: #0e639c; color: #fff;
border: none; border-radius: 4px; cursor: pointer; font-family: inherit;
}
button:hover { background: #1177bb; }
</style>
</head>
<body>
<h2>&#9654; Eaglercraft Live Console</h2>
<div id="logs">Connecting to server log…</div>
<form action="/command" method="POST" target="_blank"
onsubmit="setTimeout(()=>this.reset(),10)">
<input type="text" name="cmd"
placeholder="e.g. op YourName | say Hello!"
autocomplete="off" autofocus>
<button type="submit">Send</button>
</form>
<script>
const logs = document.getElementById('logs');
let last = '';
async function poll() {
try {
const t = await fetch('/logs').then(r => r.text());
if (t !== last) {
last = t;
const atBottom =
logs.scrollHeight - logs.clientHeight <= logs.scrollTop + 60;
logs.textContent = t;
if (atBottom) logs.scrollTop = logs.scrollHeight;
}
} catch(_) {}
setTimeout(poll, 1000);
}
poll();
</script>
</body>
</html>`;
// ── HTTP Server ───────────────────────────────────────────────────────────────
const server = http.createServer((req, res) => {
// ── GET / → console page
if (req.method === 'GET' && req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(PAGE_HTML);
}
// ── GET /logs → last 200 lines of log
if (req.method === 'GET' && req.url === '/logs') {
exec(`tail -n 200 "${LOG_FILE}"`, (err, stdout) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(stdout || '(Waiting for server output…)');
});
return;
}
// ── POST /command → write to MC stdin
if (req.method === 'POST' && req.url === '/command') {
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', () => {
const cmd = new URLSearchParams(body).get('cmd') || '';
const safe = cmd.trim().replace(/[\r\n]+/g, ''); // no newline injection
if (safe && mcProcess.stdin.writable) {
mcProcess.stdin.write(safe + '\n');
console.log(`[Console] Command sent: ${safe}`);
}
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('ok');
});
return;
}
res.writeHead(404);
res.end('Not found');
});
// ── Upgrade → proxy WebSocket to Eaglercraft
server.on('upgrade', (req, socket, head) => {
console.log(`[Proxy] WS upgrade from ${socket.remoteAddress} → MC:${MC_PORT}`);
proxy.ws(req, socket, head);
});
server.listen(WEB_PORT, '0.0.0.0', () => {
console.log(`[WebConsole] Listening on http://0.0.0.0:${WEB_PORT}`);
});

Xet Storage Details

Size:
6.12 kB
·
Xet hash:
d992d36e79a1c66f2949a0bfd4068251744b654f3551e3baef53a9be2e65eade

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.