test(websocket): connection-local overlay verification for browser-registered ops
Ported the alknet-http overlay verification to the channels-over-WS session (tests/ws_overlay_ops.rs, test-support feature, 8 tests): - overlay mechanism: browser-registered ops land in the connection's Layer 2 overlay (register_imported), exposed via overlay_env() — no PeerIds (browsers are not peers); PeerRef::Specific to a browser id routes to nothing (NOT_FOUND) - hub→browser call through compose_root_env's attached overlay - AccessControl on browser ops gates hub calls (scope match allows, missing scope FORBIDDEN) - overlay dies with the connection; no leak between connections; in-flight calls to browser ops resolve on close - wire-level: 10 interleaved concurrent calls across two WS sessions — no cross-correlation, no deadlock; disconnect mid-call resolves and a fresh session works (no listener wedge) byte_adapter: read_eof Notify now gated to the wss feature (its only consumer is from_wss) so a test-support-only build is warning-free. Verified: cargo test (182 lib), --all-features (227 lib + 5 MCP + 8 overlay + 10 WS integration), clippy -D warnings (default, test-support, all-features), fmt.
This commit is contained in:
@@ -33,10 +33,12 @@
|
||||
use std::{
|
||||
io,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "wss"))]
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::ws::{CloseFrame, Message as AxumMessage, WebSocket};
|
||||
use futures::channel::mpsc as futures_mpsc;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
@@ -81,6 +83,7 @@ pub struct WsByteStream {
|
||||
pub struct WsPumps {
|
||||
read_task: tokio::task::JoinHandle<()>,
|
||||
write_task: tokio::task::JoinHandle<()>,
|
||||
#[cfg(feature = "wss")]
|
||||
read_eof: Arc<tokio::sync::Notify>,
|
||||
}
|
||||
|
||||
@@ -93,6 +96,7 @@ impl WsPumps {
|
||||
/// Fires when the WS read side reaches EOF (socket close from either
|
||||
/// side) — used by `from_wss`'s connection-drop monitor to await
|
||||
/// socket EOF (ADR-070).
|
||||
#[cfg(feature = "wss")]
|
||||
pub(crate) async fn read_eof(&self) {
|
||||
self.read_eof.notified().await;
|
||||
}
|
||||
@@ -106,9 +110,11 @@ pub fn split_ws_to_bytes(socket: WebSocket) -> (WsByteStream, WsPumps) {
|
||||
let (read_tx, read_rx) = mpsc::channel::<Vec<u8>>(READ_SLOTS);
|
||||
let (write_tx, mut write_rx) = futures_mpsc::channel::<WriteMsg>(WRITE_SLOTS);
|
||||
|
||||
#[cfg(feature = "wss")]
|
||||
let read_eof = Arc::new(tokio::sync::Notify::new());
|
||||
|
||||
let write_tx_for_read = write_tx.clone();
|
||||
#[cfg(feature = "wss")]
|
||||
let read_eof_for_task = Arc::clone(&read_eof);
|
||||
let read_task = tokio::spawn(async move {
|
||||
while let Some(msg) = ws_stream.next().await {
|
||||
@@ -129,6 +135,7 @@ pub fn split_ws_to_bytes(socket: WebSocket) -> (WsByteStream, WsPumps) {
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wss")]
|
||||
read_eof_for_task.notify_waiters();
|
||||
});
|
||||
|
||||
@@ -184,6 +191,7 @@ pub fn split_ws_to_bytes(socket: WebSocket) -> (WsByteStream, WsPumps) {
|
||||
WsPumps {
|
||||
read_task,
|
||||
write_task,
|
||||
#[cfg(feature = "wss")]
|
||||
read_eof,
|
||||
},
|
||||
)
|
||||
@@ -367,6 +375,7 @@ where
|
||||
WsPumps {
|
||||
read_task,
|
||||
write_task,
|
||||
#[cfg(feature = "wss")]
|
||||
read_eof,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user