poc4 wit rust

This commit is contained in:
Mateusz Gruszczyński
2026-08-16 15:34:53 +02:00
parent e5d344622e
commit 40474cdc59
29 changed files with 2692 additions and 159 deletions
+33 -6
View File
@@ -20,7 +20,7 @@ import urllib.parse
from collections import defaultdict, deque
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from typing import Callable
from typing import Any, Callable
from .config import Config
from .auth import SessionAuth
@@ -122,6 +122,7 @@ class WebServer:
ndr_analyzer: NDRAnalyzer | None = None,
backup_manager: BackupManager | None = None,
forensic_pcap: ForensicPcapRing | None = None,
traffic_source: Any | None = None,
metrics_provider: Callable[[], str] | None = None,
) -> None:
self.config = config
@@ -137,6 +138,7 @@ class WebServer:
self.threat_intel = threat_intel
self.ndr_analyzer = ndr_analyzer
self.forensic_pcap = forensic_pcap
self.traffic_source = traffic_source
self.metrics_provider = metrics_provider
self.metrics_access = MetricsAccessControl(config) if metrics_provider is not None else None
self.backup_manager = backup_manager or BackupManager(config.db_path, os.path.dirname(config.db_path) or ".")
@@ -162,10 +164,30 @@ class WebServer:
def _analytics_payload(self, window_seconds: int) -> dict:
if self.analytics_cache is not None:
return self.analytics_cache.get(window_seconds)
if self.traffic_history is not None:
return self.traffic_history.analytics(window_seconds)
return {"window_seconds": window_seconds, "events": 0, "timeline": []}
payload = self.analytics_cache.get(window_seconds)
elif self.traffic_history is not None:
payload = self.traffic_history.analytics(window_seconds)
else:
payload = {"window_seconds": window_seconds, "events": 0, "timeline": []}
return self._overlay_current_throughput(payload, window_seconds)
def _overlay_current_throughput(self, payload: dict, window_seconds: int) -> dict:
source = self.traffic_source
if source is None or not hasattr(source, "overlay_current"):
return payload
try:
return source.overlay_current(payload, window_seconds)
except Exception:
return payload
def _current_throughput_payload(self, window_seconds: int) -> dict:
source = self.traffic_source
if source is None or not hasattr(source, "current_throughput"):
return {"window_seconds": window_seconds, "current_bps": 0}
try:
return source.current_throughput(window_seconds)
except Exception:
return {"window_seconds": window_seconds, "current_bps": 0}
def _login_allowed(self, client_ip: str) -> bool:
now = time.monotonic()
@@ -297,7 +319,8 @@ class WebServer:
query = urllib.parse.parse_qs(parsed.query)
window = self._query_int(query, "window", 3600, 60, config.traffic_retention_hours * 3600)
try:
self._json(traffic_history.throughput_analytics(window))
payload = traffic_history.throughput_analytics(window)
self._json(outer._overlay_current_throughput(payload, window))
except RedisUnavailableError as exc:
self._json({"error": f"Redis throughput history unavailable: {exc}"}, status=503)
return
@@ -778,6 +801,7 @@ class WebServer:
self._ws_send_json(bootstrap)
last_status = time.monotonic()
last_analytics = last_status
last_throughput = 0.0
while True:
if not self._ws_client_control():
return
@@ -819,6 +843,9 @@ class WebServer:
time.sleep(0.25)
now = time.monotonic()
if now - last_throughput >= 1:
self._ws_send_json({"type": "throughput", "data": outer._current_throughput_payload(window)})
last_throughput = now
if now - last_status >= 5:
self._ws_send_json({"type": "status", "data": outer._status_payload()})
last_status = now