From 0e505ae4927eac82410e83a250cc809aee830cbc Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 03:25:29 -0700 Subject: [PATCH 1/2] chore(quest): claim quest/m1/net-internals.md Quest-Claim: 4f7e6ca734d3ab2d From 9d67265332f1b47e2617dce789c524d3f628f649 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 04:14:37 -0700 Subject: [PATCH 2/2] perf(net): borrow group transports and erase private parameters Co-Authored-By: GPT-6 --- bench/README.md | 10 + quest/m1/README.md | 1 - quest/m1/net-internals.md | 27 - quest/m2/wire-fuzz-coverage.md | 1 - rs/moq-net/src/driver.rs | 2 +- rs/moq-net/src/ietf/adapter.rs | 134 ++- rs/moq-net/src/ietf/auth.rs | 29 +- rs/moq-net/src/ietf/publisher.rs | 1138 ++++++++++++++-------- rs/moq-net/src/ietf/publisher/tracks.rs | 105 +- rs/moq-net/src/ietf/request_stream.rs | 88 +- rs/moq-net/src/ietf/request_update.rs | 4 +- rs/moq-net/src/ietf/session.rs | 229 +++-- rs/moq-net/src/ietf/subscriber.rs | 726 ++++++++------ rs/moq-net/src/ietf/subscriber/tracks.rs | 181 ++-- rs/moq-net/src/ietf/token.rs | 6 +- rs/moq-net/src/lite/error.rs | 4 +- rs/moq-net/src/lite/publisher.rs | 732 ++++++++------ rs/moq-net/src/lite/session.rs | 169 ++-- rs/moq-net/src/lite/setup.rs | 24 +- rs/moq-net/src/lite/subscriber.rs | 509 +++++----- rs/moq-net/src/server.rs | 6 +- rs/moq-net/src/transport/boxed.rs | 4 +- rs/moq-uring/benches/worker_turns.rs | 22 +- 23 files changed, 2422 insertions(+), 1729 deletions(-) delete mode 100644 quest/m1/net-internals.md diff --git a/bench/README.md b/bench/README.md index 8be337740f5..cb001c4fc8e 100644 --- a/bench/README.md +++ b/bench/README.md @@ -69,6 +69,16 @@ Runtime comparison requires Linux because io\_uring and relay process metrics come from Linux interfaces. The default worker count is the number of logical CPUs the run may use. +Measure `moq-uring`'s actual `Local` thread guard separately from I/O: + +```bash +nix develop --command cargo bench --locked -p moq-uring --bench worker_turns -- local_thread_check +``` + +This compares the same constant-returning transport method directly and through +`Local`. It isolates the thread guard; it does not attribute runtime workload CPU +to that check or disable the production safety guard. + Sweep the relay's QUIC shard count against the connection count, for the room (`video`: every connection publishes and subscribes) and `fanout` (one publisher, the rest subscribers) workloads: diff --git a/quest/m1/README.md b/quest/m1/README.md index c4d2e4f177e..4291e557365 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -136,7 +136,6 @@ tracks, so per-group stats stop costing cluster announces. - [Wire-compat audio](/quest/m1/wire-compat-audio.md) - the wire-compat media lanes decode and check the interop tone across releases - [Interop AAC](/quest/m1/interop-aac.md) - the Rust interop publisher adds an AAC tone and every subscriber checks it beside Opus - [Interop pre-skip](/quest/m1/interop-preskip.md) - the interop tone check anchors phase to timestamps, so a misapplied pre-skip fails -- [moq-net internals](/quest/m1/net-internals.md) - no per-group session clones, no transport type parameter in lite and IETF internals, and the `Local` check measured - [Fragmented QUIC sends](/quest/m1/quic-send-fragments.md) - a chunk-size by retained-flight sweep decides whether `SendBuffer::get`'s front-to-back scan needs a cursor or index - [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut - [Subscribe update camera check](/quest/m1/subscribe-update-churn.md) - a person checks a physical-camera publish for SUBSCRIBE_UPDATE chatter; bbb and the fake camera measured quiet diff --git a/quest/m1/net-internals.md b/quest/m1/net-internals.md deleted file mode 100644 index 96a85cc7e2f..00000000000 --- a/quest/m1/net-internals.md +++ /dev/null @@ -1,27 +0,0 @@ -# [M] moq-net internals after transport erasure - -## Goal - -With the transport boxed, the lite publisher stops cloning the session and -group per group, and the lite and IETF internals lose the transport type -parameter they keep only for test mocks. A `just bench-runtime` run on -io_uring measures the cost of the `Local` thread check. - -## Plan - -Follow-ups from [moq-dev/moq#6176](https://github.com/moq-dev/moq/pull/6176), -decided 2026-10-21 with the maintainer. - -- **Per-group clones.** The lite publisher clones its session and group for - each group it serves. Borrow or share them instead, and show the win on the - session delivery benches. -- **Type parameter.** Lite and IETF internals stay generic over the - transport only so tests can inject mocks. Mock behind the boxed transport - instead, and drop the parameter. -- **`Local` check.** Run `just bench-runtime` on io_uring and report what the - `Local` thread check costs; act on it only if it shows. - -Dropped: renaming the over-long `session_delivery_*` bench IDs, since it -loses their history for a cosmetic gain. - -Public API: none. Wire: none. diff --git a/quest/m2/wire-fuzz-coverage.md b/quest/m2/wire-fuzz-coverage.md index aeafa303687..31d2049118f 100644 --- a/quest/m2/wire-fuzz-coverage.md +++ b/quest/m2/wire-fuzz-coverage.md @@ -28,5 +28,4 @@ Public API: none. Wire: none. ## Related -- [moq-net internals](/quest/m1/net-internals.md) - the session drivers these targets exercise - [CI cost and latency](/quest/m0/ci/README.md) - where the nightly budget lives diff --git a/rs/moq-net/src/driver.rs b/rs/moq-net/src/driver.rs index f32f4c3ae9c..4966fe5c0ee 100644 --- a/rs/moq-net/src/driver.rs +++ b/rs/moq-net/src/driver.rs @@ -26,7 +26,7 @@ pub struct Driver { /// The protocol half of a machine, one variant per negotiated wire protocol. pub(crate) enum Protocol { /// Boxed for size only. - Lite(Box>), + Lite(Box), Ietf(crate::ietf::Driver), } diff --git a/rs/moq-net/src/ietf/adapter.rs b/rs/moq-net/src/ietf/adapter.rs index bbab81b152e..846a3472ad1 100644 --- a/rs/moq-net/src/ietf/adapter.rs +++ b/rs/moq-net/src/ietf/adapter.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; use std::{ collections::{HashMap, VecDeque}, sync::{Arc, Mutex, Weak}, @@ -443,14 +445,14 @@ impl crate::transport::Error for AdapterError { } } -pub enum AdapterSend { - Real(S::SendStream), +pub(crate) enum AdapterSend { + Real(crate::transport::boxed::SendStream), Virtual(VirtualSendStream), } -impl crate::transport::poll::SendStream for AdapterSend { - type Error = AdapterError<::Error>; - type Group = ::Group; +impl crate::transport::poll::SendStream for AdapterSend { + type Error = AdapterError<::Error>; + type Group = ::Group; fn poll_write(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { match self { @@ -504,19 +506,16 @@ impl crate::transport::poll::SendStream for } #[allow(clippy::large_enum_variant)] -pub enum AdapterRecv { - Real(S::RecvStream), +pub(crate) enum AdapterRecv { + Real(crate::transport::boxed::RecvStream), Virtual(crate::transport::poll::Buffered), } -impl crate::transport::poll::RecvStream for AdapterRecv { - type Error = AdapterError<::Error>; - type Lease<'a> - = AdapterLease<'a, S> - where - S: 'a; +impl crate::transport::poll::RecvStream for AdapterRecv { + type Error = AdapterError<::Error>; + type Lease<'a> = AdapterLease<'a>; - fn poll_lease(&mut self, cx: &mut Context<'_>, want: usize) -> Poll, Self::Error>> { + fn poll_lease(&mut self, cx: &mut Context<'_>, want: usize) -> Poll, Self::Error>> { match self { Self::Real(s) => s .poll_lease(cx, want) @@ -544,12 +543,12 @@ impl crate::transport::poll::RecvStream for } /// A [`Lease`](crate::transport::poll::Lease) of an [`AdapterRecv`]. -pub enum AdapterLease<'a, S: crate::transport::poll::Session + 'a> { - Real(::Lease<'a>), +pub(crate) enum AdapterLease<'a> { + Real(::Lease<'a>), Virtual(crate::transport::poll::BufferedLease<'a>), } -impl Buf for AdapterLease<'_, S> { +impl Buf for AdapterLease<'_> { fn remaining(&self) -> usize { match self { Self::Real(l) => l.remaining(), @@ -579,7 +578,7 @@ impl Buf for AdapterLease<'_, S> { } } -impl crate::transport::poll::Lease for AdapterLease<'_, S> { +impl crate::transport::poll::Lease for AdapterLease<'_> { fn is_fin(&self) -> bool { match self { Self::Real(l) => l.is_fin(), @@ -848,9 +847,9 @@ impl Shared { } #[derive(Clone)] -pub struct ControlStreamAdapter { +pub(crate) struct ControlStreamAdapter { stats: crate::stats::Session, - inner: S, + inner: Transport, shared: Arc, control: Control, version: Version, @@ -858,8 +857,8 @@ pub struct ControlStreamAdapter { park: kio::Park, } -impl ControlStreamAdapter { - pub fn new(inner: S, control: Control, version: Version) -> Self { +impl ControlStreamAdapter { + pub fn new(inner: Transport, control: Control, version: Version) -> Self { Self { stats: Default::default(), inner, @@ -877,7 +876,7 @@ impl ControlStreamAdapter { /// Open a real (non-virtual) bidi stream, bypassing control stream multiplexing. /// Used for v16 SubscribeNamespace which moved to its own bidi stream. - pub async fn open_native_bi(&mut self) -> Result<(AdapterSend, AdapterRecv), crate::Error> { + pub async fn open_native_bi(&mut self) -> Result<(AdapterSend, AdapterRecv), crate::Error> { let (send, recv) = self .inner .open_bi(Default::default()) @@ -893,8 +892,8 @@ impl ControlStreamAdapter { /// instead of the session tearing down. pub async fn run( &self, - reader: Reader, - writer: Writer, + reader: Reader, + writer: Writer, goaway: crate::goaway::Protocol, ) -> Result<(), Error> { let res = { @@ -986,7 +985,7 @@ impl ControlStreamAdapter { /// Writer task: drains the queue and writes to the control stream. The peer's /// STOP_SENDING, seen while idle or as a failed write, is a protocol violation. - async fn run_write(&self, mut writer: Writer) -> Result<(), Error> { + async fn run_write(&self, mut writer: Writer) -> Result<(), Error> { loop { let msg = kio::wait(|waiter| { // Never finished, so any end is the peer's or the session's. @@ -1012,7 +1011,7 @@ impl ControlStreamAdapter { /// Dispatcher loop that reads control stream messages and routes them. async fn run_read( &self, - mut reader: Reader, + mut reader: Reader, goaway: crate::goaway::Protocol, ) -> Result<(), Error> { loop { @@ -1299,9 +1298,9 @@ fn lookup_namespace_request_id( Ok(namespaces.get(direction, &ns)) } -impl crate::transport::poll::Session for ControlStreamAdapter { - type SendStream = AdapterSend; - type RecvStream = AdapterRecv; +impl crate::transport::poll::Session for ControlStreamAdapter { + type SendStream = AdapterSend; + type RecvStream = AdapterRecv; type Error = crate::Error; fn poll_accept_bi( @@ -2147,9 +2146,9 @@ mod tests { ids: &[u64], then: &[u8], ) -> ( - ControlStreamAdapter, - Reader, - Writer, + ControlStreamAdapter, + Reader, + Writer, crate::lite::test_transport::Log, ) { use crate::lite::test_transport::{Log, ScriptedSession, SinkSend}; @@ -2166,10 +2165,18 @@ mod tests { let (_, recv) = session.open_bi(Default::default()).await.unwrap(); // We are the server, so the client's request IDs are even. let control = Control::new(None, false).with_window(window, false, VERSION); - let adapter = ControlStreamAdapter::new(session, control, VERSION); + let adapter = ControlStreamAdapter::new(Transport::new(session.clone()), control, VERSION); let log = Log::default(); - let writer = Writer::new(SinkSend::new(log.clone()), VERSION); - (adapter, Reader::new(recv, VERSION), writer, log) + let writer = Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(log.clone())), + VERSION, + ); + ( + adapter, + Reader::new(crate::transport::boxed::RecvStream::new(recv), VERSION), + writer, + log, + ) } #[moq_clock::test] @@ -2191,9 +2198,12 @@ mod tests { let (_, recv) = crate::transport::poll::Session::open_bi(&mut session, Default::default()) .await .unwrap(); - let adapter = ControlStreamAdapter::new(session, Control::new(None, true), version).with_stats(&stats); + let adapter = ControlStreamAdapter::new(Transport::new(session.clone()), Control::new(None, true), version) + .with_stats(&stats); let mut virtual_stream = super::super::request_stream::with_stats( - Stream::open(&mut adapter.clone(), version).await.unwrap(), + Stream::open(&mut crate::driver::Transport::new(adapter.clone()), version) + .await + .unwrap(), &stats, version, ); @@ -2205,7 +2215,10 @@ mod tests { virtual_stream.writer.encode(&msg).await.unwrap(); let raw = adapter.shared.control.pop().await.unwrap(); let log = Log::default(); - let mut physical = Writer::new(SinkSend::new(log.clone()), version); + let mut physical = Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(log.clone())), + version, + ); physical.write_all(&mut raw.clone()).await.unwrap(); assert_eq!( registry.snapshot().control(), @@ -2214,7 +2227,10 @@ mod tests { ); assert_eq!(*log.writes.lock().unwrap(), raw); let (_, goaway) = crate::goaway::Handle::new(false); - let mut reading = std::pin::pin!(adapter.run_read(Reader::new(recv, version), goaway)); + let mut reading = std::pin::pin!(adapter.run_read( + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + goaway + )); assert!(futures::poll!(reading.as_mut()).is_pending()); assert_eq!(virtual_stream.reader.varint().await.unwrap(), ietf::FetchCancel::ID); virtual_stream.reader.decode::().await.unwrap(); @@ -2239,16 +2255,20 @@ mod tests { async fn a_legacy_control_stream_fin_or_reset_is_a_protocol_violation() { use crate::lite::test_transport::{DeadStreamSession, ScriptedSession}; for version in [Version::Draft14, Version::Draft15, Version::Draft16] { - let mut session = ScriptedSession::eof(Vec::new()); - let stream = crate::coding::Stream::open(&mut session, version).await.unwrap(); - let adapter = ControlStreamAdapter::new(session, Control::new(None, true), version); + let session = ScriptedSession::eof(Vec::new()); + let stream = crate::coding::Stream::open(&mut Transport::new(session.clone()), version) + .await + .unwrap(); + let adapter = ControlStreamAdapter::new(Transport::new(session.clone()), Control::new(None, true), version); let (_handle, protocol) = crate::goaway::Handle::new(false); let err = adapter.run(stream.reader, stream.writer, protocol).await.unwrap_err(); assert!(matches!(err, Error::ProtocolViolation), "{version:?}: {err:?}"); - let mut session = DeadStreamSession::bis(0); - let stream = crate::coding::Stream::open(&mut session, version).await.unwrap(); - let adapter = ControlStreamAdapter::new(session, Control::new(None, true), version); + let session = DeadStreamSession::bis(0); + let stream = crate::coding::Stream::open(&mut Transport::new(session.clone()), version) + .await + .unwrap(); + let adapter = ControlStreamAdapter::new(Transport::new(session.clone()), Control::new(None, true), version); let (_handle, protocol) = crate::goaway::Handle::new(false); let err = adapter.run(stream.reader, stream.writer, protocol).await.unwrap_err(); assert!(matches!(err, Error::ProtocolViolation), "{version:?}: {err:?}"); @@ -2261,11 +2281,13 @@ mod tests { async fn a_legacy_control_stream_stopped_while_idle_is_a_protocol_violation() { use crate::transport::memory; for version in [Version::Draft14, Version::Draft15, Version::Draft16] { - let (mut session, mut peer) = memory::pair(memory::Config::default()); - let stream = crate::coding::Stream::open(&mut session, version).await.unwrap(); + let (session, mut peer) = memory::pair(memory::Config::default()); + let stream = crate::coding::Stream::open(&mut Transport::new(session.clone()), version) + .await + .unwrap(); let mut remote = crate::coding::Stream::accept(&mut peer, version).await.unwrap(); remote.reader.abort(&Error::Cancel); - let adapter = ControlStreamAdapter::new(session, Control::new(None, true), version); + let adapter = ControlStreamAdapter::new(Transport::new(session.clone()), Control::new(None, true), version); let (_handle, protocol) = crate::goaway::Handle::new(false); let res = moq_clock::timeout( std::time::Duration::from_secs(10), @@ -2336,11 +2358,19 @@ mod tests { let script = encode_raw(ietf::SubscribeUpdate::ID, &Bytes::copy_from_slice(body), version); let mut session = ScriptedSession::new(script.to_vec()); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let adapter = ControlStreamAdapter::new(session, Control::new(None, false), version); + let adapter = + ControlStreamAdapter::new(Transport::new(session.clone()), Control::new(None, false), version); let log = Log::default(); - let writer = Writer::new(SinkSend::new(log.clone()), version); + let writer = Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(log.clone())), + version, + ); let (_, goaway) = crate::goaway::Handle::new(true); - let mut run = std::pin::pin!(adapter.run(Reader::new(recv, version), writer, goaway)); + let mut run = std::pin::pin!(adapter.run( + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + writer, + goaway + )); assert!(futures::poll!(run.as_mut()).is_pending(), "{version}"); let written = log.writes.lock().unwrap().clone(); diff --git a/rs/moq-net/src/ietf/auth.rs b/rs/moq-net/src/ietf/auth.rs index 1ef662f10a5..835c127addc 100644 --- a/rs/moq-net/src/ietf/auth.rs +++ b/rs/moq-net/src/ietf/auth.rs @@ -8,6 +8,8 @@ //! The wire carries prefixes, so a grant is told only when it is a union of subtrees. //! Anything narrower is refused with NOT_SUPPORTED rather than widened. +#[cfg(feature = "async")] +use crate::driver::Transport; use std::task::Poll; use std::time::Duration; @@ -223,9 +225,7 @@ fn from_code(code: u64) -> Error { /// Refuse an AUTH past our GOAWAY cutoff with AUTH_ERROR, the only answer its presenter reads. #[cfg(feature = "async")] -pub(super) async fn refuse_going_away( - mut stream: Stream, -) -> Result<(), Error> { +pub(super) async fn refuse_going_away(mut stream: Stream) -> Result<(), Error> { let reply = AuthError { code: GOING_AWAY, reason: "going away".to_string(), @@ -254,19 +254,16 @@ pub(super) fn peer_grant( /// the tokens as unsupported. #[cfg(feature = "async")] #[allow(clippy::too_many_arguments)] -pub(super) async fn run_present( +pub(super) async fn run_present( runtime: crate::time::Deadlines, - session: S, + session: Transport, control: Control, handle: Handle, peer_setup: peer::PeerSetup, version: Version, going_away: crate::goaway::GoingAway, stats: crate::stats::Session, -) -> Result<(), Error> -where - S: crate::transport::poll::Boxable, -{ +) -> Result<(), Error> { if !peer_setup.get().await.auth { handle.unsupported(); return std::future::pending().await; @@ -322,10 +319,10 @@ where /// One token's Auth request. #[cfg(feature = "async")] -struct Present { +struct Present { stats: crate::stats::Session, runtime: crate::time::Deadlines, - session: S, + session: Transport, control: Control, handle: Handle, version: Version, @@ -333,7 +330,7 @@ struct Present { } #[cfg(feature = "async")] -impl Present { +impl Present { /// Send the token, then track its grant until either side ends it, resolving with why. #[cfg(feature = "async")] async fn run(&self, token: Bytes) -> Error { @@ -446,9 +443,9 @@ pub(super) struct Serve { impl Serve { /// Answer one Auth request. The stream lives as long as the token. #[cfg(feature = "async")] - pub(super) async fn run( + pub(super) async fn run( self, - mut stream: Stream, + mut stream: Stream, msg: Auth, version: Version, ) -> Result<(), Error> { @@ -527,11 +524,11 @@ impl crate::coding::Decode for Unexpected { /// Write the acceptor's replies until either side ends the token. `default` feeds /// the default acceptor's grant into the outbox as it changes. #[cfg(feature = "async")] -async fn serve_issue( +async fn serve_issue( runtime: &crate::time::Deadlines, issue: &kio::Shared, mut default: Option<&mut crate::auth::DefaultGrant>, - stream: &mut Stream, + stream: &mut Stream, version: Version, goaways: &mut super::request_stream::GoAways, ) -> Result<(), Error> { diff --git a/rs/moq-net/src/ietf/publisher.rs b/rs/moq-net/src/ietf/publisher.rs index 904e11179e1..a941aeeb3e4 100644 --- a/rs/moq-net/src/ietf/publisher.rs +++ b/rs/moq-net/src/ietf/publisher.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; use crate::{frame, group, origin, track}; use futures::FutureExt as _; use std::{ @@ -394,19 +396,19 @@ fn jitter(delay: Duration) -> Duration { } /// Where one announce loop's advertisements go. -enum Target { +enum Target { /// Inline NAMESPACE entries on the SUBSCRIBE_NAMESPACE stream that asked for them /// (draft-16+). - Inline(Stream), + Inline(Stream), /// Each advertisement on its own PUBLISH_NAMESPACE request. Unsolicited when there /// is no stream; draft-14/15 answer a SUBSCRIBE_NAMESPACE this way, since they /// predate NAMESPACE, and hold onto its stream to end with the subscription. - Requests(Option>), + Requests(Option>), } -impl Target { +impl Target { /// The SUBSCRIBE_NAMESPACE stream this loop answers, if any. - fn stream(&mut self) -> Option<&mut Stream> { + fn stream(&mut self) -> Option<&mut Stream> { match self { Self::Inline(stream) | Self::Requests(Some(stream)) => Some(stream), Self::Requests(None) => None, @@ -420,7 +422,7 @@ impl Target { fn poll_closed( &mut self, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, version: Version, cx: &mut std::task::Context<'_>, ) -> Poll> { @@ -434,7 +436,7 @@ impl Target { fn poll_event( &mut self, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, version: Version, cx: &mut std::task::Context<'_>, ) -> Poll { @@ -470,15 +472,15 @@ impl Target { } /// One announce loop's state: where its advertisements go, and what the peer holds. -struct Namespaces { +struct Namespaces { /// What the peer declared in its SETUP, which decides what an advertisement carries. peer: cluster::Peer, - target: Target, + target: Target, /// Every announced broadcast under this loop's prefix. watched: HashMap, /// The open PUBLISH_NAMESPACE request carrying each advertised namespace. Empty when /// the entries ride a SUBSCRIBE_NAMESPACE stream inline. - requests: HashMap>, + requests: HashMap, /// Requests with an update to send, in the order they asked for a request ID. Each /// waits for credit beside the loop's other work and computes its update when it gets /// one, so a later change supersedes an earlier one that is still waiting. @@ -503,8 +505,8 @@ struct Namespaces { epochs: bool, } -impl Namespaces { - fn new(peer: cluster::Peer, target: Target) -> Self { +impl Namespaces { + fn new(peer: cluster::Peer, target: Target) -> Self { Self { peer, target, @@ -661,11 +663,11 @@ impl std::task::Wake for RequestWaker { } #[derive(Clone)] -pub(super) struct Publisher { +pub(super) struct Publisher { pub(super) withdrawal: crate::session::Withdrawal, // Arms the advertise, retry, and linger timers. runtime: crate::time::Deadlines, - session: S, + session: Transport, // Traffic stats are attributed through this tagged origin handle. origin: origin::Consumer, pub(super) control: Control, @@ -681,7 +683,7 @@ pub(super) struct Publisher { // What the peer declared in its SETUP, filled when that stream is read. peer_setup: peer::PeerSetup, // Shared across request handlers; None marks a dispatched subscription still resolving. - joins: kio::Shared>>>>, + joins: kio::Shared>>>>, version: Version, // Our grant (MoQ Auth): only what it lets us publish is advertised and served, and a // shrink withdraws what it no longer covers. @@ -747,13 +749,10 @@ impl Drop for Join { } } -impl Publisher -where - S: crate::transport::poll::Boxable, -{ +impl Publisher { pub fn new( runtime: crate::time::Deadlines, - session: S, + session: Transport, origin: origin::Consumer, control: Control, peer_hop: Option, @@ -872,7 +871,7 @@ where &self, id: u64, body: ietf::Body, - stream: Stream, + stream: Stream, epochs: bool, ) -> Result, Error> { let this = self.clone(); @@ -1068,7 +1067,7 @@ where /// other decode error leaves the session open. fn reject_token( &self, - stream: Stream, + stream: Stream, kind: request::Kind, body: ietf::Body, err: DecodeError, @@ -1088,7 +1087,7 @@ where #[cfg(test)] fn run_subscribe_stream( self, - stream: Stream, + stream: Stream, msg: ietf::Subscribe<'_>, ) -> impl std::future::Future> { let gate = crate::auth::Gate::new( @@ -1101,7 +1100,7 @@ where fn serve_subscribe_stream( self, - mut stream: Stream, + mut stream: Stream, mut msg: ietf::Subscribe<'_>, gate: crate::auth::Gate, ) -> impl std::future::Future> { @@ -1313,26 +1312,27 @@ where let filter = msg.filter; let namespace = msg.track_namespace.to_owned(); let token = request_grant.is_some(); - let save_join = - |largest: Option, cache: &crate::track::Consumer, ranking: &Ranking>| { - if let Some(join) = &_join { - let joined = match (filter, largest) { - (Filter::NextObject, Some(largest)) => Joined::Group { - end: Location { - group: largest.group, - object: largest.object + 1, - }, - cache: cache.clone(), - namespace: namespace.clone(), - token, - ranking: ranking.clone(), + let save_join = |largest: Option, + cache: &crate::track::Consumer, + ranking: &Ranking>| { + if let Some(join) = &_join { + let joined = match (filter, largest) { + (Filter::NextObject, Some(largest)) => Joined::Group { + end: Location { + group: largest.group, + object: largest.object + 1, }, - (Filter::NextObject, None) => Joined::Empty, - _ => Joined::Unsupported, - }; - join.joins.lock().insert(request_id, Some(joined)); - } - }; + cache: cache.clone(), + namespace: namespace.clone(), + token, + ranking: ranking.clone(), + }, + (Filter::NextObject, None) => Joined::Empty, + _ => Joined::Unsupported, + }; + join.joins.lock().insert(request_id, Some(joined)); + } + }; save_join(edge.largest, &cache, &track_serve.ranking); // A fill reads the group cache through its own consumer, independent of the @@ -1511,10 +1511,10 @@ where /// it. async fn write_end_of_track( &self, - stream: &mut Stream, - track_serve: &mut TrackServe, + stream: &mut Stream, + track_serve: &mut TrackServe, request_finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, ) { let Some(end) = track_serve.end() else { return; @@ -1545,7 +1545,7 @@ where /// group streams, returning how serving ended. async fn write_publish_done( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, served: Served, streams: u64, @@ -1579,10 +1579,10 @@ where async fn run_subscription( &self, - stream: &mut Stream, - serve: &mut TrackServe, + stream: &mut Stream, + serve: &mut TrackServe, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, fill: impl std::future::Future, request_grant: Option, ) -> Option { @@ -1741,7 +1741,7 @@ where &self, track: &crate::track::Consumer, msg: &ietf::Subscribe<'_>, - ) -> Result<(TrackServe, LiveEdge), Error> { + ) -> Result<(TrackServe, LiveEdge), Error> { // A live SUBSCRIBE's NEW_GROUP_REQUEST asks nothing more: subscribing is itself a join, // which the track's refresh ratio judges. let mut subscription = serving_subscription(msg.subscriber_priority).with_order(msg.group_order.to_order()); @@ -1812,9 +1812,9 @@ where /// while it waits; anything else fails the update, ending the request. async fn wait_resume( &self, - stream: &mut Stream, + stream: &mut Stream, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, msg: &mut ietf::Subscribe<'_>, ) -> Result> { let mut session = self.session.clone(); @@ -1891,9 +1891,9 @@ where /// draft 16, where UNSUBSCRIBE cancels, or from its request stream after. fn poll_subscribe_update( &self, - stream: &mut Stream, + stream: &mut Stream, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, cx: &mut std::task::Context<'_>, ) -> Poll { if *finished { @@ -1918,9 +1918,9 @@ where /// Request ID. Pending once the requester finished sending where a FIN does not cancel. fn poll_update( &self, - stream: &mut Stream, + stream: &mut Stream, finished: &mut bool, - goaways: &mut super::request_stream::Messages, + goaways: &mut super::request_stream::Messages, cx: &mut std::task::Context<'_>, ) -> Poll { use super::request_stream::{Next, Update}; @@ -1962,8 +1962,8 @@ where /// An error is how the request ends. async fn apply_subscription_update( &self, - stream: &mut Stream, - serve: &mut TrackServe, + stream: &mut Stream, + serve: &mut TrackServe, request_grant: &Option, renewal: &mut request_update::Renewal, update: super::request_stream::Update, @@ -2054,7 +2054,7 @@ where /// later drafts name none. Draft-14 answers nothing and never reaches here. async fn write_request_ok( &self, - writer: &mut Writer, + writer: &mut Writer, request_id: RequestId, largest: Option, ) -> Result<(), Error> { @@ -2076,7 +2076,7 @@ where /// already refused. async fn reject_subscribe( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, reason: &str, @@ -2092,7 +2092,7 @@ where /// Write a subscribe error on the bidi stream writer. async fn write_subscribe_error( &self, - writer: &mut Writer, + writer: &mut Writer, request_id: RequestId, err: &Error, reason: &str, @@ -2114,7 +2114,7 @@ where async fn run_fill( &self, fill: FillServe, - ranking: &Ranking>, + ranking: &Ranking>, track: track::Consumer, timescale: Option, opened: &AtomicU64, @@ -2192,7 +2192,7 @@ where /// properties (the timestamp) and the payload go on the wire. A fetch object has no /// status field from draft-16 onward; older drafts require Normal for an empty object. async fn write_fetch_group( - stream: &mut Writer, Version>, + stream: &mut Writer, Version>, mut group: group::Consumer, sequence: u64, skip: u64, @@ -2351,7 +2351,7 @@ where /// Write one fetch object's header and timestamp properties in the negotiated layout. async fn write_fetch_object( - stream: &mut Writer, Version>, + stream: &mut Writer, Version>, header: FetchObjectInfo<'_>, ) -> Result<(), Error> { let FetchObjectInfo { @@ -2431,7 +2431,7 @@ where /// Write a whole fetch object's length and payload, after its header. async fn write_fetch_payload( - stream: &mut Writer, Version>, + stream: &mut Writer, Version>, payload: bytes::Bytes, version: Version, ) -> Result<(), Error> { @@ -2448,7 +2448,7 @@ where } /// Register a pending subscription until the returned guard drops. - fn register_join(&self, request_id: RequestId) -> Join> { + fn register_join(&self, request_id: RequestId) -> Join> { self.joins.lock().insert(request_id, None); Join { joins: self.joins.clone(), @@ -2480,14 +2480,14 @@ where } #[cfg(test)] - async fn run_fetch_stream(self, stream: Stream, msg: ietf::Fetch<'_>) -> Result<(), Error> { + async fn run_fetch_stream(self, stream: Stream, msg: ietf::Fetch<'_>) -> Result<(), Error> { let gate = self.fetch_gate(&msg); self.serve_fetch_stream(stream, msg, gate).await } async fn serve_fetch_stream( mut self, - mut stream: Stream, + mut stream: Stream, msg: ietf::Fetch<'_>, admission: FetchGate, ) -> Result<(), Error> { @@ -2974,10 +2974,19 @@ where /// to answer the FETCH with. async fn joined( &mut self, - stream: &mut Stream, + stream: &mut Stream, subscribe_id: RequestId, ) -> Result< - Result<(Location, track::Consumer, crate::PathOwned, Ranking>, bool), (Error, &'static str)>, + Result< + ( + Location, + track::Consumer, + crate::PathOwned, + Ranking>, + bool, + ), + (Error, &'static str), + >, Error, > { // Request streams can arrive out of order. Wait on registration, while bounding @@ -3062,7 +3071,7 @@ where #[cfg(test)] fn run_track_status_stream( self, - stream: Stream, + stream: Stream, msg: ietf::TrackStatus<'_>, ) -> impl std::future::Future> { let gate = crate::auth::Gate::new( @@ -3075,7 +3084,7 @@ where async fn serve_track_status_stream( self, - mut stream: Stream, + mut stream: Stream, msg: ietf::TrackStatus<'_>, mut gate: crate::auth::Gate, ) -> Result<(), Error> { @@ -3171,7 +3180,7 @@ where async fn reject_track_status( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, ) -> Result<(), Error> { @@ -3185,7 +3194,7 @@ where /// never send. Both exist only from draft-16, so the reply is always REQUEST_ERROR. async fn reject_namespace_request( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, reason: &str, ) -> Result<(), Error> { @@ -3200,7 +3209,7 @@ where /// close is not optional. async fn reject_fetch( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, reason: &str, @@ -3222,7 +3231,7 @@ where /// draft-17). async fn sync_namespace( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, suffix: &crate::PathOwned, path: &crate::PathOwned, ) -> Result<(), Error> { @@ -3412,7 +3421,7 @@ where /// Returns what the refusal, if any, said about coming back. async fn advertise_namespace( &self, - requests: &mut HashMap>, + requests: &mut HashMap, watch: &mut Watched, path: &crate::PathOwned, suffix: crate::PathOwned, @@ -3538,7 +3547,7 @@ where /// is advertised under the session's scope. fn offer( &self, - ns: &Namespaces, + ns: &Namespaces, suffix: &crate::PathOwned, path: &crate::PathOwned, ) -> Option<(Advert, Option)> { @@ -3570,7 +3579,7 @@ where /// Drop queued updates that no longer have anything to send, so the next one to take /// a request ID is one that will use it: drafts before 17 require the next ID. - fn prune_updates(&self, ns: &mut Namespaces, prefix: &crate::PathOwned) { + fn prune_updates(&self, ns: &mut Namespaces, prefix: &crate::PathOwned) { while let Some(suffix) = ns.updates.front() { let wants = ns.requests.get(suffix).is_some_and(|request| { request.queued @@ -3602,7 +3611,7 @@ where /// the two. async fn send_update( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, prefix: &crate::PathOwned, request_id: RequestId, ) -> Result<(), Error> { @@ -3661,7 +3670,7 @@ where /// What came back for an update in flight, polling only the requests that woke. fn poll_answer( - requests: &mut HashMap>, + requests: &mut HashMap, inflight: &mut VecDeque<(crate::time::Instant, crate::PathOwned)>, woken: &Arc, now: crate::time::Instant, @@ -3720,7 +3729,7 @@ where /// advertisement the peer ends waits out its own growing backoff before coming back. async fn answered( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, prefix: &crate::PathOwned, suffix: crate::PathOwned, answer: Result, @@ -3853,7 +3862,7 @@ where /// The announce loop is single-threaded over origin updates, so an open that parks /// forever parks everything, including the unannounces that release the streams the /// peer is waiting on us to retire. Failing instead keeps the loop moving. - async fn open_request(&self) -> Result>, Error> { + async fn open_request(&self) -> Result>, Error> { let mut session = self.session.clone(); let mut open = std::pin::pin!(Stream::open(&mut session, self.version)); let mut timeout = crate::time::Deadline::after(&self.runtime, ADVERTISE_TIMEOUT); @@ -3885,8 +3894,8 @@ where /// namespace stays outstanding and the retry re-offers it. async fn read_response( &self, - request: &mut Stream, - messages: &mut super::request_stream::Messages, + request: &mut Stream, + messages: &mut super::request_stream::Messages, ) -> Result { let mut read = std::pin::pin!(messages.next(&mut request.reader)); let mut timeout = crate::time::Deadline::after(&self.runtime, ADVERTISE_TIMEOUT); @@ -3907,8 +3916,8 @@ where /// carried it (PUBLISH_NAMESPACE_DONE before draft-17, a cancel after). async fn withdraw_namespace( &self, - target: &mut Target, - requests: &mut HashMap>, + target: &mut Target, + requests: &mut HashMap, suffix: crate::PathOwned, ) -> Result<(), Error> { match target { @@ -3932,7 +3941,12 @@ where } /// Withdraw one PUBLISH_NAMESPACE request, best effort: the peer may already be gone. - async fn end_request(&self, mut stream: Stream, path: &crate::PathOwned, request_id: RequestId) { + async fn end_request( + &self, + mut stream: Stream, + path: &crate::PathOwned, + request_id: RequestId, + ) { // Draft-17+ withdraws by cancelling the request in both directions; a FIN is only // allowed to end SUBSCRIBE_NAMESPACE and SUBSCRIBE_TRACKS. if !matches!(self.version, Version::Draft14 | Version::Draft15 | Version::Draft16) { @@ -3956,11 +3970,7 @@ where /// Close out every open PUBLISH_NAMESPACE request. A no-op for a loop whose entries /// ride the SUBSCRIBE_NAMESPACE stream itself, which retracts them by ending. - async fn withdraw_requests( - &self, - target: &mut Target, - requests: &mut HashMap>, - ) { + async fn withdraw_requests(&self, target: &mut Target, requests: &mut HashMap) { let suffixes: Vec = requests.keys().cloned().collect(); for suffix in suffixes { let _ = self.withdraw_namespace(target, requests, suffix).await; @@ -4010,7 +4020,7 @@ where #[cfg(test)] async fn run_subscribe_namespace_stream( self, - stream: Stream, + stream: Stream, msg: ietf::SubscribeNamespace<'_>, ) -> Result<(), Error> { let gate = crate::auth::Gate::new( @@ -4023,7 +4033,7 @@ where async fn serve_subscribe_namespace_stream( self, - mut stream: Stream, + mut stream: Stream, msg: ietf::SubscribeNamespace<'_>, gate: crate::auth::Gate, ) -> Result<(), Error> { @@ -4195,7 +4205,7 @@ where &self, mut announced: crate::announce::Consumer, mut prefix: crate::PathOwned, - mut ns: Namespaces, + mut ns: Namespaces, initial: Vec, ) -> Result<(), Error> { let mut finished = false; @@ -4439,7 +4449,7 @@ where /// Whether a restart onto `update` replaces one instance the peer holds by epoch with /// another, rather than ending the advertisement. - fn replaces(ns: &Namespaces, update: &crate::announce::Announce) -> bool { + fn replaces(ns: &Namespaces, update: &crate::announce::Announce) -> bool { let held = ns .watched .get(&update.prefix) @@ -4450,7 +4460,7 @@ where /// Reconcile what the peer holds with one route (un)announce. async fn apply_update( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, prefix: &crate::PathOwned, update: crate::announce::Announce, active: bool, @@ -4493,8 +4503,8 @@ struct Terminal { /// Serves a track's groups, one machine per group. One at a time waits for stream credit; /// the rest wait in the cache, so what a peer withholding credit makes this hold is bounded /// by the credit it grants, not by how long it withholds it. -struct TrackServe { - session: S, +struct TrackServe { + session: Transport, track: track::Subscriber, request_id: RequestId, version: Version, @@ -4503,14 +4513,14 @@ struct TrackServe { /// The one group waiting for stream credit. The cursor hands out no other meanwhile, so /// the backlog stays in the cache, which bills, ages, and evicts it, and the cursor's /// budget skips whatever went stale. - opening: Option>, + opening: Option, /// The groups with a stream, serving or awaiting the acknowledgement of their FIN. - children: kio::Tasks>, + children: kio::Tasks, /// The subscriber priority, which every group stream follows while it is open. priority: kio::Producer, /// Where the group streams are ranked: the subscription's send group, or the session's /// queue once [`Self::ranked`] on a transport without groups. - ranking: Ranking>, + ranking: Ranking>, /// The track finished: the in-flight group machines drain, then FIN. draining: bool, /// Group streams opened, shared with the group machines. @@ -4529,9 +4539,9 @@ struct TrackServe { dynamic: bool, } -impl TrackServe { +impl TrackServe { fn new( - session: S, + session: Transport, mut track: track::Subscriber, request_id: RequestId, version: Version, @@ -5143,12 +5153,12 @@ impl Queued { /// Serves one group on its own unidirectional stream in the moq-transport /// subgroup format. -struct GroupServe { - session: S, +struct GroupServe { + session: Transport, /// The subscription's count of opened streams, bumped once this one opens. opened: Arc, msg: ietf::GroupHeader, - rank: Rank>, + rank: Rank>, group: group::Consumer, timescale: Option, version: Version, @@ -5157,7 +5167,7 @@ struct GroupServe { ended: bool, terminal: Option>, marked: bool, - state: GroupState, + state: GroupState, /// A long cached group drains a slice per poll, so its siblings still run. budget: kio::coop::Budget, } @@ -5165,13 +5175,13 @@ struct GroupServe { // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum GroupState { +enum GroupState { /// Waiting for stream credit on this machine's own session handle. Open, /// Streaming objects: the write buffer drains first, then the pending chunk, /// then the pending frame, then the next frame. Serve { - writer: Writer, + writer: Writer, frame: Option, chunk: Option, batch: Box>, @@ -5180,12 +5190,12 @@ enum GroupState { /// Every frame is written and the FIN sent: wait for the acknowledgement so a /// late cancel or expiry can still reset the stream. Closed { - writer: Writer, + writer: Writer, }, Done, } -impl kio::Task for GroupServe { +impl kio::Task for GroupServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -5196,11 +5206,11 @@ impl kio::Task for GroupServe { } } -impl GroupServe { +impl GroupServe { fn new( - session: S, + session: Transport, msg: ietf::GroupHeader, - rank: Rank>, + rank: Rank>, mut group: group::Consumer, timescale: Option, version: Version, @@ -5633,11 +5643,11 @@ fn buffer_object( /// One draft-14/15 advertisement: the PUBLISH_NAMESPACE request it rode on and /// what closes it out with PUBLISH_NAMESPACE_DONE. -struct NamespaceRequest { +struct NamespaceRequest { path: crate::PathOwned, request_id: RequestId, - stream: Stream, - messages: super::request_stream::Messages, + stream: Stream, + messages: super::request_stream::Messages, /// The auth the peer holds the request under: the one it opened with, or the one /// its last update carried. Held, so the credential stays presented while it does. auth: Option, @@ -5666,7 +5676,7 @@ mod group_priority_test { crate::track::Info::timed(), ); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), track.subscribe(None), RequestId(0), Version::Draft22, @@ -5695,7 +5705,7 @@ mod group_priority_test { crate::track::Info::timed(), ); let mut serve = TrackServe::new( - SinkSession::new(log.clone()), + crate::driver::Transport::new(SinkSession::new(log.clone())), track.subscribe(None), RequestId(1), Version::Draft22, @@ -5720,7 +5730,7 @@ mod group_priority_test { crate::track::Info::timed(), ); let mut serve = TrackServe::new( - SinkSession::new(log.clone()).with_unacked_fin(), + crate::driver::Transport::new(SinkSession::new(log.clone()).with_unacked_fin()), track.subscribe(None), RequestId(0), Version::Draft22, @@ -5770,7 +5780,7 @@ mod group_priority_test { group.write_frame(Timestamp::ZERO, b"x".as_slice()).unwrap(); } let mut serve = TrackServe::new( - SinkSession::new(log.clone()), + crate::driver::Transport::new(SinkSession::new(log.clone())), track.subscribe(None), RequestId(0), version, @@ -5841,7 +5851,7 @@ mod group_priority_test { let terminal = Arc::new(Terminal::default()); terminal.end.set(track::Position { group: 0, frame: 1 }).unwrap(); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), ietf::GroupHeader { track_alias: 0, group_id: 0, @@ -5930,7 +5940,7 @@ mod group_priority_test { let low = kio::Producer::new(-28); let mut serves = [(&low, 1), (&high, 0)].map(|(priority, subscribe)| { GroupServe::new( - SinkSession::new(log.clone()), + crate::driver::Transport::new(SinkSession::new(log.clone())), msg.clone(), rank_in(&queue, priority, subscribe), group.consume(), @@ -6024,7 +6034,7 @@ mod group_priority_test { /// poll stays under `most` by `progress` and leaves the sibling its turn. /// Each task-set pass returns to the executor so its children's yields reach the task. async fn serve_beside_a_sibling( - mut serve: TrackServe, + mut serve: TrackServe, mut produce: impl FnMut() -> bool + 'static, progress: impl Fn() -> usize, most: usize, @@ -6084,7 +6094,7 @@ mod group_priority_test { let subscriber = track.subscribe(track::Subscription::default().with_max_delay(std::time::Duration::from_secs(3600))); let serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6134,7 +6144,7 @@ mod group_priority_test { .with_max_delay(std::time::Duration::from_secs(3600)), ); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6190,7 +6200,7 @@ mod group_priority_test { .with_max_delay(std::time::Duration::from_secs(3600)), ); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6238,7 +6248,7 @@ mod group_priority_test { } group.finish().unwrap(); let serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6276,7 +6286,7 @@ mod group_priority_test { track.finish().unwrap(); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), version, @@ -6305,7 +6315,7 @@ mod group_priority_test { track.finish().unwrap(); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6331,7 +6341,7 @@ mod group_priority_test { /// Poll `serve` a few times, yielding between them, so its per-poll budget lets every /// group that is ready move on. - async fn settle_serve(serve: &mut TrackServe) { + async fn settle_serve(serve: &mut TrackServe) { for _ in 0..8 { let _ = serve.poll(&kio::Waiter::noop()); moq_clock::sim::yield_now().await; @@ -6357,7 +6367,7 @@ mod group_priority_test { let subscriber = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(3600))); let serve = TrackServe::new( - session.clone(), + crate::driver::Transport::new(session.clone()), subscriber, RequestId(id), Version::Draft22, @@ -6402,7 +6412,7 @@ mod group_priority_test { ); let subscriber = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(3600))); let mut serve = TrackServe::new( - SinkSession::gated_open_uni(gate.consume()), + crate::driver::Transport::new(SinkSession::gated_open_uni(gate.consume())), subscriber, RequestId(0), Version::Draft22, @@ -6448,7 +6458,7 @@ mod group_priority_test { let group = subscriber.recv_group().await.unwrap().expect("old group"); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), ietf::GroupHeader { track_alias: 0, group_id: 0, @@ -6495,7 +6505,7 @@ mod group_priority_test { let group = subscriber.recv_group().await.unwrap().expect("old group"); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), ietf::GroupHeader { track_alias: 0, group_id: 0, @@ -6547,7 +6557,7 @@ mod group_priority_test { let _other = queue.insert(Priority::new(22, 1, 0)); let priority = kio::Producer::new(72); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), ietf::GroupHeader { track_alias: 0, group_id: 0, @@ -6598,7 +6608,7 @@ mod group_priority_test { frame.write(b"a".as_slice()).unwrap(); let group = subscriber.recv_group().await.unwrap().expect("old group"); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), ietf::GroupHeader { track_alias: 0, group_id: 0, @@ -6694,7 +6704,7 @@ mod subscribe_cursor_test { track.finish().unwrap(); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(1), Version::Draft14, @@ -6718,8 +6728,10 @@ mod serve_tests { #[moq_clock::test] async fn idle_advertisements_keep_reading_goaways() { let version = Version::Draft21; - let mut session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let suffix: crate::PathOwned = "room".into(); let mut requests = HashMap::new(); requests.insert( @@ -6728,7 +6740,10 @@ mod serve_tests { path: suffix.clone(), request_id: RequestId(0), stream, - messages: super::super::request_stream::Messages::new(session.clone(), true), + messages: super::super::request_stream::Messages::new( + crate::driver::Transport::new(session.clone()), + true, + ), auth: None, queued: false, pending: None, @@ -6741,28 +6756,13 @@ mod serve_tests { let runtime = crate::time::sim(); let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); assert!( - Publisher::::poll_answer( - &mut requests, - &mut inflight, - &woken, - runtime.now(), - version, - &mut cx - ) - .is_pending() + Publisher::poll_answer(&mut requests, &mut inflight, &woken, runtime.now(), version, &mut cx).is_pending() ); assert!(session.log.closes().is_empty()); session.push(&[0x10, 0, 2, 0, 0]); woken.suffixes.lock().unwrap().push(suffix); assert!(matches!( - Publisher::::poll_answer( - &mut requests, - &mut inflight, - &woken, - runtime.now(), - version, - &mut cx - ), + Publisher::poll_answer(&mut requests, &mut inflight, &woken, runtime.now(), version, &mut cx), Poll::Ready((_, Err(Error::ProtocolViolation))) )); assert_eq!(session.log.closes()[0].0, 0x03); @@ -6775,11 +6775,16 @@ mod serve_tests { h.publisher.control.accept(RequestId(0)).unwrap(); assert_eq!(h.publisher.control.goaway().unwrap(), RequestId(2)); // REQUEST_UPDATE, Request ID 2, no parameters. - let mut session = ScriptedSession::new(vec![0x02, 0, 2, 2, 0]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(vec![0x02, 0, 2, 2, 0]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -6804,10 +6809,12 @@ mod serve_tests { async fn a_subscription_keeps_its_goaway_count_until_the_final_marker() { for version in [Version::Draft18, Version::Draft22] { let h = serve(version); - let mut session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -6815,7 +6822,8 @@ mod serve_tests { None, ); let mut finished = false; - let mut goaways = super::super::request_stream::Messages::new(h.session.clone(), false); + let mut goaways = + super::super::request_stream::Messages::new(crate::driver::Transport::new(h.session.clone()), false); { let run = h.publisher.run_subscription( &mut stream, @@ -6861,7 +6869,7 @@ mod serve_tests { /// A publisher whose origin serves one broadcast ("room") with one track ("video"). struct Serve { - publisher: Publisher, + publisher: Publisher, session: ScriptedSession, log: Log, track: track::Producer, @@ -6892,7 +6900,7 @@ mod serve_tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -6921,12 +6929,16 @@ mod serve_tests { Version::Draft22, ] { let h = serve(version); - let mut session = ScriptedSession::per_stream_eof(vec![vec![]]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream_eof(vec![vec![]]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -6972,12 +6984,16 @@ mod serve_tests { Version::Draft22, ] { let h = serve(version); - let mut session = ScriptedSession::per_stream_reset(vec![vec![]]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream_reset(vec![vec![]]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7033,7 +7049,9 @@ mod serve_tests { (ietf::Subscribe::ID, bytes::Bytes::from(subscribe_body)), (ietf::Fetch::ID, bytes::Bytes::from(fetch_body)), ] { - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let task = h .publisher .handle_stream(id, ietf::Body(body.clone()), stream, false) @@ -7042,7 +7060,9 @@ mod serve_tests { drop(task); assert_eq!(h.publisher.owed.load(Ordering::Relaxed), 0, "release a cancelled task"); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); assert!( h.publisher .handle_stream(id, ietf::Body(bytes::Bytes::new()), stream, false) @@ -7051,7 +7071,9 @@ mod serve_tests { assert_eq!(h.publisher.owed.load(Ordering::Relaxed), 0, "release malformed input"); if id == ietf::Fetch::ID { - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .handle_stream(id, ietf::Body(body), stream, false) .unwrap() @@ -7066,11 +7088,16 @@ mod serve_tests { async fn subscription_update_applies_priority_without_ending_the_request() { let version = Version::Draft19; let h = serve(version); - let mut session = ScriptedSession::per_stream(vec![vec![0x02, 0, 4, 2, 1, 0x20, 10, 0x02, 0, 2, 4, 0]]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream(vec![vec![0x02, 0, 4, 2, 1, 0x20, 10, 0x02, 0, 2, 4, 0]]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7098,14 +7125,19 @@ mod serve_tests { let version = Version::Draft19; let h = serve(version); let session = ScriptedSession::new(Vec::new()); - let mut stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); // Another subscription's group at 100 shares the queue, so the update moves this // subscription's stream past it. let queue = PriorityQueue::default(); let _other = queue.insert(Priority::new(100, 1, 0)); - let mut goaways = super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7283,7 +7315,9 @@ mod serve_tests { let mut group = h.track.create_group(group::Info { sequence: 0 }).unwrap(); group.write_frame(timestamp(), b"head".as_slice()).unwrap(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, join_current_group())); serve_until(serve.as_mut(), "the fill finished and the group stream opened", || { let data = data_streams(&h.log); @@ -7315,7 +7349,9 @@ mod serve_tests { let mut group = h.track.create_group(group::Info { sequence: 0 }).unwrap(); group.write_frame(timestamp(), b"head".as_slice()).unwrap(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, join_current_group())); serve_until(serve.as_mut(), "the fill finished and the group stream opened", || { let data = data_streams(&h.log); @@ -7345,11 +7381,16 @@ mod serve_tests { async fn an_unsupported_track_error_is_not_a_failed_update() { let version = Version::Draft18; let h = serve(version); - let mut session = ScriptedSession::per_stream(vec![vec![]]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream(vec![vec![]]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7410,7 +7451,9 @@ mod serve_tests { // The request stream shares the data streams' log, and its peer speaks later. let mut request = ScriptedSession::new(Vec::new()); request.log = h.log.clone(); - let stream = Stream::open(&mut request.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(request.clone()), version) + .await + .unwrap(); let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, join_current_group())); serve_until( serve.as_mut(), @@ -7504,12 +7547,16 @@ mod serve_tests { async fn legacy_subscription_update_keeps_the_subscription() { for version in [Version::Draft14, Version::Draft15, Version::Draft16] { let h = serve(version); - let mut session = ScriptedSession::new(legacy_update(version, 10, true)); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(legacy_update(version, 10, true)); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7552,12 +7599,16 @@ mod serve_tests { async fn a_legacy_update_pauses_the_subscription() { for version in [Version::Draft14, Version::Draft15, Version::Draft16] { let h = serve(version); - let mut session = ScriptedSession::new(legacy_update(version, 10, false)); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(legacy_update(version, 10, false)); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7612,7 +7663,9 @@ mod serve_tests { let h = serve(version); let mut request = ScriptedSession::new(Vec::new()); request.log = h.log.clone(); - let stream = Stream::open(&mut request.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(request.clone()), version) + .await + .unwrap(); let mut msg = subscribe(Filter::NextObject, None); msg.forward = !start_paused; let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, msg)); @@ -7673,7 +7726,9 @@ mod serve_tests { group.write_frame(timestamp(), b"head".as_slice()).unwrap(); let mut request = ScriptedSession::new(Vec::new()); request.log = h.log.clone(); - let stream = Stream::open(&mut request.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(request.clone()), version) + .await + .unwrap(); let mut msg = subscribe(Filter::NextObject, None); msg.forward = false; let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, msg)); @@ -7701,7 +7756,9 @@ mod serve_tests { let h = serve(version); let mut request = ScriptedSession::new(Vec::new()); request.log = h.log.clone(); - let stream = Stream::open(&mut request.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(request.clone()), version) + .await + .unwrap(); let mut msg = subscribe(Filter::NextObject, None); msg.forward = false; let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, msg)); @@ -7786,7 +7843,9 @@ mod serve_tests { for refresh in [Some(1), None] { let h = serve_track(version, crate::track::Info::timed().with_refresh(refresh)); let _group = refresh_group(&h); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let msg = ietf::Subscribe { new_group: Some(0), ..subscribe(Filter::NextObject, None) @@ -7812,7 +7871,9 @@ mod serve_tests { let version = Version::Draft22; let h = serve_track(version, crate::track::Info::timed().with_refresh(1)); let _group = refresh_group(&h); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let msg = subscribe( Filter::Absolute { start: Location { group: 4, object: 0 }, @@ -7833,7 +7894,9 @@ mod serve_tests { for (value, wanted) in [(0, 5), (5, 5), (4, 0)] { let h = serve_track(version, crate::track::Info::timed().with_refresh(1)); let _group = refresh_group(&h); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let msg = ietf::Subscribe { new_group: Some(value), ..subscribe( @@ -7857,13 +7920,15 @@ mod serve_tests { for version in [Version::Draft15, Version::Draft16, Version::Draft22] { for (value, wanted) in [(0, 5), (5, 5), (4, 0)] { let h = serve_track(version, crate::track::Info::timed().with_refresh(1)); - let mut session = ScriptedSession::new(new_group_update(version, 10, value)); - let mut stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(new_group_update(version, 10, value)); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); // Subscribed before the group, so only the update can ask for a new one. let subscriber = h.track.subscribe(None); let _group = refresh_group(&h); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), subscriber, RequestId(0), version, @@ -7871,8 +7936,10 @@ mod serve_tests { None, ); let mut finished = false; - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut run = std::pin::pin!(h.publisher.run_subscription( &mut stream, &mut serving, @@ -7899,12 +7966,16 @@ mod serve_tests { async fn a_new_group_update_without_refresh_fails() { for version in [Version::Draft15, Version::Draft16, Version::Draft22] { let h = serve(version); - let mut session = ScriptedSession::new(new_group_update(version, 10, 9)); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(new_group_update(version, 10, 9)); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -7983,12 +8054,16 @@ mod serve_tests { ), ] { let h = serve(version); - let mut session = ScriptedSession::per_stream(vec![update_with_tokens(version, &[token])]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream(vec![update_with_tokens(version, &[token])]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -8052,7 +8127,9 @@ mod serve_tests { let mut body = request(&tokens); body.push(0); let h = serve(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let closed = h .publisher .clone() @@ -8084,12 +8161,16 @@ mod serve_tests { (Version::Draft22, [TOKEN, other], 0x3), ] { let h = serve(version); - let mut session = ScriptedSession::per_stream(vec![update_with_tokens(version, &tokens)]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream(vec![update_with_tokens(version, &tokens)]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -8131,12 +8212,16 @@ mod serve_tests { async fn subscription_track_property_filter_closes_the_session() { for version in [Version::Draft19, Version::Draft21, Version::Draft22] { let h = serve(version); - let mut session = ScriptedSession::new(vec![0x02, 0, 6, 2, 1, 0x29, 2, 0, 0]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(vec![0x02, 0, 6, 2, 1, 0x29, 2, 0, 0]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -8165,12 +8250,16 @@ mod serve_tests { async fn source_decode_failure_keeps_the_session() { for version in [Version::Draft16, Version::Draft19, Version::Draft22] { let h = serve(version); - let mut session = ScriptedSession::new(Vec::new()); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::new(Vec::new()); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -8195,8 +8284,10 @@ mod serve_tests { for version in [Version::Draft18, Version::Draft21, Version::Draft22] { let h = serve(version); settle().await; - let mut session = ScriptedSession::new(Vec::new()); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(Vec::new()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut running = std::pin::pin!(h.publisher.clone().run_subscribe_namespace_stream( stream, ietf::SubscribeNamespace { @@ -8235,8 +8326,10 @@ mod serve_tests { for version in [Version::Draft21, Version::Draft22] { let h = serve(version); settle().await; - let mut session = ScriptedSession::new(Vec::new()).with_unacked_fin(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(Vec::new()).with_unacked_fin(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(0), namespace: crate::Path::new("room"), @@ -8278,8 +8371,10 @@ mod serve_tests { .announce("new/second", crate::origin::Route::default()) .unwrap(); settle().await; - let mut session = ScriptedSession::new(Vec::new()); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(Vec::new()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(0), namespace: crate::Path::new("old"), @@ -8332,8 +8427,10 @@ mod serve_tests { for version in [Version::Draft17, Version::Draft18, Version::Draft19, Version::Draft22] { let h = serve(version); moq_clock::sim::yield_now().await; - let mut session = ScriptedSession::per_stream_eof(vec![vec![]]); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::per_stream_eof(vec![vec![]]); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(0), namespace: crate::Path::new(""), @@ -8381,8 +8478,10 @@ mod serve_tests { // runtime before subscribing or the lookup 404s. moq_clock::sleep(std::time::Duration::from_millis(1)).await; - let mut session = h.session.clone(); - let stream = Stream::open(&mut session, h.publisher.version).await.unwrap(); + let session = h.session.clone(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), h.publisher.version) + .await + .unwrap(); let mut serve = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, msg)); // Everything cached serves immediately; the subscription then parks at the live @@ -8423,8 +8522,10 @@ mod serve_tests { }; let h = serve(version); - let mut session = h.session.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = h.session.clone(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut msg = subscribe(Filter::NextObject, None); msg.track_namespace = crate::Path::new("absent"); @@ -8433,8 +8534,10 @@ mod serve_tests { let expected = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); match version { Version::Draft14 => { @@ -8479,7 +8582,10 @@ mod serve_tests { /// The refusal of request [`REQUEST_ID`] as gone, as draft-17 and later frame it. async fn unroutable(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestError::ID).await.unwrap(); writer .encode(&ietf::RequestError { @@ -8557,7 +8663,9 @@ mod serve_tests { let expected = unroutable(version).await; for (id, body) in pinned_requests(version, named) { let mark = h.log.writes.lock().unwrap().len(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut task = h .publisher .clone() @@ -8610,7 +8718,9 @@ mod serve_tests { encode(&mut body).unwrap(); let mark = h.log.writes.lock().unwrap().len(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .handle_stream(ietf::Subscribe::ID, ietf::Body(body.into()), stream, true) @@ -8632,7 +8742,9 @@ mod serve_tests { for version in [Version::Draft17, Version::Draft22] { let h = serve(version); for (id, body) in pinned_requests(version, &crate::Epoch::mint()) { - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let result = h .publisher .clone() @@ -8683,7 +8795,9 @@ mod serve_tests { group.write_frame(timestamp(), b"b".as_slice()).unwrap(); moq_clock::sleep(std::time::Duration::from_millis(1)).await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); let body = track_status("room", wanted, version); h.publisher @@ -8773,7 +8887,9 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); h.publisher = h.publisher.clone().with_auth(auth.clone()); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); let body = track_status("live/cam", true, version); let mut answer = std::pin::pin!( @@ -8844,7 +8960,7 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -8853,7 +8969,9 @@ mod serve_tests { ) .with_auth(auth.clone()); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mark = session.log.writes.lock().unwrap().len(); // The request stream stops taking writes, so the answer parks on it. let Ok(mut writable) = bi.write() else { @@ -8902,7 +9020,9 @@ mod serve_tests { /// Run one TRACK_STATUS to its end, returning the refusal code it got, if any. async fn answer_code(h: &Serve, body: Vec, version: Version) -> Option { - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); h.publisher .clone() @@ -8981,7 +9101,9 @@ mod serve_tests { /// closes the session over an `Err`. async fn refusal(version: Version, id: u64, body: Vec) -> u64 { let h = serve(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); h.publisher .clone() @@ -9010,7 +9132,9 @@ mod serve_tests { for version in [Version::Draft19, Version::Draft20, Version::Draft21, Version::Draft22] { let h = serve(version); for fetch in [false, true] { - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); if fetch { h.publisher @@ -9095,7 +9219,9 @@ mod serve_tests { let h = serve(version); let claim = h._origin.dynamic_route("", crate::origin::Route::default()).unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); let body = track_status(path, true, version); let mut serving = std::pin::pin!( @@ -9122,7 +9248,9 @@ mod serve_tests { for version in [Version::Draft14, Version::Draft16, Version::Draft20] { let mut h = serve(version); h.publisher.subscriptions = crate::session::Slots::new(0); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut body = Vec::new(); subscribe(Filter::NextObject, None) .encode_msg(&mut Encoder::new(&mut body, version.into()), version) @@ -9246,7 +9374,9 @@ mod serve_tests { } }; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mark = h.log.writes.lock().unwrap().len(); let task = h .publisher @@ -9300,7 +9430,9 @@ mod serve_tests { ]; for (version, body) in cases { let h = serve(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let body = ietf::Body(bytes::Bytes::copy_from_slice(body)); assert!( h.publisher @@ -9563,7 +9695,9 @@ mod serve_tests { publish_groups(&mut h, LATEST); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serve = std::pin::pin!( h.publisher .clone() @@ -9643,7 +9777,9 @@ mod serve_tests { /// fetch ran; the subscription is parked at the live edge and writes nothing meanwhile. async fn joining_fetch(h: &Serve, mark: usize) -> Result, Error> { let version = h.publisher.version; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_fetch_stream( @@ -9699,7 +9835,9 @@ mod serve_tests { settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serve = std::pin::pin!( h.publisher .clone() @@ -9822,7 +9960,9 @@ mod serve_tests { let mut h = serve(version); publish_groups(&mut h, 5); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut data = Vec::new(); subscribe(Filter::NextObject, None) .encode_msg(&mut Encoder::new(&mut data, version.into()), version) @@ -9857,7 +9997,9 @@ mod serve_tests { futures::poll!(fetching.as_mut()).is_pending(), "allow SUBSCRIBE to arrive on its stream" ); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut data = Vec::new(); subscribe(Filter::NextObject, None) .encode_msg(&mut Encoder::new(&mut data, version.into()), version) @@ -9880,7 +10022,9 @@ mod serve_tests { async fn a_joining_fetch_wakes_when_its_pending_subscription_is_dropped() { for version in JOINING_DRAFTS { let h = serve(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut data = Vec::new(); subscribe(Filter::NextObject, None) .encode_msg(&mut Encoder::new(&mut data, version.into()), version) @@ -9920,7 +10064,9 @@ mod serve_tests { async fn a_joining_fetch_times_out_an_unresolved_subscription() { let version = Version::Draft17; let h = serve(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let _serving = h .publisher .clone() @@ -9951,7 +10097,9 @@ mod serve_tests { group.write_frame(timestamp(), b"frame".as_slice()).unwrap(); group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = Box::pin( h.publisher .clone() @@ -10014,7 +10162,9 @@ mod serve_tests { let mut h = serve(version); publish_groups(&mut h, 5); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = std::pin::pin!( h.publisher .clone() @@ -10050,7 +10200,9 @@ mod serve_tests { for version in JOINING_DRAFTS { let h = serve(version); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = std::pin::pin!( h.publisher .clone() @@ -10204,7 +10356,9 @@ mod serve_tests { ) -> bytes::Bytes { let version = h.publisher.version; let mark = h.log.writes.lock().unwrap().len(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_fetch_stream( @@ -10420,7 +10574,9 @@ mod serve_tests { // Drafts 16 and 17 answer TRACK_STATUS with REQUEST_OK, which has no block. if version == Version::Draft22 { let h = serve_track(version, info); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .handle_stream( @@ -10474,7 +10630,9 @@ mod serve_tests { // Draft 17 forbids the 7-byte varints draft 18 allows, and draft 16 has QUIC varints. for version in [Version::Draft16, Version::Draft17] { let h = serve_track(version, info.clone()); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_subscribe_stream(stream, subscribe(Filter::NextObject, None)) @@ -11094,7 +11252,7 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -11103,7 +11261,9 @@ mod serve_tests { ) .with_auth(auth.clone()); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mark = session.log.writes.lock().unwrap().len(); let location = Location { group: 0, object: 0 }; let mut fetch = std::pin::pin!(publisher.run_fetch_stream( @@ -11187,7 +11347,7 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -11196,7 +11356,9 @@ mod serve_tests { ) .with_auth(auth.clone()); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut subscription = std::pin::pin!( publisher .clone() @@ -11211,7 +11373,9 @@ mod serve_tests { futures::future::Either::Right((res, _)) => panic!("{version}: subscription ended: {res:?}"), } - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mark = session.log.writes.lock().unwrap().len(); let mut fetch = std::pin::pin!(publisher.clone().run_fetch_stream( stream, @@ -11297,7 +11461,7 @@ mod serve_tests { }); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -11306,7 +11470,9 @@ mod serve_tests { ) .with_auth(auth.clone()); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut msg = token_subscribe(); if !token { msg.authorization_token = None; @@ -11332,7 +11498,9 @@ mod serve_tests { futures::future::Either::Right((res, _)) => panic!("{version}: subscription ended: {res:?}"), } - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mark = session.log.writes.lock().unwrap().len(); let mut fetch = std::pin::pin!(publisher.clone().run_fetch_stream( stream, @@ -11442,7 +11610,7 @@ mod serve_tests { auth.authorize(&crate::auth::Grant::default()); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -11451,7 +11619,9 @@ mod serve_tests { ) .with_auth(auth.clone()); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut subscription = std::pin::pin!(publisher.clone().run_subscribe_stream(stream, token_subscribe())); let accepted = async { requests.next().await.expect("a request") }; let request = match futures::future::select(std::pin::pin!(accepted), subscription.as_mut()).await { @@ -11566,7 +11736,9 @@ mod serve_tests { group.write_frame(timestamp(), b"4-0".as_slice()).unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = std::pin::pin!( h.publisher .clone() @@ -11585,7 +11757,9 @@ mod serve_tests { }, ] { let mark = h.log.writes.lock().unwrap().len(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_fetch_stream( @@ -11618,7 +11792,9 @@ mod serve_tests { publish_pairs(&mut h, 3, None); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = std::pin::pin!( h.publisher .clone() @@ -11627,7 +11803,9 @@ mod serve_tests { registered(&h, serving.as_mut()).await; let mark = h.log.writes.lock().unwrap().len(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_fetch_stream( @@ -11798,7 +11976,7 @@ mod serve_tests { group.finish().unwrap(); let mut serve = GroupServe::new( - session, + crate::driver::Transport::new(session.clone()), header(), Rank::solo(kio::Producer::new(0).consume()), consumer, @@ -11862,7 +12040,14 @@ mod serve_tests { start: Some(Location { group: 0, object: 0 }), end: Some(EndLocation { group: 0, object }), }; - let mut serve = TrackServe::new(session, subscriber, RequestId(0), Version::Draft20, range, None); + let mut serve = TrackServe::new( + crate::driver::Transport::new(session.clone()), + subscriber, + RequestId(0), + Version::Draft20, + range, + None, + ); kio::wait(|waiter| serve.poll(waiter)).await.unwrap(); let mut buf = bytes::Bytes::from(log.writes.lock().unwrap().clone()); @@ -11895,7 +12080,7 @@ mod serve_tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -11955,7 +12140,10 @@ mod serve_tests { /// One REQUEST_UPDATE carrying a fresh AUTHORIZATION TOKEN, framed as the peer sends it. async fn subscribe_update_with_token(version: Version, forward: bool) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let subscription_request_id = match version { Version::Draft14 | Version::Draft15 | Version::Draft16 => Some(RequestId(REQUEST_ID)), _ => None, @@ -11982,7 +12170,10 @@ mod serve_tests { /// unkeyed on draft-17+. async fn request_ok_bytes(version: Version, request_id: RequestId) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -12000,7 +12191,10 @@ mod serve_tests { /// `write_subscribe_error(.., &Error::Unauthorized, reason)`. async fn request_error_bytes(version: Version, request_id: RequestId, reason: &str) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let request_id = matches!(version, Version::Draft15 | Version::Draft16).then_some(request_id); writer.varint(ietf::RequestError::ID).await.unwrap(); writer @@ -12041,7 +12235,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let answered = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { @@ -12132,7 +12328,9 @@ mod serve_tests { let (auth, mut requests, _cred) = auth_covering_other(); let h = serve_with_auth(version, auth, subscribe_update_with_token(version, false).await); let rt = h.publisher.runtime.clone(); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); let _held = first.accept(grant_all_expiring(&rt, Some(60))); @@ -12178,7 +12376,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); // The renewal is held until the setup writes have settled, so anything written after // it is released is the renewal's answer. @@ -12314,7 +12514,10 @@ mod serve_tests { /// told apart on the wire. async fn subscribe_update_token_rid(version: Version, rid: u64) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let subscription_request_id = match version { Version::Draft14 | Version::Draft15 | Version::Draft16 => Some(RequestId(REQUEST_ID)), _ => None, @@ -12342,7 +12545,10 @@ mod serve_tests { /// once rather than held. async fn subscribe_update_bare_rid(version: Version, rid: u64) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let subscription_request_id = match version { Version::Draft14 | Version::Draft15 | Version::Draft16 => Some(RequestId(REQUEST_ID)), _ => None, @@ -12385,7 +12591,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); // Hold the first renewal (0x40) so the next two (0x42, 0x44) are read and buffered while // its verdict is pending: the exact window the single slot used to collapse. @@ -12458,7 +12666,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); // Accept the initial token, then never answer a renewal, so the buffer only grows. let acceptor = async move { @@ -12511,7 +12721,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); @@ -12556,7 +12768,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); @@ -12601,7 +12815,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); @@ -12623,8 +12839,10 @@ mod serve_tests { // Draft-19 answers each with a REQUEST_OK, request id omitted. let one_ok = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -12669,7 +12887,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let release = Release::default(); let acceptor = { let release = release.clone(); @@ -12736,7 +12956,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); let _held = first.accept(grant_all_expiring(&rt, None)); @@ -12790,7 +13012,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.unwrap(); @@ -12828,7 +13052,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let popped = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { let popped = popped.clone(); @@ -12865,7 +13091,10 @@ mod serve_tests { /// One UNSUBSCRIBE keyed to the subscription, the draft-14/15/16 cancellation message. async fn unsubscribe_bytes(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::Unsubscribe::ID).await.unwrap(); writer .encode(&ietf::Unsubscribe { @@ -12896,7 +13125,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); let _issued = first.accept(crate::auth::Grant::all()); @@ -12937,7 +13168,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let answered = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { @@ -13012,7 +13245,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let popped = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { @@ -13078,7 +13313,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let consulted = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { let consulted = consulted.clone(); @@ -13130,7 +13367,9 @@ mod serve_tests { group.finish().unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let serving = h.publisher.clone().run_subscribe_stream(stream, token_subscribe()); let serving: Serving = Box::pin(async move { let acceptor = async move { @@ -13214,7 +13453,9 @@ mod serve_tests { let _cred = auth.present(bytes::Bytes::from_static(b"cred"), true).unwrap(); auth.granted(0, crate::auth::Grant::all()); let h = serve_with_auth(VERSION, auth, Vec::new()); - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let consulted = std::sync::Arc::new(AtomicU64::new(0)); let acceptor = { @@ -13274,12 +13515,16 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); auth.authorize(&crate::auth::Grant::all()); let h = serve_with_auth(version, auth, Vec::new()); - let mut session = ScriptedSession::per_stream(vec![update_with_tokens(version, &[TOKEN])]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut goaways = - super::super::request_stream::Messages::new(h.session.clone(), h.publisher.control.client()); + let session = ScriptedSession::per_stream(vec![update_with_tokens(version, &[TOKEN])]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut goaways = super::super::request_stream::Messages::new( + crate::driver::Transport::new(h.session.clone()), + h.publisher.control.client(), + ); let mut serving = TrackServe::new( - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h.track.subscribe(None), RequestId(0), version, @@ -13331,7 +13576,9 @@ mod serve_tests { let mut group = h.track.create_group(group::Info { sequence: 0 }).unwrap(); group.write_frame(timestamp(), b"frame".as_slice()).unwrap(); settle().await; - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let mut serving = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, token_subscribe())); for _ in 0..50 { assert!( @@ -13348,7 +13595,9 @@ mod serve_tests { let auth = crate::auth::Handle::new(false); auth.authorize(&limit); let h = serve_with_auth(version, auth, Vec::new()); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); let mut serving = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, token_subscribe())); let mut res = None; for _ in 0..50 { @@ -13361,8 +13610,10 @@ mod serve_tests { assert!(matches!(res, Some(Ok(()))), "refused, not failed or served: {res:?}"); let refusal = { let log = Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestError::ID).await.unwrap(); writer .encode(&ietf::RequestError { @@ -13390,7 +13641,9 @@ mod serve_tests { let _requests = auth.requests().unwrap(); let mut h = serve_with_auth(VERSION, auth, Vec::new()); h.publisher.subscriptions = crate::session::Slots::new(1); - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); { let mut serving = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, token_subscribe())); for _ in 0..10 { @@ -13412,7 +13665,9 @@ mod serve_tests { let mut requests = auth.requests().unwrap(); let mut h = serve_with_auth(VERSION, auth, Vec::new()); h.publisher.subscriptions = crate::session::Slots::new(1); - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let taken = { let mut serving = std::pin::pin!(h.publisher.clone().run_subscribe_stream(stream, token_subscribe())); let mut taken = None; @@ -13461,7 +13716,9 @@ mod serve_tests { ); auth.authorize(&crate::auth::Grant::default()); let h = serve_with_auth(VERSION, auth, Vec::new()); - let stream = Stream::open(&mut h.session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), VERSION) + .await + .unwrap(); let res = h .publisher .clone() @@ -13589,13 +13846,7 @@ mod tests { /// broadcasts: `from/peer`, whose only route flows through `assigned`, and /// `from/us`, which does not. The producers are returned so the routes outlive /// the assertions. - async fn echo_harness( - assigned: crate::Hop, - ) -> ( - Publisher, - origin::Consumer, - Vec, - ) { + async fn echo_harness(assigned: crate::Hop) -> (Publisher, origin::Consumer, Vec) { let other = crate::Hop::new(778).unwrap(); let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let consumer = origin.consume(); @@ -13603,7 +13854,7 @@ mod tests { let session = crate::lite::test_transport::SinkSession::new(Default::default()); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), Some(assigned), @@ -13661,7 +13912,7 @@ mod tests { let consumer = origin.consume(); let publisher = Publisher::new( crate::time::sim(), - crate::lite::test_transport::SinkSession::new(Default::default()), + crate::driver::Transport::new(crate::lite::test_transport::SinkSession::new(Default::default())), origin.consume(), Control::new(None, false), Some(assigned), @@ -13732,7 +13983,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - crate::lite::test_transport::SinkSession::new(Default::default()), + crate::driver::Transport::new(crate::lite::test_transport::SinkSession::new(Default::default())), origin.consume(), Control::new(None, false), Some(assigned), @@ -13780,7 +14031,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -13801,7 +14052,9 @@ mod tests { .unwrap(); settle().await; - let stream = Stream::open(&mut session.clone(), Version::Draft17).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Draft17) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(1), namespace: crate::Path::new(""), @@ -13815,7 +14068,7 @@ mod tests { let expected = crate::lite::test_transport::Log::default(); let mut writer = crate::coding::Writer::new( - crate::lite::test_transport::SinkSend::new(expected.clone()), + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(expected.clone())), Version::Draft17, ); writer.varint(ietf::RequestOk::ID).await.unwrap(); @@ -13849,7 +14102,7 @@ mod tests { let log = session.log.clone(); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), Some(assigned), @@ -13871,7 +14124,9 @@ mod tests { .unwrap(); settle().await; - let stream = Stream::open(&mut session.clone(), Version::Draft16).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Draft16) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(1), namespace: crate::Path::new(""), @@ -13917,7 +14172,10 @@ mod tests { /// for in milliseconds. Zero means it does not want the namespace offered again. async fn publish_namespace_error(version: Version, retry_interval: u64) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestError::ID).await.unwrap(); writer @@ -13954,7 +14212,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14012,7 +14270,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14070,7 +14328,10 @@ mod tests { async fn publish_namespace_ok(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); match version { Version::Draft14 => { @@ -14134,7 +14395,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), consumer, Control::new(None, false), None, @@ -14142,7 +14403,9 @@ mod tests { VERSION, ); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(1), namespace: crate::Path::new(""), @@ -14220,7 +14483,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14261,7 +14524,7 @@ mod tests { peer_setup.set(peer::Peer::default()); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14319,7 +14582,10 @@ mod tests { settle().await; let ok = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(ok.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(ok.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -14340,7 +14606,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14431,7 +14697,7 @@ mod tests { }; let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), consume, Control::new(None, false), None, @@ -14439,7 +14705,9 @@ mod tests { version, ); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(1), namespace: crate::Path::new(prefix), @@ -14588,7 +14856,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14596,7 +14864,9 @@ mod tests { version, ); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::SubscribeNamespace { request_id: RequestId(1), namespace: crate::Path::new(""), @@ -14679,7 +14949,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14757,7 +15027,7 @@ mod tests { let session = crate::lite::test_transport::SinkSession::new(Default::default()); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), Some(assigned), @@ -14805,7 +15075,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14869,7 +15139,10 @@ mod tests { /// PUBLISH_NAMESPACE_DONE withdrawing the first request, "cam". async fn publish_namespace_done(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::PublishNamespaceDone::ID).await.unwrap(); writer .encode(&ietf::PublishNamespaceDone { @@ -14884,7 +15157,10 @@ mod tests { /// PUBLISH_NAMESPACE_CANCEL letting go of the first request, "cam". async fn publish_namespace_cancel(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::PublishNamespaceCancel::ID).await.unwrap(); writer .encode(&ietf::PublishNamespaceCancel { @@ -14901,7 +15177,10 @@ mod tests { /// The bytes of one REQUEST_UPDATE, framed as the publisher writes it. async fn request_update(version: Version, msg: &ietf::PublishNamespaceUpdate) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::PublishNamespaceUpdate::ID).await.unwrap(); writer.encode(msg).await.unwrap(); log.writes.lock().unwrap().clone() @@ -14939,7 +15218,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15006,8 +15285,10 @@ mod tests { // The PUBLISH_NAMESPACE is answered cleanly; its update's OK carries a count. let counted = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(counted.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(counted.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -15025,7 +15306,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15096,7 +15377,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15165,15 +15446,12 @@ mod tests { auth: &crate::auth::Handle, scripts: Vec>, version: Version, - ) -> ( - Publisher, - crate::lite::test_transport::Log, - ) { + ) -> (Publisher, crate::lite::test_transport::Log) { let session = crate::lite::test_transport::ScriptedSession::per_stream(scripts); let log = session.log.clone(); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15522,10 +15800,10 @@ mod tests { let _cam = origin.announce("cam", crate::origin::Route::default()).unwrap(); settle().await; - let (session, mut peer) = memory::pair(memory::Config::default()); + let (session, peer) = memory::pair(memory::Config::default()); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15534,11 +15812,14 @@ mod tests { ); let run = moq_clock::sim::spawn(publisher.run_publish_namespaces()); - let mut offered = async || { - let mut stream = moq_clock::timeout(Duration::from_secs(10), Stream::accept(&mut peer, VERSION)) - .await - .expect("no advertisement") - .unwrap(); + let offered = async || { + let mut stream = moq_clock::timeout( + Duration::from_secs(10), + Stream::accept(&mut crate::driver::Transport::new(peer.clone()), VERSION), + ) + .await + .expect("no advertisement") + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::PublishNamespace::ID); let _: ietf::Body = stream.reader.decode().await.unwrap(); stream @@ -15588,10 +15869,10 @@ mod tests { .collect(); settle().await; - let (session, mut peer) = memory::pair(memory::Config::default()); + let (session, peer) = memory::pair(memory::Config::default()); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15601,11 +15882,14 @@ mod tests { let run = moq_clock::sim::spawn(publisher.run_publish_namespaces()); // The next advertisement, with the namespace it names. - let mut offered = async || { - let mut stream = moq_clock::timeout(Duration::from_secs(10), Stream::accept(&mut peer, version)) - .await - .expect("no advertisement") - .unwrap(); + let offered = async || { + let mut stream = moq_clock::timeout( + Duration::from_secs(10), + Stream::accept(&mut crate::driver::Transport::new(peer.clone()), version), + ) + .await + .expect("no advertisement") + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::PublishNamespace::ID); let body: ietf::Body = stream.reader.decode().await.unwrap(); let name = match body.0.windows(5).any(|window| window == b"a-cam") { @@ -15674,7 +15958,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15683,10 +15967,13 @@ mod tests { ); let run = moq_clock::sim::spawn(publisher.run_publish_namespaces()); - let mut stream = moq_clock::timeout(Duration::from_secs(10), Stream::accept(&mut peer, version)) - .await - .expect("no advertisement") - .unwrap(); + let mut stream = moq_clock::timeout( + Duration::from_secs(10), + Stream::accept(&mut crate::driver::Transport::new(peer.clone()), version), + ) + .await + .expect("no advertisement") + .unwrap(); stream.reader.abort(&Error::Cancel); match version { @@ -15706,10 +15993,13 @@ mod tests { } _ => { // Offered again after the backoff, on a session that stays open. - moq_clock::timeout(Duration::from_secs(10), Stream::accept(&mut peer, version)) - .await - .unwrap_or_else(|_| panic!("{version}: not offered again")) - .unwrap(); + moq_clock::timeout( + Duration::from_secs(10), + Stream::accept(&mut crate::driver::Transport::new(peer.clone()), version), + ) + .await + .unwrap_or_else(|_| panic!("{version}: not offered again")) + .unwrap(); assert!(!run.is_finished(), "{version}: the loop ended"); } } @@ -15736,7 +16026,7 @@ mod tests { let peer = session.clone(); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15835,7 +16125,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15897,7 +16187,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15955,7 +16245,7 @@ mod tests { let log = session.log.clone(); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16003,7 +16293,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16047,7 +16337,7 @@ mod tests { let log = session.log.clone(); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16097,7 +16387,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16142,7 +16432,7 @@ mod tests { /// A publisher talking to a scripted peer that never answers, over one bidi stream. struct Harness { - publisher: Publisher, + publisher: Publisher, session: crate::lite::test_transport::ScriptedSession, log: crate::lite::test_transport::Log, /// Keeps the origin alive; the publisher only holds a consumer. @@ -16160,7 +16450,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16181,7 +16471,9 @@ mod tests { async fn subscribe_missing(version: Version) -> (Vec, Vec) { let h = harness(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_subscribe_stream( @@ -16215,7 +16507,9 @@ mod tests { async fn fetch_refused(version: Version, fetch_type: FetchType<'_>) -> (Vec, Vec) { let h = harness(version); - let stream = Stream::open(&mut h.session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) + .await + .unwrap(); h.publisher .clone() .run_fetch_stream( @@ -17163,7 +17457,7 @@ mod compression_tests { .unwrap(); let log = Log::default(); let mut serve = TrackServe::new( - SinkSession::new(log.clone()), + crate::driver::Transport::new(SinkSession::new(log.clone())), subscriber, RequestId(0), version, diff --git a/rs/moq-net/src/ietf/publisher/tracks.rs b/rs/moq-net/src/ietf/publisher/tracks.rs index 1401014785a..408555a0ca8 100644 --- a/rs/moq-net/src/ietf/publisher/tracks.rs +++ b/rs/moq-net/src/ietf/publisher/tracks.rs @@ -9,6 +9,7 @@ //! with PUBLISH_SKIPPED and the subscriber SUBSCRIBEs to what it wants. Draft-18 has no such //! skip, so there the request is refused. +use crate::driver::Transport; use std::collections::HashSet; use hashlink::LinkedHashMap; @@ -200,15 +201,12 @@ enum Wait { Failed(Error), } -impl Publisher -where - S: crate::transport::poll::Boxable, -{ +impl Publisher { /// Answer a SUBSCRIBE_TRACKS: list every track under its prefix until the subscriber /// cancels or the session ends, then let the PUBLISHes it made run to their own end. pub(super) async fn serve_subscribe_tracks_stream( self, - mut stream: Stream, + mut stream: Stream, msg: ietf::SubscribeTracks<'_>, ) -> Result<(), Error> { if let Some(error) = super::super::namespace::refusal(&msg.prefix, self.version) { @@ -420,9 +418,9 @@ where /// ending it, such as a REQUEST_UPDATE we refuse. fn poll_listing_cancel( &self, - stream: &mut Stream, + stream: &mut Stream, finished: &mut bool, - goaways: &mut super::super::request_stream::Messages, + goaways: &mut super::super::request_stream::Messages, cx: &mut std::task::Context<'_>, ) -> Poll> { use super::super::request_stream::{NamespaceUpdate, Next}; @@ -476,7 +474,7 @@ where /// Write the pending PUBLISH_SKIPPEDs, buffering the next only once the last is out, so /// a peer that stops reading leaves the rest collapsing in `skips`. fn poll_write_skips( - stream: &mut Stream, + stream: &mut Stream, skips: &Skips, waiter: &kio::Waiter, cx: &mut std::task::Context<'_>, @@ -1004,7 +1002,7 @@ where /// Mark a paused subscription for joining FETCHes: draft-18 section 5.1 refuses one /// unless the subscription forwards. - pub(super) fn pause_join(&self, join: Option<&Join>>) { + pub(super) fn pause_join(&self, join: Option<&Join>>) { if let Some(join) = join { join.joins.lock().insert(join.request_id, Some(Joined::Empty)); } @@ -1015,7 +1013,7 @@ where /// section 9.5). `Err(())` when the subscriber cancelled. async fn resume_failed( &self, - stream: &mut Stream, + stream: &mut Stream, request_id: RequestId, answer: bool, err: Error, @@ -1036,18 +1034,18 @@ where #[allow(clippy::too_many_arguments)] async fn resume_publish( &self, - stream: &mut Stream, + stream: &mut Stream, track: &track::Consumer, namespace: &crate::PathOwned, request_id: RequestId, params: &mut Params, how: Resume, dynamic: bool, - join: Option<&Join>>, + join: Option<&Join>>, listed: &kio::Consumer<()>, gate: &mut crate::auth::Gate, finished: &mut bool, - goaways: &mut super::super::request_stream::Messages, + goaways: &mut super::super::request_stream::Messages, opened: &mut u64, ) -> Result { let mut subscription = serving_subscription(params.priority); @@ -1223,7 +1221,6 @@ mod tests { use super::*; use crate::model::ProduceTest as _; use crate::transport::memory; - use crate::transport::poll::Session as _; const TIMEOUT: Duration = Duration::from_secs(10); @@ -1239,7 +1236,7 @@ mod tests { /// the peer's end of its session. struct Harness { version: Version, - publisher: Publisher, + publisher: Publisher, session: memory::Session, peer: memory::Session, broadcast: crate::broadcast::Producer, @@ -1263,7 +1260,7 @@ mod tests { setup.set(declared); let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -1300,12 +1297,19 @@ mod tests { impl Harness { /// Send `msg` on a new request stream, dispatched as the session would. - async fn request(&mut self, msg: &M) -> Stream { - let mut stream = Stream::open(&mut self.peer, self.version).await.unwrap(); + async fn request(&mut self, msg: &M) -> Stream { + let mut stream = Stream::open(&mut crate::driver::Transport::new(self.peer.clone()), self.version) + .await + .unwrap(); stream.writer.varint(M::ID).await.unwrap(); stream.writer.encode(msg).await.unwrap(); - let mut accepted = timeout(Stream::accept(&mut self.session, self.version)).await.unwrap(); + let mut accepted = timeout(Stream::accept( + &mut crate::driver::Transport::new(self.session.clone()), + self.version, + )) + .await + .unwrap(); let id = accepted.reader.varint().await.unwrap(); let body: ietf::Body = accepted.reader.decode().await.unwrap(); let task = self.publisher.handle_stream(id, body, accepted, false).unwrap(); @@ -1314,8 +1318,13 @@ mod tests { } /// The next PUBLISH the publisher opens: its stream, namespace, track and FORWARD. - async fn publish(&mut self) -> (Stream, String, String, bool) { - let mut stream = timeout(Stream::accept(&mut self.peer, self.version)).await.unwrap(); + async fn publish(&mut self) -> (Stream, String, String, bool) { + let mut stream = timeout(Stream::accept( + &mut crate::driver::Transport::new(self.peer.clone()), + self.version, + )) + .await + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::Publish::ID); let body: ietf::Body = stream.reader.decode().await.unwrap(); let publish: ietf::Publish = body.message(self.version).unwrap(); @@ -1330,13 +1339,13 @@ mod tests { } /// The next message on a request stream: its type and body. - async fn next(stream: &mut Stream) -> (u64, ietf::Body) { + async fn next(stream: &mut Stream) -> (u64, ietf::Body) { let id = timeout(stream.reader.varint()).await.unwrap(); let body = stream.reader.decode().await.unwrap(); (id, body) } - async fn send(stream: &mut Stream, msg: &M) { + async fn send(stream: &mut Stream, msg: &M) { stream.writer.varint(M::ID).await.unwrap(); stream.writer.encode(msg).await.unwrap(); } @@ -1347,7 +1356,7 @@ mod tests { /// Answer a PUBLISH with a PUBLISH_OK leaving it paused, which draft-20 on cannot /// change. From draft-18 it is sent as REQUEST_OK. - async fn publish_ok(stream: &mut Stream) { + async fn publish_ok(stream: &mut Stream) { stream.writer.varint(ietf::RequestOk::ID).await.unwrap(); stream .writer @@ -1459,7 +1468,7 @@ mod tests { .await .unwrap(); opened += 1; - let mut reader = crate::coding::Reader::new(recv, version); + let mut reader = crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version); let mut bytes = Vec::new(); while let Some(chunk) = timeout(std::future::poll_fn(|cx| reader.poll_read_chunk(cx, 1024))) .await @@ -1510,7 +1519,12 @@ mod tests { let mut request = h.request(&listing(false)).await; assert_eq!(next(&mut request).await.0, ietf::RequestOk::ID, "{version}"); let mut stream = loop { - let mut stream = timeout(Stream::accept(&mut h.peer, version)).await.unwrap(); + let mut stream = timeout(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version, + )) + .await + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::Publish::ID); let body: ietf::Body = stream.reader.decode().await.unwrap(); let publish: ietf::Publish = body.message(version).unwrap(); @@ -1530,7 +1544,7 @@ mod tests { let recv = timeout(std::future::poll_fn(|cx| h.peer.poll_accept_uni(cx))) .await .unwrap(); - let mut reader = crate::coding::Reader::new(recv, version); + let mut reader = crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version); let mut bytes = Vec::new(); while let Some(chunk) = timeout(std::future::poll_fn(|cx| reader.poll_read_chunk(cx, 1024))) .await @@ -1568,7 +1582,10 @@ mod tests { } skipped.sort(); assert_eq!(skipped, ["audio", "video"], "{version}"); - let opened = futures::poll!(std::pin::pin!(Stream::accept(&mut h.peer, version))); + let opened = futures::poll!(std::pin::pin!(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version + ))); assert!(opened.is_pending(), "{version}: a skipped track was PUBLISHed"); } } @@ -1673,7 +1690,10 @@ mod tests { .create_track("captions", crate::track::Info::timed()) .unwrap(); moq_clock::sleep(Duration::from_millis(10)).await; - let opened = futures::poll!(std::pin::pin!(Stream::accept(&mut h.peer, version))); + let opened = futures::poll!(std::pin::pin!(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version + ))); assert!(opened.is_pending(), "{version}: PUBLISHed after the cancel"); drop(h.broadcast); @@ -1709,7 +1729,10 @@ mod tests { for _ in 0..2 { assert_eq!(next(&mut relisting).await.0, ietf::PublishSkipped::ID); } - let opened = futures::poll!(std::pin::pin!(Stream::accept(&mut h.peer, version))); + let opened = futures::poll!(std::pin::pin!(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version + ))); assert!(opened.is_pending(), "PUBLISHed a track twice"); } else { let _publishes = [h.publish().await, h.publish().await]; @@ -2089,7 +2112,8 @@ mod tests { group.finish().unwrap(); moq_clock::sleep(Duration::from_millis(10)).await; while let Poll::Ready(recv) = futures::poll!(std::future::poll_fn(|cx| h.peer.poll_accept_uni(cx))) { - let mut reader = crate::coding::Reader::new(recv.unwrap(), version); + let mut reader = + crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv.unwrap()), version); let mut bytes = Vec::new(); while let Some(chunk) = timeout(std::future::poll_fn(|cx| reader.poll_read_chunk(cx, 1024))) .await @@ -2166,7 +2190,12 @@ mod tests { }; let mut request = h.request(&request).await; assert_eq!(next(&mut request).await.0, ietf::RequestOk::ID, "{version}"); - let mut stream = timeout(Stream::accept(&mut h.peer, version)).await.unwrap(); + let mut stream = timeout(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version, + )) + .await + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::Publish::ID); let body: ietf::Body = stream.reader.decode().await.unwrap(); let publish: ietf::Publish = body.message(version).unwrap(); @@ -2280,7 +2309,7 @@ mod tests { }); h.publisher = Publisher::new( crate::time::sim(), - h.session.clone(), + crate::driver::Transport::new(h.session.clone()), h._origin.consume(), Control::new(None, false), None, @@ -2291,7 +2320,10 @@ mod tests { let first = h.request(&listing(false)).await; moq_clock::sleep(Duration::from_millis(10)).await; - let opened = futures::poll!(std::pin::pin!(Stream::accept(&mut h.peer, version))); + let opened = futures::poll!(std::pin::pin!(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version + ))); assert!(opened.is_pending(), "{version}: listed a track before the setup answer"); first.writer.abort(&Error::Cancel); @@ -2325,7 +2357,10 @@ mod tests { let mut request = h.request(&listing(false)).await; assert_eq!(next(&mut request).await.0, ietf::RequestOk::ID, "{version}"); moq_clock::sleep(Duration::from_millis(10)).await; - let opened = futures::poll!(std::pin::pin!(Stream::accept(&mut h.peer, version))); + let opened = futures::poll!(std::pin::pin!(Stream::accept( + &mut crate::driver::Transport::new(h.peer.clone()), + version + ))); assert!(opened.is_pending(), "{version}: listed a track the grant denies"); auth.authorize(&crate::auth::Grant::all()); diff --git a/rs/moq-net/src/ietf/request_stream.rs b/rs/moq-net/src/ietf/request_stream.rs index 52fb4173b20..bc87bcbedbc 100644 --- a/rs/moq-net/src/ietf/request_stream.rs +++ b/rs/moq-net/src/ietf/request_stream.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; use std::task::{Context, Poll, ready}; use super::{Message, Version}; @@ -8,11 +10,11 @@ use crate::{ /// Legacy receives are framed once by the physical multiplexer, not again by /// the virtual request decoder. Encodes still count at their typed codec. -pub(super) fn with_stats( - stream: Stream, +pub(super) fn with_stats( + stream: Stream, stats: &crate::stats::Session, version: Version, -) -> Stream { +) -> Stream { let mut stream = stream.with_stats(stats); if matches!(version, Version::Draft14 | Version::Draft15 | Version::Draft16) { stream.reader = stream.reader.with_stats(&Default::default()); @@ -28,10 +30,10 @@ pub(super) fn fin_cancels(version: Version) -> bool { } /// Watch abrupt cancellation after the requester has finished sending messages. -pub(super) fn poll_cancel( - stream: &mut Stream, +pub(super) fn poll_cancel( + stream: &mut Stream, finished: &mut bool, - messages: &mut Messages, + messages: &mut Messages, version: Version, cx: &mut Context<'_>, ) -> Poll> { @@ -57,8 +59,8 @@ pub(super) fn poll_cancel( /// what it sent meanwhile: a waiting message (an update, say) ends the watch on the reader and /// is read once the request is answered. A withdrawal queued behind an update is therefore seen /// only then; until the verifier answers, the requester holds nothing but its own slot. -pub(super) fn poll_withdrawn( - stream: &mut Stream, +pub(super) fn poll_withdrawn( + stream: &mut Stream, version: Version, cx: &mut Context<'_>, ) -> Poll<()> { @@ -87,8 +89,8 @@ pub(super) fn poll_withdrawn( /// An update modifies the request rather than ending it, and the requests watched here /// apply none, so each is refused with [`refuse_update`] and the request stays open. Any /// other message is `Err(Cancel)`, and the stream finishing is `Ok(())`. -pub(super) fn poll_legacy_end( - stream: &mut Stream, +pub(super) fn poll_legacy_end( + stream: &mut Stream, version: Version, cx: &mut Context<'_>, ) -> Poll> { @@ -108,8 +110,8 @@ pub(super) fn poll_legacy_end( /// Draft 14 answers no update. Drafts 15 and 16 answer each with exactly one REQUEST_OK or /// REQUEST_ERROR naming the update's own Request ID, and a refusal leaves any request but a /// subscription standing, so NOT_SUPPORTED is the whole answer. -pub(super) fn refuse_update( - writer: &mut crate::coding::Writer, +pub(super) fn refuse_update( + writer: &mut crate::coding::Writer, body: &super::Body, version: Version, ) -> Result<(), Error> { @@ -246,13 +248,13 @@ impl GoAways { } /// The messages on one request stream, keeping GOAWAY validation across response phases. -pub(super) struct Messages { - session: S, +pub(super) struct Messages { + session: Transport, goaways: GoAways, } -impl Messages { - pub fn new(session: S, client: bool) -> Self { +impl Messages { + pub fn new(session: Transport, client: bool) -> Self { Self { session, goaways: GoAways::new(client), @@ -311,8 +313,8 @@ impl Messages { } /// Refuse a modern request with its complete REQUEST_ERROR, then finish the response. -pub(super) async fn reject( - mut stream: Stream, +pub(super) async fn reject( + mut stream: Stream, error: super::RequestError<'_>, ) -> Result<(), Error> { stream.writer.varint(super::RequestError::ID).await?; @@ -326,8 +328,8 @@ pub(super) async fn reject( /// /// Each draft-14 error message has the REQUEST_ERROR body that draft-15 folded them into, so /// only the message type changes; draft-17 then drops the Request ID. -pub(super) async fn write_error( - writer: &mut crate::coding::Writer, +pub(super) async fn write_error( + writer: &mut crate::coding::Writer, kind: super::error::request::Kind, request_id: super::RequestId, err: &Error, @@ -569,9 +571,11 @@ mod tests { for version in [Version::Draft18, Version::Draft19, Version::Draft21, Version::Draft22] { // GOAWAY, REQUEST_OK, then another GOAWAY on the same stream. let script = vec![0x10, 0, 2, 0, 0, 0x07, 0, 0, 0x10, 0, 2, 0, 0]; - let mut session = ScriptedSession::eof(script); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut messages = Messages::new(session.clone(), true); + let session = ScriptedSession::eof(script); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut messages = Messages::new(crate::driver::Transport::new(session.clone()), true); assert_eq!(messages.message(&mut stream.reader).await.unwrap().0, 0x07); assert!(matches!( messages.message(&mut stream.reader).await, @@ -590,9 +594,15 @@ mod tests { let registry = Registry::new(Default::default()); let stats = registry.tier(Tier::default()).session(""); let version = Version::Draft22; - let mut session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0, 0x07, 0, 0]); - let mut stream = with_stats(Stream::open(&mut session, version).await.unwrap(), &stats, version); - let mut messages = Messages::new(session.clone(), true); + let session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0, 0x07, 0, 0]); + let mut stream = with_stats( + Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(), + &stats, + version, + ); + let mut messages = Messages::new(crate::driver::Transport::new(session.clone()), true); assert_eq!(messages.message(&mut stream.reader).await.unwrap().0, 0x07); let rx = |class| { let rows = registry.snapshot().control(); @@ -606,9 +616,11 @@ mod tests { async fn a_goaway_does_not_cancel_a_pending_request() { use crate::lite::test_transport::ScriptedSession; for version in [Version::Draft18, Version::Draft21, Version::Draft22] { - let mut session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); - let mut stream = Stream::open(&mut session, version).await.unwrap(); - let mut messages = Messages::new(session.clone(), false); + let session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0]); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let mut messages = Messages::new(crate::driver::Transport::new(session.clone()), false); let mut finished = false; assert!( futures::poll!(std::future::poll_fn(|cx| poll_cancel( @@ -654,10 +666,12 @@ mod tests { }; let mut update = vec![super::super::SubscribeUpdate::ID as u8, 0, body.len() as u8]; update.extend_from_slice(body); - let mut session = ScriptedSession::new(update); - let mut stream = Stream::open(&mut session, version).await.unwrap(); + let session = ScriptedSession::new(update); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut finished = false; - let mut messages = Messages::new(session.clone(), false); + let mut messages = Messages::new(crate::driver::Transport::new(session.clone()), false); let polled = futures::poll!(std::future::poll_fn(|cx| poll_cancel( &mut stream, @@ -771,13 +785,19 @@ mod tests { Kind::TrackStatus, ] { let shared = Log::default(); - let mut writer = crate::coding::Writer::new(SinkSend::new(shared.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(shared.clone())), + version, + ); write_error(&mut writer, kind, request_id, &err, reason, version) .await .unwrap(); let legacy = Log::default(); - let mut writer = crate::coding::Writer::new(SinkSend::new(legacy.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(legacy.clone())), + version, + ); let error_code = to_code(&err, kind, version); let reason_phrase = reason.into(); match kind { diff --git a/rs/moq-net/src/ietf/request_update.rs b/rs/moq-net/src/ietf/request_update.rs index 256cdbc33a9..cfba92c239e 100644 --- a/rs/moq-net/src/ietf/request_update.rs +++ b/rs/moq-net/src/ietf/request_update.rs @@ -136,7 +136,9 @@ pub(super) struct Verdict { /// Close `session` for a peer past the MAX_REQUEST_UPDATES we advertised, returning the error /// that ends the request. -pub(super) fn too_many(session: &mut S) -> Error { +#[cfg(feature = "async")] +pub(super) fn too_many(session: &mut crate::driver::Transport) -> Error { + use crate::transport::poll::Session as _; let err = SessionError::TooManyRequestUpdates; session.close(super::error::to_session_code(&err), "too many request updates"); Error::Session(err) diff --git a/rs/moq-net/src/ietf/session.rs b/rs/moq-net/src/ietf/session.rs index 8e99324e2a1..0c3300748b8 100644 --- a/rs/moq-net/src/ietf/session.rs +++ b/rs/moq-net/src/ietf/session.rs @@ -1,3 +1,4 @@ +use crate::driver::Transport; use crate::origin; use crate::transport::poll::Session as _; use crate::{ @@ -16,18 +17,18 @@ use super::{ }; /// Everything one moq-transport session needs to start. -pub struct Config { +pub struct Config { /// The runtime that arms the session's timers. pub runtime: crate::time::Deadlines, /// Where the session's control traffic is counted, even with neither origin set. pub stats: crate::stats::Session, - pub session: S, + pub session: Transport, /// The bidi SETUP stream (draft-14 through draft-16 only). Draft-17+ passes `None` /// and exchanges SETUP on uni streams instead. - pub setup: Option>, + pub setup: Option>, pub request_id_max: Option, @@ -70,7 +71,7 @@ pub struct Config { /// The peer's SETUP stream, when it was already read before [`start`] (a draft-17+ /// server that gated on the client's path via [`accept_setup`]). It becomes the /// GOAWAY channel; `None` lets the uni loop read the SETUP itself. - pub peer_setup_stream: Option>, + pub peer_setup_stream: Option>, /// What that pre-read SETUP declared, so the session does not have to parse it /// twice. `None` when [`Self::peer_setup_stream`] is. @@ -84,7 +85,7 @@ pub struct Config { /// Uni streams that arrived before that pre-read SETUP (see [`PeerSetup::early`]), /// classified by the session before it accepts any more. - pub early_unis: Vec>, + pub early_unis: Vec>, /// The extensions our SETUP offers. Drafts 14-16 already sent it, so there this only /// records what it said. MoQ Auth is offered only while [`Self::auth`] supports it too. @@ -113,7 +114,7 @@ impl std::future::Future for Driver { } } -pub fn start(config: Config) -> Result<(Driver, crate::goaway::Handle), Error> { +pub fn start(config: Config) -> Result<(Driver, crate::goaway::Handle), Error> { let Config { runtime, stats, @@ -349,7 +350,10 @@ pub fn start(config: Config) -> Result<(Driver, crate: reader, } } - _ => Stream::open(&mut crate::driver::Transport::new(sub_ns_adapter), version).await?, + _ => { + Stream::open(&mut crate::driver::Transport::new(sub_ns_adapter.clone()), version) + .await? + } }; if let Err(err) = sub_ns.run_subscribe_namespace(stream, prefix, snapshot).await { // The peer breaking the protocol is fatal, and the driver @@ -649,7 +653,7 @@ pub fn start(config: Config) -> Result<(Driver, crate: /// /// Dropping them first would reset the control stream ahead of the close, and a strict peer /// closes over that reset with its own PROTOCOL_VIOLATION before it reads our code. -fn close(session: &mut S, res: &Result<(), Error>) { +fn close(session: &mut Transport, res: &Result<(), Error>) { match res { Err(err @ (Error::Transport(_) | Error::IdleTimeout)) => { tracing::info!(%err, "session terminated"); @@ -670,9 +674,9 @@ fn close(session: &mut S, res: &Result<(), E } /// What a peer's SETUP told us, beyond the stream it arrived on. -pub struct PeerSetup { +pub struct PeerSetup { /// The SETUP stream, which becomes the GOAWAY channel. - pub stream: Reader, + pub stream: Reader, /// The SETUP's encoded size, counted once the session's stats are known. pub size: usize, @@ -689,7 +693,7 @@ pub struct PeerSetup { /// Uni streams that arrived before the SETUP, type peeked but unread. The drafts say /// to buffer early data until the control streams arrive, so the session classifies /// these once it starts. QUIC stream credit bounds how many can pile up. - pub early: Vec>, + pub early: Vec>, } /// The Hop ID this session declares and detects loops against. @@ -712,16 +716,13 @@ fn self_origin(publish: Option<&origin::Consumer>, subscribe: Option<&origin::Pr /// [`PeerSetup::early`] for the session to classify. Pass the returned reader to /// [`start`] as its `peer_setup_stream` so GOAWAY monitoring continues without /// re-reading it. -pub async fn accept_setup( - session: &mut S, - version: Version, -) -> Result, Error> { +pub async fn accept_setup(session: &mut Transport, version: Version) -> Result { let outer_version = crate::Version::Ietf(version); let mut early = Vec::new(); loop { let recv = session.accept_uni().await.map_err(Error::from_transport)?; - let mut reader: Reader = Reader::new(recv, outer_version); + let mut reader: Reader = Reader::new(recv, outer_version); let kind = match reader.varint_peek().await { Ok(kind) => kind, @@ -801,8 +802,8 @@ fn peer_from_params(params: &ietf::Parameters, version: Version) -> Result( - mut session: S, +async fn run_setup( + mut session: Transport, version: Version, path: Option, authority: Option, @@ -819,7 +820,8 @@ async fn run_setup( .open_uni(Default::default()) .await .map_err(Error::from_transport)?; - let mut writer: Writer = Writer::new(send, outer_version).with_stats(&stats); + let mut writer: Writer = + Writer::new(send, outer_version).with_stats(&stats); let mut parameters = ietf::Parameters::default(); parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec()); @@ -951,11 +953,11 @@ impl UniType { } /// Setup and lifecycle state for the incoming uni stream dispatcher. -struct UniSetup { +struct UniSetup { peer: Option, read: bool, /// Streams accepted before the session started, handled before accepting more. - early: Vec>, + early: Vec>, /// Our role, which decides what the peer's SETUP and GOAWAY may carry. client: bool, version: Version, @@ -969,17 +971,17 @@ struct UniSetup { /// the peer has not sent yet, held back by connection flow control that the later /// streams' unread data is using up. Waiting here for its type would deadlock the /// connection. -struct Unis { - session: S, - uni: Uni, - early: std::collections::VecDeque>, +struct Unis { + session: Transport, + uni: Uni, + early: std::collections::VecDeque>, tasks: TaskSet, fatal: kio::Shared>, ended: Option, } -impl Unis { - fn new(session: S, subscriber: Subscriber, setup: UniSetup) -> Self { +impl Unis { + fn new(session: Transport, subscriber: Subscriber, setup: UniSetup) -> Self { Self { uni: Uni { subscriber, @@ -1055,8 +1057,8 @@ impl Unis { /// What serving one incoming uni stream needs from its session. #[derive(Clone)] -struct Uni { - subscriber: Subscriber, +struct Uni { + subscriber: Subscriber, peer_setup: Option, /// Exactly one SETUP per endpoint. seen_setup: std::sync::Arc, @@ -1065,9 +1067,9 @@ struct Uni { version: Version, } -impl Uni { +impl Uni { /// Read the stream's type and serve it, failing only when the stream breaks the session. - async fn serve(self, mut reader: Reader) -> Result<(), Error> { + async fn serve(self, mut reader: Reader) -> Result<(), Error> { reader = reader.with_stats(self.subscriber.stats()); let Self { mut subscriber, @@ -1169,10 +1171,7 @@ fn died_before_header(err: &Error) -> bool { /// /// A transport without datagrams never delivers one, so this parks. A transport failure /// or a malformed datagram ends the session. -async fn run_datagrams(mut session: S, subscriber: Subscriber) -> Result<(), Error> -where - S: crate::transport::poll::Boxable, -{ +async fn run_datagrams(mut session: Transport, subscriber: Subscriber) -> Result<(), Error> { if session.max_datagram_size() == 0 { return Ok(()); } @@ -1206,18 +1205,15 @@ pub(super) fn stop_on_error( } /// Accept incoming bidi streams, leaving each request to read its own header. -async fn run_dispatch( - mut session: S, - publisher: Publisher, - subscriber: Subscriber, +async fn run_dispatch( + mut session: Transport, + publisher: Publisher, + subscriber: Subscriber, peer_setup: peer::PeerSetup, // Answers the peer's Auth requests, on the versions that can negotiate them. serve: Option, version: Version, -) -> Result<(), Error> -where - S: crate::transport::poll::Boxable, -{ +) -> Result<(), Error> { use std::task::Poll; // PUBLISH_NAMESPACE decodes differently once the MoQ Cluster extension is @@ -1300,9 +1296,9 @@ where /// What serving one incoming bidi request needs from its session. #[derive(Clone)] -struct Bidi { - publisher: Publisher, - subscriber: Subscriber, +struct Bidi { + publisher: Publisher, + subscriber: Subscriber, peer: cluster::Peer, /// Whether both sides negotiated MoQ Epoch. epoch: bool, @@ -1311,9 +1307,9 @@ struct Bidi { version: Version, } -impl Bidi { +impl Bidi { /// Read and serve a request, failing only when it breaks the session. - async fn serve(self, mut stream: Stream) -> Result<(), Error> { + async fn serve(self, mut stream: Stream) -> Result<(), Error> { stream = super::request_stream::with_stats(stream, self.publisher.stats(), self.version); let Self { publisher, @@ -1417,11 +1413,7 @@ impl Bidi { /// Refuse a request past our GOAWAY cutoff with the answer its kind reads: an AUTH /// presenter reads only AUTH_OK and AUTH_ERROR. -async fn refuse_going_away( - stream: Stream, - id: u64, - version: Version, -) -> Result<(), Error> { +async fn refuse_going_away(stream: Stream, id: u64, version: Version) -> Result<(), Error> { if id == auth::Auth::ID { return auth::refuse_going_away(stream).await; } @@ -1535,11 +1527,7 @@ impl Drop for AuthClose { /// /// Judges the publisher's serving origin rather than the raw one: an origin that also /// consumes holds what the peer sent us, which is not ours to publish back. -async fn enforce_grant( - auth: crate::auth::Handle, - publisher: Publisher, - mut session: S, -) -> Result<(), Error> { +async fn enforce_grant(auth: crate::auth::Handle, publisher: Publisher, mut session: Transport) -> Result<(), Error> { let origin = publisher.serving_origin().await; // Checking what we publish is not a local reader asking to discover anything. let mut announced = origin.clone().serving().announced(); @@ -1618,7 +1606,7 @@ mod tests { let (driver, _) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -1674,7 +1662,7 @@ mod tests { let (driver, _) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -1721,7 +1709,7 @@ mod tests { let (driver, _) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -1755,7 +1743,10 @@ mod tests { #[test] fn object_overflow_is_session_fatal_but_a_stream_error_is_not() { - let mut reader = Reader::new(crate::lite::test_transport::PendingRecv, Version::Draft22); + let mut reader = Reader::new( + crate::transport::boxed::RecvStream::new(crate::lite::test_transport::PendingRecv), + Version::Draft22, + ); let err = stop_on_error(&mut reader, Err(SessionError::ProtocolViolation.into())).unwrap_err(); assert_eq!(SessionError::from(&err), SessionError::ProtocolViolation); assert!(stop_on_error(&mut reader, Err(Error::Unsupported)).is_ok()); @@ -1773,7 +1764,10 @@ mod tests { /// can't drift from the encoder under test. async fn namespace_without_hop_path(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer @@ -1817,7 +1811,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -1881,7 +1875,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -1919,7 +1913,10 @@ mod tests { /// The bytes of one legacy SUBSCRIBE_NAMESPACE, as the session writes them. async fn subscribe_namespace_legacy(version: Version, namespace: &str) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let msg = ietf::SubscribeNamespaceLegacy { request_id: RequestId(0), namespace: crate::Path::new(namespace), @@ -1948,8 +1945,8 @@ mod tests { let gate = kio::Producer::new(true); let session = crate::lite::test_transport::SinkSession::gated_bi(gate.consume()); let log = session.log.clone(); - let mut session = crate::driver::Transport::new(session); - let setup = Stream::open(&mut session, version) + let session = crate::driver::Transport::new(session.clone()); + let setup = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) .await .expect("open the control stream"); @@ -2045,7 +2042,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2149,7 +2146,7 @@ mod tests { let (driver, goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2234,7 +2231,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2307,7 +2304,10 @@ mod tests { /// The bytes of a peer's Auth request presenting its connection credential. async fn auth_request(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer .encode_message(&auth::Auth { request_id: RequestId(0), @@ -2331,7 +2331,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2421,7 +2421,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2465,7 +2465,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2525,7 +2525,10 @@ mod tests { /// dispatch loop runs. async fn subgroup_header(version: Version, track_alias: u64, sub_group_id: u64) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer .encode(&ietf::GroupHeader { @@ -2563,7 +2566,7 @@ mod tests { async fn drive_unis( version: Version, session: crate::lite::test_transport::ScriptedSession, - accepted: Option>, + accepted: Option, retired_alias: Option, ) -> (crate::lite::test_transport::Log, Option>) { let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); @@ -2573,7 +2576,7 @@ mod tests { let peer_setup = peer::PeerSetup::default(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, true), None, @@ -2595,7 +2598,7 @@ mod tests { let read = accepted.is_some(); let early = accepted.map(|accepted| accepted.early).unwrap_or_default(); let mut unis = Unis::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, UniSetup { peer: Some(peer_setup), @@ -2732,7 +2735,7 @@ mod tests { start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2812,12 +2815,14 @@ mod tests { ) .unwrap(); - let mut session = crate::lite::test_transport::ScriptedSession::new(Vec::new()).with_incoming_unis(vec![ + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()).with_incoming_unis(vec![ uni_stream(VERSION, PADDING), subgroup_header(VERSION, 7, 0).await, setup, ]); - let accepted = accept_setup(&mut session, VERSION).await.expect("accept the SETUP"); + let accepted = accept_setup(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .expect("accept the SETUP"); assert_eq!(accepted.early.len(), 2, "both early streams are held"); assert!(session.log.stops().is_empty(), "stopped {:?}", session.log.stops()); @@ -2876,7 +2881,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -2945,7 +2950,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, client: false, @@ -2981,7 +2986,10 @@ mod tests { /// The second has no advertisement left to name. async fn publish_namespace_then_two_withdrawals(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::PublishNamespace::ID).await.unwrap(); writer @@ -3014,7 +3022,7 @@ mod tests { async fn publish_namespace_ok(request_id: RequestId) -> Vec { let log = crate::lite::test_transport::Log::default(); let mut writer = crate::coding::Writer::new( - crate::lite::test_transport::SinkSend::new(log.clone()), + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), Version::Draft14, ); @@ -3041,8 +3049,8 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::new(publish_namespace_then_two_withdrawals(VERSION).await); let log = session.log.clone(); - let mut session = crate::driver::Transport::new(session); - let setup = Stream::open(&mut session, VERSION) + let session = crate::driver::Transport::new(session.clone()); + let setup = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) .await .expect("open the control stream"); @@ -3164,9 +3172,13 @@ mod tests { } }; let log = session.log.clone(); - let mut session = crate::driver::Transport::new(session); + let session = crate::driver::Transport::new(session.clone()); let setup = match version { - Version::Draft14 => Some(Stream::open(&mut session, version).await.unwrap()), + Version::Draft14 => Some( + Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(), + ), _ => None, }; let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); @@ -3343,7 +3355,6 @@ mod tests { #[moq_clock::test] async fn a_control_stream_fin_or_reset_is_a_protocol_violation() { use crate::lite::test_transport::{Close, DeadStreamSession, ScriptedSession}; - use crate::transport::poll::Session as _; for version in [Version::Draft17, Version::Draft18, Version::Draft21, Version::Draft22] { let session = ScriptedSession::new(Vec::new()).with_incoming_unis(vec![setup_stream( version, @@ -3360,9 +3371,14 @@ mod tests { let mut session = DeadStreamSession::unis(1); let recv = session.accept_uni().await.unwrap(); let (_handle, protocol) = crate::goaway::Handle::new(false); - let err = run_goaway(Reader::new(recv, version), version, true, protocol) - .await - .unwrap_err(); + let err = run_goaway( + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + version, + true, + protocol, + ) + .await + .unwrap_err(); assert_eq!(SessionError::from(&err), SessionError::ProtocolViolation, "{version:?}"); } } @@ -3371,8 +3387,6 @@ mod tests { /// so an application leaving over it cannot close first, without our code. #[moq_clock::test] async fn a_goaway_with_more_behind_it_never_surfaces() { - use crate::transport::poll::Session as _; - for version in [Version::Draft18, Version::Draft21] { let request_id = (version == Version::Draft18).then_some(0); let two = [goaway(version, request_id), goaway(version, request_id)].concat(); @@ -3381,9 +3395,14 @@ mod tests { let stream = std::future::poll_fn(|cx| session.poll_accept_uni(cx)).await.unwrap(); let (handle, protocol) = crate::goaway::Handle::new(false); - let err = read_goaways(Reader::new(stream, version), version, true, protocol) - .await - .expect_err("a second GOAWAY is fatal"); + let err = read_goaways( + Reader::new(crate::transport::boxed::RecvStream::new(stream), version), + version, + true, + protocol, + ) + .await + .expect_err("a second GOAWAY is fatal"); assert_eq!(SessionError::from(&err), SessionError::ProtocolViolation, "{version:?}"); assert!( handle.consumer().peek().is_none(), @@ -3405,7 +3424,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -3475,7 +3494,7 @@ mod tests { control.accept(RequestId(first + 4)).unwrap(); let (handle, goaway_protocol) = crate::goaway::Handle::new(!client); let mut setup = std::pin::pin!(run_setup( - session, + crate::driver::Transport::new(session.clone()), VERSION, None, None, @@ -3508,7 +3527,7 @@ mod tests { let (driver, _goaway) = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session: crate::driver::Transport::new(session), + session: crate::driver::Transport::new(session.clone()), setup: None, request_id_max: None, limits: Default::default(), @@ -3553,9 +3572,11 @@ mod tests { frame(VERSION, ietf::RequestError::ID, &[&[0x6, 0][..], &body[1..]].concat()), ), ] { - let mut session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); let log = session.log.clone(); - let stream = Stream::open(&mut session, VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); refuse_going_away(stream, id, VERSION).await.unwrap(); assert_eq!(*log.writes.lock().unwrap(), answer, "{id:#x}"); } diff --git a/rs/moq-net/src/ietf/subscriber.rs b/rs/moq-net/src/ietf/subscriber.rs index e8835fbebc4..faccce2cd94 100644 --- a/rs/moq-net/src/ietf/subscriber.rs +++ b/rs/moq-net/src/ietf/subscriber.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; use std::{ collections::{HashMap, hash_map::Entry}, sync::atomic::{AtomicU64, Ordering}, @@ -748,7 +750,7 @@ impl Drop for JoiningTask { } #[derive(Clone)] -pub(super) struct Subscriber { +pub(super) struct Subscriber { // Scoped to a minted source on the clone that serves its requests. validity: crate::model::broadcast::RequestValidity, // The publisher instance the minted source was resolved under (MoQ Epoch), named on @@ -757,7 +759,7 @@ pub(super) struct Subscriber { epoch: Option, // Arms the track-alias and request-id timeouts. runtime: crate::time::Deadlines, - session: S, + session: Transport, // Traffic stats are attributed through this tagged origin handle. origin: origin::Producer, control: Control, @@ -796,7 +798,7 @@ pub(super) struct Subscriber { // tracks it lists to us. pub(super) announces: crate::session::Slots, // What SUBSCRIBE_TRACKS lists of the peer's tracks. - listings: Lock>, + listings: Lock, } /// The prefixes to issue SUBSCRIBE_NAMESPACE for: `origin`'s permitted scope, @@ -857,14 +859,11 @@ async fn resolve_track_alias( .await } -impl Subscriber -where - S: crate::transport::poll::Boxable, -{ +impl Subscriber { #[allow(clippy::too_many_arguments)] pub fn new( runtime: crate::time::Deadlines, - session: S, + session: Transport, origin: origin::Producer, control: Control, peer_hop: Option, @@ -1157,9 +1156,9 @@ where /// `snapshot` holds the origin's announce consumers under the prefix short of /// synced. It drops once the NAMESPACE messages MoQ Active Count promised are /// in, on REQUEST_OK without the extension, or when no request goes out at all. - pub async fn run_subscribe_namespace( + pub async fn run_subscribe_namespace( &mut self, - mut stream: Stream, + mut stream: Stream, prefix: PathOwned, snapshot: crate::model::Snapshot, ) -> Result<(), Error> { @@ -1296,15 +1295,15 @@ where /// as an update rather than a second advertisement, and the caller can release /// whatever is still held when the stream ends. #[allow(clippy::too_many_arguments)] - async fn run_namespace_entries( + async fn run_namespace_entries( &mut self, - stream: &mut Stream, + stream: &mut Stream, prefix: &PathOwned, peer: &cluster::Peer, negotiated: ietf::Negotiated, live: &mut HashMap, mut initial: Initial, - messages: &mut super::request_stream::Messages, + messages: &mut super::request_stream::Messages, ) -> Result<(), Error> { loop { // Every counted NAMESPACE is in the origin by now, dropped ones included. @@ -1412,7 +1411,7 @@ where &mut self, id: u64, body: ietf::Body, - stream: Stream, + stream: Stream, peer: cluster::Peer, epoch: bool, declared: Option, @@ -1503,7 +1502,7 @@ where /// other decode error leaves the session open. fn reject_token( &self, - stream: Stream, + stream: Stream, kind: request::Kind, body: ietf::Body, err: DecodeError, @@ -1552,7 +1551,7 @@ where #[cfg(test)] async fn run_publish_namespace_stream( &mut self, - stream: Stream, + stream: Stream, msg: ietf::PublishNamespace<'_>, peer: cluster::Peer, declared: Option, @@ -1576,7 +1575,7 @@ where async fn serve_publish_namespace_stream( &mut self, - mut stream: Stream, + mut stream: Stream, incoming: IncomingNamespace<'_>, ) -> Result<(), Error> { let IncomingNamespace { @@ -1768,7 +1767,7 @@ where /// (moq-transport Section 9.5.1). async fn run_publish_namespace_updates( &mut self, - stream: &mut Stream, + stream: &mut Stream, path: &PathOwned, held: Held, peer: cluster::Peer, @@ -2095,7 +2094,7 @@ where /// and PUBLISH_NAMESPACE_CANCEL before it, where the request outlives its stream. async fn cancel_announce( &self, - stream: &mut Stream, + stream: &mut Stream, request_id: RequestId, path: &PathOwned, err: &Error, @@ -2133,7 +2132,7 @@ where /// a feature we don't implement is not a protocol violation. async fn run_publish_stream( &mut self, - mut stream: Stream, + mut stream: Stream, msg: ietf::Publish<'_>, ) -> Result<(), Error> { if let Some(error) = super::namespace::refusal(&msg.track_namespace, self.version) { @@ -2178,7 +2177,7 @@ where Ok(()) } - async fn write_ok(&self, stream: &mut Stream, request_id: RequestId) -> Result<(), Error> { + async fn write_ok(&self, stream: &mut Stream, request_id: RequestId) -> Result<(), Error> { match self.version { Version::Draft14 => { stream.writer.buffer_varint(ietf::PublishNamespaceOk::ID)?; @@ -2213,7 +2212,7 @@ where /// Refuse a PUBLISH_NAMESPACE on the bidi stream that carries it. async fn write_error( &self, - stream: &mut Stream, + stream: &mut Stream, request_id: RequestId, err: &Error, reason: &str, @@ -2232,7 +2231,7 @@ where /// Refuse a PUBLISH on the bidi stream that carries it. async fn write_publish_error( &self, - stream: &mut Stream, + stream: &mut Stream, request_id: RequestId, err: &Error, reason: &str, @@ -2689,7 +2688,7 @@ where &self, path: &Path<'_>, lister: &std::sync::Arc, - listening: &mut Option>, + listening: &mut Option, waiter: &kio::Waiter, ) { loop { @@ -3741,10 +3740,10 @@ where /// Read the subscription's PUBLISH_DONE, and on the way the answers to the /// REQUEST_UPDATEs counted in `unanswered`. Any other message is unexpected. async fn read_publish_done( - reader: &mut Reader, + reader: &mut Reader, version: Version, unanswered: &AtomicU64, - messages: &mut super::request_stream::Messages, + messages: &mut super::request_stream::Messages, ) -> Result, Error> { // A refused update is followed by PUBLISH_DONE, which ends the subscription. Its // count stays, so no further update goes out meanwhile, and no answer is owed. @@ -3782,7 +3781,7 @@ where /// carrying only what changed, under a Request ID of its own. async fn write_update( &self, - writer: &mut Writer, + writer: &mut Writer, subscription: RequestId, update: Update, ) -> Result<(), Error> { @@ -3821,7 +3820,7 @@ where /// cancellation (draft-19 section 3.3.2), so section 3.3.3's pair applies, an endpoint /// that has already FINed its sending direction cancels with STOP_SENDING on the /// receiving one. - async fn cancel_subscribe(&self, stream: Stream, request_id: RequestId) { + async fn cancel_subscribe(&self, stream: Stream, request_id: RequestId) { let Stream { mut writer, mut reader } = stream; if self.unsubscribes() @@ -3852,7 +3851,7 @@ where async fn write_unsubscribe( &self, - writer: &mut crate::coding::Writer, + writer: &mut crate::coding::Writer, request_id: RequestId, ) -> Result<(), Error> { writer.varint(ietf::Unsubscribe::ID).await?; @@ -3982,7 +3981,7 @@ where async fn finish_joining_fetch( &mut self, - mut stream: Stream, + mut stream: Stream, progress: kio::Shared, ) -> Result<(), Error> { let cancelled = |waiter: &kio::Waiter| { @@ -4035,8 +4034,8 @@ where async fn read_subscribe_response( &self, - stream: &mut Stream, - messages: &mut super::request_stream::Messages, + stream: &mut Stream, + messages: &mut super::request_stream::Messages, ) -> Result, Error> { // Read type_id + size + body from the stream let super::request_stream::Framed(type_id, body) = messages.message(&mut stream.reader).await?; @@ -4222,7 +4221,10 @@ where /// Read the answer to a TRACK_STATUS: TRACK_STATUS_OK, or the publisher's refusal as an /// error. - async fn read_track_status_response(&self, stream: &mut Stream) -> Result { + async fn read_track_status_response( + &self, + stream: &mut Stream, + ) -> Result { let mut messages = super::request_stream::Messages::new(self.session.clone(), self.control.client()); let super::request_stream::Framed(type_id, body) = messages.message(&mut stream.reader).await?; let mut data = body.decoder(self.version); @@ -4242,7 +4244,10 @@ where Err(request::from_code(code, request::Kind::TrackStatus, self.version)) } - pub async fn recv_group(&mut self, stream: &mut Reader) -> Result<(), Error> { + pub async fn recv_group( + &mut self, + stream: &mut Reader, + ) -> Result<(), Error> { let group: ietf::GroupHeader = stream.decode().await?; // Ranked as the least urgent subscription until its alias resolves. stream.set_priority(crate::priority::recv_group(i8::MIN, group.group_id, Default::default())); @@ -4588,10 +4593,7 @@ impl Decode for PeekFirst { } } -impl Subscriber -where - S: crate::transport::poll::Boxable, -{ +impl Subscriber { /// The group producer this subgroup stream writes into, and the Object ID it starts at. /// /// The first object is peeked before any producer exists, since a standalone @@ -4600,7 +4602,7 @@ where /// fetch stream began, which the first Object ID decides. async fn open_group( &self, - stream: &mut Reader, + stream: &mut Reader, track: &mut track::Producer, fill: &kio::Producer, resume: Option, @@ -4803,8 +4805,8 @@ enum IngestPhase { } impl GroupIngest { - fn new( - subscriber: &Subscriber, + fn new( + subscriber: &Subscriber, group: &ietf::GroupHeader, timescale: Option, start: Option, @@ -4825,10 +4827,7 @@ impl GroupIngest { } } -impl Subscriber -where - S: crate::transport::poll::Boxable, -{ +impl Subscriber { /// Read a fill fetch stream: the head of the group a subscription joins part way through. /// /// A draft-20 fill answers the FILL_PARAMETERS we sent and is named by the SUBSCRIBE's @@ -4837,7 +4836,10 @@ where /// into a group producer of its own and hands that to the subgroup stream carrying the /// rest of the group; see [`Fill`]. A reset stream is the publisher's fill-failure /// signal, and arrives here as a read error, which drops the head and the join with it. - pub async fn recv_fill(&mut self, stream: &mut Reader) -> Result<(), Error> { + pub async fn recv_fill( + &mut self, + stream: &mut Reader, + ) -> Result<(), Error> { // The dispatcher peeked the stream type to get here. let _ = stream.varint().await?; let header: ietf::FetchHeader = stream.decode().await?; @@ -4959,7 +4961,7 @@ where /// half-written head is a group with no end. async fn run_fill( &mut self, - stream: &mut Reader, + stream: &mut Reader, track: &mut track::Producer, timescale: Option, resume: Option, @@ -4995,7 +4997,7 @@ where /// objects below `resume` are dropped: another route already delivered them. async fn run_fill_objects( &mut self, - stream: &mut Reader, + stream: &mut Reader, track: &mut track::Producer, timescale: Option, resume: Option, @@ -5098,7 +5100,7 @@ where /// past it unless `keep`. async fn recv_fetch_payload( &self, - stream: &mut Reader, + stream: &mut Reader, producer: &mut crate::recv::Group, payload: FetchPayload, ) -> Result { @@ -5458,7 +5460,7 @@ where } /// Cancel a FETCH using the negotiated draft's existing cancellation signal. - async fn cancel_group_fetch(&self, mut stream: Stream, request_id: RequestId) { + async fn cancel_group_fetch(&self, mut stream: Stream, request_id: RequestId) { stream.reader.abort(&Error::Cancel); match self.version { Version::Draft14 | Version::Draft15 | Version::Draft16 => { @@ -5481,8 +5483,8 @@ where /// Read the answer to a FETCH: FETCH_OK, or the publisher's refusal as an error. async fn read_fetch_response( &self, - stream: &mut Stream, - messages: &mut super::request_stream::Messages, + stream: &mut Stream, + messages: &mut super::request_stream::Messages, ) -> Result { let super::request_stream::Framed(type_id, body) = messages.message(&mut stream.reader).await?; let mut data = body.decoder(self.version); @@ -5504,7 +5506,7 @@ where /// Write a group FETCH's objects into the group it accepted. async fn recv_group_fetch( &mut self, - stream: &mut Reader, + stream: &mut Reader, slot: kio::Producer, ) -> Result<(), Error> { // FETCH_OK can trail its own fetch stream. Taking the group in the same step is @@ -5588,7 +5590,7 @@ where /// Before draft-20 they must also reach it. async fn recv_group_fetch_objects( &self, - stream: &mut Reader, + stream: &mut Reader, producer: &mut crate::recv::Group, start: u64, end: Option, @@ -6019,12 +6021,12 @@ mod tests { use crate::transport::poll::Session as _; let mut session = ScriptedSession::eof(responses); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut reader = Reader::new(recv, Version::Draft19); - let result = Subscriber::::read_publish_done( + let mut reader = Reader::new(crate::transport::boxed::RecvStream::new(recv), Version::Draft19); + let result = Subscriber::read_publish_done( &mut reader, Version::Draft19, &AtomicU64::new(0), - &mut crate::ietf::request_stream::Messages::new(session.clone(), true), + &mut crate::ietf::request_stream::Messages::new(crate::driver::Transport::new(session.clone()), true), ) .await; if clean { @@ -6056,7 +6058,7 @@ mod tests { let mut session = ScriptedSession::new(wire); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut reader = Reader::new(recv, VERSION); + let mut reader = Reader::new(crate::transport::boxed::RecvStream::new(recv), VERSION); let result = decode_fetch_object(&mut reader, VERSION, true) .now_or_never() .expect("refused at the prefix, not parked on the body"); @@ -6194,7 +6196,7 @@ mod tests { Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6279,7 +6281,7 @@ mod tests { peer_setup.set(peer::Peer::default()); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), scoped, Control::new(None, false), None, @@ -6299,7 +6301,9 @@ mod tests { ); let prefix = namespaces.pop().unwrap(); - let stream = Stream::open(&mut session.clone(), Version::Draft16).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Draft16) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_subscribe_namespace(stream, prefix, crate::model::Snapshot::landed())); // Parks awaiting the peer's response; the request is already on the wire. @@ -6314,7 +6318,10 @@ mod tests { /// framing can't drift from the encoder under test. async fn namespace_response(version: Version, suffix: &str) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer @@ -6361,7 +6368,7 @@ mod tests { peer_setup.set(peer::Peer::default()); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), scoped, Control::new(None, false), None, @@ -6374,7 +6381,9 @@ mod tests { ); let prefix = subscribe_prefixes(&subscriber.origin).pop().expect("one prefix"); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); // Parks on the read after the scripted NAMESPACE is consumed. let mut run = std::pin::pin!(subscriber.run_subscribe_namespace(stream, prefix, crate::model::Snapshot::landed())); @@ -6410,8 +6419,10 @@ mod tests { for (reflected, drops) in [(false, true), (true, true), (true, false)] { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -6455,7 +6466,7 @@ mod tests { }); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6468,7 +6479,9 @@ mod tests { ); let prefix = subscribe_prefixes(&subscriber.origin).pop().expect("one prefix"); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_subscribe_namespace(stream, prefix, crate::model::Snapshot::landed())); let mut result = None; @@ -6493,8 +6506,10 @@ mod tests { for (negotiated, count) in [(true, None), (false, Some(0))] { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -6516,7 +6531,7 @@ mod tests { }); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6528,7 +6543,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let res = subscriber .run_subscribe_namespace( stream, @@ -6547,7 +6564,10 @@ mod tests { /// NAMESPACE_DONE for one prefixed with `-`. async fn counted_response(version: Version, active: Option, entries: &[&str]) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -6590,11 +6610,7 @@ mod tests { version: Version, active_count: bool, session: crate::lite::test_transport::ScriptedSession, - ) -> ( - Subscriber, - crate::origin::Consumer, - crate::model::Snapshot, - ) { + ) -> (Subscriber, crate::origin::Consumer, crate::model::Snapshot) { let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let consumer = origin.consume(); let snapshot = origin.snapshot(""); @@ -6606,7 +6622,7 @@ mod tests { }); let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6629,7 +6645,9 @@ mod tests { crate::lite::test_transport::ScriptedSession::new(counted_response(VERSION, Some(2), entries).await); let (mut subscriber, consumer, snapshot) = counted_subscriber(VERSION, true, session.clone()); let mut cursor = consumer.announced(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_subscribe_namespace(stream, crate::Path::new("").to_owned(), snapshot)); for _ in 0..10 { @@ -6651,7 +6669,9 @@ mod tests { let (mut subscriber, consumer, snapshot) = counted_subscriber(VERSION, false, session.clone()); let cursor = consumer.announced(); assert!(!cursor.is_synced()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_subscribe_namespace(stream, crate::Path::new("").to_owned(), snapshot)); for _ in 0..10 { @@ -6672,7 +6692,9 @@ mod tests { session.close(crate::lite::test_transport::Close::Fin); } let (mut subscriber, _consumer, snapshot) = counted_subscriber(VERSION, true, session.clone()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let res = subscriber .run_subscribe_namespace(stream, crate::Path::new("").to_owned(), snapshot) .await; @@ -6765,9 +6787,7 @@ mod tests { /// Build a subscriber with `subscribes` pre-populated, so alias binding can be /// exercised without driving a whole SUBSCRIBE exchange. - fn subscriber_with_tracks( - tracks: &[(RequestId, &str, &str)], - ) -> Subscriber { + fn subscriber_with_tracks(tracks: &[(RequestId, &str, &str)]) -> Subscriber { let (tasks, task_set) = crate::util::TaskSet::new(); // The tests drive binding directly, so nothing spawns; leaking keeps the handle alive // without a spawner. @@ -6775,7 +6795,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - crate::lite::test_transport::SinkSession::new(Default::default()), + crate::driver::Transport::new(crate::lite::test_transport::SinkSession::new(Default::default())), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7025,8 +7045,10 @@ mod tests { // A peer that rejects the subscribe outright. let rejection = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::RequestError::ID).await.unwrap(); writer .encode(&ietf::RequestError { @@ -7048,7 +7070,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7096,7 +7118,7 @@ mod tests { fn waiting_on_auth( version: Version, ) -> ( - Subscriber, + Subscriber, crate::lite::test_transport::Log, crate::auth::Handle, Vec, @@ -7111,7 +7133,7 @@ mod tests { let (tasks, task_set) = crate::util::TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7220,7 +7242,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7291,7 +7313,7 @@ mod tests { let (auth, _cred) = revocable_auth(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(Some(RequestId(1)), false), None, @@ -7356,7 +7378,7 @@ mod tests { let (auth, _cred) = revocable_auth(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7421,7 +7443,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7498,7 +7520,7 @@ mod tests { let control = Control::new(credit.then_some(RequestId(1)), false); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), control.clone(), None, @@ -7700,7 +7722,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -7823,10 +7845,16 @@ mod tests { let log = session.log.clone(); let control = Control::new(None, false); - let adapter = super::super::adapter::ControlStreamAdapter::new(session.clone(), control.clone(), VERSION); + let adapter = super::super::adapter::ControlStreamAdapter::new( + crate::driver::Transport::new(session.clone()), + control.clone(), + VERSION, + ); // The one real bidi everything is multiplexed onto. - let control_stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let control_stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let running = adapter.clone(); let (_goaway_handle, goaway) = crate::goaway::Handle::new(true); moq_clock::sim::spawn(async move { @@ -7836,7 +7864,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - adapter, + crate::driver::Transport::new(adapter), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), control, None, @@ -7910,7 +7938,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -8006,8 +8034,10 @@ mod tests { // A peer that accepts the subscription, binding alias 7, then says nothing more. let subscribe_ok = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::SubscribeOk::ID).await.unwrap(); writer .encode(&ietf::SubscribeOk { @@ -8031,7 +8061,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -8115,8 +8145,10 @@ mod tests { let subscribe_ok = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer.varint(ietf::SubscribeOk::ID).await.unwrap(); writer .encode(&ietf::SubscribeOk { @@ -8138,7 +8170,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -8269,7 +8301,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(2).unwrap()).produce(), Control::new(None, false), None, @@ -8356,7 +8388,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -8442,7 +8474,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -8560,7 +8592,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -8573,7 +8605,7 @@ mod tests { ); subscriber.announces = crate::session::Slots::new(1); - let advert = |subscriber: &Subscriber<_>| subscriber.route(None, &cluster::Peer::default()).expect("route"); + let advert = |subscriber: &Subscriber| subscriber.route(None, &cluster::Peer::default()).expect("route"); let a = crate::Path::new("a").to_owned(); let b = crate::Path::new("b").to_owned(); let (first, repeat, over, last) = ( @@ -8614,7 +8646,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), Some(assigned), @@ -8675,7 +8707,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), Some(peer), @@ -8715,7 +8747,7 @@ mod tests { std::mem::forget(task_set); let mut subscriber = Subscriber::new( crate::time::sim(), - crate::lite::test_transport::SinkSession::new(Default::default()), + crate::driver::Transport::new(crate::lite::test_transport::SinkSession::new(Default::default())), origin.clone(), Control::new(None, false), Some(peer), @@ -8754,12 +8786,7 @@ mod tests { assert!(routed_now(&consumer, "room/host").is_some()); } - fn cluster_subscriber( - self_origin: crate::Hop, - ) -> ( - Subscriber, - crate::origin::Producer, - ) { + fn cluster_subscriber(self_origin: crate::Hop) -> (Subscriber, crate::origin::Producer) { let session = crate::lite::test_transport::SinkSession::new(Default::default()); let origin = crate::origin::Config::new(self_origin).produce(); let (tasks, task_set) = crate::util::TaskSet::new(); @@ -8769,7 +8796,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.clone(), Control::new(None, false), None, @@ -8903,7 +8930,7 @@ mod tests { peer_setup.set(peer::Peer::default()); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -8915,7 +8942,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); subscriber .run_subscribe_namespace( stream, @@ -8944,8 +8973,10 @@ mod tests { let script = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::RequestOk::ID).await.unwrap(); writer .encode(&ietf::RequestOk { @@ -8988,7 +9019,7 @@ mod tests { }); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -9000,7 +9031,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_subscribe_namespace( stream, crate::Path::new("").to_owned(), @@ -9054,7 +9087,7 @@ mod tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -9065,7 +9098,9 @@ mod tests { tasks, Default::default(), ); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::PublishNamespace { request_id: RequestId(0), track_namespace: crate::Path::new("room/host"), @@ -9099,7 +9134,10 @@ mod tests { let path = crate::Path::new("room/host").to_owned(); let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer .encode_message(&ietf::PublishNamespaceDone { track_namespace: path.borrow(), @@ -9116,7 +9154,7 @@ mod tests { std::mem::forget(task_set); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -9128,7 +9166,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let msg = ietf::PublishNamespace { request_id: RequestId(0), track_namespace: path.borrow(), @@ -9163,8 +9203,10 @@ mod tests { let mut script = vec![ietf::SubscribeUpdate::ID as u8, 0, body.len() as u8]; script.extend_from_slice(body); let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); writer .encode_message(&ietf::PublishNamespaceDone { track_namespace: path.borrow(), @@ -9180,7 +9222,7 @@ mod tests { std::mem::forget(task_set); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -9192,7 +9234,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::PublishNamespace { request_id: RequestId(0), track_namespace: path.borrow(), @@ -9238,7 +9282,10 @@ mod tests { // The peer sends something that does not belong on this stream, ending it with an // error while the advertisement is still live. let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::NamespaceDone::ID).await.unwrap(); let script = log.writes.lock().unwrap().clone(); @@ -9247,7 +9294,7 @@ mod tests { std::mem::forget(task_set); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -9260,7 +9307,9 @@ mod tests { ); let path = crate::Path::new("room/host").to_owned(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let msg = ietf::PublishNamespace { request_id: RequestId(0), track_namespace: path.borrow(), @@ -9477,7 +9526,7 @@ mod tests { let path = crate::Path::new("room/host").to_owned(); let peer = cluster::Peer::default(); let (old, new) = (crate::Epoch::mint(), crate::Epoch::mint()); - let advert = |subscriber: &Subscriber<_>, epoch: &crate::Epoch| { + let advert = |subscriber: &Subscriber, epoch: &crate::Epoch| { subscriber .route(None, &peer) .expect("route") @@ -9521,7 +9570,7 @@ mod tests { let path = crate::Path::new("room/host").to_owned(); let peer = cluster::Peer::default(); let (old, new) = (crate::Epoch::mint(), crate::Epoch::mint()); - let advert = |subscriber: &Subscriber<_>, epoch: &crate::Epoch| { + let advert = |subscriber: &Subscriber, epoch: &crate::Epoch| { subscriber .route(None, &peer) .expect("route") @@ -9655,7 +9704,10 @@ mod tests { async fn publish_namespace_updates(updates: &[cluster::Advert]) -> Vec { const VERSION: Version = Version::Draft19; let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); for (i, advert) in updates.iter().enumerate() { writer.varint(ietf::PublishNamespaceUpdate::ID).await.unwrap(); @@ -9685,13 +9737,15 @@ mod tests { attached: &cluster::Advert, script: Vec, ) -> ( - Subscriber, + Subscriber, crate::origin::Consumer, - Stream, + Stream, crate::origin::Driver, + crate::lite::test_transport::Log, ) { const VERSION: Version = Version::Draft19; let session = crate::lite::test_transport::ScriptedSession::new(script); + let log = session.log.clone(); let (origin, driver) = crate::origin::Producer::new(crate::origin::Config::new(self_origin)); let consumer = origin.consume(); let (tasks, task_set) = crate::util::TaskSet::new(); @@ -9701,7 +9755,7 @@ mod tests { let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, true), None, @@ -9719,8 +9773,10 @@ mod tests { assert_eq!(id, 0, "the harness advertisement is the first"); assert!(routed_now(&consumer, "room/host").is_some(), "attached to start with"); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); - (subscriber, consumer, stream, driver) + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); + (subscriber, consumer, stream, driver, log) } /// Build a subscriber whose peer replays `updates` on one PUBLISH_NAMESPACE stream, @@ -9731,16 +9787,17 @@ mod tests { attached: &cluster::Advert, updates: &[cluster::Advert], ) -> ( - Subscriber, + Subscriber, crate::origin::Consumer, - Stream, + Stream, + crate::lite::test_transport::Log, ) { let script = publish_namespace_updates(updates).await; - let (subscriber, consumer, stream, driver) = update_harness(self_origin, peer, attached, script).await; + let (subscriber, consumer, stream, driver, log) = update_harness(self_origin, peer, attached, script).await; // Dropping the driver tears the origin down, so leak it: these tests only // need the synchronous half. std::mem::forget(driver); - (subscriber, consumer, stream) + (subscriber, consumer, stream, log) } /// How many times `type_id` was written to the peer, as a one-byte message type. @@ -9789,8 +9846,8 @@ mod tests { let peer = peer_9(); let (clean, _) = clean_and_looped(); let script = publish_namespace_updates(std::slice::from_ref(&clean)).await; - let (mut subscriber, _consumer, mut stream, _driver) = update_harness(self_origin, &peer, &clean, script).await; - let log = subscriber.session.log.clone(); + let (mut subscriber, _consumer, mut stream, _driver, log) = + update_harness(self_origin, &peer, &clean, script).await; // The initial request is already retired; its ID remains permanently spent. assert!(subscriber.control.accept(RequestId(3)).unwrap().is_none()); let mut attached = Some(0); @@ -9823,8 +9880,8 @@ mod tests { let peer = peer_9(); let (clean, looped) = clean_and_looped(); - let (mut subscriber, consumer, mut stream) = reflected_harness(self_origin, &peer, &clean, &[looped]).await; - let log = subscriber.session.log.clone(); + let (mut subscriber, consumer, mut stream, log) = + reflected_harness(self_origin, &peer, &clean, &[looped]).await; let path = crate::Path::new("room/host").to_owned(); let mut attached = Some(0); @@ -9873,7 +9930,7 @@ mod tests { let peer = peer_9(); let (clean, looped) = clean_and_looped(); - let (mut subscriber, consumer, mut stream) = + let (mut subscriber, consumer, mut stream, _log) = reflected_harness(self_origin, &peer, &clean, &[looped, clean.clone()]).await; let path = crate::Path::new("room/host").to_owned(); @@ -9925,7 +9982,7 @@ mod tests { std::mem::forget(task_set); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, true), None, @@ -9964,7 +10021,9 @@ mod tests { .start_announce(path.clone(), advert, Admit::Token(Some(hold))) .unwrap(); - let mut stream = Stream::open(&mut session.clone(), Version::Draft19).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Draft19) + .await + .unwrap(); let mut attached = Some(0); { let mut run = std::pin::pin!(subscriber.run_publish_namespace_updates( @@ -10014,8 +10073,10 @@ mod tests { let script = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::PublishNamespaceUpdate::ID).await.unwrap(); writer .encode(&ietf::PublishNamespaceUpdate { @@ -10031,9 +10092,9 @@ mod tests { writes.clone() }; - let (mut subscriber, consumer, mut stream, driver) = update_harness(self_origin, &peer, &held, script).await; + let (mut subscriber, consumer, mut stream, driver, log) = + update_harness(self_origin, &peer, &held, script).await; std::mem::forget(driver); - let log = subscriber.session.log.clone(); assert_eq!(routed_now(&consumer, "room/host").expect("routed").cost.value(), 4); let path = crate::Path::new("room/host").to_owned(); @@ -10080,8 +10141,8 @@ mod tests { }; let script = publish_namespace_updates(&[cheaper]).await; - let (mut subscriber, _consumer, mut stream, driver) = update_harness(self_origin, &peer, &clean, script).await; - let log = subscriber.session.log.clone(); + let (mut subscriber, _consumer, mut stream, driver, log) = + update_harness(self_origin, &peer, &clean, script).await; // Tear the origin down underneath the advertisement: the route can no longer be // repriced, which is the one way an in-place update fails. @@ -10138,9 +10199,9 @@ mod tests { }; let script = publish_namespace_updates(&[other_publisher]).await; - let (mut subscriber, consumer, mut stream, driver) = update_harness(self_origin, &peer, &clean, script).await; + let (mut subscriber, consumer, mut stream, driver, log) = + update_harness(self_origin, &peer, &clean, script).await; std::mem::forget(driver); - let log = subscriber.session.log.clone(); let path = crate::Path::new("room/host").to_owned(); let mut attached = Some(0); @@ -10184,8 +10245,10 @@ mod tests { let script = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::PublishNamespace::ID).await.unwrap(); writer .encode(&ietf::PublishNamespace { @@ -10206,7 +10269,8 @@ mod tests { writes.clone() }; - let (mut subscriber, _consumer, mut stream, driver) = update_harness(self_origin, &peer, &clean, script).await; + let (mut subscriber, _consumer, mut stream, driver, _log) = + update_harness(self_origin, &peer, &clean, script).await; std::mem::forget(driver); let path = crate::Path::new("room/host").to_owned(); @@ -10283,7 +10347,7 @@ mod tests { let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -10295,7 +10359,9 @@ mod tests { Default::default(), ); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let msg = ietf::Publish { request_id: RequestId(1), track_namespace: crate::Path::new("room/host"), @@ -10324,8 +10390,10 @@ mod tests { const NOT_SUPPORTED: u64 = 0x3; let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); match version { Version::Draft14 => { @@ -10372,7 +10440,7 @@ mod tests { version: Version, first_script: Vec, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, crate::auth::Auth, origin::Consumer, @@ -10386,11 +10454,11 @@ mod tests { /// [`auth_announce_harness`] over a given session, such as one that finishes the stream /// after its script. - fn auth_announce_harness_on( + fn auth_announce_harness_on( version: Version, session: S, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, crate::auth::Auth, origin::Consumer, @@ -10427,7 +10495,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, // The announcing peer is the server here, so its update IDs are odd. Control::new(None, true), @@ -10475,7 +10543,10 @@ mod tests { /// sends it. async fn publish_namespace_update_with_token(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let msg = ietf::PublishNamespaceUpdate { request_id: RequestId(3), namespace_request_id: (version == Version::Draft16).then_some(RequestId(1)), @@ -10492,7 +10563,10 @@ mod tests { /// parameters (HOP_PATH/ROUTE_COST), framed as the peer sends it. async fn publish_namespace_update_with_token_and_cluster(version: Version) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let msg = ietf::PublishNamespaceUpdate { request_id: RequestId(3), namespace_request_id: None, @@ -10511,7 +10585,9 @@ mod tests { async fn a_publish_namespace_token_authorizes_an_uncovered_announce() { const VERSION: Version = Version::Draft18; let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(VERSION, Vec::new()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async { let mut held = Vec::new(); @@ -10556,8 +10632,11 @@ mod tests { ] { let gate = kio::Producer::new(false); let session = crate::lite::test_transport::SinkSession::gated_bi(gate.consume()); - let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness_on(version, session); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let (mut subscriber, mut requests, _cred, consumer, session) = + auth_announce_harness_on(version, session.clone()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_publish_namespace_stream( stream, token_publish_namespace(), @@ -10638,18 +10717,23 @@ mod tests { const VERSION: Version = Version::Draft16; let done = { let log = crate::lite::test_transport::Log::default(); - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION) - .encode_message(&ietf::PublishNamespaceDone { - track_namespace: crate::Path::new("room/alice"), - request_id: RequestId(1), - }) - .await - .unwrap(); + crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ) + .encode_message(&ietf::PublishNamespaceDone { + track_namespace: crate::Path::new("room/alice"), + request_id: RequestId(1), + }) + .await + .unwrap(); log.writes.lock().unwrap().clone() }; // The application never takes the token, so only the withdrawal can end the wait. let (mut subscriber, _requests, _cred, consumer, session) = auth_announce_harness(VERSION, done); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_publish_namespace_stream( stream, token_publish_namespace(), @@ -10682,7 +10766,9 @@ mod tests { async fn a_refused_publish_namespace_token_is_not_announced() { const VERSION: Version = Version::Draft18; let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(VERSION, Vec::new()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async { let request = requests.next().await.expect("a request"); @@ -10723,7 +10809,9 @@ mod tests { let _cred = auth.present(bytes::Bytes::from_static(b"cred"), true).unwrap(); auth.granted(0, crate::auth::Grant::all()); let (mut subscriber, mut requests, consumer, session) = announce_harness_with(VERSION, auth); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let consulted = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { @@ -10775,7 +10863,9 @@ mod tests { let auth = crate::auth::Handle::new(false); auth.authorize(&limit("room")); let (mut subscriber, mut requests, consumer, session) = announce_harness_with(VERSION, auth.clone()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let consulted = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { let consulted = consulted.clone(); @@ -10830,7 +10920,9 @@ mod tests { let auth = crate::auth::Handle::new(false); auth.authorize(&crate::auth::Grant::default()); let (mut subscriber, mut requests, consumer, session) = announce_harness_with(VERSION, auth.clone()); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let request = requests.next().await.expect("a request"); let _held = request.accept(crate::auth::Grant::all()); @@ -10881,8 +10973,10 @@ mod tests { // The announce's peer says nothing; the subscription's accepts it. let subscribe_ok = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::SubscribeOk::ID).await.unwrap(); let ok = ietf::SubscribeOk { request_id: None, @@ -10898,7 +10992,9 @@ mod tests { // Serve the route, which the harness leaves undriven. let (tasks, mut task_set) = crate::util::TaskSet::new(); subscriber.tasks = tasks; - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut run = std::pin::pin!(subscriber.run_publish_namespace_stream( stream, token_publish_namespace(), @@ -10974,7 +11070,9 @@ mod tests { let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(version, publish_namespace_update_with_token(version).await); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let answered = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { @@ -11046,9 +11144,12 @@ mod tests { async fn a_lapsed_announce_grant_retracts_before_the_peer_reads() { const VERSION: Version = Version::Draft18; let session = crate::lite::test_transport::ScriptedSession::per_stream(vec![Vec::new()]).with_unacked_fin(); - let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness_on(VERSION, session); + let (mut subscriber, mut requests, _cred, consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let request = requests.next().await.expect("a request"); @@ -11111,9 +11212,12 @@ mod tests { script.extend(body); let session = crate::lite::test_transport::ScriptedSession::per_stream(vec![script]).with_unacked_fin(); - let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness_on(VERSION, session); + let (mut subscriber, mut requests, _cred, consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let request = requests.next().await.expect("a request"); @@ -11152,7 +11256,9 @@ mod tests { let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness(version, publish_namespace_update_with_token(version).await); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let answered = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { @@ -11205,8 +11311,12 @@ mod tests { if version == Version::Draft16 { let cancel = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new( + log.clone(), + )), + version, + ); writer .encode_message(&ietf::PublishNamespaceCancel { track_namespace: crate::Path::new("room/alice"), @@ -11238,7 +11348,9 @@ mod tests { for version in [Version::Draft16, Version::Draft18] { let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(version, publish_namespace_update_with_token(version).await); - let stream = Stream::open(&mut session.clone(), version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let tokenless = ietf::PublishNamespace { request_id: RequestId(1), track_namespace: crate::Path::new("other/alice"), @@ -11283,7 +11395,9 @@ mod tests { let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(VERSION, publish_namespace_update_with_token_and_cluster(VERSION).await); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); // A negotiated peer over a free link, so the advertised cost is the route's warm cost. let peer = cluster::Peer { @@ -11336,7 +11450,10 @@ mod tests { cost: Option, ) -> Vec { let log = crate::lite::test_transport::Log::default(); - let mut writer = crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), version); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + version, + ); let msg = ietf::PublishNamespaceUpdate { request_id: RequestId(rid), namespace_request_id: None, @@ -11363,7 +11480,9 @@ mod tests { script.extend(publish_namespace_update_token_rid(VERSION, 0x07, Some(hop_path(&[7, 11])), None).await); let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness(VERSION, script); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); // A negotiated peer over a free link, so the advertised cost is the route's warm cost. let peer = cluster::Peer { @@ -11444,7 +11563,9 @@ mod tests { } let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness(VERSION, script); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); // Accept the initial token, then never answer a renewal, so the buffer only grows. let acceptor = async move { @@ -11502,7 +11623,9 @@ mod tests { } let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness(VERSION, script); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); @@ -11545,7 +11668,9 @@ mod tests { } let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness(VERSION, script); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); @@ -11587,7 +11712,9 @@ mod tests { } let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness(VERSION, script); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); @@ -11633,9 +11760,12 @@ mod tests { script.extend(publish_namespace_update_token_rid(VERSION, rid, None, None).await); } let session = crate::lite::test_transport::ScriptedSession::per_stream(vec![script]).with_unacked_fin(); - let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness_on(VERSION, session); + let (mut subscriber, mut requests, _cred, consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); let rt = subscriber.runtime.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); @@ -11675,7 +11805,7 @@ mod tests { version: Version, limit: Option, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, origin::Consumer, crate::lite::test_transport::ScriptedSession, @@ -11692,7 +11822,7 @@ mod tests { version: Version, auth: crate::auth::Handle, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, origin::Consumer, crate::lite::test_transport::ScriptedSession, @@ -11707,7 +11837,7 @@ mod tests { auth: crate::auth::Handle, session: crate::lite::test_transport::ScriptedSession, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, origin::Consumer, crate::lite::test_transport::ScriptedSession, @@ -11723,7 +11853,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -11751,7 +11881,9 @@ mod tests { { let (mut subscriber, mut requests, consumer, session) = auth_announce_harness_no_ext(VERSION, Some(crate::auth::Grant::default())); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let consulted = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { let consulted = consulted.clone(); @@ -11798,7 +11930,9 @@ mod tests { { let (mut subscriber, mut requests, consumer, session) = auth_announce_harness_no_ext(VERSION, Some(crate::auth::Grant::default())); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let request = requests.next().await.expect("a request reaches the acceptor"); request.reject(crate::SessionError::Unauthorized, "no"); @@ -11837,8 +11971,11 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::per_stream_eof(vec![ publish_namespace_update_with_token(VERSION).await, ]); - let (mut subscriber, mut requests, _cred, consumer, session) = auth_announce_harness_on(VERSION, session); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let (mut subscriber, mut requests, _cred, consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let popped = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0)); let acceptor = { let popped = popped.clone(); @@ -11888,8 +12025,10 @@ mod tests { const VERSION: Version = Version::Draft18; let queued = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::PublishNamespaceUpdate::ID).await.unwrap(); writer .encode(&ietf::PublishNamespaceUpdate { @@ -11906,9 +12045,12 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::per_stream_eof(vec![ [publish_namespace_update_with_token(VERSION).await, queued].concat(), ]); - let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness_on(VERSION, session); + let (mut subscriber, mut requests, _cred, _consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); let control = subscriber.control.clone(); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); let _issued = first.accept(crate::auth::Grant::all()); @@ -11945,8 +12087,10 @@ mod tests { const VERSION: Version = Version::Draft18; let queued = { let log = crate::lite::test_transport::Log::default(); - let mut writer = - crate::coding::Writer::new(crate::lite::test_transport::SinkSend::new(log.clone()), VERSION); + let mut writer = crate::coding::Writer::new( + crate::transport::boxed::SendStream::new(crate::lite::test_transport::SinkSend::new(log.clone())), + VERSION, + ); writer.varint(ietf::PublishNamespaceUpdate::ID).await.unwrap(); writer .encode(&ietf::PublishNamespaceUpdate { @@ -11976,8 +12120,11 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::per_stream_eof(vec![ [publish_namespace_update_with_token(VERSION).await, queued].concat(), ]); - let (mut subscriber, mut requests, _cred, _consumer, session) = auth_announce_harness_on(VERSION, session); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let (mut subscriber, mut requests, _cred, _consumer, session) = + auth_announce_harness_on(VERSION, session.clone()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let first = requests.next().await.expect("a request"); let _issued = first.accept(crate::auth::Grant::all()); @@ -12032,7 +12179,9 @@ mod tests { for (grant, admitted) in [(read_only, false), (write_only, true)] { let (mut subscriber, mut requests, consumer, session) = auth_announce_harness_no_ext(VERSION, Some(crate::auth::Grant::default())); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let acceptor = async move { let request = requests.next().await.expect("a request reaches the acceptor"); let _issued = request.accept(grant); @@ -12072,7 +12221,9 @@ mod tests { async fn a_token_less_request_on_a_no_auth_session_is_unchanged() { const VERSION: Version = Version::Draft18; let (mut subscriber, _requests, consumer, session) = auth_announce_harness_no_ext(VERSION, None); - let stream = Stream::open(&mut session.clone(), VERSION).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut msg = token_publish_namespace(); msg.authorization_token = None; @@ -12414,7 +12565,6 @@ mod stitch_tests { coding::{Encode as _, Encoder}, lite::test_transport::ScriptedSession, model::ProduceTest, - transport::poll::Session as _, util::{TaskSet, Tasks}, }; @@ -12590,18 +12740,16 @@ mod stitch_tests { } /// A reader over the next scripted stream, decoded as draft-18. - async fn read_draft18( - session: &ScriptedSession, - ) -> Reader<::RecvStream, Version> { + async fn read_draft18(session: &ScriptedSession) -> Reader { let mut session = session.clone(); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - Reader::new(recv, Version::Draft18) + Reader::new(crate::transport::boxed::RecvStream::new(recv), Version::Draft18) } /// A subscriber holding one draft-20 subscription, as its SUBSCRIBE_OK left it: the /// alias bound, the timescale declared, and `fill` waiting on its fetch stream. struct Harness { - subscriber: Subscriber, + subscriber: Subscriber, session: ScriptedSession, track: track::Producer, fill: kio::Producer, @@ -12622,7 +12770,7 @@ mod stitch_tests { let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -12705,10 +12853,10 @@ mod stitch_tests { } /// A reader over the next scripted stream, standing in for one the peer opened. - async fn stream(&self) -> Reader<::RecvStream, Version> { + async fn stream(&self) -> Reader { let mut session = self.session.clone(); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - Reader::new(recv, VERSION) + Reader::new(crate::transport::boxed::RecvStream::new(recv), VERSION) } } @@ -12898,12 +13046,12 @@ mod stitch_tests { false => (origin, None), }; - let mut downstream = ScriptedSession::per_stream(vec![vec![]]); + let downstream = ScriptedSession::per_stream(vec![vec![]]); let peer = peer::PeerSetup::default(); peer.set(peer::Peer::default()); let publisher = crate::ietf::Publisher::new( crate::time::sim(), - downstream.clone(), + crate::driver::Transport::new(downstream.clone()), served.consume(), Control::new(None, false), None, @@ -12976,7 +13124,9 @@ mod stitch_tests { .unwrap(); ietf::Subscribe::ID }; - let stream = Stream::open(&mut downstream, egress).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(downstream.clone()), egress) + .await + .unwrap(); publisher .handle_stream(id, ietf::Body(body.into()), stream, false) .unwrap() @@ -13680,12 +13830,12 @@ mod stitch_tests { } false => (origin, None), }; - let mut downstream = ScriptedSession::per_stream(vec![vec![]]).with_datagrams(65535); + let downstream = ScriptedSession::per_stream(vec![vec![]]).with_datagrams(65535); let peer = peer::PeerSetup::default(); peer.set(peer::Peer::default()); let publisher = crate::ietf::Publisher::new( crate::time::sim(), - downstream.clone(), + crate::driver::Transport::new(downstream.clone()), served.consume(), Control::new(None, false), None, @@ -13726,7 +13876,9 @@ mod stitch_tests { subscribe .encode_msg(&mut Encoder::new(&mut body, version.into()), version) .unwrap(); - let stream = Stream::open(&mut downstream, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(downstream.clone()), version) + .await + .unwrap(); publisher .handle_stream(ietf::Subscribe::ID, ietf::Body(body.into()), stream, false) .unwrap() @@ -13790,12 +13942,12 @@ mod stitch_tests { .recv_datagram(datagram.encode_bytes(ingress).unwrap()) .unwrap(); track.finish().unwrap(); - let mut downstream = ScriptedSession::per_stream(vec![vec![]]).with_datagrams(65535); + let downstream = ScriptedSession::per_stream(vec![vec![]]).with_datagrams(65535); let peer = peer::PeerSetup::default(); peer.set(peer::Peer::default()); let publisher = crate::ietf::Publisher::new( crate::time::sim(), - downstream.clone(), + crate::driver::Transport::new(downstream.clone()), origin.consume(), Control::new(None, false), None, @@ -13823,7 +13975,9 @@ mod stitch_tests { subscribe .encode_msg(&mut Encoder::new(&mut body, egress.into()), egress) .unwrap(); - let stream = Stream::open(&mut downstream, egress).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(downstream.clone()), egress) + .await + .unwrap(); publisher .handle_stream(ietf::Subscribe::ID, ietf::Body(body.into()), stream, false) .unwrap() @@ -15237,8 +15391,8 @@ mod stitch_tests { /// A subscriber reading one scripted group fetch stream, already past its header. struct GroupFetchRun { - subscriber: Subscriber, - stream: Reader<::RecvStream, Version>, + subscriber: Subscriber, + stream: Reader, track: track::Producer, _tasks: (Tasks, TaskSet), } @@ -15249,7 +15403,7 @@ mod stitch_tests { let tasks = TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -15269,7 +15423,7 @@ mod stitch_tests { Self { subscriber, - stream: Reader::new(recv, version), + stream: Reader::new(crate::transport::boxed::RecvStream::new(recv), version), track, _tasks: tasks, } @@ -15326,7 +15480,6 @@ mod joining_fetch_tests { coding::{Encode as _, Encoder}, lite::test_transport::ScriptedSession, model::ProduceTest, - transport::poll::Session as _, util::{TaskSet, Tasks}, }; use futures::FutureExt; @@ -15440,7 +15593,7 @@ mod joining_fetch_tests { } struct JoinRun { - subscriber: Subscriber, + subscriber: Subscriber, session: ScriptedSession, _hold: ( crate::broadcast::Producer, @@ -15466,7 +15619,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), control, None, @@ -15555,10 +15708,7 @@ mod joining_fetch_tests { )); } - fn pending_join( - session: S, - version: Version, - ) -> (Subscriber, track::Producer, TaskSet) { + fn pending_join(session: Transport, version: Version) -> (Subscriber, track::Producer, TaskSet) { let (tasks, task_set) = TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), @@ -15601,7 +15751,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -15678,7 +15828,7 @@ mod joining_fetch_tests { async fn a_request_failing_mid_head_settles_the_fill() { for version in [Version::Draft18, Version::Draft19] { let session = ScriptedSession::per_stream_reset(vec![fetch_ok(version)]); - let (subscriber, track, _tasks) = pending_join(session, version); + let (subscriber, track, _tasks) = pending_join(crate::driver::Transport::new(session.clone()), version); let fill = subscriber.state.lock().subscribes[&RequestId(99)].fill.clone(); // A fetch stream is writing the head. if let Ok(mut state) = fill.write() { @@ -15700,7 +15850,8 @@ mod joining_fetch_tests { let gate = kio::Producer::new(false); let session = ScriptedSession::gated_open(Vec::new(), gate.consume()); let log = session.log.clone(); - let (mut subscriber, track, _tasks) = pending_join(session, version); + let (mut subscriber, track, _tasks) = + pending_join(crate::driver::Transport::new(session.clone()), version); let route = kio::Producer::new(()); subscriber.validity = crate::model::broadcast::RequestValidity::token(Some(route.consume())); let mut joining = subscriber.start_joining_fetch(RequestId(99), &track).unwrap(); @@ -15731,7 +15882,7 @@ mod joining_fetch_tests { let gate = kio::Producer::new(false); let session = ScriptedSession::gated_open(Vec::new(), gate.consume()); let log = session.log.clone(); - let (subscriber, track, mut tasks) = pending_join(session, version); + let (subscriber, track, mut tasks) = pending_join(crate::driver::Transport::new(session.clone()), version); let mut joining = subscriber.start_joining_fetch(RequestId(99), &track).unwrap(); assert!(joining.poll(&kio::Waiter::noop()).is_pending()); drop(joining); @@ -15752,7 +15903,7 @@ mod joining_fetch_tests { let gate = kio::Producer::new(false); let session = crate::lite::test_transport::SinkSession::gated_bi_prefix(2, gate.consume()); let log = session.log.clone(); - let (subscriber, track, mut tasks) = pending_join(session, version); + let (subscriber, track, mut tasks) = pending_join(crate::driver::Transport::new(session.clone()), version); let mut joining = subscriber.start_joining_fetch(RequestId(99), &track).unwrap(); assert!(joining.poll(&kio::Waiter::noop()).is_pending()); assert_eq!(log.writes.lock().unwrap().len(), 2, "partial header"); @@ -15790,7 +15941,7 @@ mod joining_fetch_tests { for version in [Version::Draft14, Version::Draft15, Version::Draft16] { let session = ScriptedSession::per_stream(Vec::new()).with_unacked_fin(); let log = session.log.clone(); - let (subscriber, track, mut tasks) = pending_join(session, version); + let (subscriber, track, mut tasks) = pending_join(crate::driver::Transport::new(session.clone()), version); let mut joining = subscriber.start_joining_fetch(RequestId(99), &track).unwrap(); assert!(joining.poll(&kio::Waiter::noop()).is_pending()); drop(joining); @@ -15971,7 +16122,7 @@ mod joining_fetch_tests { w.bytes(b"x").unwrap(); let data = ScriptedSession::new(objects); let (_, recv) = data.clone().open_bi(Default::default()).await.unwrap(); - let mut reader = Reader::new(recv, version); + let mut reader = Reader::new(crate::transport::boxed::RecvStream::new(recv), version); let mut receiving = run.subscriber.clone(); let mut fill = Box::pin(receiving.recv_fill(&mut reader)); assert!(futures::poll!(fill.as_mut()).is_pending()); @@ -16014,7 +16165,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16125,7 +16276,7 @@ mod joining_fetch_tests { objects.push(b'x'); let data = ScriptedSession::new(objects); let (_, recv) = data.clone().open_bi(Default::default()).await.unwrap(); - let mut reader = Reader::new(recv, version); + let mut reader = Reader::new(crate::transport::boxed::RecvStream::new(recv), version); let mut receiving = subscriber.clone(); let mut fill = Box::pin(receiving.recv_group_fetch(&mut reader, slot.clone())); assert!(futures::poll!(fill.as_mut()).is_pending()); @@ -16258,7 +16409,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16324,7 +16475,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16465,7 +16616,7 @@ mod joining_fetch_tests { let (tasks, _task_set) = crate::util::TaskSet::new(); let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16498,7 +16649,7 @@ mod joining_fetch_tests { // The fetch stream, as the peer would open it. let (_, recv) = session.clone().open_bi(Default::default()).await.unwrap(); - let mut stream = Reader::new(recv, version); + let mut stream = Reader::new(crate::transport::boxed::RecvStream::new(recv), version); subscriber .clone() .recv_fill(&mut stream) @@ -16566,11 +16717,11 @@ mod new_group_tests { const VERSION: Version = Version::Draft22; - type PeerStream = Stream; + type PeerStream = Stream; struct Relay { track: track::Consumer, - probe: Subscriber, + probe: Subscriber, peer: memory::Session, serving: moq_clock::sim::JoinHandle<()>, /// Landed groups stay open, as a live publisher's would. @@ -16585,7 +16736,7 @@ mod new_group_tests { let (tasks, task_set) = TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16632,7 +16783,9 @@ mod new_group_tests { impl Relay { /// Accept the SUBSCRIBE the relay sends upstream, returning its NEW_GROUP_REQUEST. async fn accept(&mut self) -> (PeerStream, Option) { - let mut stream = Stream::accept(&mut self.peer, VERSION).await.unwrap(); + let mut stream = Stream::accept(&mut crate::driver::Transport::new(self.peer.clone()), VERSION) + .await + .unwrap(); let (id, body) = read(&mut stream).await; assert_eq!(id, ietf::Subscribe::ID); let msg = ietf::Subscribe::decode_msg(&mut body.decoder(VERSION), VERSION).unwrap(); @@ -16881,15 +17034,12 @@ mod track_property_tests { /// Subscribe to one track through a relay on `version`, whose publisher answers with /// `block` as SUBSCRIBE_OK's Track Properties, returning what the subscriber got. - async fn subscribe( - version: Version, - block: &[u8], - ) -> (Result, Subscriber) { - let (session, mut peer) = memory::pair(memory::Config::default()); + async fn subscribe(version: Version, block: &[u8]) -> (Result, Subscriber) { + let (session, peer) = memory::pair(memory::Config::default()); let (tasks, _task_set) = TaskSet::new(); let mut subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -16912,7 +17062,9 @@ mod track_property_tests { .await; }); - let mut stream = Stream::accept(&mut peer, version).await.unwrap(); + let mut stream = Stream::accept(&mut crate::driver::Transport::new(peer.clone()), version) + .await + .unwrap(); assert_eq!(stream.reader.varint().await.unwrap(), ietf::Subscribe::ID); let _subscribe: ietf::Body = stream.reader.decode().await.unwrap(); diff --git a/rs/moq-net/src/ietf/subscriber/tracks.rs b/rs/moq-net/src/ietf/subscriber/tracks.rs index 63af5130715..9a5678a08b9 100644 --- a/rs/moq-net/src/ietf/subscriber/tracks.rs +++ b/rs/moq-net/src/ietf/subscriber/tracks.rs @@ -18,6 +18,7 @@ //! SUBSCRIBE_TRACKS yet, and one that refuses, resets, or ignores it fails or empties only //! that listing, leaving the session and its SUBSCRIBEs alone. +use crate::driver::Transport; use std::sync::Arc; use super::*; @@ -41,9 +42,9 @@ pub(super) fn listing_end(done: &ietf::PublishDone, version: Version) -> Result< } /// A paused upstream subscription and the request stream that controls it. -pub(super) struct Upstream { - pub(super) stream: Stream, - pub(super) messages: Messages, +pub(super) struct Upstream { + pub(super) stream: Stream, + pub(super) messages: Messages, pub(super) request_id: RequestId, pub(super) alias: u64, /// The Track Properties the PUBLISH or SUBSCRIBE_OK declared. @@ -55,39 +56,30 @@ pub(super) struct Upstream { } /// Hands a paused subscription from the task watching it to a subscription resuming it. -pub(super) struct Handoff { +#[derive(Default)] +pub(super) struct Handoff { /// A subscription asked for it. wanted: bool, /// Handed over by the watcher. - upstream: Option>, + upstream: Option, /// The entry was let go, so the watcher cancels the subscription. gone: bool, } -impl Default for Handoff { - fn default() -> Self { - Self { - wanted: false, - upstream: None, - gone: false, - } - } -} - /// One listed track and the upstream subscription that holds it. -struct Entry { +struct Entry { /// Its TRACK_INFO, once known: a paused SUBSCRIBE learns it from its SUBSCRIBE_OK. info: Option, /// The subscription holding it, once known. request_id: Option, /// Set while it is paused, or still opening, and a watcher owns it. `None` while a /// subscription forwarding it owns it. - handoff: Option>>, + handoff: Option>, /// Discovery state the peer makes us hold, as for a lite listed track. _slot: crate::session::Slot, } -impl Drop for Entry { +impl Drop for Entry { fn drop(&mut self) { if let Some(handoff) = &self.handoff { handoff.lock().gone = true; @@ -113,24 +105,14 @@ struct Request { } /// The session's listings of the peer's tracks. -pub(super) struct Listings { +#[derive(Default)] +pub(super) struct Listings { listeners: HashMap, requests: HashMap, - entries: HashMap>, + entries: HashMap, next: u64, } -impl Default for Listings { - fn default() -> Self { - Self { - listeners: HashMap::new(), - requests: HashMap::new(), - entries: HashMap::new(), - next: 0, - } - } -} - /// A SUBSCRIBE_TRACKS for its task to send. struct Opening { key: u64, @@ -141,7 +123,7 @@ struct Opening { gone: kio::Producer<()>, } -impl Listings { +impl Listings { fn key(&mut self) -> u64 { self.next += 1; self.next @@ -272,7 +254,7 @@ impl Listings { self.release(); } - fn insert(&mut self, key: TrackKey, entry: Entry) { + fn insert(&mut self, key: TrackKey, entry: Entry) { if let Some(info) = &entry.info { for lister in self.listers(&key.0) { let _ = lister.add(key.1.clone(), info.clone()); @@ -293,14 +275,14 @@ impl Listings { } /// The entry held by the subscription with `request_id`, if this is it. - fn held_by(&mut self, key: &TrackKey, request_id: RequestId) -> Option<&mut Entry> { + fn held_by(&mut self, key: &TrackKey, request_id: RequestId) -> Option<&mut Entry> { self.entries .get_mut(key) .filter(|entry| entry.request_id == Some(request_id)) } /// The entry `handoff` belongs to, if it still stands. - fn watched_by(&mut self, key: &TrackKey, handoff: &kio::Shared>) -> Option<&mut Entry> { + fn watched_by(&mut self, key: &TrackKey, handoff: &kio::Shared) -> Option<&mut Entry> { self.entries .get_mut(key) .filter(|entry| entry.handoff.as_ref().is_some_and(|held| held.same_channel(handoff))) @@ -323,13 +305,13 @@ impl Listings { } /// A broadcast's listing through this session, until dropped. -pub(super) struct Listening { - listings: kio::Lock>, +pub(super) struct Listening { + listings: kio::Lock, key: u64, failed: kio::Consumer>, } -impl Listening { +impl Listening { /// Ready with the error that failed the listing. pub(super) fn poll_failed(&self, waiter: &kio::Waiter) -> Poll { match self.failed.poll(waiter, |failed| match &**failed { @@ -343,29 +325,26 @@ impl Listening { } } -impl Drop for Listening { +impl Drop for Listening { fn drop(&mut self) { self.listings.lock().unlisten(self.key); } } /// What to do with a PUBLISH. -enum Offer { +enum Offer { /// No listing asked for it. Unsolicited, /// Refused with this code and reason. Refuse(u64, &'static str), /// Accepted paused and held as the entry `handoff` watches. - Hold(kio::Shared>), + Hold(kio::Shared), } -impl Subscriber -where - S: crate::transport::poll::Boxable, -{ +impl Subscriber { /// List `path`'s tracks into `lister` until the returned guard drops, through a /// SUBSCRIBE_TRACKS covering it. - pub(super) fn listen(&self, path: PathOwned, lister: Arc) -> Listening { + pub(super) fn listen(&self, path: PathOwned, lister: Arc) -> Listening { let (key, failed, opening) = self.listings.lock().listen(path, lister); if let Some(opening) = opening { let this = self.clone(); @@ -586,7 +565,7 @@ where }; return listings.insert(key, entry); } - let handoff = kio::Shared::>::default(); + let handoff = kio::Shared::::default(); let entry = Entry { info: None, request_id: None, @@ -614,11 +593,7 @@ where /// Open a paused SUBSCRIBE for a skipped track and list it once its SUBSCRIBE_OK /// arrives. `None` once its entry was let go. - async fn open_paused( - &self, - key: &TrackKey, - handoff: &kio::Shared>, - ) -> Result>, Error> { + async fn open_paused(&self, key: &TrackKey, handoff: &kio::Shared) -> Result, Error> { let gone = |waiter: &kio::Waiter| { handoff .poll(waiter, |handoff| match handoff.gone { @@ -767,7 +742,7 @@ where /// refuse a redundant one, and decline one no listing asked for. pub(super) async fn serve_publish( &mut self, - mut stream: Stream, + mut stream: Stream, msg: ietf::Publish<'_>, ) -> Result<(), Error> { let key: TrackKey = (msg.track_namespace.to_owned(), msg.track_name.as_ref().into()); @@ -829,7 +804,7 @@ where Offer::Refuse(duplicate, "already subscribed") } None => { - let handoff = kio::Shared::>::default(); + let handoff = kio::Shared::::default(); let entry = Entry { info: Some(info), request_id: Some(msg.request_id), @@ -914,7 +889,7 @@ where /// Watch a paused subscription until it ends, its entry is let go, or a subscription /// takes it to resume. - async fn watch(&self, key: TrackKey, mut upstream: Upstream, handoff: kio::Shared>) { + async fn watch(&self, key: TrackKey, mut upstream: Upstream, handoff: kio::Shared) { let mut session = self.session.clone(); enum Step { Closed, @@ -1010,7 +985,7 @@ where } /// Ask for the paused subscription a listing holds for this track, to resume it. - pub(super) fn want(&self, key: &TrackKey) -> Option>> { + pub(super) fn want(&self, key: &TrackKey) -> Option> { let listings = self.listings.lock(); let handoff = listings.entries.get(key)?.handoff.clone()?; handoff.lock().wanted = true; @@ -1018,7 +993,7 @@ where } /// Ready with the subscription `handoff` hands over, or `None` once it ended instead. - pub(super) fn poll_handoff(handoff: &kio::Shared>, waiter: &kio::Waiter) -> Poll>> { + pub(super) fn poll_handoff(handoff: &kio::Shared, waiter: &kio::Waiter) -> Poll> { let mut handoff = ready!( handoff.poll(waiter, |handoff| match handoff.gone || handoff.upstream.is_some() { true => Poll::Ready(()), @@ -1029,7 +1004,7 @@ where } /// Give up wanting `handoff`, holding again what it already handed over. - pub(super) fn unwant(&self, key: TrackKey, handoff: &kio::Shared>) { + pub(super) fn unwant(&self, key: TrackKey, handoff: &kio::Shared) { let upstream = { let mut held = handoff.lock(); held.wanted = false; @@ -1079,8 +1054,8 @@ where /// Hold a paused subscription again as its track's entry, watched until a reader /// resumes it, or cancel it if the entry is gone. - pub(super) fn hold(&self, key: TrackKey, upstream: Upstream) { - let handoff = kio::Shared::>::default(); + pub(super) fn hold(&self, key: TrackKey, upstream: Upstream) { + let handoff = kio::Shared::::default(); let held = match self.listings.lock().held_by(&key, upstream.request_id) { Some(entry) => { entry.handoff = Some(handoff.clone()); @@ -1101,7 +1076,7 @@ where } /// Pause a subscription nobody reads that is its track's entry, and hold it again. - pub(super) async fn pause(&self, key: TrackKey, mut upstream: Upstream) { + pub(super) async fn pause(&self, key: TrackKey, mut upstream: Upstream) { self.park_subscribe(upstream.request_id); let pause = Forward { forward: false, @@ -1153,7 +1128,7 @@ where /// Set a held subscription's Forward State with REQUEST_UPDATE. pub(super) async fn write_forward( &self, - writer: &mut Writer, + writer: &mut Writer, forward: &Forward, ) -> Result<(), Error> { let request_id = self.control.next_request_id(&self.runtime).await?; @@ -1188,8 +1163,8 @@ where /// Read the answer to a SUBSCRIBE, or to the REQUEST_UPDATE resuming `held`. pub(super) async fn read_answer( &self, - stream: &mut Stream, - messages: &mut Messages, + stream: &mut Stream, + messages: &mut Messages, held: Option<&mut Resumed>, ) -> Result, Error> { let Some(held) = held else { @@ -1265,14 +1240,14 @@ mod tests { const TIMEOUT: Duration = Duration::from_secs(1); - type PeerStream = Stream; + type PeerStream = Stream; /// A subscriber listing `broadcast` over a raw peer that plays the publisher. struct Harness { - subscriber: Subscriber, + subscriber: Subscriber, peer: memory::Session, tracks: crate::broadcast::Tracks, - listening: Listening, + listening: Listening, version: Version, _broadcast: crate::broadcast::Producer, _driver: moq_clock::sim::JoinHandle<()>, @@ -1288,7 +1263,7 @@ mod tests { let driver = moq_clock::sim::spawn(async move { kio::wait(|waiter| task_set.poll(waiter)).await }); let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(), Control::new(None, false), None, @@ -1344,10 +1319,13 @@ mod tests { impl Harness { /// Accept the SUBSCRIBE_TRACKS and establish it. async fn establish(&mut self) -> PeerStream { - let mut stream = moq_clock::timeout(TIMEOUT, Stream::accept(&mut self.peer, self.version)) - .await - .expect("no SUBSCRIBE_TRACKS") - .unwrap(); + let mut stream = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(self.peer.clone()), self.version), + ) + .await + .expect("no SUBSCRIBE_TRACKS") + .unwrap(); let (id, body) = read(&mut stream).await; assert_eq!(id, ietf::SubscribeTracks::ID); let msg: ietf::SubscribeTracks = body.message(self.version).unwrap(); @@ -1439,7 +1417,9 @@ mod tests { /// Send `publish`, returning the answer. async fn offer(&mut self, publish: ietf::Publish<'_>) -> (PeerStream, u64, ietf::Body) { - let mut stream = Stream::open(&mut self.peer, self.version).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(self.peer.clone()), self.version) + .await + .unwrap(); stream.writer.varint(ietf::Publish::ID).await.unwrap(); stream.writer.encode(&publish).await.unwrap(); @@ -1585,10 +1565,13 @@ mod tests { write(&mut listing, ietf::PublishSkipped::ID, &skipped).await; assert_eq!(event(&mut h.tracks), None, "{version}: listed before it answered"); - let mut stream = moq_clock::timeout(TIMEOUT, Stream::accept(&mut h.peer, version)) - .await - .expect("no paused SUBSCRIBE") - .unwrap(); + let mut stream = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(h.peer.clone()), version), + ) + .await + .expect("no paused SUBSCRIBE") + .unwrap(); let (id, body) = read(&mut stream).await; assert_eq!(id, ietf::Subscribe::ID, "{version}"); let msg: ietf::Subscribe = body.message(version).unwrap(); @@ -1625,10 +1608,13 @@ mod tests { track_name: "audio".into(), }; write(&mut listing, ietf::PublishSkipped::ID, &skipped).await; - let mut stream = moq_clock::timeout(TIMEOUT, Stream::accept(&mut h.peer, version)) - .await - .expect("no paused SUBSCRIBE") - .unwrap(); + let mut stream = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(h.peer.clone()), version), + ) + .await + .expect("no paused SUBSCRIBE") + .unwrap(); let _ = read(&mut stream).await; let refused = ietf::RequestError { request_id: None, @@ -1725,10 +1711,13 @@ mod tests { "TRACK_ENDED failed the listing" ); - let mut stream = moq_clock::timeout(TIMEOUT, Stream::accept(&mut h.peer, version)) - .await - .expect("the copy did not SUBSCRIBE") - .unwrap(); + let mut stream = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(h.peer.clone()), version), + ) + .await + .expect("the copy did not SUBSCRIBE") + .unwrap(); let (id, _) = read(&mut stream).await; assert_eq!(id, ietf::Subscribe::ID); } @@ -1787,10 +1776,13 @@ mod tests { let version = Version::Draft22; for case in ["refused", "reset", "silent"] { let mut h = harness(version); - let mut listing = moq_clock::timeout(TIMEOUT, Stream::accept(&mut h.peer, version)) - .await - .expect("no SUBSCRIBE_TRACKS") - .unwrap(); + let mut listing = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(h.peer.clone()), version), + ) + .await + .expect("no SUBSCRIBE_TRACKS") + .unwrap(); let (id, _) = read(&mut listing).await; assert_eq!(id, ietf::SubscribeTracks::ID); let _held = match case { @@ -1823,10 +1815,13 @@ mod tests { } let (_track, reader, _serving) = h.read_track("video").await; - let mut stream = moq_clock::timeout(TIMEOUT, Stream::accept(&mut h.peer, version)) - .await - .expect("no SUBSCRIBE") - .unwrap(); + let mut stream = moq_clock::timeout( + TIMEOUT, + Stream::accept(&mut crate::driver::Transport::new(h.peer.clone()), version), + ) + .await + .expect("no SUBSCRIBE") + .unwrap(); let (id, body) = read(&mut stream).await; assert_eq!(id, ietf::Subscribe::ID, "{case}"); let msg: ietf::Subscribe = body.message(version).unwrap(); diff --git a/rs/moq-net/src/ietf/token.rs b/rs/moq-net/src/ietf/token.rs index 70f80f000e5..0e4f4ab4138 100644 --- a/rs/moq-net/src/ietf/token.rs +++ b/rs/moq-net/src/ietf/token.rs @@ -7,6 +7,8 @@ #[cfg(feature = "async")] use crate::coding::Stream; +#[cfg(feature = "async")] +use crate::driver::Transport; use crate::{ DecodeError, Error, SessionError, @@ -108,8 +110,8 @@ pub(super) fn reason(err: &DecodeError) -> &'static str { /// Section 8.9 rejects the message rather than the session. Every request starts with its /// Request ID, so it is read from the undecoded `body`. #[cfg(feature = "async")] -pub(super) async fn reject( - mut stream: Stream, +pub(super) async fn reject( + mut stream: Stream, kind: request::Kind, body: super::Body, err: DecodeError, diff --git a/rs/moq-net/src/lite/error.rs b/rs/moq-net/src/lite/error.rs index e1c3236f1d6..98c77a3984a 100644 --- a/rs/moq-net/src/lite/error.rs +++ b/rs/moq-net/src/lite/error.rs @@ -27,7 +27,9 @@ pub(crate) fn from_transport(error: impl crate::transport::Error) -> Error { } /// Classify control bytes at a stream boundary, keeping a transport FIN/reset distinct. -pub(super) fn control(session: &mut S, err: Error) -> Error { +#[cfg(feature = "async")] +pub(super) fn control(session: &mut crate::driver::Transport, err: Error) -> Error { + use crate::transport::poll::Session as _; let err = match err { Error::Decode(crate::DecodeError::Short) => err, err => crate::auth::protocol_error(err), diff --git a/rs/moq-net/src/lite/publisher.rs b/rs/moq-net/src/lite/publisher.rs index dafbe367716..47b897b850d 100644 --- a/rs/moq-net/src/lite/publisher.rs +++ b/rs/moq-net/src/lite/publisher.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; #[cfg(test)] use std::sync::atomic::AtomicU64; @@ -25,10 +27,10 @@ use crate::{ use super::Version; -pub(super) struct PublisherConfig { +pub(super) struct PublisherConfig { /// The runtime that arms the publisher's timers. pub runtime: crate::time::Deadlines, - pub session: S, + pub session: Transport, /// The origin we read local broadcasts from. Traffic stats are attributed /// through this handle: tag it with [`origin::Consumer::with_stats`] first. pub origin: origin::Consumer, @@ -56,10 +58,10 @@ pub(super) struct PublisherConfig { } /// Context shared by every control-stream child. -struct Shared { +struct Shared { client: bool, withdrawal: crate::session::Withdrawal, - session: S, + session: Transport, origin: origin::Consumer, self_origin: Hop, // The peer's SETUP, read for the origin id it declared. Used to serve the @@ -132,7 +134,7 @@ fn position_cursor(track: &mut track::Subscriber, version: Version, start_group: } } -impl Shared { +impl Shared { /// Watches whether the session still lets us serve `broadcast` to the peer: our /// grant, and the ceiling on what the peer may subscribe to. fn gate(&self, broadcast: &crate::Path) -> crate::auth::Gate { @@ -168,20 +170,20 @@ impl Shared { /// The publisher half: accepts control streams and drives each as a child state /// machine. Resolves only on a transport error; children never end the session. -pub(super) struct Publisher { - shared: Arc>, +pub(super) struct Publisher { + shared: Arc, // Cloned into each control-stream child that arms timers (PROBE, announce linger). runtime: crate::time::Deadlines, // A dedicated accept handle: the poll interface takes `&mut self`, and the // shared context stays behind the Arc for the per-stream children. - accept: S, - children: kio::Tasks>, + accept: Transport, + children: kio::Tasks, /// Aborts the session on a publication outside our grant (dialing side only). enforce: Option, } -impl Publisher { - pub fn new(config: PublisherConfig) -> Self { +impl Publisher { + pub fn new(config: PublisherConfig) -> Self { // Identity stamped onto outbound announce hops. Derived from the // origin we're consuming so it matches the local relay identity // across every session, required for cross-session loop detection. @@ -219,10 +221,7 @@ impl Publisher { } } -impl Publisher -where - S: crate::transport::poll::Session, -{ +impl Publisher { pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll> { if let Some(enforce) = &mut self.enforce && let Poll::Ready(res) = enforce.poll(&self.shared, waiter) @@ -266,10 +265,10 @@ where } #[cfg(test)] -impl Publisher { +impl Publisher { /// Test shim: drive one announce-interest stream like the old `run_announce`. async fn run_announce( - stream: &mut Stream, + stream: &mut Stream, origin: &origin::Consumer, announced: &mut announce::Consumer, self_origin: Hop, @@ -285,36 +284,36 @@ impl Publisher { } /// One accepted control stream, dispatched on its first varint. -struct Control { - shared: Arc>, +struct Control { + shared: Arc, // Handed to the children that arm timers (PROBE, announce linger). runtime: crate::time::Deadlines, - state: ControlState, + state: ControlState, } // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum ControlState { +enum ControlState { /// Reading the stream's type. Start { - stream: Stream, + stream: Stream, }, - Announce(AnnounceServe), - Subscribe(RequestServe>), - Fetch(RequestServe), - TrackInfo(RequestServe), - Tracks(RequestServe), - Probe(ProbeServe), - Auth(AuthServe), + Announce(AnnounceServe), + Subscribe(RequestServe), + Fetch(RequestServe), + TrackInfo(RequestServe), + Tracks(RequestServe), + Probe(ProbeServe), + Auth(AuthServe), /// Decoding the peer's GOAWAY, surfaced through [`crate::Session::draining`]. Goaway { - stream: Stream, + stream: Stream, }, Done, } -impl kio::Task for Control { +impl kio::Task for Control { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -326,7 +325,7 @@ impl kio::Task for Control { } } -impl Control { +impl Control { fn poll_serve(&mut self, waiter: &kio::Waiter) -> Poll> { loop { match &mut self.state { @@ -415,9 +414,9 @@ impl Control { /// Answers one of the peer's tokens: the app's verdict when it took the requests, /// otherwise the grant our own origin handles allow for the connection's /// credential. The stream lives as long as the token. -struct AuthServe { - shared: Arc>, - stream: Option>, +struct AuthServe { + shared: Arc, + stream: Option>, /// Shared with the app's [`crate::auth::Request`] / [`crate::auth::Issued`], or /// filled in by the default acceptor. serving: Option, @@ -429,8 +428,8 @@ struct AuthServe { unsupported: bool, } -impl AuthServe { - fn new(shared: Arc>, stream: Stream) -> Result { +impl AuthServe { + fn new(shared: Arc, stream: Stream) -> Result { // The Auth Stream is lite-07+ only. if !shared.version.has_auth() { return Err(Error::UnexpectedStream); @@ -574,7 +573,11 @@ impl AuthServe { } } - fn write(shared: &Shared, stream: &mut Stream, reply: crate::auth::Reply) -> Result { + fn write( + shared: &Shared, + stream: &mut Stream, + reply: crate::auth::Reply, + ) -> Result { let msg = match reply { crate::auth::Reply::Grant(grant) => { let now = shared.runtime.now(); @@ -612,11 +615,7 @@ struct Enforce { } impl Enforce { - fn poll( - &mut self, - shared: &Shared, - waiter: &kio::Waiter, - ) -> Poll> { + fn poll(&mut self, shared: &Shared, waiter: &kio::Waiter) -> Poll> { let announced = match &mut self.announced { Some(announced) => announced, None => { @@ -644,10 +643,10 @@ impl Enforce { /// /// Reports when the supervisor's estimate moves enough to matter, or once the /// last report ages out, rather than on a timer: an idle session costs nothing. -struct ProbeServe { - shared: Arc>, +struct ProbeServe { + shared: Arc, runtime: crate::time::Deadlines, - stream: Option>, + stream: Option>, /// The supervisor's estimate. Holding it is what keeps the supervisor sampling. estimate: kio::Consumer, /// The estimate last weighed, so only a new one wakes this stream. @@ -659,7 +658,7 @@ struct ProbeServe { budget: kio::coop::Budget, } -impl ProbeServe { +impl ProbeServe { /// The shortest age the bitrate threshold decays from. const PROBE_INTERVAL: Duration = Duration::from_millis(100); const PROBE_MAX_AGE: Duration = Duration::from_secs(10); @@ -706,7 +705,7 @@ impl ProbeServe { Self::PROBE_MAX_AGE - range.mul_f64(delta / Self::PROBE_MAX_DELTA) } - fn new(shared: Arc>, runtime: crate::time::Deadlines, stream: Stream) -> Self { + fn new(shared: Arc, runtime: crate::time::Deadlines, stream: Stream) -> Self { Self { estimate: shared.estimate.consume(), seen: None, @@ -837,10 +836,10 @@ impl ProbeServe { /// Serves one announce-interest stream: the initial set, then updates as routes, /// demand, and the origin change. -struct AnnounceServe { +struct AnnounceServe { _withdrawing: crate::session::Withdrawing, - shared: Arc>, - stream: Option>, + shared: Arc, + stream: Option>, state: AnnounceState, } @@ -861,8 +860,8 @@ enum AnnounceState { }, } -impl AnnounceServe { - fn new(shared: Arc>, stream: Stream) -> Self { +impl AnnounceServe { + fn new(shared: Arc, stream: Stream) -> Self { Self { _withdrawing: shared.withdrawal.register(), shared, @@ -1035,7 +1034,7 @@ impl AnnounceRun { } } - fn sent(&mut self, stream: &mut Stream) -> Result<(), Error> { + fn sent(&mut self, stream: &mut Stream) -> Result<(), Error> { if let Some(remaining) = &mut self.initial { *remaining = remaining.saturating_sub(1); if *remaining == 0 { @@ -1053,9 +1052,9 @@ impl AnnounceRun { /// Apply a change to what we may announce: withdraw what it no longer covers and, /// when it grew, re-read the origin to announce what it now does. - fn regrant( + fn regrant( &mut self, - stream: &mut Stream, + stream: &mut Stream, origin: &origin::Consumer, permit: crate::auth::Permit, ) -> Result<(), Error> { @@ -1112,9 +1111,9 @@ impl AnnounceRun { /// Put `suffix` on the wire with this chain and cost: start it, restart it in place /// when its metadata changed, or leave it alone when the peer already holds it. - fn advertise( + fn advertise( &mut self, - stream: &mut Stream, + stream: &mut Stream, suffix: crate::PathOwned, hops: Hops, cost: crate::origin::Cost, @@ -1188,9 +1187,9 @@ impl AnnounceRun { } /// Start advertising `suffix`, recording its announce id. - fn start( + fn start( &mut self, - stream: &mut Stream, + stream: &mut Stream, suffix: crate::PathOwned, hops: Hops, cost: crate::origin::Cost, @@ -1211,9 +1210,9 @@ impl AnnounceRun { /// Replace the peer's advertisement for `suffix` with another publisher instance: /// ANNOUNCE_RESTART on lite-07, an end and a fresh start before it. - fn restart( + fn restart( &mut self, - stream: &mut Stream, + stream: &mut Stream, suffix: crate::PathOwned, hops: Hops, cost: crate::origin::Cost, @@ -1247,9 +1246,9 @@ impl AnnounceRun { } /// Retract the peer's advertisement for `suffix`, if it holds one. - fn retract( + fn retract( &mut self, - stream: &mut Stream, + stream: &mut Stream, suffix: crate::PathOwned, absolute: &crate::Path, ) -> Result<(), Error> { @@ -1274,9 +1273,9 @@ impl AnnounceRun { } /// Buffer ANNOUNCE_INIT (Lite01/02) or ANNOUNCE_OK and its initial actives (Lite05+). - fn init( + fn init( &mut self, - stream: &mut Stream, + stream: &mut Stream, origin: &origin::Consumer, announced: &mut announce::Consumer, ) -> Result<(), Error> { @@ -1328,9 +1327,9 @@ impl AnnounceRun { /// Retract every live announcement and FIN once flushed. An unanswered request /// still gets its initial burst first, since the peer expects that before a FIN. - fn withdraw( + fn withdraw( &mut self, - stream: &mut Stream, + stream: &mut Stream, origin: &origin::Consumer, announced: &mut announce::Consumer, ) -> Result<(), Error> { @@ -1351,9 +1350,9 @@ impl AnnounceRun { /// Stream updates as they arrive. Closure wins the race so a dead peer can't /// stall on a busy announce feed. - fn poll( + fn poll( &mut self, - stream: &mut Stream, + stream: &mut Stream, origin: &origin::Consumer, announced: &mut announce::Consumer, waiter: &kio::Waiter, @@ -1477,7 +1476,7 @@ fn is_cancel(err: &Error) -> bool { } /// One kind of request stream (TRACK, SUBSCRIBE, FETCH), served by [`RequestServe`]. -trait Request: Sized { +trait Request: Sized { /// Names the request in logs. const KIND: &'static str; /// Whether we answer the requester's FIN with our own. Otherwise we reset: the reply @@ -1502,7 +1501,7 @@ trait Request: Sized { fn epoch(msg: &Self::Message) -> Option<&crate::Epoch>; /// Start answering, once the broadcast resolves. - fn start(shared: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result; + fn start(shared: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result; /// Apply an update from the requester. fn update(&mut self, update: Self::Update); @@ -1511,8 +1510,8 @@ trait Request: Sized { /// between them even while work stays ready, and `Break` once all of it is buffered. fn poll( &mut self, - shared: &Shared, - writer: &mut Writer, + shared: &Shared, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>>; } @@ -1534,10 +1533,10 @@ impl Decode for NoUpdate { /// closing its send direction (FIN or reset) ends it. An abandoned request then releases /// its upstream lookup instead of pinning it for an answer nobody reads. Updates are not a /// close: they reach the reply, held until it starts. -struct RequestServe> { - shared: Arc>, +struct RequestServe { + shared: Arc, // Taken to abort. - stream: Option>, + stream: Option>, state: RequestState, // Counted in `Shared::owed` until the reply is delivered, so a draining close waits for it. owing: bool, @@ -1579,8 +1578,8 @@ enum RequestState { }, } -impl> RequestServe { - fn new(shared: Arc>, stream: Stream) -> Self { +impl RequestServe { + fn new(shared: Arc, stream: Stream) -> Self { shared.owed.fetch_add(1, Ordering::Relaxed); Self { shared, @@ -1807,7 +1806,7 @@ impl> RequestServe { } } -impl> Drop for RequestServe { +impl Drop for RequestServe { fn drop(&mut self) { self.settle(); } @@ -1924,7 +1923,7 @@ struct TrackInfoServe { querying: track::Querying, } -impl Request for TrackInfoServe { +impl Request for TrackInfoServe { const KIND: &'static str = "track info"; const GRACEFUL: bool = false; const CHARGE: Option = Some(Charge::Track); @@ -1940,7 +1939,7 @@ impl Request for TrackInfoServe { msg.epoch.as_ref() } - fn start(_: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { + fn start(_: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { let querying = broadcast.track(&msg.track)?.query().into_inner(); Ok(Self { querying }) } @@ -1951,8 +1950,8 @@ impl Request for TrackInfoServe { fn poll( &mut self, - shared: &Shared, - writer: &mut Writer, + shared: &Shared, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>> { let ietf = ready!(shared.peer_setup.poll_ietf(waiter)); @@ -1979,7 +1978,7 @@ struct TracksServe { tracks: crate::broadcast::Tracks, } -impl Request for TracksServe { +impl Request for TracksServe { const KIND: &'static str = "tracks"; const GRACEFUL: bool = false; const CHARGE: Option = Some(Charge::Tracks); @@ -1995,7 +1994,7 @@ impl Request for TracksServe { msg.epoch.as_ref() } - fn start(shared: &Shared, _: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { + fn start(shared: &Shared, _: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { Ok(Self { tracks: broadcast.tracks_as(shared.lister)?, }) @@ -2007,8 +2006,8 @@ impl Request for TracksServe { fn poll( &mut self, - shared: &Shared, - writer: &mut Writer, + shared: &Shared, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>> { // Pull an event only once the last is out, so a stalled requester's changes collapse @@ -2034,7 +2033,7 @@ impl Request for TracksServe { /// Answers a SUBSCRIBE stream: streams the track's groups (and best-effort datagrams) /// until the track ends. -enum SubscribeServe { +enum SubscribeServe { /// Waiting for the model subscription to be confirmed. Confirm { /// Boxed: the request is far larger than the other states' handles. @@ -2046,10 +2045,10 @@ enum SubscribeServe { }, /// Streaming groups and datagrams. Boxed: by far the largest state, and the enum /// is moved on every transition. - Run(Box>), + Run(Box), /// The track finished: draining the in-flight group streams before the FIN. Drain { - children: kio::Tasks>, + children: kio::Tasks, /// The subscription's demand lasts until its groups drain. A relay cancels its /// upstream subscription once nobody subscribes, and the publisher then resets /// every group still on the wire. `None` only in passing between states. @@ -2057,7 +2056,7 @@ enum SubscribeServe { }, } -impl Request for SubscribeServe { +impl Request for SubscribeServe { const KIND: &'static str = "subscribed"; // Ending a subscription early is still a valid end. const GRACEFUL: bool = true; @@ -2074,7 +2073,7 @@ impl Request for SubscribeServe { msg.epoch.as_ref() } - fn start(shared: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { + fn start(shared: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { let subscription = crate::track::Subscription { priority: msg.priority, max_delay: serving_max_delay(shared.version, msg.max_delay), @@ -2107,8 +2106,8 @@ impl Request for SubscribeServe { fn poll( &mut self, - shared: &Shared, - writer: &mut Writer, + shared: &Shared, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>> { loop { @@ -2246,7 +2245,7 @@ enum FetchServe { /// A batch of frames read for egress, each with what the wire needs beside it. type Objects = arrayvec::ArrayVec; -impl Request for FetchServe { +impl Request for FetchServe { const KIND: &'static str = "fetch"; const FETCH: bool = true; // The response carries no header, so a run cut short would read as whole. @@ -2264,7 +2263,7 @@ impl Request for FetchServe { msg.epoch.as_ref() } - fn start(_: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { + fn start(_: &Shared, msg: Self::Message, broadcast: crate::broadcast::Consumer) -> Result { let fetching = broadcast .track(&msg.track)? .fetch_group( @@ -2285,8 +2284,8 @@ impl Request for FetchServe { fn poll( &mut self, - shared: &Shared, - writer: &mut Writer, + shared: &Shared, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>> { loop { @@ -2671,7 +2670,7 @@ mod announce_test { use crate::model::ProduceTest; use std::sync::Mutex; - type TestPublisher = Publisher; + type TestPublisher = Publisher; const VERSION: Version = Version::Lite06; @@ -2716,9 +2715,12 @@ mod announce_test { cursor: 0, version: Version::Lite07, }; - let mut stream = Stream:: { - writer: Writer::new(SinkSend::stepped(log, budget.consume()), Version::Lite07), - reader: Reader::new(PendingRecv, Version::Lite07), + let mut stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::stepped(log, budget.consume())), + Version::Lite07, + ), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), Version::Lite07), }; let mut run = AnnounceRun::new(crate::Path::new("").to_owned(), consumer.hop(), Version::Lite07); let waiter = kio::Waiter::noop(); @@ -2755,9 +2757,12 @@ mod announce_test { cursor: 0, version: Version::Lite07, }; - let mut stream = Stream:: { - writer: Writer::new(SinkSend::stepped(log, budget.consume()), Version::Lite07), - reader: Reader::new(PendingRecv, Version::Lite07), + let mut stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::stepped(log, budget.consume())), + Version::Lite07, + ), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), Version::Lite07), }; let mut run = AnnounceRun::new(crate::Path::new("").to_owned(), consumer.hop(), Version::Lite07); let waiter = kio::Waiter::noop(); @@ -2794,9 +2799,12 @@ mod announce_test { cursor: 0, version: Version::Lite07, }; - let mut stream = Stream:: { - writer: Writer::new(SinkSend::stepped(log, budget.consume()), Version::Lite07), - reader: Reader::new(PendingRecv, Version::Lite07), + let mut stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::stepped(log, budget.consume())), + Version::Lite07, + ), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), Version::Lite07), }; let mut run = AnnounceRun::new(crate::Path::new("").to_owned(), consumer.hop(), Version::Lite07); let waiter = kio::Waiter::noop(); @@ -2847,9 +2855,12 @@ mod announce_test { cursor: 0, version: Version::Lite07, }; - let mut stream = Stream:: { - writer: Writer::new(SinkSend::stepped(log, budget.consume()), Version::Lite07), - reader: Reader::new(PendingRecv, Version::Lite07), + let mut stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::stepped(log, budget.consume())), + Version::Lite07, + ), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), Version::Lite07), }; let mut run = AnnounceRun::new(crate::Path::new("").to_owned(), consumer.hop(), Version::Lite07); let waiter = kio::Waiter::noop(); @@ -2884,9 +2895,12 @@ mod announce_test { cursor: 0, version: Version::Lite07, }; - let mut stream = Stream:: { - writer: Writer::new(SinkSend::new(log), Version::Lite07), - reader: Reader::new(PendingRecv, Version::Lite07), + let mut stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(log)), + Version::Lite07, + ), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), Version::Lite07), }; let mut run = AnnounceRun::new(crate::Path::new("").to_owned(), consumer.hop(), Version::Lite07); assert!( @@ -2995,9 +3009,9 @@ mod announce_test { let writes = log.writes.clone(); let consumer = origin.consume(); assert!(!consumer.announced().is_synced(), "the relay itself is still syncing"); - let mut stream = Stream:: { - writer: Writer::new(SinkSend::new(log), VERSION), - reader: Reader::new(PendingRecv, VERSION), + let mut stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(SinkSend::new(log)), VERSION), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), VERSION), }; let _task = moq_clock::sim::spawn(async move { let mut announced = consumer.announced(); @@ -3028,9 +3042,9 @@ mod announce_test { let log = Log::default(); let writes = log.writes.clone(); let consumer = origin.consume(); - let mut stream = Stream:: { - writer: Writer::new(SinkSend::new(log), version), - reader: Reader::new(PendingRecv, version), + let mut stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(SinkSend::new(log)), version), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), version), }; let task = moq_clock::sim::spawn(async move { let mut announced = consumer.announced(); @@ -3280,9 +3294,9 @@ mod announce_test { let log = Log::default(); let writes = log.writes.clone(); let consumer = origin.consume().excluding(peer); - let mut stream = Stream:: { - writer: Writer::new(SinkSend::new(log), VERSION), - reader: Reader::new(PendingRecv, VERSION), + let mut stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(SinkSend::new(log)), VERSION), + reader: Reader::new(crate::transport::boxed::RecvStream::new(PendingRecv), VERSION), }; let task = moq_clock::sim::spawn(async move { let mut announced = consumer.announced(); @@ -3606,13 +3620,9 @@ struct Steer { order: Order, } -/// Shared per-subscription state for the publisher side. Cloned cheaply. Every -/// field is either small or already Arc-backed for each in-flight serve_group task -/// so each in-flight group reads the latest SUBSCRIBE_UPDATE steer via its own -/// consumer cursor. -#[derive(Clone)] -struct Subscription { - session: S, +/// The subscription owns the transport handles used to open its group streams. +struct Subscription { + session: Transport, id: u64, track_name: Arc, priority: PriorityQueue, @@ -3620,7 +3630,24 @@ struct Subscription { publisher: i8, /// The subscription's send group, ranking it against the session's others, or `None` /// on a transport without groups, where `priority` ranks every group stream instead. - group: Option>, + group: Option>, + steer: kio::Consumer, + /// Last steer observed by this clone, so a change only fires once. + steer_seen: Steer, + version: Version, + /// How frames and datagrams are stamped, or `None` when they carry no timestamp. + stamp: Option, + /// The clock an untimed track's Lite05/06 send times are read from. + runtime: crate::time::Deadlines, + /// Outcomes shared by the subscription and every group it serves. + outcomes: Arc, + /// Whether the session negotiated the `ietf` extension, so streams carry relay state. + ietf: bool, +} + +/// Each group keeps its own steering cursor, without a session or send-group owner. +struct GroupContext { + id: u64, steer: kio::Consumer, /// Last steer observed by this clone, so a change only fires once. steer_seen: Steer, @@ -3635,6 +3662,18 @@ struct Subscription { ietf: bool, } +impl GroupContext { + /// Remember an encode failure the group stream could not carry. + /// + /// The first one wins. The run loop resets the subscribe stream with it. + fn note_unencodable(&self, err: &Error) { + let mut slot = self.outcomes.unencodable.lock().unwrap(); + if slot.is_none() { + *slot = Some(err.clone()); + } + } +} + /// Group outcomes the subscription must report even if no header reached the peer. #[derive(Default)] struct GroupOutcomes { @@ -3644,7 +3683,20 @@ struct GroupOutcomes { dropped: Mutex>, } -impl Subscription { +impl Subscription { + fn group_context(&self) -> GroupContext { + GroupContext { + id: self.id, + steer: self.steer.clone(), + steer_seen: self.steer_seen, + version: self.version, + stamp: self.stamp, + runtime: self.runtime.clone(), + outcomes: self.outcomes.clone(), + ietf: self.ietf, + } + } + /// Send one datagram best-effort over a QUIC datagram (lite-05 §6.4). /// /// It goes in the subscription's send group, ranked like a stream carrying its group, so @@ -3727,16 +3779,6 @@ impl Subscription { self.steer_seen } - /// Remember an encode failure the group stream could not carry. - /// - /// The first one wins. The run loop resets the subscribe stream with it. - fn note_unencodable(&self, err: &Error) { - let mut slot = self.outcomes.unencodable.lock().unwrap(); - if slot.is_none() { - *slot = Some(err.clone()); - } - } - /// Take the encode failure, if a group recorded one. fn take_unencodable(&self) -> Option { self.outcomes.unencodable.lock().unwrap().take() @@ -3746,20 +3788,21 @@ impl Subscription { /// error the machine otherwise swallows after aborting the stream. #[cfg(test)] async fn serve_group( - self, + mut self, sequence: u64, frame_start: u64, priority: PriorityHandle, group: group::Consumer, ) -> Result<(), Error> { let mut serve = Box::new(GroupServe::new( - self, + self.group_context(), sequence, frame_start, false, Rank::Queue(priority), group, )); + kio::wait(|waiter| serve.poll_open(&mut self.session, self.group.as_ref(), waiter)).await?; kio::wait(move |waiter| serve.poll_serve(waiter)).await } } @@ -3767,8 +3810,8 @@ impl Subscription { /// A subscription's run loop: one subscriber cursor serving groups, datagrams, /// and SUBSCRIBE_UPDATE messages, with a machine per group it serves, one at a time /// waiting for stream credit. -struct TrackRun { - ctx: Subscription, +struct TrackRun { + ctx: Subscription, track: track::Subscriber, /// Broadcasts SUBSCRIBE_UPDATE priorities to the in-flight group machines. steer_tx: kio::Producer, @@ -3802,13 +3845,13 @@ struct TrackRun { /// which bills, ages, and evicts it, and the cursor's budget skips whatever went stale /// meanwhile: a machine per parked group would hold state for as long as the peer /// withholds credit. - opening: Option>, + opening: Option, /// The groups with a stream, serving or awaiting the acknowledgement of their FIN. - children: kio::Tasks>, + children: kio::Tasks, } -impl TrackRun { - fn new(ctx: Subscription, mut track: track::Subscriber, bounds: Bounds, steer_tx: kio::Producer) -> Self { +impl TrackRun { + fn new(ctx: Subscription, mut track: track::Subscriber, bounds: Bounds, steer_tx: kio::Producer) -> Self { // Apply the initial cap from the original Subscribe. Subsequent updates // flow through the SUBSCRIBE_UPDATE arm below. track.end_at(bounds.end_group.map_or(Bound::Unbounded, Bound::Included)); @@ -3920,7 +3963,11 @@ impl TrackRun { /// Serve until the live edge reaches the track's boundary. #[cfg(test)] - fn poll(&mut self, writer: &mut Writer, waiter: &kio::Waiter) -> Poll> { + fn poll( + &mut self, + writer: &mut Writer, + waiter: &kio::Waiter, + ) -> Poll> { while ready!(self.poll_step(writer, waiter))?.is_continue() {} writer.poll_flush(&mut waiter.context()) } @@ -3930,7 +3977,7 @@ impl TrackRun { /// requester while work stays ready. fn poll_step( &mut self, - writer: &mut Writer, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Poll, Error>> { let mut cx = waiter.context(); @@ -3940,7 +3987,7 @@ impl TrackRun { // The group waiting for stream credit joins the others once it has one, or fails // without one. if let Some(opening) = &mut self.opening - && let Poll::Ready(res) = opening.poll_open(waiter) + && let Poll::Ready(res) = opening.poll_open(&mut self.ctx.session, self.ctx.group.as_ref(), waiter) { let opening = self.opening.take().expect("polled above"); match res { @@ -4083,7 +4130,7 @@ impl TrackRun { /// for it instead, including ranges skipped while finding the first servable group. fn poll_forward_drop( &mut self, - writer: &mut Writer, + writer: &mut Writer, waiter: &kio::Waiter, ) -> Result { if !self.emit_range { @@ -4136,7 +4183,7 @@ impl TrackRun { &mut self, range: Range, err: &StreamError, - writer: &mut Writer, + writer: &mut Writer, ) -> Result<(), Error> { let Some(served) = &mut self.served else { return Ok(()); @@ -4156,7 +4203,10 @@ impl TrackRun { /// Name every sequence from the start to the end that this subscription never got. The /// track has ended, so none of them will be served now: groups it never produced (a /// skipped sequence), and groups the cursor passed over (stale, or missing their head). - fn drop_unserved(&mut self, writer: &mut Writer) -> Result<(), Error> { + fn drop_unserved( + &mut self, + writer: &mut Writer, + ) -> Result<(), Error> { let Some(start) = self.start else { // Without a SUBSCRIBE_START the subscriber owes itself no group (see // `SubStream::owed`) and settles on the FIN alone, so there is nothing to drop. @@ -4173,7 +4223,7 @@ impl TrackRun { } } -impl TrackRun { +impl TrackRun { /// Send SUBSCRIBE_START for the first servable group, then serve it. /// /// A relay caches groups in upstream arrival order, and a newer group's stream can @@ -4185,7 +4235,7 @@ impl TrackRun { &mut self, group: group::Consumer, source: Option, - writer: &mut Writer, + writer: &mut Writer, ) -> Result<(), Error> { let mut start = source.map_or(group.sequence, |source| source.min(group.sequence)); // A group given up cannot be where the feed starts. This stops at the held group @@ -4246,7 +4296,7 @@ impl TrackRun { // Use the latest steer for new groups so SUBSCRIBE_UPDATE applies to them too. let steer = self.ctx.steer_current(); let rank = match &self.ctx.group { - Some(group) => Rank::Group(group.clone()), + Some(_) => Rank::Group, // The subscribe id scopes the group tie-break: one queue serves every // subscription on the session, and only groups of the same one may be // ranked against each other by sequence, in that subscription's order. @@ -4260,7 +4310,7 @@ impl TrackRun { }; debug_assert!(self.opening.is_none(), "one group waits for stream credit at a time"); self.opening = Some(GroupServe::new( - self.ctx.clone(), + self.ctx.group_context(), sequence, frame_start, capped, @@ -4271,18 +4321,18 @@ impl TrackRun { } /// Where a group stream is ranked. -enum Rank { +enum Rank { /// In the subscription's send group, by its sequence in the subscription's order. - Group(G), + Group, /// In the session-wide queue, on a transport without send groups. Queue(PriorityHandle), } /// Serves one group on its own unidirectional stream: the header, then every /// frame, applying queue and SUBSCRIBE_UPDATE priority changes as they land. -struct GroupServe { - ctx: Subscription, - rank: Rank>, +struct GroupServe { + ctx: GroupContext, + rank: Rank, group: group::Consumer, sequence: u64, frame_start: u64, @@ -4292,7 +4342,7 @@ struct GroupServe { // frame's delta is absolute (against an implicit prev value of 0), every // subsequent delta is signed against the previous frame. prev_ts: u64, - state: GroupState, + state: GroupState, // A long cached group drains a slice per poll, so its siblings still run. budget: kio::coop::Budget, } @@ -4300,13 +4350,13 @@ struct GroupServe { // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum GroupState { - /// Waiting for stream credit on this machine's own session handle. +enum GroupState { + /// Waiting for stream credit on the subscription's session handle. Open, /// Streaming frames: the write buffer drains first, then the pending chunk, /// then the pending frame, then the next frame. Serve { - writer: Writer, + writer: Writer, frame: Option, chunk: Option, batch: Box, @@ -4317,18 +4367,18 @@ enum GroupState { /// Every frame is written and the FIN sent: wait for the acknowledgement so a /// late cancel or expiry can still reset the stream. Closed { - writer: Writer, + writer: Writer, }, Done, } -impl GroupServe { +impl GroupServe { fn new( - ctx: Subscription, + ctx: GroupContext, sequence: u64, frame_start: u64, capped: bool, - rank: Rank>, + rank: Rank, group: group::Consumer, ) -> Self { // A lite-07 peer receives a compressed group as stored, others inflated. @@ -4360,7 +4410,12 @@ impl GroupServe { /// Wait for stream credit, then write the group header, leaving the machine serving. /// Gives up once the group can no longer be sent, so a parked group never spends the /// credit it was waiting for on a reset. - fn poll_open(&mut self, waiter: &kio::Waiter) -> Poll> { + fn poll_open( + &mut self, + session: &mut Transport, + group: Option<&GroupOf>, + waiter: &kio::Waiter, + ) -> Poll> { if !matches!(self.state, GroupState::Open) { return Poll::Ready(Ok(())); } @@ -4371,8 +4426,8 @@ impl GroupServe { } let mut cx = waiter.context(); let options = match &mut self.rank { - Rank::Group(group) => SendOptions { - group: Some(&*group), + Rank::Group => SendOptions { + group, priority: crate::priority::in_group(self.sequence, self.frame_start, self.ctx.steer_seen.order), }, Rank::Queue(handle) => SendOptions { @@ -4380,7 +4435,7 @@ impl GroupServe { priority: handle.send_order().into(), }, }; - let stream = match ready!(self.ctx.session.poll_open_uni(&mut cx, options)) { + let stream = match ready!(session.poll_open_uni(&mut cx, options)) { Ok(stream) => stream, Err(err) => { self.settle_open(false); @@ -4457,7 +4512,7 @@ impl GroupServe { self.ctx.steer_seen = value; // The run loop moves the send group itself; a stream only follows the order. let order = match &mut self.rank { - Rank::Group(_) => crate::priority::in_group(self.sequence, self.frame_start, value.order), + Rank::Group => crate::priority::in_group(self.sequence, self.frame_start, value.order), Rank::Queue(handle) => { PriorityHandle::send_order_of(handle.steer(value.priority, value.order)).into() } @@ -4467,7 +4522,7 @@ impl GroupServe { } match &mut self.state { - GroupState::Open => ready!(self.poll_open(waiter))?, + GroupState::Open => unreachable!("the subscription opens a group before scheduling it"), GroupState::Serve { writer, frame, @@ -4678,7 +4733,7 @@ impl GroupServe { } } -impl kio::Task for GroupServe { +impl kio::Task for GroupServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -4689,7 +4744,7 @@ impl kio::Task for GroupServe { } } -impl GroupServe { +impl GroupServe { /// Account for a group that failed with `err`: a reset can lose its header, and a group /// that never got a stream has none, so the control stream names it with that error. fn settle_failed(&self, err: &Error) { @@ -4859,7 +4914,7 @@ mod serve_group_test { let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -4906,7 +4961,7 @@ mod serve_group_test { let log = session.log.clone(); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -4957,7 +5012,7 @@ mod serve_group_test { let session = SinkSession::new(log.clone()); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5008,7 +5063,7 @@ mod serve_group_test { let log = session.log.clone(); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5076,7 +5131,7 @@ mod serve_group_test { let session = SinkSession::gated_open_uni(gate.consume()); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5120,7 +5175,7 @@ mod serve_group_test { /// Step `run` until it has nothing ready, yielding between steps so a long drain stays /// under the simulator's per-poll limit. - async fn settle_run(run: &mut TrackRun, writer: &mut Writer) { + async fn settle_run(run: &mut TrackRun, writer: &mut Writer) { while run.poll_step(writer, &kio::Waiter::noop()).is_ready() { moq_clock::sim::yield_now().await; } @@ -5250,7 +5305,7 @@ mod serve_group_test { let log = session.log.clone(); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5326,7 +5381,7 @@ mod serve_group_test { let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5376,7 +5431,7 @@ mod serve_group_test { let log = session.log.clone(); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5425,7 +5480,7 @@ mod serve_group_test { let log = session.log.clone(); let steer = kio::Producer::new(Steer::default()); let subscription = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5472,7 +5527,7 @@ mod serve_group_test { fn lite07_run( session: SinkSession, track: track::Subscriber, - ) -> (TrackRun, Writer, Log) { + ) -> (TrackRun, Writer, Log) { lite_run(Version::Lite07, session, track) } @@ -5481,12 +5536,15 @@ mod serve_group_test { version: Version, session: SinkSession, track: track::Subscriber, - ) -> (TrackRun, Writer, Log) { + ) -> (TrackRun, Writer, Log) { let log = Log::default(); - let writer = Writer::new(SinkSend::new(log.clone()), version); + let writer = Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(log.clone())), + version, + ); let steer = kio::Producer::new(Steer::default()); let ctx = Subscription { - session, + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -5566,10 +5624,10 @@ mod serve_group_test { ); // Old groups stay worth sending, so both are in flight at once. let subscriber = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(3600))); - let mut session = SinkSession::new(Log::default()).with_groups().with_unacked_fin(); + let session = SinkSession::new(Log::default()).with_groups().with_unacked_fin(); let log = session.log.clone(); let (mut run, mut writer, _) = lite_run(Version::Lite06, session.clone(), subscriber); - run.ctx.group = crate::transport::poll::Session::send_group(&mut session, 3); + run.ctx.group = crate::transport::poll::Session::send_group(&mut run.ctx.session, 3); write_group(&mut track, 0, 0); write_group(&mut track, 1, 1); @@ -5620,13 +5678,13 @@ mod serve_group_test { crate::track::Info::timed(), ); let subscriber = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(3600))); - let mut session = SinkSession::new(Log::default()) + let session = SinkSession::new(Log::default()) .with_groups() .with_datagrams(1200) .with_unacked_fin(); let log = session.log.clone(); let (mut run, mut writer, _) = lite_run(Version::Lite06, session.clone(), subscriber); - run.ctx.group = crate::transport::poll::Session::send_group(&mut session, 3); + run.ctx.group = crate::transport::poll::Session::send_group(&mut run.ctx.session, 3); write_group(&mut track, 0, 0); let sequence = track @@ -5652,10 +5710,10 @@ mod serve_group_test { crate::track::Info::timed(), ); let subscriber = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(3600))); - let mut session = SinkSession::new(Log::default()).with_groups().with_datagrams(1200); + let session = SinkSession::new(Log::default()).with_groups().with_datagrams(1200); let log = session.log.clone(); let (mut run, mut writer, _) = lite_run(Version::Lite06, session.clone(), subscriber); - run.ctx.group = crate::transport::poll::Session::send_group(&mut session, 3); + run.ctx.group = crate::transport::poll::Session::send_group(&mut run.ctx.session, 3); let first = track .append_datagram(Timestamp::from_millis(1).unwrap(), b"a".as_slice()) @@ -5803,7 +5861,11 @@ mod serve_group_test { } /// The SUBSCRIBE_DROP ranges a run loop's subscribe stream carried, once flushed. - async fn drops(writer: &mut Writer, log: &Log, version: Version) -> Vec<(u64, u64)> { + async fn drops( + writer: &mut Writer, + log: &Log, + version: Version, + ) -> Vec<(u64, u64)> { // The serve flushes what the run loop buffered before its FIN. kio::wait(|waiter| writer.poll_flush(&mut waiter.context())) .await @@ -6509,7 +6571,7 @@ mod serve_group_test { .with_max_delay(Duration::from_secs(60)), ); let (mut run, mut writer, _log) = lite_run(Version::Lite05, SinkSession::new(Log::default()), subscriber); - let mut settle = |run: &mut TrackRun| { + let mut settle = |run: &mut TrackRun| { let res = kio::wait(|waiter| run.poll(&mut writer, waiter)).now_or_never(); assert!(res.is_none(), "the run ended"); run.ctx.outcomes.opened.load(Ordering::Relaxed) @@ -6603,8 +6665,8 @@ mod serve_group_test { /// A lite-07 run over a relay's track, whose upstream subscription still waits on the /// source's SUBSCRIBE_START, on a subscribe stream the test can push updates onto. struct RelayRun { - run: TrackRun, - writer: Writer, + run: TrackRun, + writer: Writer, session: ScriptedSession, outcomes: Arc, } @@ -6619,11 +6681,14 @@ mod serve_group_test { let subscriber = track.subscribe(subscription); let session = ScriptedSession::new(Vec::new()); - let writer = Writer::new(SinkSend::new(session.log.clone()), Version::Lite07); + let writer = Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::new(session.log.clone())), + Version::Lite07, + ); let steer = kio::Producer::new(Steer::default()); let outcomes = Arc::::default(); let ctx = Subscription { - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), id: 0, track_name: "test".into(), priority: PriorityQueue::default(), @@ -6947,7 +7012,7 @@ mod tests { let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin: origin.consume(), version: Version::Lite06, peer_setup, @@ -7008,11 +7073,13 @@ mod tests { let gate = kio::Producer::new(true); let session = SinkSession::gated_bi(gate.consume()); let log = session.log.clone(); - let mut stream = Stream::open(&mut session.clone(), Version::Lite01).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Lite01) + .await + .unwrap(); let consumer = origin.consume().excluding(assigned); let mut announced = consumer.announced(); - let mut run = std::pin::pin!(Publisher::::run_announce( + let mut run = std::pin::pin!(Publisher::run_announce( &mut stream, &consumer, &mut announced, @@ -7044,10 +7111,12 @@ mod tests { let gate = kio::Producer::new(true); let session = SinkSession::gated_bi(gate.consume()); let log = session.log.clone(); - let mut stream = Stream::open(&mut session.clone(), Version::Lite01).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Lite01) + .await + .unwrap(); let consumer = origin.consume(); let mut announced = consumer.announced(); - let mut run = std::pin::pin!(Publisher::::run_announce( + let mut run = std::pin::pin!(Publisher::run_announce( &mut stream, &consumer, &mut announced, @@ -7078,7 +7147,9 @@ mod tests { let gate = kio::Producer::new(true); let session = SinkSession::gated_bi(gate.consume()); let log = session.log.clone(); - let mut stream = Stream::open(&mut session.clone(), Version::Lite01).await.unwrap(); + let mut stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Lite01) + .await + .unwrap(); let consumer = origin.consume(); let mut announced = consumer.announced(); @@ -7108,12 +7179,12 @@ mod tests { /// Build the poll-based PROBE server around a stream opened by the test peer, /// following `estimate` as it would the supervisor's. - fn probe_server( - session: S, - stream: Stream, + fn probe_server( + session: Transport, + stream: Stream, version: Version, estimate: &kio::Producer, - ) -> ProbeServe { + ) -> ProbeServe { let origin = Hop::random().produce(); let (_, goaway) = crate::goaway::Handle::new(true); let publisher = Publisher::new(PublisherConfig { @@ -7139,11 +7210,13 @@ mod tests { use kio::Task; for version in [Version::Lite04, Version::Lite05, Version::Lite06, Version::Lite07] { // A complete two-byte body with an empty URI and one unread byte. - let mut session = ScriptedSession::new(vec![2, 0, 0]); + let session = ScriptedSession::new(vec![2, 0, 0]); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session, stream, version, &estimate); + let probe = probe_server(crate::driver::Transport::new(session), stream, version, &estimate); let stream = probe.stream.expect("probe stream"); let mut control = Control { shared: probe.shared, @@ -7175,11 +7248,13 @@ mod tests { (Version::Lite06, lite::ControlType::Tracks as u8), ]; for (version, kind) in cases { - let mut session = ScriptedSession::new(vec![kind]); + let session = ScriptedSession::new(vec![kind]); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session, stream, version, &estimate); + let probe = probe_server(crate::driver::Transport::new(session), stream, version, &estimate); let stream = probe.stream.expect("probe stream"); let mut control = Control { shared: probe.shared, @@ -7196,7 +7271,7 @@ mod tests { struct Probing { estimate: kio::Producer, log: crate::lite::test_transport::Log, - server: ProbeServe, + server: ProbeServe, version: Version, _gate: kio::Producer, } @@ -7204,12 +7279,14 @@ mod tests { impl Probing { async fn new(stats: crate::lite::test_transport::SinkStats, version: Version) -> Self { let gate = kio::Producer::new(true); - let mut session = SinkSession::gated_bi(gate.consume()).with_stats(stats); + let session = SinkSession::gated_bi(gate.consume()).with_stats(stats); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); // The supervisor's construction-time snapshot. let estimate = kio::Producer::new(crate::session::Estimate::read(&session)); - let server = probe_server(session, stream, version, &estimate); + let server = probe_server(crate::driver::Transport::new(session), stream, version, &estimate); Self { estimate, log, @@ -7384,7 +7461,7 @@ mod tests { } /// Drive `serve` until it ends, or everything parks: whether it ended. - async fn drive>(serve: &mut RequestServe) -> bool { + async fn drive(serve: &mut RequestServe) -> bool { moq_clock::timeout(Duration::from_millis(1), kio::wait(|waiter| serve.poll(waiter))) .await .is_ok() @@ -7392,12 +7469,7 @@ mod tests { /// Serve an `R` request whose broadcast or track never resolves, then have the /// requester close its send side. - async fn leave_request>( - version: Version, - request: &impl Encode, - wait: Wait, - close: Close, - ) { + async fn leave_request(version: Version, request: &impl Encode, wait: Wait, close: Close) { let case = format!("{} over {version:?}, waiting on the {wait:?}, {close:?}", R::KIND); let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); // Held, never answered. @@ -7418,7 +7490,7 @@ mod tests { let (_, goaway) = crate::goaway::Handle::new(true); let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(ScriptedSession::new(Vec::new())), origin: origin.consume(), version, peer_setup, @@ -7442,11 +7514,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, version), - reader: crate::coding::Reader::new(recv, version), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), version), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version), }; - let mut serve = RequestServe::<_, R>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await, "{case}: nothing to answer with"); // The lookup reached the track, which stays wanted while the requester waits. @@ -7513,7 +7585,7 @@ mod tests { start_frame: 0, end_frame: None, }; - leave_request::>(version, &subscribe, wait, close).await; + leave_request::(version, &subscribe, wait, close).await; let fetch = lite::Fetch { epoch: None, @@ -7551,7 +7623,7 @@ mod tests { let publisher = Publisher::new(PublisherConfig { estimate: kio::Producer::default().weak(), runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(ScriptedSession::new(Vec::new())), origin: origin.consume(), version, peer_setup, @@ -7584,11 +7656,17 @@ mod tests { .unwrap(); // A closed gate is a reply blocked on flow control, never reopened. let gate = kio::Producer::new(!blocked); - let stream = Stream:: { - writer: Writer::new(SinkSend::gated(session.log.clone(), gate.consume()), version), - reader: crate::coding::Reader::new(recv, version), + let stream = Stream:: { + writer: Writer::new( + crate::transport::boxed::SendStream::new(SinkSend::gated( + session.log.clone(), + gate.consume(), + )), + version, + ), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version), }; - let mut serve = RequestServe::<_, TrackInfoServe>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await, "{case}: ended before the requester closed"); assert!( @@ -7640,7 +7718,7 @@ mod tests { let version = Version::Lite07; let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(ScriptedSession::new(Vec::new())), origin: origin.consume(), version, peer_setup, @@ -7677,11 +7755,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, version), - reader: crate::coding::Reader::new(recv, version), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), version), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version), }; - let mut serve = RequestServe::<_, SubscribeServe>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await); let update = |wanted_group, priority| lite::SubscribeUpdate { @@ -7759,7 +7837,7 @@ mod tests { let publisher = Publisher::new(PublisherConfig { estimate: kio::Producer::default().weak(), runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(ScriptedSession::new(Vec::new())), origin: origin.consume(), version, peer_setup, @@ -7794,11 +7872,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, version), - reader: crate::coding::Reader::new(recv, version), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), version), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version), }; - let mut serve = RequestServe::<_, SubscribeServe>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await); let track = dynamic .requested_track() @@ -7920,7 +7998,7 @@ mod tests { let mut publisher = Publisher::new(PublisherConfig { estimate: kio::Producer::default().weak(), runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin.consume(), version: VERSION, peer_setup: crate::lite::PeerSetup::new(false, crate::transport::Binding::InBand), @@ -7961,7 +8039,7 @@ mod tests { let (_, goaway) = crate::goaway::Handle::new(true); let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(ScriptedSession::new(Vec::new())), origin: origin.consume(), version: VERSION, peer_setup, @@ -7993,11 +8071,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, VERSION), - reader: crate::coding::Reader::new(recv, VERSION), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), VERSION), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), VERSION), }; - let mut serve = RequestServe::<_, FetchServe>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await, "the open group holds the response"); // The track runs a full second past the group's successor. @@ -8026,9 +8104,11 @@ mod tests { let peer_setup = crate::lite::PeerSetup::new(false, crate::transport::Binding::InBand); peer_setup.set(crate::lite::Setup::default()); let (_, goaway) = crate::goaway::Handle::new(true); + let session = ScriptedSession::new(Vec::new()); + let log = session.log.clone(); let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()), + session: crate::driver::Transport::new(session), origin: origin.consume(), version: VERSION, peer_setup, @@ -8063,11 +8143,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, VERSION), - reader: crate::coding::Reader::new(recv, VERSION), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), VERSION), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), VERSION), }; - let mut request = RequestServe::<_, FetchServe>::new(publisher.shared.clone(), stream); + let mut request = RequestServe::::new(publisher.shared.clone(), stream); if count < 2 { assert!(!drive(&mut request).await); held.push(request); @@ -8088,7 +8168,7 @@ mod tests { "same group coalesces in the model" ); assert_eq!( - publisher.shared.session.log.closes(), + log.closes(), vec![( crate::SessionError::TooManyRequests.to_code(), "too many fetches".to_owned() @@ -8155,12 +8235,19 @@ mod tests { bitrate: Some(4_000_000), rtt: Some(20), }; - let mut session = ScriptedSession::new(target.encode_bytes(version).unwrap().to_vec()) + let session = ScriptedSession::new(target.encode_bytes(version).unwrap().to_vec()) .with_stats(crate::lite::test_transport::SinkStats::default().with_send_rate(1_000_000)); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let mut serve = probe_server(session.clone(), stream, version, &estimate); + let mut serve = probe_server( + crate::driver::Transport::new(session.clone()), + stream, + version, + &estimate, + ); assert!( serve.poll_probe(&kio::Waiter::noop()).is_pending(), "{version}: target ended Report" @@ -8188,12 +8275,19 @@ mod tests { rtt: Some(20), }; let script = target.encode_bytes(version).unwrap().repeat(TARGETS); - let mut session = ScriptedSession::new(script) + let session = ScriptedSession::new(script) .with_stats(crate::lite::test_transport::SinkStats::default().with_send_rate(1_000_000)); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); session.close(Close::Fin); let estimate = kio::Producer::default(); - let mut serve = probe_server(session.clone(), stream, version, &estimate); + let mut serve = probe_server( + crate::driver::Transport::new(session.clone()), + stream, + version, + &estimate, + ); // Without a budget the first poll drains every target and reaches the FIN. assert!( serve.poll_probe(&kio::Waiter::noop()).is_pending(), @@ -8226,11 +8320,18 @@ mod tests { start_frame: 0, end_frame: None, }; - let mut session = ScriptedSession::new(request.encode_bytes(version).unwrap().to_vec()); + let session = ScriptedSession::new(request.encode_bytes(version).unwrap().to_vec()); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session.clone(), stream, version, &estimate); + let probe = probe_server( + crate::driver::Transport::new(session.clone()), + stream, + version, + &estimate, + ); probe.shared.peer_setup.set(lite::Setup::default()); let mut shared = probe.shared; Arc::get_mut(&mut shared).expect("one owner").origin = origin.consume(); @@ -8271,12 +8372,21 @@ mod tests { epoch: None, }; let request = request.encode_bytes(version).unwrap().to_vec(); - let mut session = ScriptedSession::per_stream(vec![request.clone(), request]); + let session = ScriptedSession::per_stream(vec![request.clone(), request]); let log = session.log.clone(); - let older = Stream::open(&mut session, version).await.unwrap(); - let newer = Stream::open(&mut session, version).await.unwrap(); + let older = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); + let newer = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session.clone(), older, version, &estimate); + let probe = probe_server( + crate::driver::Transport::new(session.clone()), + older, + version, + &estimate, + ); probe.shared.peer_setup.set(lite::Setup::default()); let mut shared = probe.shared; Arc::get_mut(&mut shared).expect("one owner").origin = origin.consume(); @@ -8287,7 +8397,7 @@ mod tests { }; // Whether the control is still serving after the runtime settles. - async fn serving(control: &mut Control) -> bool { + async fn serving(control: &mut Control) -> bool { moq_clock::timeout(Duration::from_millis(1), kio::wait(|waiter| control.poll(waiter))) .await .is_err() @@ -8324,11 +8434,18 @@ mod tests { start_frame: 0, end_frame: None, }; - let mut session = ScriptedSession::new(request.encode_bytes(version).unwrap().to_vec()); + let session = ScriptedSession::new(request.encode_bytes(version).unwrap().to_vec()); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session.clone(), stream, version, &estimate); + let probe = probe_server( + crate::driver::Transport::new(session.clone()), + stream, + version, + &estimate, + ); probe.shared.peer_setup.set(lite::Setup::default()); let mut shared = probe.shared; Arc::get_mut(&mut shared).expect("one owner").origin = origin.consume(); @@ -8365,11 +8482,13 @@ mod tests { let msg = lite::Goaway { uri: std::borrow::Cow::Owned(uri), }; - let mut session = ScriptedSession::new(msg.encode_bytes(version).unwrap().to_vec()); + let session = ScriptedSession::new(msg.encode_bytes(version).unwrap().to_vec()); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session, stream, version, &estimate); + let probe = probe_server(crate::driver::Transport::new(session), stream, version, &estimate); let mut control = Control { shared: probe.shared, runtime: crate::time::sim(), @@ -8386,12 +8505,14 @@ mod tests { ); } for end in [Close::Fin, Close::Reset] { - let mut session = ScriptedSession::new(Vec::new()); + let session = ScriptedSession::new(Vec::new()); session.close(end); let log = session.log.clone(); - let stream = Stream::open(&mut session, version).await.unwrap(); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let estimate = kio::Producer::default(); - let probe = probe_server(session, stream, version, &estimate); + let probe = probe_server(crate::driver::Transport::new(session), stream, version, &estimate); let mut control = Control { shared: probe.shared, runtime: crate::time::sim(), @@ -8406,13 +8527,15 @@ mod tests { } /// A publisher on a session with send groups. - fn grouped_publisher(origin: origin::Consumer) -> Publisher { + fn grouped_publisher(origin: origin::Consumer) -> (Publisher, crate::lite::test_transport::Log) { let peer_setup = crate::lite::PeerSetup::new(false, crate::transport::Binding::InBand); peer_setup.set(crate::lite::Setup::default()); let (_, goaway) = crate::goaway::Handle::new(true); - Publisher::new(PublisherConfig { + let session = ScriptedSession::new(Vec::new()).with_groups(); + let log = session.log.clone(); + let publisher = Publisher::new(PublisherConfig { runtime: crate::time::sim(), - session: ScriptedSession::new(Vec::new()).with_groups(), + session: crate::driver::Transport::new(session), origin, version: Version::Lite07, peer_setup, @@ -8424,22 +8547,20 @@ mod tests { subscriptions: Default::default(), fetches: Default::default(), estimate: kio::Producer::default().weak(), - }) + }); + (publisher, log) } /// Subscribe to `broadcast`'s `track` at the subscriber `priority`, resolving the track /// with `info`, until the subscription runs. async fn subscribe_at( - publisher: &Publisher, + publisher: &Publisher, dynamic: &mut broadcast::Dynamic, broadcast: &'static str, track: &'static str, priority: i8, info: track::Info, - ) -> ( - RequestServe>, - track::Producer, - ) { + ) -> (RequestServe, track::Producer) { let version = Version::Lite07; let msg = lite::Subscribe { order: crate::track::Order::Descending, @@ -8463,11 +8584,11 @@ mod tests { }) .await .unwrap(); - let stream = Stream:: { - writer: Writer::new(send, version), - reader: crate::coding::Reader::new(recv, version), + let stream = Stream:: { + writer: Writer::new(crate::transport::boxed::SendStream::new(send), version), + reader: crate::coding::Reader::new(crate::transport::boxed::RecvStream::new(recv), version), }; - let mut serve = RequestServe::<_, SubscribeServe<_>>::new(publisher.shared.clone(), stream); + let mut serve = RequestServe::::new(publisher.shared.clone(), stream); assert!(!drive(&mut serve).await); let track = dynamic .requested_track() @@ -8491,8 +8612,7 @@ mod tests { let broadcast = origin.create_broadcast("a").unwrap(); let mut dynamic = broadcast.dynamic(); broadcast.announce(Default::default()).unwrap(); - let publisher = grouped_publisher(origin.consume()); - let log = publisher.shared.session.log.clone(); + let (publisher, log) = grouped_publisher(origin.consume()); let video = track::Info::timed().with_priority(60); let audio = track::Info::timed().with_priority(80); diff --git a/rs/moq-net/src/lite/session.rs b/rs/moq-net/src/lite/session.rs index ef8cb2fce8b..d6bd8b3f932 100644 --- a/rs/moq-net/src/lite/session.rs +++ b/rs/moq-net/src/lite/session.rs @@ -1,4 +1,6 @@ +use crate::driver::Transport; use crate::origin; +use crate::transport::poll::Session as _; use crate::{ Error, Hop, SessionError, bandwidth, coding::{Reader, Stream, Writer}, @@ -11,13 +13,12 @@ use super::{ DataType, PeerSetup, Publisher, PublisherConfig, Setup, Subscriber, SubscriberConfig, SubscriberDriver, Version, }; -pub(crate) struct SessionStart { +pub(crate) struct SessionStart { pub recv_bandwidth: Option, /// The estimate PROBE reports, published by the session's supervisor. pub estimate: kio::Producer, - /// The session's protocol machine, named so its `Send`-ness stays inferred - /// from the transport instead of being fixed by a box. - pub driver: Driver, + /// The session's protocol machine over the boxed transport. + pub driver: Driver, /// The session-side GOAWAY halves, stored on the public [`crate::Session`]. pub goaway: crate::goaway::Handle, /// The session's AUTH tokens and grants, stored on the public [`crate::Session`]. @@ -33,11 +34,8 @@ pub(crate) struct SessionStart { /// /// Pass the result to [`start`] as its `peer_setup` so capability gating resolves /// without re-reading SETUP, and every held stream is handed back to the driver. -pub async fn accept_setup( - session: &mut S, - version: Version, -) -> Result, Error> { - let mut accept = SetupAccept:: { +pub async fn accept_setup(session: &mut Transport, version: Version) -> Result { + let mut accept = SetupAccept { version, pending: Vec::new(), early: Vec::new(), @@ -46,15 +44,15 @@ pub async fn accept_setup( kio::wait(|waiter| accept.poll(session, waiter)).await } -struct SetupAccept { +struct SetupAccept { version: Version, - pending: Vec>, - early: Vec>, - setup: Option>, + pending: Vec>, + early: Vec>, + setup: Option>, } -impl SetupAccept { - fn poll(&mut self, session: &mut S, waiter: &kio::Waiter) -> Poll, Error>> { +impl SetupAccept { + fn poll(&mut self, session: &mut Transport, waiter: &kio::Waiter) -> Poll> { let Self { version, pending, @@ -135,17 +133,17 @@ impl SetupAccept { } /// The peer's pre-read SETUP and the streams held until it arrived. -pub struct AcceptedSetup { +pub struct AcceptedSetup { /// The SETUP decoded before origin binding. pub setup: Setup, /// The SETUP's encoded size, counted once the session's stats are known. pub size: usize, /// Streams with their type still buffered for the session classifier. - pub early: Vec>, + pub early: Vec>, } /// Everything one moq-lite session needs to start. -pub struct Config { +pub struct Config { /// The runtime that arms the session's timers. pub runtime: crate::time::Deadlines, @@ -159,11 +157,11 @@ pub struct Config { /// The transport carrying the session. Cloned into every loop that outlives /// [`start`], so the connection closes when the last of them drops. - pub session: S, + pub session: Transport, /// The stream used to set up the session, after exchanging setup messages. /// NOTE: No longer used in draft-03. - pub setup_stream: Option>, + pub setup_stream: Option>, /// We will publish any local broadcasts from this origin, when set. pub publish: Option, @@ -188,7 +186,7 @@ pub struct Config { /// The peer's SETUP, when it was already read before [`start`] (e.g. a server that /// gated on the client's path via [`accept_setup`]). Seeds the peer-setup slot so /// the Setup Stream isn't expected again. `None` reads it from the wire as usual. - pub peer_setup: Option>, + pub peer_setup: Option, /// The session's auth handle, created before [`start`] so a server can take the /// peer's token requests during its handshake. Supports AUTH exactly when `version` @@ -201,10 +199,7 @@ pub struct Config { /// Start a lite session. /// /// Returns the receive-bandwidth consumer (if any) plus the driver that runs the session. -pub fn start(config: Config) -> Result, Error> -where - S: crate::transport::poll::Session, -{ +pub fn start(config: Config) -> Result { let Config { runtime, stats, @@ -374,31 +369,28 @@ where /// The lite session driver: one poll function racing every protocol arm, in /// place of a task set of boxed futures. -pub(crate) struct Driver { +pub(crate) struct Driver { /// Presenting our tokens, one AUTH stream each. - auth: Present, + auth: Present, pub(crate) local_close: std::sync::Arc, /// Advertising our capabilities, or `None` once sent (or on a version with no /// Setup Stream). - setup: Option>, + setup: Option, /// Sending our single GOAWAY if the drain trigger fires, or `None` once done. - goaway: Option>, + goaway: Option, /// The legacy session stream (pre-lite-03). Only its *error* ends the race, so /// the publisher and subscriber keep running while it sits idle. - session_stream: Option>, + session_stream: Option>, /// The first terminal outcome, retained while received streams drain. ending: Option>, - publisher: Publisher, - subscriber: SubscriberDriver, + publisher: Publisher, + subscriber: SubscriberDriver, /// For the terminal close: the machine's last act reports the outcome to /// the peer through the transport. - session: S, + session: Transport, } -impl Driver -where - S: crate::transport::poll::Session, -{ +impl Driver { pub(crate) fn poll(&mut self, waiter: &kio::Waiter) -> Poll> { if self.ending.is_none() { let res = std::task::ready!(self.poll_protocol(waiter)); @@ -487,7 +479,7 @@ where } } -impl Drop for Driver { +impl Drop for Driver { fn drop(&mut self) { // Dropped without finishing: release anything still waiting on a token. self.auth.handle.close(Error::Cancel); @@ -495,14 +487,14 @@ impl Drop for Driver { } /// Opens one AUTH stream per token this side presents. -struct Present { +struct Present { stats: crate::stats::Session, runtime: crate::time::Deadlines, - session: S, + session: Transport, version: Version, handle: crate::auth::Handle, going_away: crate::goaway::GoingAway, - tokens: kio::Tasks>, + tokens: kio::Tasks, /// Set by a token whose peer broke the protocol, which ends the session. violation: kio::Shared>, /// Whether the first poll decided who answers the peer's tokens. @@ -511,7 +503,7 @@ struct Present { _setup: Option, } -impl Present { +impl Present { /// Resolve only when a token's peer broke the protocol. fn poll(&mut self, waiter: &kio::Waiter) -> Poll { if !self.started { @@ -544,25 +536,30 @@ impl Present { /// One token's AUTH stream: send the token, then track the grant until either /// side ends it. -struct PresentToken { +struct PresentToken { stats: crate::stats::Session, runtime: crate::time::Deadlines, - session: S, + session: Transport, version: Version, handle: crate::auth::Handle, going_away: crate::goaway::GoingAway, violation: kio::Shared>, id: u64, - state: PresentState, + state: PresentState, } -enum PresentState { - Open { token: bytes::Bytes }, - Run { stream: Stream, answered: bool }, +enum PresentState { + Open { + token: bytes::Bytes, + }, + Run { + stream: Stream, + answered: bool, + }, Done, } -impl kio::Task for PresentToken { +impl kio::Task for PresentToken { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -594,7 +591,7 @@ impl kio::Task for PresentToken { } } -impl PresentToken { +impl PresentToken { /// Run the stream, resolving with why the token ended. fn poll_present(&mut self, waiter: &kio::Waiter) -> Poll { let mut cx = Context::from_waker(waiter.waker()); @@ -685,10 +682,7 @@ impl PresentToken { /// Drain SessionInfo updates off the legacy session stream, resolving only when /// the stream dies (a FIN counts: the peer abandoned the session). // TODO do something useful with the updates -fn poll_session_stream( - stream: &mut Stream, - cx: &mut Context<'_>, -) -> Poll { +fn poll_session_stream(stream: &mut Stream, cx: &mut Context<'_>) -> Poll { loop { match ready!(stream.reader.poll_decode_maybe::(cx)) { Ok(Some(_info)) => {} @@ -701,29 +695,29 @@ fn poll_session_stream( /// Advertise our capabilities on a uni Setup Stream, then FIN. Best-effort: an /// error is logged and the machine finishes; the peer falls back to "no /// capabilities" for us. -struct SendSetup { +struct SendSetup { stats: crate::stats::Session, version: Version, - state: SendSetupState, + state: SendSetupState, } -enum SendSetupState { +enum SendSetupState { /// Waiting for stream credit on our own session handle. Open { - session: S, + session: Transport, setup: Box, }, /// Flushing the buffered SETUP, then FIN and wait for the acknowledgement (a /// reset racing the FIN would discard the unacked message). Send { - writer: Writer, + writer: Writer, finished: bool, }, Done, } -impl SendSetup { - fn new(session: S, setup: Setup, version: Version, stats: crate::stats::Session) -> Self { +impl SendSetup { + fn new(session: Transport, setup: Setup, version: Version, stats: crate::stats::Session) -> Self { Self { stats, version, @@ -773,30 +767,35 @@ impl SendSetup { /// Send our single GOAWAY when the drain trigger fires. The session supervisor /// enforces the deadline independently, including on versions with no GOAWAY message. -struct SendGoaway { +struct SendGoaway { stats: crate::stats::Session, version: Version, goaway: crate::goaway::Protocol, /// Opening a stream and watching the session close each need their own handle. - closed: S, - session: S, - state: SendGoawayState, + closed: Transport, + session: Transport, + state: SendGoawayState, } -enum SendGoawayState { +enum SendGoawayState { Waiting, Open { payload: crate::goaway::Goaway, }, /// Keep the writer through FIN acknowledgement, since dropping it resets the stream. Send { - stream: Stream, + stream: Stream, finished: bool, }, } -impl SendGoaway { - fn new(session: S, goaway: crate::goaway::Protocol, version: Version, stats: crate::stats::Session) -> Self { +impl SendGoaway { + fn new( + session: Transport, + goaway: crate::goaway::Protocol, + version: Version, + stats: crate::stats::Session, + ) -> Self { Self { stats, version, @@ -940,7 +939,7 @@ mod tests { stats: Default::default(), client: true, limits: Default::default(), - session: transport, + session: crate::driver::Transport::new(transport.clone()), setup_stream: None, publish: None, subscribe: None, @@ -973,7 +972,7 @@ mod tests { stats: Default::default(), client: false, limits: Default::default(), - session: transport, + session: crate::driver::Transport::new(transport.clone()), setup_stream: None, publish: None, subscribe: None, @@ -1060,7 +1059,7 @@ mod tests { stats: Default::default(), client: true, limits: Default::default(), - session: transport, + session: crate::driver::Transport::new(transport.clone()), setup_stream: None, publish: None, subscribe: None, @@ -1092,19 +1091,21 @@ mod tests { Setup::default() .encode(&mut crate::coding::Encoder::new(&mut setup, version.into()), version) .unwrap(); - let mut session = + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()).with_incoming_unis(vec![Vec::new(), setup]); - let accepted = accept_setup(&mut session, version).await.unwrap(); + let accepted = accept_setup(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); assert_eq!(accepted.early.len(), 1); } #[moq_clock::test] async fn accept_setup_refuses_two_incomplete_setup_streams() { use futures::FutureExt; - let mut session = + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()).with_incoming_unis(vec![vec![1], vec![1]]); assert!(matches!( - accept_setup(&mut session, Version::Lite05).now_or_never(), + accept_setup(&mut crate::driver::Transport::new(session.clone()), Version::Lite05).now_or_never(), Some(Err(Error::ProtocolViolation)) )); } @@ -1128,7 +1129,7 @@ mod tests { let mut started = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session, + session: crate::driver::Transport::new(session.clone()), setup_stream: None, publish: None, subscribe: None, @@ -1183,7 +1184,7 @@ mod tests { let mut started = start(Config { runtime: crate::time::sim(), stats: Default::default(), - session, + session: crate::driver::Transport::new(session.clone()), setup_stream: None, publish: None, subscribe: None, @@ -1211,13 +1212,13 @@ mod tests { transport: ScriptedSession, version: Version, client: bool, - peer_setup: Option>, - ) -> SessionStart { + peer_setup: Option, + ) -> SessionStart { start(Config { runtime: crate::time::sim(), stats: Default::default(), client, - session: transport, + session: crate::driver::Transport::new(transport.clone()), setup_stream: None, publish: None, subscribe: None, @@ -1254,8 +1255,10 @@ mod tests { #[moq_clock::test] async fn unknown_client_role_remains_bidirectional() { for version in [Version::Lite05, Version::Lite06, Version::Lite07] { - let mut transport = ScriptedSession::new(Vec::new()).with_incoming_unis(vec![vec![1, 4, 1, 3, 1, 3]]); - let setup = accept_setup(&mut transport, version).await.unwrap(); + let transport = ScriptedSession::new(Vec::new()).with_incoming_unis(vec![vec![1, 4, 1, 3, 1, 3]]); + let setup = accept_setup(&mut crate::driver::Transport::new(transport.clone()), version) + .await + .unwrap(); assert_eq!(setup.setup.role, None); let log = transport.log.clone(); let mut started = raw_session(transport, version, false, Some(setup)); diff --git a/rs/moq-net/src/lite/setup.rs b/rs/moq-net/src/lite/setup.rs index 2cfcb16b144..a168fb60d5e 100644 --- a/rs/moq-net/src/lite/setup.rs +++ b/rs/moq-net/src/lite/setup.rs @@ -56,8 +56,10 @@ impl ProbeLevel { /// Both metrics are sampled rather than declared, so this only works for a /// transport whose figures exist by the time the session starts. QUIC and TCP /// both qualify: their RTT comes from the handshake, which has already happened. - pub fn detect(session: &S) -> Self { + #[cfg(feature = "async")] + pub fn detect(session: &crate::driver::Transport) -> Self { use crate::transport::Stats as _; + use crate::transport::poll::Session as _; let stats = session.stats(); match stats.estimated_send_rate().is_some() || stats.rtt().is_some() { true => Self::Report, @@ -441,7 +443,10 @@ mod tests { fn detect_reports_nothing_without_stats() { use crate::lite::test_transport::{SinkSession, SinkStats}; let session = SinkSession::new(Default::default()).with_stats(SinkStats::default()); - assert_eq!(ProbeLevel::detect(&session), ProbeLevel::None); + assert_eq!( + ProbeLevel::detect(&crate::driver::Transport::new(session.clone())), + ProbeLevel::None + ); } /// Either metric alone is enough to report, since the two PROBE fields are @@ -453,11 +458,17 @@ mod tests { let rtt_only = SinkStats::default().with_rtt(std::time::Duration::from_millis(40)); let session = SinkSession::new(Default::default()).with_stats(rtt_only); - assert_eq!(ProbeLevel::detect(&session), ProbeLevel::Report); + assert_eq!( + ProbeLevel::detect(&crate::driver::Transport::new(session.clone())), + ProbeLevel::Report + ); let rate_only = SinkStats::default().with_send_rate(1_000_000); let session = SinkSession::new(Default::default()).with_stats(rate_only); - assert_eq!(ProbeLevel::detect(&session), ProbeLevel::Report); + assert_eq!( + ProbeLevel::detect(&crate::driver::Transport::new(session.clone())), + ProbeLevel::Report + ); } /// Probing to a local target never reaches the wire, so a sender alone promises the @@ -469,7 +480,10 @@ mod tests { let stats = SinkStats::default().with_send_rate(1_000_000); let session = SinkSession::new(Default::default()).with_stats(stats).with_probe(); - assert_eq!(ProbeLevel::detect(&session), ProbeLevel::Report); + assert_eq!( + ProbeLevel::detect(&crate::driver::Transport::new(session.clone())), + ProbeLevel::Report + ); } #[test] diff --git a/rs/moq-net/src/lite/subscriber.rs b/rs/moq-net/src/lite/subscriber.rs index 043228a6b36..796d9f57ef3 100644 --- a/rs/moq-net/src/lite/subscriber.rs +++ b/rs/moq-net/src/lite/subscriber.rs @@ -1,3 +1,5 @@ +use crate::driver::Transport; +use crate::transport::poll::Session as _; use crate::{frame, group, origin, track}; use std::{ collections::{BTreeMap, BTreeSet, HashMap}, @@ -18,9 +20,9 @@ use crate::tail::{self, Reading, Settle, Tail}; use kio::Lock; -pub(super) struct SubscriberConfig { +pub(super) struct SubscriberConfig { pub runtime: crate::time::Deadlines, - pub session: S, + pub session: Transport, /// The origin into which remote broadcasts are inserted. Traffic stats are /// attributed through this handle: tag it with [`origin::Producer::with_stats`] /// first. @@ -46,9 +48,9 @@ pub(super) struct SubscriberConfig { } #[derive(Clone)] -pub(super) struct Subscriber { +pub(super) struct Subscriber { runtime: crate::time::Deadlines, - session: S, + session: Transport, origin: origin::Producer, recv_bandwidth: Option, @@ -100,8 +102,8 @@ struct TrackEntry { tail: kio::Producer, } -impl Subscriber { - pub fn new(config: SubscriberConfig) -> Self { +impl Subscriber { + pub fn new(config: SubscriberConfig) -> Self { // Identity for incoming-hop loop detection. Derived from the local // origin we publish into so it matches the relay identity across // every session sharing that origin, required for cross-session @@ -592,26 +594,30 @@ impl Drop for SubscriptionCleanup { } } -pub(super) struct SubscriberDriver { - subscriber: Subscriber, +pub(super) struct SubscriberDriver { + subscriber: Subscriber, /// Aborts whatever is still subscribed when the session ends. cleanup: SubscriptionCleanup, /// Which prefixes to ask the peer about. discovery: crate::discovery::Discovery, /// One machine per prefix asked about. Only an error ends the session; a /// prefix finishing cleanly (publisher FIN) just retires. - prefixes: HashMap>, - uni: UniAccept, + prefixes: HashMap, + uni: UniAccept, /// PROBE feedback; finishes quietly when unsupported or given up on. - bandwidth: Option>, + bandwidth: Option, /// Datagram receive; inert on a version or transport without datagrams. - datagrams: Option>, + datagrams: Option, /// One machine per minted source, serving the origin's track requests. - sources: kio::Tasks>, + sources: kio::Tasks, } -impl SubscriberDriver { - pub fn new(subscriber: Subscriber, early: Vec>, client: bool) -> Self { +impl SubscriberDriver { + pub fn new( + subscriber: Subscriber, + early: Vec>, + client: bool, + ) -> Self { // Lite03/04 mark no initial set, so a watch would read as synced before the peer // answers it. Asking for everything at connect keeps their discovery eager instead. let lazy = client && !matches!(subscriber.version, Version::Lite03 | Version::Lite04); @@ -716,7 +722,7 @@ impl SubscriberDriver { } } -impl Drop for SubscriberDriver { +impl Drop for SubscriberDriver { fn drop(&mut self) { // `abort` already recorded a session error when the driver failed. A driver // dropped without that still has to name an end before its setup machines drop. @@ -726,15 +732,15 @@ impl Drop for SubscriberDriver { /// Accepts incoming uni streams (GROUP data plus the peer's SETUP) and drives /// each as a child machine. Resolves only on a transport error. -struct UniAccept { - subscriber: Subscriber, +struct UniAccept { + subscriber: Subscriber, // A dedicated accept handle: the poll interface takes `&mut self`. - accept: S, - children: kio::Tasks>, + accept: Transport, + children: kio::Tasks, } -impl UniAccept { - fn new(subscriber: Subscriber, early: Vec>) -> Self { +impl UniAccept { + fn new(subscriber: Subscriber, early: Vec>) -> Self { let accept = subscriber.session.clone(); let mut children = kio::Tasks::new(); for reader in early { @@ -779,35 +785,35 @@ impl UniAccept { } /// One accepted uni stream, dispatched on its first varint. -struct UniServe { - subscriber: Subscriber, - state: UniState, +struct UniServe { + subscriber: Subscriber, + state: UniState, } // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum UniState { +enum UniState { /// Reading the stream's type. Start { - reader: Reader, + reader: Reader, }, /// Reading the peer's single SETUP message, recorded so capability-gated /// streams (PROBE) can consult it. lite-05+ only. Setup { - reader: Reader, + reader: Reader, }, /// Discarding a lite-07+ padding stream until FIN. Padding { - reader: Reader, + reader: Reader, /// A peer that keeps chunks ready must not hold the driver for as long as they arrive. budget: kio::coop::Budget, }, - Group(GroupRecv), + Group(GroupRecv), Done, } -impl kio::Task for UniServe { +impl kio::Task for UniServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -824,7 +830,7 @@ impl kio::Task for UniServe { } } -impl UniServe { +impl UniServe { /// Abort the stream with the given error, wherever the reader currently lives. fn abort(&mut self, err: &Error) { match &mut self.state { @@ -916,9 +922,9 @@ impl UniServe { } /// Receives one GROUP stream into its subscription's track producer. -struct GroupRecv { - subscriber: Subscriber, - reader: Reader, +struct GroupRecv { + subscriber: Subscriber, + reader: Reader, state: GroupRecvState, /// Held while parked on the peer's SETUP, so a drain can tell it never arrives. setup_wait: Option, @@ -957,8 +963,8 @@ enum GroupRecvState { Done, } -impl GroupRecv { - fn new(subscriber: Subscriber, reader: Reader) -> Self { +impl GroupRecv { + fn new(subscriber: Subscriber, reader: Reader) -> Self { Self { subscriber, reader, @@ -1381,15 +1387,15 @@ impl FrameIngest { /// /// A decode error or an unknown subscribe id drops that datagram without tearing /// down the session (best-effort); only a transport-level failure ends the loop. -struct DatagramRecv { - subscriber: Subscriber, +struct DatagramRecv { + subscriber: Subscriber, // A dedicated receive handle: the poll interface takes `&mut self`. - recv: S, + recv: Transport, enabled: bool, } -impl DatagramRecv { - fn new(subscriber: Subscriber) -> Self { +impl DatagramRecv { + fn new(subscriber: Subscriber) -> Self { let recv = subscriber.session.clone(); let enabled = subscriber.version.has_datagrams() && recv.max_datagram_size() > 0; Self { @@ -1418,15 +1424,15 @@ impl DatagramRecv { /// Loops forever: wait for a consumer, race the probe stream against the /// consumer leaving, then loop back. Transport errors stay per-stream; malformed /// control bytes end the session. -struct RecvBandwidth { - subscriber: Subscriber, - state: BandwidthState, +struct RecvBandwidth { + subscriber: Subscriber, + state: BandwidthState, } // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum BandwidthState { +enum BandwidthState { /// lite-05+ negotiates probing: only open a PROBE stream if the peer /// advertised it (Report or higher) in its SETUP. Older versions have no /// SETUP, so probe is always available there. @@ -1434,11 +1440,11 @@ enum BandwidthState { /// Wait until at least one consumer is interested in the estimate. WaitUsed, /// Race the last consumer leaving against the probe stream ending. - Probing(ProbeStream), + Probing(ProbeStream), } -impl RecvBandwidth { - fn new(subscriber: Subscriber) -> Self { +impl RecvBandwidth { + fn new(subscriber: Subscriber) -> Self { Self { subscriber, state: BandwidthState::Gate, @@ -1500,20 +1506,20 @@ impl RecvBandwidth { /// One PROBE stream: send the type, then feed the peer's estimates into the /// bandwidth producer until it FINs. -struct ProbeStream { - subscriber: Subscriber, - session: S, - state: ProbeState, +struct ProbeStream { + subscriber: Subscriber, + session: Transport, + state: ProbeState, } -enum ProbeState { +enum ProbeState { Open, - Send { stream: Stream }, - Read { stream: Stream }, + Send { stream: Stream }, + Read { stream: Stream }, } -impl ProbeStream { - fn new(subscriber: &Subscriber) -> Self { +impl ProbeStream { + fn new(subscriber: &Subscriber) -> Self { Self { subscriber: subscriber.clone(), session: subscriber.session.clone(), @@ -1560,34 +1566,40 @@ impl ProbeStream { /// One announce-interest stream: sends the ANNOUNCE_REQUEST for a prefix, then /// feeds every received announce into the origin. Only its *error* ends the /// session; a publisher FIN is a clean end for the prefix alone. -struct AnnouncePrefix { - subscriber: Subscriber, +struct AnnouncePrefix { + subscriber: Subscriber, prefix: PathOwned, - state: PrefixState, + state: PrefixState, /// Holds the origin's announce consumers under the prefix unsynced /// until the peer's initial set is in. Dropped at the boundary the version /// marks, or with the stream. snapshot: Option, } -enum PrefixState { +enum PrefixState { /// Opening the control stream (after the GOAWAY gate). Open, /// Flushing the buffered request. - Send { stream: Stream }, + Send { stream: Stream }, /// Lite05+: reading the publisher's ANNOUNCE_OK. - ReadOk { stream: Stream }, + ReadOk { stream: Stream }, /// Waiting for the link cost (may block on the peer's SETUP). Cost { - stream: Stream, + stream: Stream, responder_origin: Option, /// Lite05+: the ANNOUNCE_STARTs the publisher counted into its initial set. initial: u64, }, /// Lite01/02: reading the ANNOUNCE_INIT set. - ReadInit { stream: Stream, run: PrefixRun }, + ReadInit { + stream: Stream, + run: PrefixRun, + }, /// Streaming announce updates. - Run { stream: Stream, run: PrefixRun }, + Run { + stream: Stream, + run: PrefixRun, + }, } /// The announce-decode loop's state, split out so the states above can share it. @@ -1610,10 +1622,10 @@ struct PrefixRun { initial: u64, } -impl AnnouncePrefix { +impl AnnouncePrefix { /// `snapshot` was taken when the prefix was first wanted, so a consumer of the /// origin never reads as synced before the request even goes out. - fn new(subscriber: Subscriber, prefix: PathOwned, snapshot: crate::model::Snapshot) -> Self { + fn new(subscriber: Subscriber, prefix: PathOwned, snapshot: crate::model::Snapshot) -> Self { Self { subscriber, prefix, @@ -1835,29 +1847,29 @@ struct MintedSource { /// takes no new tracks but lets those in flight run to their own end (moq-lite: /// retraction does not disturb subscriptions already in flight); the session /// dying drops them. -struct SourceServe { +struct SourceServe { validity: crate::model::broadcast::RequestValidity, - subscriber: Subscriber, + subscriber: Subscriber, path: PathOwned, epoch: Option, source: crate::model::broadcast::SourceGuard, dynamic: crate::broadcast::Dynamic, route: kio::Consumer<()>, // A dedicated close-watch handle, since each pending operation needs its own. - closed: S, - tracks: kio::Tasks>, + closed: Transport, + tracks: kio::Tasks, // The source ended: no more track requests will arrive. ended: bool, /// Answers listings of the source with the peer's TRACKS. lister: crate::broadcast::Lister, /// The peer's listing, while anyone lists the source. - listing: Option>, + listing: Option, } /// Forwards the peer's TRACKS listing of a source into the source's lister. -struct TracksRecv { - session: S, - stream: Option>, +struct TracksRecv { + session: Transport, + stream: Option>, /// What the peer lists, each holding an `announces` slot: discovery state the peer /// makes us hold. listed: HashMap, crate::session::Slot>, @@ -1875,9 +1887,9 @@ struct TracksRecv { validity: crate::model::broadcast::RequestValidity, } -impl TracksRecv { +impl TracksRecv { /// Apply the peer's events until it ends the listing, or the error that ends it. - fn poll(&mut self, source: &SourceServe, waiter: &kio::Waiter) -> Poll> { + fn poll(&mut self, source: &SourceServe, waiter: &kio::Waiter) -> Poll> { if self.stream.is_none() { self.validity.check(waiter)?; } @@ -1938,8 +1950,8 @@ impl TracksRecv { } } -impl SourceServe { - fn new(subscriber: Subscriber, minted: MintedSource) -> Self { +impl SourceServe { + fn new(subscriber: Subscriber, minted: MintedSource) -> Self { let closed = subscriber.session.clone(); Self { lister: minted @@ -2019,7 +2031,7 @@ impl SourceServe { } } -impl kio::Task for SourceServe { +impl kio::Task for SourceServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -2101,11 +2113,13 @@ mod tests { } /// A live feed whose ledger is `tail`. - async fn feed_sub(tail: &kio::Producer) -> Sub { - let mut session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); + async fn feed_sub(tail: &kio::Producer) -> Sub { + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); Sub::Active(SubStream { order: crate::track::Order::Descending, - stream: Stream::open(&mut session, Version::Lite04).await.unwrap(), + stream: Stream::open(&mut crate::driver::Transport::new(session.clone()), Version::Lite04) + .await + .unwrap(), id: 0, max_delay: Duration::ZERO, start: None, @@ -2216,7 +2230,9 @@ mod tests { let floor = Position::group(if update { 5 } else { 2 }); let mut sub = Sub::Active(SubStream { order: crate::track::Order::Descending, - stream: Stream::open(&mut h.session.clone(), Version::Lite04).await.unwrap(), + stream: Stream::open(&mut crate::driver::Transport::new(h.session.clone()), Version::Lite04) + .await + .unwrap(), id: 0, max_delay: Duration::ZERO, start: Some(floor), @@ -2312,17 +2328,9 @@ mod tests { 0, "an empty expired gap does not self-wake" ); - fetches.poll( - &Sub::::None, - start, - &waiter, - ); + fetches.poll(&Sub::None, start, &waiter); wakes.0.store(0, atomic::Ordering::Relaxed); - fetches.poll( - &Sub::::None, - start, - &waiter, - ); + fetches.poll(&Sub::None, start, &waiter); assert_eq!( wakes.0.load(atomic::Ordering::Relaxed), 0, @@ -2506,12 +2514,7 @@ mod tests { /// still missing a grace after a later group arrived). A newer group alone settles /// nothing, since QUIC does not order streams. A fetch nobody waits on any more is /// dropped, as [`FetchServeRun`] does, so a far-future one isn't held forever. - fn poll( - &mut self, - sub: &Sub, - now: crate::time::Instant, - waiter: &kio::Waiter, - ) { + fn poll(&mut self, sub: &Sub, now: crate::time::Instant, waiter: &kio::Waiter) { let Sub::Active(active) = sub else { for (req, _) in self.held.drain(..) { req.reject(Error::NotFound); @@ -2613,8 +2616,10 @@ mod tests { /// either way after SUBSCRIBE_START answered the SUBSCRIBE. #[moq_clock::test] async fn the_owed_floor_follows_the_demand() { - let mut session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); - let stream = Stream::open(&mut session, VERSION).await.unwrap(); + let session = crate::lite::test_transport::ScriptedSession::new(Vec::new()); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), VERSION) + .await + .unwrap(); let mut sub = SubStream { order: crate::track::Order::Descending, stream, @@ -2657,12 +2662,14 @@ mod tests { } async fn receive_padding(version: Version, bytes: Vec) { - let mut session = crate::lite::test_transport::ScriptedSession::new(bytes); - let stream = Stream::open(&mut session, version).await.unwrap(); + let session = crate::lite::test_transport::ScriptedSession::new(bytes); + let stream = Stream::open(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); let log = session.log.clone(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -2777,7 +2784,7 @@ mod tests { lite::Setup::default() .encode(&mut crate::coding::Encoder::new(&mut setup, version.into()), version) .unwrap(); - let mut session = + let session = crate::lite::test_transport::ScriptedSession::eof(Vec::new()).with_incoming_unis(if pre_read { vec![Vec::new(), vec![42], bytes, setup] } else { @@ -2786,7 +2793,9 @@ mod tests { let log = session.log.clone(); let peer_setup = lite::PeerSetup::new(false, crate::transport::Binding::InBand); let early = if pre_read { - let accepted = lite::accept_setup(&mut session, version).await.unwrap(); + let accepted = lite::accept_setup(&mut crate::driver::Transport::new(session.clone()), version) + .await + .unwrap(); assert_eq!(accepted.early.len(), 2); assert!(log.stops().is_empty()); peer_setup.set(accepted.setup); @@ -2796,7 +2805,7 @@ mod tests { }; let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -2856,7 +2865,7 @@ mod tests { let mut session = crate::lite::test_transport::ScriptedSession::eof(script); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -2887,7 +2896,10 @@ mod tests { ); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut group = GroupRecv::new(subscriber, Reader::new(recv, version)); + let mut group = GroupRecv::new( + subscriber, + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + ); let res = kio::wait(|waiter| group.poll_serve(waiter)).await; match version { Version::Lite05 => { @@ -2944,7 +2956,7 @@ mod tests { }); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -2980,7 +2992,10 @@ mod tests { ); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut group = GroupRecv::new(subscriber, Reader::new(recv, version)); + let mut group = GroupRecv::new( + subscriber, + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + ); let res = kio::wait(|waiter| group.poll_serve(waiter)).await; (res, track, pool) } @@ -3127,7 +3142,7 @@ mod tests { let mut session = crate::lite::test_transport::ScriptedSession::eof(script); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -3164,7 +3179,10 @@ mod tests { ); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut group = GroupRecv::new(subscriber, Reader::new(recv, version)); + let mut group = GroupRecv::new( + subscriber, + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + ); let res = kio::wait(|waiter| group.poll_serve(waiter)).await; (res, track) } @@ -3237,7 +3255,7 @@ mod tests { let clock = crate::time::Deadlines::new(crate::time::Instant::now()); let subscriber = Subscriber::new(SubscriberConfig { runtime: clock.clone(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -3271,7 +3289,10 @@ mod tests { ); let (_, recv) = session.open_bi(Default::default()).await.unwrap(); - let mut group = GroupRecv::new(subscriber, Reader::new(recv, version)); + let mut group = GroupRecv::new( + subscriber, + Reader::new(crate::transport::boxed::RecvStream::new(recv), version), + ); let res = kio::wait(|waiter| group.poll_serve(waiter)).await; assert!(matches!(res, Err(Error::Duplicate)), "{res:?}"); drop(group); @@ -3306,7 +3327,7 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::eof(responses); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -3378,7 +3399,7 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::eof(responses); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -3448,7 +3469,7 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::new(responses); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -3507,7 +3528,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version, @@ -3606,7 +3627,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::default(), + session: crate::driver::Transport::new(SinkSession::default()), origin, recv_bandwidth: None, version: VERSION, @@ -3679,7 +3700,7 @@ mod tests { async fn session_death_rejects_a_track_waiting_for_info() { let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::default(), + session: crate::driver::Transport::new(SinkSession::default()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version: VERSION, @@ -3739,7 +3760,7 @@ mod tests { ] { let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version: VERSION, @@ -3791,10 +3812,10 @@ mod tests { session: SinkSession, auth: crate::auth::Handle, validity: crate::model::broadcast::RequestValidity, - ) -> (SourceServe, crate::broadcast::Consumer, kio::Producer<()>) { + ) -> (SourceServe, crate::broadcast::Consumer, kio::Producer<()>) { let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version: Version::Lite07, @@ -3917,7 +3938,7 @@ mod tests { let _token = auth.present(bytes::Bytes::from_static(b"new"), false).unwrap(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::default(), + session: crate::driver::Transport::new(SinkSession::default()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version: VERSION, @@ -3976,7 +3997,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version: VERSION, @@ -4043,7 +4064,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version: VERSION, @@ -4089,7 +4110,7 @@ mod tests { /// Everything a `handle_subscription` test needs to stay alive for the call. struct Harness { - serve: TrackServe, + serve: TrackServe, session: SinkSession, producer: track::Producer, _broadcast: crate::broadcast::Producer, @@ -4106,7 +4127,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: session.clone(), + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version, @@ -4175,7 +4196,7 @@ mod tests { let (session, mut peer) = crate::transport::memory::pair(Default::default()); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version: VERSION, @@ -4220,7 +4241,7 @@ mod tests { let (session, mut peer) = crate::transport::memory::pair(Default::default()); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin: origin::Config::new(crate::Hop::new(1).unwrap()).produce(), recv_bandwidth: None, version, @@ -4588,7 +4609,7 @@ mod tests { assert!(matches!(serving.sub, Sub::Active(_)), "the reader opens the upstream"); let established = h.wire().len(); - let arrive = |serving: &ServeLoop, sequence| { + let arrive = |serving: &ServeLoop, sequence| { let mut group = serving.serving.create_group(group::Info { sequence }).unwrap(); for frame in [&b"key"[..], b"abc", b"d"] { group.write_frame(None, frame).unwrap(); @@ -4638,7 +4659,7 @@ mod tests { let mut sub = Sub::None; let demand = |group: u64| Some(Subscription::default().with_start(Position::group(group))); - let applies = |sub: &Sub| matches!(sub, Sub::Active(active) if active.start == active.requested); + let applies = |sub: &Sub| matches!(sub, Sub::Active(active) if active.start == active.requested); // Establish from group 3; the peer's START is considered in flight. h.serve @@ -4731,7 +4752,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: VERSION, @@ -4786,7 +4807,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin: origin.clone(), recv_bandwidth: None, version: VERSION, @@ -4840,7 +4861,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin: origin.clone(), recv_bandwidth: None, version: VERSION, @@ -4868,9 +4889,9 @@ mod tests { // machine serving the source minted for it. async fn serve_one( origin: &origin::Producer, - subscriber: &Subscriber, + subscriber: &Subscriber, announced: &mut Announced, - ) -> (crate::broadcast::Consumer, SourceServe) { + ) -> (crate::broadcast::Consumer, SourceServe) { let consumer = origin.consume(); let request = moq_clock::sim::spawn(async move { consumer.request_broadcast("pool/p", None).await }); let ready = kio::wait(|waiter| announced.ready.poll_pop(waiter)).await.unwrap(); @@ -4909,7 +4930,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin: origin.clone(), recv_bandwidth: None, version: VERSION, @@ -4965,7 +4986,7 @@ mod tests { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: Version::Lite03, @@ -5024,7 +5045,7 @@ mod tests { let consumer = origin.consume(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: VERSION, @@ -5083,7 +5104,7 @@ mod tests { let consumer = origin.consume(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: VERSION, @@ -5150,7 +5171,7 @@ mod tests { let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin: origin.clone(), recv_bandwidth: None, version: VERSION, @@ -5210,7 +5231,7 @@ mod tests { let consumer = origin.consume(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version: VERSION, @@ -5257,7 +5278,7 @@ mod tests { let consumer = origin.consume(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: Version::Lite03, @@ -5334,12 +5355,12 @@ mod tests { assert_eq!(hops, vec![crate::Hop::UNKNOWN]); } - fn restart_subscriber(session: SinkSession) -> (Subscriber, crate::origin::Consumer) { + fn restart_subscriber(session: SinkSession) -> (Subscriber, crate::origin::Consumer) { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let consumer = origin.consume(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version: VERSION, @@ -5448,7 +5469,7 @@ mod tests { let consumer = origin.consume(); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: SinkSession::new(Default::default()), + session: crate::driver::Transport::new(SinkSession::new(Default::default())), origin, recv_bandwidth: None, version: VERSION, @@ -5532,7 +5553,7 @@ mod tests { let consumer = origin.consume(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session: crate::lite::test_transport::ScriptedSession::new(script), + session: crate::driver::Transport::new(crate::lite::test_transport::ScriptedSession::new(script)), origin, recv_bandwidth: None, version: VERSION, @@ -5595,15 +5616,12 @@ mod tests { fn root_prefix( version: Version, session: crate::lite::test_transport::ScriptedSession, - ) -> ( - AnnouncePrefix, - origin::Consumer, - ) { + ) -> (AnnouncePrefix, origin::Consumer) { let origin = origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let consumer = origin.consume(); let subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version, @@ -5781,7 +5799,7 @@ mod tests { let session = crate::lite::test_transport::ScriptedSession::new(script); let mut subscriber = Subscriber::new(SubscriberConfig { runtime: crate::time::sim(), - session, + session: crate::driver::Transport::new(session.clone()), origin, recv_bandwidth: None, version: VERSION, @@ -5854,8 +5872,8 @@ impl WireBounds { /// The at-most-one live upstream subscription: its control stream plus the params /// echoed in every SUBSCRIBE_UPDATE. -struct SubStream { - stream: Stream, +struct SubStream { + stream: Stream, id: u64, /// Original SUBSCRIBE params, echoed in every SUBSCRIBE_UPDATE; refreshed as the /// downstream aggregate changes. @@ -5879,7 +5897,7 @@ struct SubStream { wanted: Option, } -impl SubStream { +impl SubStream { /// The groups the publisher still owes once it has ended the subscription. /// /// `None` when nothing says which: drafts before SUBSCRIBE_END only have the FIN. @@ -5901,9 +5919,9 @@ impl SubStream { // One per track copy, which holds a live stream while anyone reads it, so boxing it // would add an allocation per upstream subscription without saving memory. #[allow(clippy::large_enum_variant)] -enum Sub { +enum Sub { None, - Active(SubStream), + Active(SubStream), } /// Every advertisement the peer currently has live on one announce stream. @@ -5968,12 +5986,7 @@ impl Announced { /// Put the peer's route into the origin, so paths under it resolve through this /// session on demand, or hold it back when the session's limit does not cover it. /// Returns whether it attached. - fn offer( - &mut self, - subscriber: &Subscriber, - path: PathOwned, - route: crate::origin::Route, - ) -> bool { + fn offer(&mut self, subscriber: &Subscriber, path: PathOwned, route: crate::origin::Route) -> bool { if !subscriber .auth .within_limit(crate::auth::Direction::Subscribe, path.as_str()) @@ -6057,7 +6070,7 @@ impl Announced { /// Serve queued requests on every ready route: mint a source per requested /// path, answer the requester with its consumer, and hand the source to the /// driver's serve machines, which own it from then on. - fn poll_serve(&mut self, subscriber: &Subscriber, waiter: &kio::Waiter) { + fn poll_serve(&mut self, subscriber: &Subscriber, waiter: &kio::Waiter) { let root = subscriber.origin.root().to_owned(); while let Poll::Ready(Ok(path)) = self.ready.poll_pop(waiter) { // A route retired since it woke has nothing left to serve. @@ -6103,7 +6116,7 @@ impl Announced { /// Apply a new limit: hold back every attached route it no longer covers, closing /// its sources (tracks in flight end on their own gates, with `Unauthorized`), and /// attach every withheld one it now does. - fn limit(&mut self, permit: &crate::auth::Permit, subscriber: &Subscriber) { + fn limit(&mut self, permit: &crate::auth::Permit, subscriber: &Subscriber) { let changed: Vec = self .routes .iter() @@ -6216,18 +6229,18 @@ enum ServeEnd { /// subscription (opened lazily on the first downstream subscriber, canceled when /// the last one leaves) concurrently with any number of one-shot fetches. #[derive(Clone)] -struct TrackServe { +struct TrackServe { validity: crate::model::broadcast::RequestValidity, /// The advertisement that minted this source, absent for standalone test sources. route: Option>, - subscriber: Subscriber, + subscriber: Subscriber, path: PathOwned, /// The publisher instance to ask for; the peer refuses a request for another. epoch: Option, name: String, } -impl TrackServe { +impl TrackServe { /// Watches whether the session still lets us receive this broadcast from the peer: /// our grant, and the ceiling on what the peer may publish. fn gate(&self) -> crate::auth::Gate { @@ -6281,10 +6294,10 @@ impl TrackServe { fn begin_subscription( &self, producer: &mut track::Producer, - sub: &mut Sub, + sub: &mut Sub, pref: Option, supports_update: bool, - ) -> Result, Error> { + ) -> Result { // An empty half-open range asks for nothing, and the wire cannot say that: its // bounds are inclusive, so the nearest encoding either hands back the position // the caller excluded or inverts the range outright once the two bounds meet. No @@ -6378,7 +6391,7 @@ impl TrackServe { /// deregisters `id` if the establish fails. /// /// The subscription's bounds come straight from the demand aggregate. - fn prepare_establish(&self, producer: &mut track::Producer, subscription: Subscription) -> Establish { + fn prepare_establish(&self, producer: &mut track::Producer, subscription: Subscription) -> Establish { let id = self.subscriber.next_id.fetch_add(1, atomic::Ordering::Relaxed); // Both halves of each bound come from the same position, so a frame can never @@ -6424,7 +6437,7 @@ impl TrackServe { async fn establish( &self, producer: &mut track::Producer, - sub: &mut Sub, + sub: &mut Sub, subscription: Subscription, ) -> Result<(), Error> { let mut est = Box::new(self.prepare_establish(producer, subscription)); @@ -6447,7 +6460,7 @@ impl TrackServe { async fn handle_subscription( &self, producer: &mut track::Producer, - sub: &mut Sub, + sub: &mut Sub, pref: Option, supports_update: bool, ) -> Result<(), Error> { @@ -6477,19 +6490,16 @@ impl TrackServe { // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum Begin { +enum Begin { /// Nothing further: the update (if any) sits in the active stream's write /// buffer, flushed by the loop. None, /// Open an upstream SUBSCRIBE for the first subscriber. - Establish(Establish), + Establish(Establish), } /// Buffer the current SUBSCRIBE parameters with an updated end. The caller flushes. -fn buffer_update( - active: &mut SubStream, - end: Option, -) -> Result<(), Error> { +fn buffer_update(active: &mut SubStream, end: Option) -> Result<(), Error> { let bounds = WireBounds::new(active.start, end); active.stream.writer.buffer(&lite::SubscribeUpdate { wanted_group: active.wanted, @@ -6506,33 +6516,33 @@ fn buffer_update( /// Opens the upstream SUBSCRIBE control stream: send the request, then (pre /// lite-05) wait for the SUBSCRIBE_OK. Resolves with the live [`SubStream`]; /// the caller deregisters the id on failure. -struct Establish { +struct Establish { validity: crate::model::broadcast::RequestValidity, - serve: TrackServe, - session: S, + serve: TrackServe, + session: Transport, // A dedicated close-watch handle for the SUBSCRIBE_OK wait. - closed: S, + closed: Transport, id: u64, subscription: Subscription, tail: kio::Producer, - state: EstablishState, + state: EstablishState, } -enum EstablishState { +enum EstablishState { Open, Send { - stream: Stream, + stream: Stream, }, /// Older drafts: the first SUBSCRIBE_OK confirms it. Bail if the session /// dies meanwhile; a dying route hands the assignment back through the /// serve loop's teardown instead. WaitOk { - stream: Stream, + stream: Stream, }, } -impl Establish { - fn poll(&mut self, waiter: &kio::Waiter) -> Poll, Error>> { +impl Establish { + fn poll(&mut self, waiter: &kio::Waiter) -> Poll> { self.validity.check(waiter)?; let mut cx = waiter.context(); loop { @@ -6601,7 +6611,7 @@ impl Establish { } } - fn activate(&self, stream: Stream) -> SubStream { + fn activate(&self, stream: Stream) -> SubStream { SubStream { stream, id: self.id, @@ -6620,9 +6630,9 @@ impl Establish { /// Drives one [`TrackServe`]: the TRACK_INFO fetch, then the serve loop, then /// the teardown that decides how the origin sees this copy end. -struct TrackServeRun { - serve: TrackServe, - state: TrackRunState, +struct TrackServeRun { + serve: TrackServe, + state: TrackRunState, /// Cancels the track once the session stops allowing its broadcast. gate: crate::auth::Gate, } @@ -6630,22 +6640,22 @@ struct TrackServeRun { // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum TrackRunState { +enum TrackRunState { /// Lite05+ learns the track's immutable properties once, up front, via a /// TRACK stream. The timescale then flows into every SUBSCRIBE and FETCH /// without a per-response header. Info { request: Option, - info: TrackInfoFetch, + info: TrackInfoFetch, }, - Serve(ServeLoop), + Serve(ServeLoop), /// Preserve the lite07 completion FIN until the publisher acknowledges it. - Finish(crate::coding::Writer), + Finish(crate::coding::Writer), Done, } -impl TrackServeRun { - fn new(serve: TrackServe, request: track::Request) -> Self { +impl TrackServeRun { + fn new(serve: TrackServe, request: track::Request) -> Self { let state = if serve.subscriber.version.has_track_stream() { TrackRunState::Info { request: Some(request), @@ -6689,7 +6699,7 @@ impl TrackServeRun { } } -impl TrackServeRun { +impl TrackServeRun { /// Nobody wants the track anymore (the origin failed over, the reader left): stop /// waiting on a token or a peer that may never answer, which would otherwise hold /// this task, its TRACK stream, and the track for good. Dropping the fetch resets the @@ -6711,7 +6721,7 @@ impl TrackServeRun { } } -impl kio::Task for TrackServeRun { +impl kio::Task for TrackServeRun { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -6805,7 +6815,7 @@ impl kio::Task for TrackServeRun { } } -impl Drop for TrackServeRun { +impl Drop for TrackServeRun { fn drop(&mut self) { // Still waiting on TRACK_INFO: the request never reached the subscribe map, // so the driver's abort cannot see it. Reject with the session's error. @@ -6822,31 +6832,31 @@ impl Drop for TrackServeRun { /// Opens a TRACK stream, reads the single TRACK_INFO, and maps it to the /// model's [`track::Info`], handing back the stream to hold. Lite05+ only. Bails if the /// session dies meanwhile. -struct TrackInfoFetch { +struct TrackInfoFetch { validity: crate::model::broadcast::RequestValidity, - session: S, + session: Transport, // A dedicated close-watch handle for the read. - closed: S, - state: TrackInfoState, + closed: Transport, + state: TrackInfoState, } -enum TrackInfoState { +enum TrackInfoState { Open, Send { - stream: Stream, + stream: Stream, }, Read { - stream: Stream, + stream: Stream, }, /// Reading the TRACK_PROPERTIES the `ietf` extension sends after TRACK_INFO. Properties { - stream: Stream, + stream: Stream, info: track::Info, }, } -impl TrackInfoFetch { - fn new(serve: &TrackServe) -> Self { +impl TrackInfoFetch { + fn new(serve: &TrackServe) -> Self { let session = serve.subscriber.session.clone(); Self { validity: serve.validity.start(), @@ -6858,9 +6868,9 @@ impl TrackInfoFetch { fn poll_fetch( &mut self, - serve: &TrackServe, + serve: &TrackServe, waiter: &kio::Waiter, - ) -> Poll), Error>> { + ) -> Poll> { self.validity.check(waiter)?; if serve .route @@ -6938,9 +6948,9 @@ impl TrackInfoFetch { /// track for us until we FIN it, which dropping this does. Held until the SUBSCRIBE that /// follows has its first response, or until nobody wants this copy, so demand never /// lapses between the two streams at any hop. -struct HeldTrack(Stream); +struct HeldTrack(Stream); -impl Drop for HeldTrack { +impl Drop for HeldTrack { fn drop(&mut self) { let _ = self.0.writer.finish(); } @@ -6950,7 +6960,7 @@ impl Drop for HeldTrack { /// the origin's logical track), driving the single upstream subscription /// (opened lazily on the first downstream subscriber, canceled when the last /// one leaves) concurrently with any number of one-shot fetches. -struct ServeLoop { +struct ServeLoop { /// This session's copy, accepted with the resolved info. The origin pumps /// it into the logical track; demand from the logical subscribers arrives /// through the producer's aggregate (including the resume floor after a source @@ -6963,34 +6973,34 @@ struct ServeLoop { demand: track::Demand, /// Serve on-demand fetches of uncached groups from this session. dynamic: track::Dynamic, - sub: Sub, - fetches: kio::Tasks>, + sub: Sub, + fetches: kio::Tasks, /// Fetches a pre-lite-05 upstream has no FETCH for, held for the live feed. feed_fetches: FeedFetches, // A dedicated close-watch handle for the session-died arm. - closed: S, + closed: Transport, // SUBSCRIBE_UPDATE only exists on Lite03+, so older peers can't carry a // preference change to an established subscription. supports_update: bool, supports_fetch: bool, - mode: ServeMode, + mode: ServeMode, /// Armed while nobody holds the copy: it stays, cache and all, for a returning /// reader until this fires. linger: crate::time::Deadline, /// The TRACK stream that answered, until a SUBSCRIBE has a response or nobody holds /// the copy. - held: Option>, + held: Option, } // A state machine's enum is its storage: one transient instance per stream, so the // big variant is the working state, not padding held in bulk. #[allow(clippy::large_enum_variant)] -enum ServeMode { +enum ServeMode { /// Selecting the next event. Select, /// Driving an upstream SUBSCRIBE open. The demand arms wait meanwhile, /// exactly like the old inline await. - Establish(Establish), + Establish(Establish), /// The upstream FIN'd, so the track is over, but QUIC does not order streams: keep /// the subscription routable until every owed group is accounted for. The grace bounds /// an unaccounted sequence, such as a lost datagram. @@ -7075,12 +7085,7 @@ impl FeedFetches { self.ready.lock().insert(sequence); } - fn poll( - &mut self, - sub: &Sub, - now: crate::time::Instant, - waiter: &kio::Waiter, - ) { + fn poll(&mut self, sub: &Sub, now: crate::time::Instant, waiter: &kio::Waiter) { let Sub::Active(_) = sub else { for (_, held) in std::mem::take(&mut self.held) { held.req.reject(Error::NotFound); @@ -7162,8 +7167,8 @@ impl FeedFetches { } } -impl ServeLoop { - fn new(serve: &TrackServe, request: track::Request, info: track::Info) -> Self { +impl ServeLoop { + fn new(serve: &TrackServe, request: track::Request, info: track::Info) -> Self { // Register the fetch handler before accepting: `accept` releases the // request's own fetch gate, and a cache-miss fetch queued while TRACK_INFO // was in flight would be drained as NotFound in the gap. @@ -7194,7 +7199,7 @@ impl ServeLoop { } } - fn poll(&mut self, serve: &TrackServe, waiter: &kio::Waiter) -> Poll { + fn poll(&mut self, serve: &TrackServe, waiter: &kio::Waiter) -> Poll { // Immutable TRACK_INFO stays usable locally after withdrawal. Its wire hold // is only a bridge to SUBSCRIBE while this source is still advertised. if self.held.is_some() @@ -7501,33 +7506,33 @@ impl ServeLoop { /// then fill the group from the bare FRAME messages that follow. The track's /// info comes from its TRACK_INFO (already known), and the group sequence /// is implicit from the request. -struct FetchServeRun { +struct FetchServeRun { validity: crate::model::broadcast::RequestValidity, gate: crate::auth::Gate, - serve: TrackServe, - session: S, + serve: TrackServe, + session: Transport, info: track::Info, group: u64, - state: FetchRunState, + state: FetchRunState, } -enum FetchRunState { +enum FetchRunState { Open { request: Option, }, Send { request: Option, - stream: Stream, + stream: Stream, frame_start: u64, }, /// Flushed; waiting for the publisher to answer before accepting. Answer { request: Option, - stream: Stream, + stream: Stream, frame_start: u64, }, Ingest { - stream: Stream, + stream: Stream, producer: crate::recv::Group, // The accepted request's demand: fetches that joined it but have not yet // picked the group up from the cache. @@ -7538,7 +7543,7 @@ enum FetchRunState { Done, } -impl FetchRunState { +impl FetchRunState { /// The downstream request, while it waits on the publisher's answer. fn request(&self) -> Option<&group::Request> { match self { @@ -7548,8 +7553,8 @@ impl FetchRunState { } } -impl FetchServeRun { - fn new(serve: TrackServe, request: group::Request, info: track::Info) -> Self { +impl FetchServeRun { + fn new(serve: TrackServe, request: group::Request, info: track::Info) -> Self { let session = serve.subscriber.session.clone(); let group = request.sequence(); Self { @@ -7564,7 +7569,7 @@ impl FetchServeRun { } } -impl Drop for FetchServeRun { +impl Drop for FetchServeRun { fn drop(&mut self) { // Dropped because the session stopped allowing the broadcast: reset with that // reason, so neither the publisher nor the waiting reader reads a routine cancel. @@ -7606,7 +7611,7 @@ impl Drop for FetchServeRun { } } -impl kio::Task for FetchServeRun { +impl kio::Task for FetchServeRun { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { diff --git a/rs/moq-net/src/server.rs b/rs/moq-net/src/server.rs index 27f25956092..fd1103dac9b 100644 --- a/rs/moq-net/src/server.rs +++ b/rs/moq-net/src/server.rs @@ -148,7 +148,7 @@ impl Server { runtime: Deadlines, session: Transport, version: lite::Version, - client_setup: Option>, + client_setup: Option, peer_hop: Option, auth: crate::auth::Handle, ) -> Result<(Session, crate::Driver), Error> { @@ -519,7 +519,7 @@ enum PausedHandshake { LiteSetup { session: Transport, version: lite::Version, - client_setup: lite::AcceptedSetup, + client_setup: lite::AcceptedSetup, }, IetfModern(PausedIetfModern), Legacy(PausedLegacy), @@ -531,7 +531,7 @@ enum PausedHandshake { struct PausedIetfModern { session: Transport, version: ietf::Version, - peer_setup: ietf::PeerSetup, + peer_setup: ietf::PeerSetup, } impl PausedIetfModern { diff --git a/rs/moq-net/src/transport/boxed.rs b/rs/moq-net/src/transport/boxed.rs index e4272edab18..2355ab87500 100644 --- a/rs/moq-net/src/transport/boxed.rs +++ b/rs/moq-net/src/transport/boxed.rs @@ -83,8 +83,8 @@ impl poll::SendGroup for Group { pub(crate) struct SendStream(Box); impl SendStream { - /// Box a stream whose send group, if any, is a [`Group`]. - pub(crate) fn new(stream: impl poll::SendStream + MaybeSend + MaybeSync) -> Self { + /// Box a stream, keeping its own send-group type behind the boundary. + pub(crate) fn new(stream: impl poll::SendStream + MaybeSend + MaybeSync) -> Self { Self(Box::new(stream)) } } diff --git a/rs/moq-uring/benches/worker_turns.rs b/rs/moq-uring/benches/worker_turns.rs index d6715742116..a8c00ce5101 100644 --- a/rs/moq-uring/benches/worker_turns.rs +++ b/rs/moq-uring/benches/worker_turns.rs @@ -67,8 +67,28 @@ fn benchmark(c: &mut criterion::Criterion) { group.finish(); } +/// Compare the same transport method before and after Local's thread guard. +/// The memory transport returns a constant here, keeping actual I/O out of the check cost. +#[cfg(target_os = "linux")] +fn local_thread_check(c: &mut criterion::Criterion) { + use std::hint::black_box; + + use moq_net::transport::{memory, poll::Session as _}; + use moq_uring::transport::Local; + + let (session, _peer) = memory::pair(memory::Config::default()); + let local = Local::new(session.clone()); + let mut group = c.benchmark_group("local_thread_check"); + group.bench_function("direct", |b| b.iter(|| black_box(&session).max_datagram_size())); + group.bench_function("checked", |b| b.iter(|| black_box(&local).max_datagram_size())); + group.finish(); +} + +#[cfg(not(target_os = "linux"))] +fn local_thread_check(_: &mut criterion::Criterion) {} + #[cfg(not(target_os = "linux"))] fn benchmark(_: &mut criterion::Criterion) {} -criterion_group!(benches, benchmark); +criterion_group!(benches, benchmark, local_thread_check); criterion_main!(benches);