Files
mc-bot/public/index.html
T
2026-08-22 11:09:05 -05:00

352 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Eaglercraft Load-Testing Dashboard</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div id="warning-banner">
<strong>FOR AUTHORIZED LOCAL TESTING ONLY</strong> — You must own the target server or have written permission to test.
Unauthorized use is illegal and unethical.
</div>
<header id="header">
<div class="header-left">
<h1>Eaglercraft Load Tester</h1>
<span class="subtitle">MC 1.12.2 (Protocol 340) — Eaglercraft WebSocket</span>
</div>
<div class="header-right">
<span id="status-indicator" class="status-dot idle"></span>
<span id="status-text">Idle</span>
<span id="uptime-text" class="uptime-text"></span>
</div>
</header>
<nav id="tab-nav">
<button class="tab-btn active" data-tab="test-control">Test Control</button>
<button class="tab-btn" data-tab="proxy-manager">Proxy Manager</button>
<button class="tab-btn" data-tab="logs">Connection Logs</button>
<button class="tab-btn" data-tab="stats">Server Stats</button>
</nav>
<div id="stats-bar">
<div class="stat-item">
<span class="stat-label">Active Bots</span>
<span class="stat-value" id="stat-active-bots">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Total Spawned</span>
<span class="stat-value" id="stat-total-spawned">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Handshakes OK</span>
<span class="stat-value" id="stat-handshakes-ok">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Failed</span>
<span class="stat-value" id="stat-failed">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Keep-Alives Sent</span>
<span class="stat-value" id="stat-keepalives">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Proxies (Alive/Dead)</span>
<span class="stat-value"><span id="stat-proxies-alive">0</span>/<span id="stat-proxies-dead">0</span></span>
</div>
<div class="stat-item">
<span class="stat-label">Avg Score</span>
<span class="stat-value" id="stat-avg-score"></span>
</div>
</div>
<main id="tab-content">
<section id="tab-test-control" class="tab-panel active">
<div class="panel-grid">
<div class="panel card">
<h2>Launch Load Test</h2>
<div class="form-group">
<label for="target-url">Target WebSocket URL</label>
<input type="text" id="target-url" placeholder="ws://your-server.com:8081" />
<span class="input-help">Eaglercraft servers use ws:// or wss:// (e.g., ws://localhost:8081)</span>
</div>
<div class="form-group">
<label for="bot-count">Number of Bots: <span id="bot-count-display">10</span></label>
<input type="range" id="bot-count" min="1" max="500" value="10" />
</div>
<div class="form-group">
<label for="spawn-delay">Spawn Delay (ms between bots): <span id="spawn-delay-display">200</span></label>
<input type="range" id="spawn-delay" min="0" max="5000" step="50" value="200" />
<span class="input-help">Time to wait between spawning each bot. 0ms = all at once, 200ms = staggered (recommended).</span>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="stay-connected" />
Keep bots connected after messages (don't auto-disconnect)
</label>
</div>
<div class="form-group">
<label for="username-prefix">Username Prefix</label>
<input type="text" id="username-prefix" value="TestBot" placeholder="TestBot" />
</div>
<div class="form-group">
<label for="bot-password">Bot Password (for /register and /login)</label>
<input type="text" id="bot-password" value="password123" placeholder="password123" />
</div>
<div class="form-group">
<label for="chat-messages">Chat Messages (one per line, sent after login)</label>
<textarea id="chat-messages" rows="4" placeholder="Hello!&#10;I just joined the server&#10;Nice server!"></textarea>
<span class="input-help">Each message sent 1.5s apart, starting after auth completes.</span>
</div>
<div class="form-group">
<label for="proxy-strategy">Proxy Strategy</label>
<select id="proxy-strategy">
<option value="best-score">Best Score (weighted)</option>
<option value="random">Random</option>
<option value="round-robin">Round Robin</option>
<option value="least-used">Least Used</option>
</select>
<span class="input-help">How bots pick from the proxy pool. Best-score favors healthy proxies.</span>
</div>
<div class="button-row">
<button id="btn-start-test" class="btn btn-primary">Run Load Test</button>
<button id="btn-stop-test" class="btn btn-danger">Stop Test</button>
<button id="btn-reset" class="btn btn-secondary" title="Force-reset if state is stuck">Force Reset</button>
</div>
</div>
<div class="panel card">
<h2>
Active Bots <span class="badge badge-info" id="active-bot-count-badge">0</span>
<button id="btn-bot-controls" class="btn btn-secondary btn-small" style="margin-left:12px;">Bot Controls</button>
</h2>
<div class="table-container" id="bots-table-container">
<table id="bots-table">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Proxy</th>
<th>State</th>
<th>Packets</th>
<th>Uptime</th>
<th>Action</th>
</tr>
</thead>
<tbody id="bots-table-body">
<tr><td colspan="7" class="empty-row">No bots running</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
<section id="tab-proxy-manager" class="tab-panel">
<div class="panel-grid">
<div class="panel card">
<h2>Upload Proxy List</h2>
<p class="help-text">
Enter one proxy per line. Supported formats:<br>
<code>socks4://host:port</code> &middot;
<code>socks5://host:port</code> &middot;
<code>socks5://user:pass@host:port</code><br>
Validation probes 8.8.8.8:53 by default; switch to "probe target" to test against the active test target.<br>
<strong>Note:</strong> Bot traffic is routed through alive proxies automatically.
</p>
<div class="form-group">
<textarea id="proxy-input" rows="10" placeholder="socks5://1.2.3.4:1080&#10;socks4://5.6.7.8:1080&#10;socks5://user:pass@9.10.11.12:1080"></textarea>
</div>
<div class="button-row">
<button id="btn-validate-proxies" class="btn btn-primary">Validate &amp; Import Proxies</button>
<button id="btn-clear-dead" class="btn btn-warning">Clear Dead Proxies</button>
<button id="btn-retest-all" class="btn btn-secondary">Re-Test All</button>
<button id="btn-retest-target" class="btn btn-secondary">Re-Test vs Target</button>
</div>
<div id="proxy-import-result" class="result-box hidden"></div>
</div>
<div class="panel card">
<h2>
Proxy Pool <span class="badge badge-info" id="proxy-count-badge">0</span>
<span class="badge badge-info" id="proxy-stats-badge">avg: —</span>
</h2>
<div class="filter-row">
<input type="text" id="proxy-search" placeholder="Filter by host…" />
<select id="proxy-status-filter">
<option value="">All</option>
<option value="alive">Alive</option>
<option value="dead">Dead</option>
<option value="degraded">Degraded</option>
<option value="unknown">Unknown</option>
</select>
<select id="proxy-sort">
<option value="added">Sort: Added</option>
<option value="score">Sort: Score</option>
<option value="latency">Sort: Latency</option>
</select>
</div>
<div class="table-container" id="proxy-table-container">
<table id="proxy-table">
<thead>
<tr>
<th>#</th>
<th>Address</th>
<th>Type</th>
<th>Status</th>
<th>Score</th>
<th>Latency</th>
<th>Last Tested</th>
<th>Action</th>
</tr>
</thead>
<tbody id="proxy-table-body">
<tr><td colspan="8" class="empty-row">No proxies loaded</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
<section id="tab-logs" class="tab-panel">
<div class="panel card full-width">
<div class="log-header">
<h2>Connection Logs</h2>
<div class="button-row">
<button id="btn-clear-logs" class="btn btn-warning">Clear Logs</button>
<label class="checkbox-label">
<input type="checkbox" id="auto-scroll-logs" checked />
Auto-scroll
</label>
<label class="checkbox-label">
<input type="checkbox" id="filter-info" checked /> Info
</label>
<label class="checkbox-label">
<input type="checkbox" id="filter-warn" checked /> Warn
</label>
<label class="checkbox-label">
<input type="checkbox" id="filter-error" checked /> Error
</label>
<label class="checkbox-label">
<input type="checkbox" id="filter-success" checked /> Success
</label>
</div>
</div>
<input type="text" id="log-search" placeholder="Filter logs by message…" />
<div id="log-console" class="log-console">
<div class="log-empty">Logs will appear here when a test is running.</div>
</div>
</div>
</section>
<section id="tab-stats" class="tab-panel">
<div class="panel-grid stats-grid">
<div class="card stat-card">
<div class="stat-card-label">Active Connections</div>
<div class="stat-card-value" id="stat2-active-bots">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Successful Logins</div>
<div class="stat-card-value" id="stat2-handshakes-ok">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Connection Failures</div>
<div class="stat-card-value" id="stat2-failed">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Total Keep-Alives</div>
<div class="stat-card-value" id="stat2-keepalives">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Alive Proxies</div>
<div class="stat-card-value" id="stat2-proxies-alive">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Dead Proxies</div>
<div class="stat-card-value" id="stat2-proxies-dead">0</div>
</div>
<div class="card stat-card">
<div class="stat-card-label">Avg Proxy Score</div>
<div class="stat-card-value" id="stat2-avg-score"></div>
</div>
<div class="card stat-card">
<div class="stat-card-label">P95 Latency</div>
<div class="stat-card-value" id="stat2-p95-latency"></div>
</div>
<div class="card stat-card wide">
<div class="stat-card-label">Target Server</div>
<div class="stat-card-value" id="stat2-target">None</div>
</div>
<div class="card stat-card wide">
<div class="stat-card-label">Test Status</div>
<div class="stat-card-value" id="stat2-status">Idle</div>
</div>
<div class="card stat-card wide">
<div class="stat-card-label">Memory (RSS)</div>
<div class="stat-card-value" id="stat2-memory"></div>
</div>
<div class="card stat-card wide">
<div class="stat-card-label">Uptime</div>
<div class="stat-card-value" id="stat2-uptime"></div>
</div>
<div class="card stat-card wide">
<div class="stat-card-label">Protocol Info</div>
<div class="stat-card-value protocol-info">MC 1.12.2 &middot; Protocol 340 &middot; VarInt-Length-Framed Packets &middot; Compression-Aware</div>
</div>
</div>
</section>
</main>
<div id="bot-controls-panel" class="side-panel">
<div class="side-panel-header">
<h3>Bot Controls</h3>
<button id="btn-close-controls" class="btn btn-secondary btn-small">&times;</button>
</div>
<div class="side-panel-body">
<div class="form-group">
<label>Send Chat to All Bots</label>
<div style="display:flex;gap:8px;">
<input type="text" id="live-chat-input" placeholder="Type a message..." style="flex:1;" />
<button id="btn-send-chat" class="btn btn-primary">Send</button>
</div>
</div>
<div class="form-group">
<label>Quick Commands</label>
<div class="button-row" id="quick-commands-row" style="flex-direction:column;">
</div>
</div>
<div class="form-group">
<label>Connected Bots</label>
<div id="controls-bot-list" class="table-container" style="max-height:300px;">
<div class="empty-row">No bots connected</div>
</div>
</div>
</div>
</div>
<div id="bot-controls-overlay" class="side-panel-overlay"></div>
<div id="bot-inspector" class="side-panel">
<div class="side-panel-header">
<h3 id="bot-inspector-title">Bot Inspector</h3>
<button id="btn-close-inspector" class="btn btn-secondary btn-small">&times;</button>
</div>
<div class="side-panel-body" id="bot-inspector-body">
</div>
</div>
<div id="bot-inspector-overlay" class="side-panel-overlay"></div>
<footer id="footer">
Eaglercraft Load-Testing Dashboard v2.0 &mdash; MC 1.12.2 &middot; For authorized local testing only.
</footer>
<script src="/socket.io/socket.io.js"></script>
<script src="/client.js"></script>
</body>
</html>