Autarch Will Control The Internet
This commit is contained in:
144
web/routes/loadtest.py
Normal file
144
web/routes/loadtest.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""Load testing web routes — start/stop/monitor load tests from the web UI."""
|
||||
|
||||
import json
|
||||
import queue
|
||||
from flask import Blueprint, render_template, request, jsonify, Response
|
||||
from web.auth import login_required
|
||||
|
||||
loadtest_bp = Blueprint('loadtest', __name__, url_prefix='/loadtest')
|
||||
|
||||
|
||||
@loadtest_bp.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
return render_template('loadtest.html')
|
||||
|
||||
|
||||
@loadtest_bp.route('/start', methods=['POST'])
|
||||
@login_required
|
||||
def start():
|
||||
"""Start a load test."""
|
||||
data = request.get_json(silent=True) or {}
|
||||
target = data.get('target', '').strip()
|
||||
if not target:
|
||||
return jsonify({'ok': False, 'error': 'Target is required'})
|
||||
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
|
||||
if tester.running:
|
||||
return jsonify({'ok': False, 'error': 'A test is already running'})
|
||||
|
||||
config = {
|
||||
'target': target,
|
||||
'attack_type': data.get('attack_type', 'http_flood'),
|
||||
'workers': int(data.get('workers', 10)),
|
||||
'duration': int(data.get('duration', 30)),
|
||||
'requests_per_worker': int(data.get('requests_per_worker', 0)),
|
||||
'ramp_pattern': data.get('ramp_pattern', 'constant'),
|
||||
'ramp_duration': int(data.get('ramp_duration', 0)),
|
||||
'method': data.get('method', 'GET'),
|
||||
'headers': data.get('headers', {}),
|
||||
'body': data.get('body', ''),
|
||||
'timeout': int(data.get('timeout', 10)),
|
||||
'follow_redirects': data.get('follow_redirects', True),
|
||||
'verify_ssl': data.get('verify_ssl', False),
|
||||
'rotate_useragent': data.get('rotate_useragent', True),
|
||||
'custom_useragent': data.get('custom_useragent', ''),
|
||||
'rate_limit': int(data.get('rate_limit', 0)),
|
||||
'payload_size': int(data.get('payload_size', 1024)),
|
||||
}
|
||||
|
||||
tester.start(config)
|
||||
return jsonify({'ok': True, 'message': 'Test started'})
|
||||
except Exception as e:
|
||||
return jsonify({'ok': False, 'error': str(e)})
|
||||
|
||||
|
||||
@loadtest_bp.route('/stop', methods=['POST'])
|
||||
@login_required
|
||||
def stop():
|
||||
"""Stop the running load test."""
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
tester.stop()
|
||||
return jsonify({'ok': True})
|
||||
except Exception as e:
|
||||
return jsonify({'ok': False, 'error': str(e)})
|
||||
|
||||
|
||||
@loadtest_bp.route('/pause', methods=['POST'])
|
||||
@login_required
|
||||
def pause():
|
||||
"""Pause the running load test."""
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
tester.pause()
|
||||
return jsonify({'ok': True})
|
||||
except Exception as e:
|
||||
return jsonify({'ok': False, 'error': str(e)})
|
||||
|
||||
|
||||
@loadtest_bp.route('/resume', methods=['POST'])
|
||||
@login_required
|
||||
def resume():
|
||||
"""Resume a paused load test."""
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
tester.resume()
|
||||
return jsonify({'ok': True})
|
||||
except Exception as e:
|
||||
return jsonify({'ok': False, 'error': str(e)})
|
||||
|
||||
|
||||
@loadtest_bp.route('/status')
|
||||
@login_required
|
||||
def status():
|
||||
"""Get current test status and metrics."""
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
metrics = tester.metrics.to_dict() if tester.running else {}
|
||||
return jsonify({
|
||||
'running': tester.running,
|
||||
'paused': not tester._pause_event.is_set() if tester.running else False,
|
||||
'metrics': metrics,
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'running': False, 'error': str(e)})
|
||||
|
||||
|
||||
@loadtest_bp.route('/stream')
|
||||
@login_required
|
||||
def stream():
|
||||
"""SSE stream for live metrics."""
|
||||
try:
|
||||
from modules.loadtest import get_load_tester
|
||||
tester = get_load_tester()
|
||||
except Exception:
|
||||
return Response("data: {}\n\n", mimetype='text/event-stream')
|
||||
|
||||
sub = tester.subscribe()
|
||||
|
||||
def generate():
|
||||
try:
|
||||
while tester.running:
|
||||
try:
|
||||
data = sub.get(timeout=2)
|
||||
yield f"data: {json.dumps(data)}\n\n"
|
||||
except queue.Empty:
|
||||
# Send keepalive
|
||||
m = tester.metrics.to_dict() if tester.running else {}
|
||||
yield f"data: {json.dumps({'type': 'metrics', 'data': m})}\n\n"
|
||||
# Send final metrics
|
||||
m = tester.metrics.to_dict()
|
||||
yield f"data: {json.dumps({'type': 'done', 'data': m})}\n\n"
|
||||
finally:
|
||||
tester.unsubscribe(sub)
|
||||
|
||||
return Response(generate(), mimetype='text/event-stream',
|
||||
headers={'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no'})
|
||||
Reference in New Issue
Block a user