352 lines
15 KiB
HTML
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! I just joined the server 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> ·
|
|
<code>socks5://host:port</code> ·
|
|
<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 socks4://5.6.7.8:1080 socks5://user:pass@9.10.11.12:1080"></textarea>
|
|
</div>
|
|
<div class="button-row">
|
|
<button id="btn-validate-proxies" class="btn btn-primary">Validate & 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 · Protocol 340 · VarInt-Length-Framed Packets · 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">×</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">×</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 — MC 1.12.2 · For authorized local testing only.
|
|
</footer>
|
|
|
|
<script src="/socket.io/socket.io.js"></script>
|
|
<script src="/client.js"></script>
|
|
</body>
|
|
</html>
|