From d2edd90479abee88f5232af6fa451b00ece43653 Mon Sep 17 00:00:00 2001 From: Alexey <247128645+axkurcom@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:16:06 +0300 Subject: [PATCH] WEB: websocket + websocket-lanes as Carrier --- src/api/mod.rs | 9 +- src/api/web_status.rs | 141 ++-- src/api/web_status/details.rs | 86 +++ src/api/web_status/query.rs | 11 +- src/api/web_status/tests.rs | 6 +- src/config/hot_reload/tests.rs | 5 +- src/config/load/runtime_web.rs | 3 +- src/config/load/strict_keys.rs | 11 +- src/config/load/validate_web.rs | 9 + src/config/load/validate_web/debug.rs | 4 +- src/config/load/validate_web/memory.rs | 4 +- src/config/load/validate_web/websocket.rs | 83 +++ .../tests/load_basic_tests/web_tests.rs | 60 +- src/config/types.rs | 4 +- src/config/types/web.rs | 66 +- src/config/types/web_debug.rs | 5 +- src/maestro/generation.rs | 12 +- src/maestro/orchestrator.rs | 7 +- .../tests/send_adversarial_tests.rs | 4 +- src/web/bridge.rs | 118 +++- src/web/http.rs | 38 +- src/web/http/body.rs | 13 +- src/web/http/decoy.rs | 1 + src/web/http/down.rs | 3 + src/web/http/response.rs | 6 +- src/web/http/tests.rs | 5 +- src/web/http/websocket.rs | 461 +++++++++++++ src/web/http/websocket/driver.rs | 638 ++++++++++++++++++ src/web/http/websocket/tests.rs | 311 +++++++++ src/web/manager.rs | 156 +++-- src/web/manager/admission.rs | 22 +- src/web/manager/budget.rs | 366 ++++++++++ src/web/manager/lifecycle.rs | 19 +- src/web/manager/state.rs | 33 +- src/web/manager/websocket.rs | 313 +++++++++ src/web/manager/websocket/tests.rs | 40 ++ src/web/session.rs | 23 +- src/web/session/backend.rs | 85 ++- src/web/session/backend_tests.rs | 16 +- src/web/session/downlink.rs | 23 +- src/web/session/lanes.rs | 9 +- src/web/session/uplink.rs | 37 +- src/web/session/websocket.rs | 250 +++++++ src/web/session/websocket/tests.rs | 135 ++++ src/web/trace/exchange.rs | 44 +- src/web/trace/mod.rs | 4 +- src/web/trace/sanitize.rs | 7 +- src/web/trace/store.rs | 23 +- src/web/trace/store/websocket.rs | 220 ++++++ src/web/trace/types.rs | 43 ++ 50 files changed, 3642 insertions(+), 350 deletions(-) create mode 100644 src/api/web_status/details.rs create mode 100644 src/config/load/validate_web/websocket.rs create mode 100644 src/web/http/websocket.rs create mode 100644 src/web/http/websocket/driver.rs create mode 100644 src/web/http/websocket/tests.rs create mode 100644 src/web/manager/budget.rs create mode 100644 src/web/manager/websocket.rs create mode 100644 src/web/manager/websocket/tests.rs create mode 100644 src/web/session/websocket.rs create mode 100644 src/web/session/websocket/tests.rs create mode 100644 src/web/trace/store/websocket.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index cee3e82..7126f4f 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -499,12 +499,9 @@ async fn handle( let result: Result>, ApiFailure> = async { match (method.as_str(), normalized_path) { - ("GET", "/web-status") => Ok(web_status::render( - query.as_deref(), - &shared.web_trace, - &cfg.web.debug, - ) - .await), + ("GET", "/web-status") => { + Ok(web_status::render(query.as_deref(), &shared.web_trace, &cfg.web.debug).await) + } ("GET", "/v1/health") => { let revision = current_revision(&shared.config_path).await?; let data = HealthData { diff --git a/src/api/web_status.rs b/src/api/web_status.rs index bee469c..41ef777 100644 --- a/src/api/web_status.rs +++ b/src/api/web_status.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use std::sync::Arc; -use base64::Engine as _; use http_body_util::Full; use hyper::body::Bytes; use hyper::header::{self, HeaderValue}; @@ -9,16 +8,17 @@ use hyper::{Response, StatusCode}; use tokio::sync::OwnedSemaphorePermit; use crate::config::WebDebugConfig; -use crate::web::trace::{ - StoredTraceRecord, TraceRecord, TraceRecordKind, WebTraceStore, -}; +use crate::web::trace::{StoredTraceRecord, TraceRecord, TraceRecordKind, WebTraceStore}; const MAX_PAGE_BYTES: usize = 8 * 1024 * 1024; const MAX_GROUPS: usize = 1024; +// Record-detail rendering remains isolated from filtering and page layout. +mod details; // Query parsing and matching remain independent from bounded HTML rendering. mod query; +use details::{push_body, push_frames, push_headers}; use query::{GroupBy, StatusQuery, client_ip, parse_query, record_matches}; struct GroupSummary { @@ -119,11 +119,18 @@ fn push_page_start(html: &mut String) { fn push_filter_form(html: &mut String, query: &StatusQuery) { html.push_str("

Filters

"); input(html, "window_secs", &query.window_secs.to_string()); - input(html, "ip", &query.ip.map(|value| value.to_string()).unwrap_or_default()); + input( + html, + "ip", + &query.ip.map(|value| value.to_string()).unwrap_or_default(), + ); input( html, "session", - &query.session.map(|value| value.to_string()).unwrap_or_default(), + &query + .session + .map(|value| value.to_string()) + .unwrap_or_default(), ); input( html, @@ -133,7 +140,12 @@ fn push_filter_form(html: &mut String, query: &StatusQuery) { input(html, "key", query.key.as_deref().unwrap_or_default()); input(html, "limit", &query.limit.to_string()); html.push_str("