feat(websocket): WS upgrade route + channels session (server producer half)

- src/websocket/byte_adapter.rs: production WsByteStream from the POC —
  inbound bounded mpsc (64 slots, backpressure), outbound chunk parser
  emitting one WS message per chunk with 1 MiB split; write-side
  backpressure now uses futures mpsc poll_ready (POC spin-wait fixed);
  text messages closed with 1002; close mapping per websocket.md
- src/websocket/upgrade.rs: /alk/channels upgrade route — bearer auth
  (401 unresolvable), identity attached to the channels Connection,
  ChannelsAdapter + install_channel_zero running
  Dispatcher::run_loop_single_stream
- test_support module (feature test-support): WsClient, chunk/frame
  assemblers; shared with from_wss consumer path (ADR-070)
- tests/ws_upgrade_session.rs: 10 integration tests — call round-trip,
  services/list ACL-filtered, 3 MiB split, interleaved calls, ACL 403,
  internal-op NOT_FOUND, text->1002 close, disconnect mid-call no-hang

Verified: cargo test (95), cargo test --all-features (95+10),
clippy -D warnings (default + all-features), fmt.
This commit is contained in:
2026-08-28 08:47:13 +00:00
parent 0c1de05f85
commit 4ba9b652b3
6 changed files with 1262 additions and 9 deletions
+7 -1
View File
@@ -17,6 +17,7 @@ name = "alkhttp"
default = ["h2", "http1"]
mcp = ["dep:rmcp"]
wss = ["dep:tokio-tungstenite"]
test-support = ["dep:tokio-tungstenite"]
h2 = ["dep:hyper", "hyper-util/http2", "hyper/http2"]
http1 = ["dep:hyper", "hyper-util/http1", "hyper/http1"]
@@ -54,4 +55,9 @@ rmcp = { version = "1.8", optional = true, default-features = false, features =
[dev-dependencies]
http-body-util = "0.1"
tower = { version = "0.5", features = ["util"] }
tower = { version = "0.5", features = ["util"] }
tokio-tungstenite = "0.28"
[[test]]
name = "ws_upgrade_session"
required-features = ["test-support"]