diff --git a/bench/README.md b/bench/README.md index 61183e645e6..57b07ac885c 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 851363759a4..a73fe69bac8 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -128,7 +128,6 @@ tracks, so per-group stats stop costing cluster announces. - [libav polyfill fork fix](/quest/m1/libav-polyfill-fork.md) - our polyfill fork copies planar audio correctly and `@moq/hang` drops its patch - [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 - [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 - [Unprefixed C++ free functions](/quest/m1/cpp-free-function-prefix.md) - generated free functions drop `moq_`, and `moq.hpp` deletes its five pass-through wrappers before C++ first publishes 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 1aa8e76df05..0c35fca8791 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 { @@ -510,19 +512,16 @@ impl crate::transport::poll::SendStream for reason = "one per stream, so boxing a variant would add an allocation per stream to save bytes nothing holds in bulk" ) )] -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) @@ -550,12 +549,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(), @@ -585,7 +584,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(), @@ -854,9 +853,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, @@ -864,8 +863,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, @@ -883,7 +882,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()) @@ -899,8 +898,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 = { @@ -992,7 +991,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. @@ -1018,7 +1017,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 { @@ -1305,9 +1304,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( @@ -2153,9 +2152,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}; @@ -2172,10 +2171,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] @@ -2197,9 +2204,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, ); @@ -2211,7 +2221,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(), @@ -2220,7 +2233,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(); @@ -2245,16 +2261,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:?}"); @@ -2267,11 +2287,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), @@ -2342,11 +2364,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 93cd1f14607..4d0e1d5aab5 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(), @@ -257,19 +257,16 @@ pub(super) fn peer_grant( clippy::too_many_arguments, reason = "the presenting task owns each piece of session state it drives" )] -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; @@ -325,10 +322,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, @@ -336,7 +333,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 { @@ -449,9 +446,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> { @@ -530,11 +527,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 9b3d2afc764..236c20a38a8 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::{ @@ -399,19 +401,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, @@ -425,7 +427,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> { @@ -439,7 +441,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 { @@ -475,15 +477,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. @@ -508,8 +510,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, @@ -666,11 +668,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, @@ -686,7 +688,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. @@ -752,13 +754,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, @@ -888,7 +887,7 @@ where &self, id: u64, body: ietf::Body, - stream: Stream, + stream: Stream, epochs: bool, ) -> Result, Error> { let this = self.clone(); @@ -1084,7 +1083,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, @@ -1104,7 +1103,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( @@ -1117,7 +1116,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> { @@ -1329,26 +1328,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 @@ -1527,10 +1527,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; @@ -1561,7 +1561,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, @@ -1595,10 +1595,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 { @@ -1757,7 +1757,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()); @@ -1828,9 +1828,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(); @@ -1907,9 +1907,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 { @@ -1934,9 +1934,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}; @@ -1978,8 +1978,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, @@ -2070,7 +2070,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> { @@ -2092,7 +2092,7 @@ where /// already refused. async fn reject_subscribe( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, reason: &str, @@ -2108,7 +2108,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, @@ -2130,7 +2130,7 @@ where async fn run_fill( &self, fill: FillServe, - ranking: &Ranking>, + ranking: &Ranking>, track: track::Consumer, timescale: Option, opened: &AtomicU64, @@ -2208,7 +2208,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, @@ -2367,7 +2367,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 { @@ -2447,7 +2447,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> { @@ -2464,7 +2464,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(), @@ -2496,14 +2496,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> { @@ -2990,10 +2990,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 @@ -3078,7 +3087,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( @@ -3091,7 +3100,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> { @@ -3187,7 +3196,7 @@ where async fn reject_track_status( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, ) -> Result<(), Error> { @@ -3201,7 +3210,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> { @@ -3216,7 +3225,7 @@ where /// close is not optional. async fn reject_fetch( &self, - mut stream: Stream, + mut stream: Stream, request_id: RequestId, err: &Error, reason: &str, @@ -3238,7 +3247,7 @@ where /// draft-17). async fn sync_namespace( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, suffix: &crate::PathOwned, path: &crate::PathOwned, ) -> Result<(), Error> { @@ -3428,7 +3437,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, @@ -3554,7 +3563,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)> { @@ -3586,7 +3595,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 @@ -3618,7 +3627,7 @@ where /// the two. async fn send_update( &self, - ns: &mut Namespaces, + ns: &mut Namespaces, prefix: &crate::PathOwned, request_id: RequestId, ) -> Result<(), Error> { @@ -3677,7 +3686,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, @@ -3736,7 +3745,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, @@ -3869,7 +3878,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); @@ -3901,8 +3910,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); @@ -3923,8 +3932,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 { @@ -3948,7 +3957,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) { @@ -3972,11 +3986,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; @@ -4026,7 +4036,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( @@ -4039,7 +4049,7 @@ where async fn serve_subscribe_namespace_stream( self, - mut stream: Stream, + mut stream: Stream, msg: ietf::SubscribeNamespace<'_>, gate: crate::auth::Gate, ) -> Result<(), Error> { @@ -4211,7 +4221,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; @@ -4452,7 +4462,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) @@ -4463,7 +4473,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, @@ -4506,8 +4516,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, @@ -4516,14 +4526,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. @@ -4542,9 +4552,9 @@ struct TrackServe { dynamic: bool, } -impl TrackServe { +impl TrackServe { fn new( - session: S, + session: Transport, mut track: track::Subscriber, request_id: RequestId, version: Version, @@ -5156,12 +5166,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, @@ -5170,7 +5180,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, } @@ -5182,13 +5192,13 @@ struct GroupServe { reason = "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" ) )] -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>, @@ -5197,12 +5207,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<()> { @@ -5213,11 +5223,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, @@ -5650,11 +5660,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, @@ -5683,7 +5693,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, @@ -5712,7 +5722,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, @@ -5737,7 +5747,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, @@ -5787,7 +5797,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, @@ -5858,7 +5868,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, @@ -5947,7 +5957,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(), @@ -6041,7 +6051,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, @@ -6101,7 +6111,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, @@ -6151,7 +6161,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, @@ -6207,7 +6217,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, @@ -6255,7 +6265,7 @@ mod group_priority_test { } group.finish().unwrap(); let serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), Version::Draft14, @@ -6293,7 +6303,7 @@ mod group_priority_test { track.finish().unwrap(); let mut serve = TrackServe::new( - session, + crate::driver::Transport::new(session.clone()), subscriber, RequestId(0), version, @@ -6322,7 +6332,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, @@ -6348,7 +6358,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; @@ -6374,7 +6384,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, @@ -6419,7 +6429,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, @@ -6465,7 +6475,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, @@ -6512,7 +6522,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, @@ -6564,7 +6574,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, @@ -6615,7 +6625,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, @@ -6711,7 +6721,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, @@ -6735,8 +6745,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( @@ -6745,7 +6757,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, @@ -6758,28 +6773,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); @@ -6792,11 +6792,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, @@ -6821,10 +6826,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, @@ -6832,7 +6839,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, @@ -6878,7 +6886,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, @@ -6909,7 +6917,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, @@ -6938,12 +6946,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, @@ -6989,12 +7001,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, @@ -7050,7 +7066,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) @@ -7059,7 +7077,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) @@ -7068,7 +7088,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() @@ -7083,11 +7105,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, @@ -7115,14 +7142,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, @@ -7300,7 +7332,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); @@ -7332,7 +7366,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); @@ -7362,11 +7398,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, @@ -7427,7 +7468,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(), @@ -7521,12 +7564,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, @@ -7569,12 +7616,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, @@ -7629,7 +7680,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)); @@ -7690,7 +7743,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)); @@ -7718,7 +7773,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)); @@ -7803,7 +7860,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) @@ -7829,7 +7888,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 }, @@ -7850,7 +7911,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( @@ -7874,13 +7937,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, @@ -7888,8 +7953,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, @@ -7916,12 +7983,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, @@ -8000,12 +8071,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, @@ -8069,7 +8144,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() @@ -8101,12 +8178,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, @@ -8148,12 +8229,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, @@ -8182,12 +8267,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, @@ -8212,8 +8301,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 { @@ -8252,8 +8343,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"), @@ -8295,8 +8388,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"), @@ -8349,8 +8444,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(""), @@ -8398,8 +8495,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 @@ -8440,8 +8539,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"); @@ -8450,8 +8551,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 => { @@ -8496,7 +8599,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 { @@ -8574,7 +8680,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() @@ -8627,7 +8735,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) @@ -8649,7 +8759,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() @@ -8700,7 +8812,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 @@ -8790,7 +8904,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!( @@ -8861,7 +8977,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, @@ -8870,7 +8986,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 { @@ -8919,7 +9037,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() @@ -8998,7 +9118,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() @@ -9027,7 +9149,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 @@ -9112,7 +9236,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!( @@ -9139,7 +9265,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) @@ -9263,7 +9391,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 @@ -9317,7 +9447,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 @@ -9580,7 +9712,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() @@ -9660,7 +9794,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( @@ -9716,7 +9852,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() @@ -9839,7 +9977,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) @@ -9874,7 +10014,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) @@ -9897,7 +10039,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) @@ -9937,7 +10081,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() @@ -9968,7 +10114,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() @@ -10031,7 +10179,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() @@ -10067,7 +10217,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() @@ -10221,7 +10373,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( @@ -10437,7 +10591,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( @@ -10491,7 +10647,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)) @@ -11111,7 +11269,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, @@ -11120,7 +11278,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( @@ -11204,7 +11364,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, @@ -11213,7 +11373,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() @@ -11228,7 +11390,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, @@ -11314,7 +11478,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, @@ -11323,7 +11487,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; @@ -11349,7 +11515,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, @@ -11459,7 +11627,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, @@ -11468,7 +11636,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 { @@ -11583,7 +11753,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() @@ -11602,7 +11774,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( @@ -11635,7 +11809,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() @@ -11644,7 +11820,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( @@ -11815,7 +11993,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, @@ -11879,7 +12057,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()); @@ -11912,7 +12097,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, @@ -11972,7 +12157,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, @@ -11999,7 +12187,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 { @@ -12017,7 +12208,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 @@ -12058,7 +12252,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 = { @@ -12149,7 +12345,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))); @@ -12195,7 +12393,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. @@ -12331,7 +12531,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, @@ -12359,7 +12562,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, @@ -12402,7 +12608,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. @@ -12475,7 +12683,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 { @@ -12528,7 +12738,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(); @@ -12573,7 +12785,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(); @@ -12618,7 +12832,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(); @@ -12640,8 +12856,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 { @@ -12686,7 +12904,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(); @@ -12753,7 +12973,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)); @@ -12807,7 +13029,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(); @@ -12845,7 +13069,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(); @@ -12882,7 +13108,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 { @@ -12913,7 +13142,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()); @@ -12954,7 +13185,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 = { @@ -13029,7 +13262,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 = { @@ -13095,7 +13330,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(); @@ -13147,7 +13384,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 { @@ -13231,7 +13470,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 = { @@ -13291,12 +13532,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, @@ -13348,7 +13593,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!( @@ -13365,7 +13612,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 { @@ -13378,8 +13627,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 { @@ -13407,7 +13658,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 { @@ -13429,7 +13682,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; @@ -13478,7 +13733,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() @@ -13606,13 +13863,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(); @@ -13620,7 +13871,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), @@ -13678,7 +13929,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), @@ -13749,7 +14000,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), @@ -13797,7 +14048,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, @@ -13818,7 +14069,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(""), @@ -13832,7 +14085,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(); @@ -13866,7 +14119,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), @@ -13888,7 +14141,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(""), @@ -13934,7 +14189,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 @@ -13971,7 +14229,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14029,7 +14287,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14087,7 +14345,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 => { @@ -14151,7 +14412,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), consumer, Control::new(None, false), None, @@ -14159,7 +14420,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(""), @@ -14237,7 +14500,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14278,7 +14541,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, @@ -14336,7 +14599,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 { @@ -14357,7 +14623,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14448,7 +14714,7 @@ mod tests { }; let publisher = Publisher::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), consume, Control::new(None, false), None, @@ -14456,7 +14722,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), @@ -14605,7 +14873,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, @@ -14613,7 +14881,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(""), @@ -14696,7 +14966,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14774,7 +15044,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), @@ -14822,7 +15092,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -14886,7 +15156,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 { @@ -14901,7 +15174,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 { @@ -14918,7 +15194,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() @@ -14956,7 +15235,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15023,8 +15302,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 { @@ -15042,7 +15323,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15113,7 +15394,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15182,15 +15463,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, @@ -15539,10 +15817,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, @@ -15551,11 +15829,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 @@ -15605,10 +15886,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, @@ -15618,11 +15899,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") { @@ -15691,7 +15975,7 @@ mod tests { }); let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15700,10 +15984,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 { @@ -15723,10 +16010,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"); } } @@ -15753,7 +16043,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, @@ -15852,7 +16142,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15914,7 +16204,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -15972,7 +16262,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, @@ -16020,7 +16310,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16064,7 +16354,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, @@ -16114,7 +16404,7 @@ mod tests { let publisher = Publisher::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.consume(), Control::new(None, false), None, @@ -16159,7 +16449,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. @@ -16177,7 +16467,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, @@ -16198,7 +16488,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( @@ -16232,7 +16524,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( @@ -17180,7 +17474,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 69906c8c8a9..b95f79869a2 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<'_>, @@ -1015,7 +1013,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)); } @@ -1026,7 +1024,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, @@ -1050,18 +1048,18 @@ where )] 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); @@ -1237,7 +1235,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); @@ -1253,7 +1250,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, @@ -1277,7 +1274,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, @@ -1314,12 +1311,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(); @@ -1328,8 +1332,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(); @@ -1344,13 +1353,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(); } @@ -1361,7 +1370,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 @@ -1504,7 +1513,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 @@ -1555,7 +1564,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(); @@ -1575,7 +1589,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 @@ -1613,7 +1627,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"); } } @@ -1718,7 +1735,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); @@ -1754,7 +1774,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]; @@ -2134,7 +2157,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 @@ -2211,7 +2235,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(); @@ -2325,7 +2354,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, @@ -2336,7 +2365,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); @@ -2370,7 +2402,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 28ddcf64e96..76c8aad76a1 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, @@ -804,8 +805,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, @@ -822,7 +823,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()); @@ -954,11 +956,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, @@ -972,17 +974,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, @@ -1058,8 +1060,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, @@ -1068,9 +1070,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, @@ -1172,10 +1174,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(()); } @@ -1209,18 +1208,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 @@ -1303,9 +1299,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, @@ -1314,9 +1310,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, @@ -1420,11 +1416,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; } @@ -1538,11 +1530,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(); @@ -1621,7 +1609,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(), @@ -1677,7 +1665,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(), @@ -1724,7 +1712,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(), @@ -1758,7 +1746,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()); @@ -1776,7 +1767,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 @@ -1820,7 +1814,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(), @@ -1884,7 +1878,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(), @@ -1922,7 +1916,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), @@ -1951,8 +1948,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"); @@ -2048,7 +2045,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(), @@ -2152,7 +2149,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(), @@ -2237,7 +2234,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(), @@ -2310,7 +2307,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), @@ -2334,7 +2334,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(), @@ -2424,7 +2424,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(), @@ -2468,7 +2468,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(), @@ -2528,7 +2528,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 { @@ -2566,7 +2569,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(); @@ -2576,7 +2579,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, @@ -2598,7 +2601,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), @@ -2735,7 +2738,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(), @@ -2815,12 +2818,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()); @@ -2879,7 +2884,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(), @@ -2948,7 +2953,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, @@ -2984,7 +2989,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 @@ -3017,7 +3025,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, ); @@ -3044,8 +3052,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"); @@ -3167,9 +3175,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(); @@ -3346,7 +3358,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, @@ -3363,9 +3374,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:?}"); } } @@ -3374,8 +3390,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(); @@ -3384,9 +3398,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(), @@ -3408,7 +3427,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(), @@ -3478,7 +3497,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, @@ -3511,7 +3530,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(), @@ -3556,9 +3575,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 9b8b8a1aa36..7b8d2e2bd2b 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}, @@ -752,7 +754,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 @@ -761,7 +763,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, @@ -800,7 +802,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, @@ -861,17 +863,14 @@ async fn resolve_track_alias( .await } -impl Subscriber -where - S: crate::transport::poll::Boxable, -{ +impl Subscriber { #[expect( clippy::too_many_arguments, reason = "private plumbing; a single-use argument struct would only rename the parameters" )] pub fn new( runtime: crate::time::Deadlines, - session: S, + session: Transport, origin: origin::Producer, control: Control, peer_hop: Option, @@ -1164,9 +1163,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> { @@ -1306,15 +1305,15 @@ where clippy::too_many_arguments, reason = "private plumbing; a single-use argument struct would only rename the parameters" )] - 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. @@ -1425,7 +1424,7 @@ where &mut self, id: u64, body: ietf::Body, - stream: Stream, + stream: Stream, peer: cluster::Peer, epoch: bool, declared: Option, @@ -1516,7 +1515,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, @@ -1565,7 +1564,7 @@ where #[cfg(test)] async fn run_publish_namespace_stream( &mut self, - stream: Stream, + stream: Stream, msg: ietf::PublishNamespace<'_>, peer: cluster::Peer, declared: Option, @@ -1589,7 +1588,7 @@ where async fn serve_publish_namespace_stream( &mut self, - mut stream: Stream, + mut stream: Stream, incoming: IncomingNamespace<'_>, ) -> Result<(), Error> { let IncomingNamespace { @@ -1781,7 +1780,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, @@ -2108,7 +2107,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, @@ -2146,7 +2145,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) { @@ -2191,7 +2190,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)?; @@ -2226,7 +2225,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, @@ -2245,7 +2244,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, @@ -2702,7 +2701,7 @@ where &self, path: &Path<'_>, lister: &std::sync::Arc, - listening: &mut Option>, + listening: &mut Option, waiter: &kio::Waiter, ) { loop { @@ -3754,10 +3753,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. @@ -3795,7 +3794,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> { @@ -3834,7 +3833,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() @@ -3865,7 +3864,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?; @@ -3995,7 +3994,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| { @@ -4048,8 +4047,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?; @@ -4235,7 +4234,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); @@ -4255,7 +4257,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())); @@ -4601,10 +4606,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 @@ -4613,7 +4615,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, @@ -4816,8 +4818,8 @@ enum IngestPhase { } impl GroupIngest { - fn new( - subscriber: &Subscriber, + fn new( + subscriber: &Subscriber, group: &ietf::GroupHeader, timescale: Option, start: Option, @@ -4838,10 +4840,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 @@ -4850,7 +4849,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?; @@ -4972,7 +4974,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, @@ -5008,7 +5010,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, @@ -5111,7 +5113,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 { @@ -5471,7 +5473,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 => { @@ -5494,8 +5496,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); @@ -5517,7 +5519,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 @@ -5601,7 +5603,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, @@ -6032,12 +6034,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 { @@ -6069,7 +6071,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"); @@ -6207,7 +6209,7 @@ mod tests { Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6292,7 +6294,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, @@ -6312,7 +6314,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. @@ -6327,7 +6331,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 @@ -6374,7 +6381,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, @@ -6387,7 +6394,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())); @@ -6423,8 +6432,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 { @@ -6468,7 +6479,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, @@ -6481,7 +6492,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; @@ -6554,7 +6567,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, @@ -6568,7 +6581,9 @@ mod tests { subscriber.announces = crate::session::Slots::new(1); 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; @@ -6594,8 +6609,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 { @@ -6617,7 +6634,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, @@ -6629,7 +6646,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, @@ -6648,7 +6667,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 { @@ -6691,11 +6713,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(""); @@ -6707,7 +6725,7 @@ mod tests { }); let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -6730,7 +6748,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 { @@ -6752,7 +6772,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 { @@ -6773,7 +6795,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; @@ -6866,9 +6890,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. @@ -6876,7 +6898,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, @@ -7126,8 +7148,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 { @@ -7149,7 +7173,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, @@ -7197,7 +7221,7 @@ mod tests { fn waiting_on_auth( version: Version, ) -> ( - Subscriber, + Subscriber, crate::lite::test_transport::Log, crate::auth::Handle, Vec, @@ -7212,7 +7236,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, @@ -7321,7 +7345,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, @@ -7392,7 +7416,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, @@ -7457,7 +7481,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, @@ -7522,7 +7546,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, @@ -7599,7 +7623,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, @@ -7801,7 +7825,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, @@ -7924,10 +7948,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 { @@ -7937,7 +7967,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, @@ -8011,7 +8041,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, @@ -8107,8 +8137,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 { @@ -8132,7 +8164,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, @@ -8216,8 +8248,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 { @@ -8239,7 +8273,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, @@ -8370,7 +8404,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, @@ -8457,7 +8491,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, @@ -8543,7 +8577,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, @@ -8661,7 +8695,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, @@ -8674,7 +8708,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) = ( @@ -8719,7 +8753,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), @@ -8780,7 +8814,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), @@ -8820,7 +8854,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), @@ -8859,12 +8893,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(); @@ -8874,7 +8903,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - session, + crate::driver::Transport::new(session.clone()), origin.clone(), Control::new(None, false), None, @@ -9012,7 +9041,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, @@ -9024,7 +9053,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, @@ -9053,8 +9084,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 { @@ -9097,7 +9130,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, @@ -9109,7 +9142,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(), @@ -9165,7 +9200,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, @@ -9176,7 +9211,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"), @@ -9210,7 +9247,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(), @@ -9227,7 +9267,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, @@ -9239,7 +9279,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(), @@ -9274,8 +9316,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(), @@ -9291,7 +9335,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, @@ -9303,7 +9347,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(), @@ -9349,7 +9395,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(); @@ -9358,7 +9407,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, @@ -9371,7 +9420,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(), @@ -9594,7 +9645,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") @@ -9642,7 +9693,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") @@ -9788,7 +9839,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(); @@ -9818,13 +9872,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(); @@ -9834,7 +9890,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, @@ -9852,8 +9908,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, @@ -9864,16 +9922,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. @@ -9922,8 +9981,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); @@ -9956,8 +10015,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); @@ -10006,7 +10065,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(); @@ -10058,7 +10117,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, @@ -10097,7 +10156,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( @@ -10147,8 +10208,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 { @@ -10164,9 +10227,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(); @@ -10213,8 +10276,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. @@ -10271,9 +10334,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); @@ -10317,8 +10380,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 { @@ -10339,7 +10404,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(); @@ -10418,7 +10484,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, @@ -10430,7 +10496,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"), @@ -10459,8 +10527,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 => { @@ -10507,7 +10577,7 @@ mod tests { version: Version, first_script: Vec, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, crate::auth::Auth, origin::Consumer, @@ -10521,11 +10591,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, @@ -10562,7 +10632,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), @@ -10610,7 +10680,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)), @@ -10627,7 +10700,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, @@ -10646,7 +10722,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(); @@ -10691,8 +10769,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(), @@ -10773,18 +10854,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(), @@ -10817,7 +10903,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"); @@ -10858,7 +10946,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 = { @@ -10910,7 +11000,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(); @@ -10965,7 +11057,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()); @@ -11016,8 +11110,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, @@ -11033,7 +11129,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(), @@ -11109,7 +11207,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 = { @@ -11181,9 +11281,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"); @@ -11246,9 +11349,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"); @@ -11287,7 +11393,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 = { @@ -11340,8 +11448,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"), @@ -11373,7 +11485,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"), @@ -11418,7 +11532,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 { @@ -11471,7 +11587,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, @@ -11498,7 +11617,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 { @@ -11579,7 +11700,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 { @@ -11637,7 +11760,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"); @@ -11680,7 +11805,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"); @@ -11722,7 +11849,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"); @@ -11768,9 +11897,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"); @@ -11810,7 +11942,7 @@ mod tests { version: Version, limit: Option, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, origin::Consumer, crate::lite::test_transport::ScriptedSession, @@ -11827,7 +11959,7 @@ mod tests { version: Version, auth: crate::auth::Handle, ) -> ( - Subscriber, + Subscriber, crate::auth::Requests, origin::Consumer, crate::lite::test_transport::ScriptedSession, @@ -11842,7 +11974,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, @@ -11858,7 +11990,7 @@ mod tests { let subscriber = Subscriber::new( crate::time::sim(), - session.clone(), + crate::driver::Transport::new(session.clone()), origin, Control::new(None, false), None, @@ -11886,7 +12018,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(); @@ -11933,7 +12067,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"); @@ -11972,8 +12108,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(); @@ -12023,8 +12162,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 { @@ -12041,9 +12182,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()); @@ -12080,8 +12224,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 { @@ -12111,8 +12257,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()); @@ -12167,7 +12316,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); @@ -12207,7 +12358,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; @@ -12549,7 +12702,6 @@ mod stitch_tests { coding::{Encode as _, Encoder}, lite::test_transport::ScriptedSession, model::ProduceTest, - transport::poll::Session as _, util::{TaskSet, Tasks}, }; @@ -12725,18 +12877,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, @@ -12757,7 +12907,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, @@ -12840,10 +12990,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) } } @@ -13033,12 +13183,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, @@ -13111,7 +13261,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() @@ -13815,12 +13967,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, @@ -13861,7 +14013,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() @@ -13925,12 +14079,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, @@ -13958,7 +14112,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() @@ -15372,8 +15528,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), } @@ -15384,7 +15540,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, @@ -15404,7 +15560,7 @@ mod stitch_tests { Self { subscriber, - stream: Reader::new(recv, version), + stream: Reader::new(crate::transport::boxed::RecvStream::new(recv), version), track, _tasks: tasks, } @@ -15461,7 +15617,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; @@ -15575,7 +15730,7 @@ mod joining_fetch_tests { } struct JoinRun { - subscriber: Subscriber, + subscriber: Subscriber, session: ScriptedSession, _hold: ( crate::broadcast::Producer, @@ -15601,7 +15756,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, @@ -15690,10 +15845,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(), @@ -15736,7 +15888,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, @@ -15813,7 +15965,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() { @@ -15835,7 +15987,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(); @@ -15866,7 +16019,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); @@ -15887,7 +16040,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"); @@ -15925,7 +16078,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); @@ -16106,7 +16259,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()); @@ -16149,7 +16302,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, @@ -16260,7 +16413,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()); @@ -16393,7 +16546,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, @@ -16459,7 +16612,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, @@ -16600,7 +16753,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, @@ -16633,7 +16786,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) @@ -16701,11 +16854,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. @@ -16720,7 +16873,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, @@ -16767,7 +16920,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(); @@ -17016,15 +17171,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, @@ -17047,7 +17199,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 c9852fbcdea..cf755fd8a5e 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()); @@ -297,14 +279,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))) @@ -327,13 +309,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 { @@ -347,29 +329,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(); @@ -590,7 +569,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, @@ -618,11 +597,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 { @@ -771,7 +746,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()); @@ -833,7 +808,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), @@ -918,7 +893,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, @@ -1014,7 +989,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; @@ -1022,7 +997,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(()), @@ -1033,7 +1008,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; @@ -1083,8 +1058,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()); @@ -1105,7 +1080,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, @@ -1157,7 +1132,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?; @@ -1192,8 +1167,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 { @@ -1269,14 +1244,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<()>, @@ -1292,7 +1267,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, @@ -1349,10 +1324,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(); @@ -1444,7 +1422,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(); @@ -1590,10 +1570,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(); @@ -1630,10 +1613,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, @@ -1730,10 +1716,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); } @@ -1792,10 +1781,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 { @@ -1828,10 +1820,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 c68720edeec..59fc94c2430 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 561a8f475e7..c8d1a12909c 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,27 @@ 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 { + #[cfg_attr( + target_arch = "wasm32", + expect( + clippy::arc_with_non_send_sync, + reason = "the browser transport is `!Send`, but native shares this state across threads" + ) + )] + 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 +228,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 +272,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,37 +291,37 @@ 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, } #[expect( clippy::large_enum_variant, reason = "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" )] -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<()> { @@ -327,7 +333,7 @@ impl kio::Task for Control { } } -impl Control { +impl Control { fn poll_serve(&mut self, waiter: &kio::Waiter) -> Poll> { loop { match &mut self.state { @@ -416,9 +422,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, @@ -430,8 +436,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); @@ -575,7 +581,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(); @@ -613,11 +623,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 => { @@ -645,10 +651,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. @@ -660,7 +666,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); @@ -707,7 +713,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, @@ -838,10 +844,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, } @@ -863,8 +869,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, @@ -1043,7 +1049,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 { @@ -1061,9 +1067,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> { @@ -1120,9 +1126,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, @@ -1196,9 +1202,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, @@ -1219,9 +1225,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, @@ -1255,9 +1261,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> { @@ -1282,9 +1288,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> { @@ -1336,9 +1342,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> { @@ -1359,9 +1365,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, @@ -1485,7 +1491,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 @@ -1510,7 +1516,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); @@ -1519,8 +1525,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>>; } @@ -1542,10 +1548,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, @@ -1587,8 +1593,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, @@ -1815,7 +1821,7 @@ impl> RequestServe { } } -impl> Drop for RequestServe { +impl Drop for RequestServe { fn drop(&mut self) { self.settle(); } @@ -1932,7 +1938,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); @@ -1948,7 +1954,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 }) } @@ -1959,8 +1965,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)); @@ -1987,7 +1993,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); @@ -2003,7 +2009,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)?, }) @@ -2015,8 +2021,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 @@ -2045,7 +2051,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. @@ -2057,10 +2063,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. @@ -2068,7 +2074,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; @@ -2085,7 +2091,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), @@ -2118,8 +2124,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 { @@ -2258,7 +2264,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. @@ -2276,7 +2282,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( @@ -2297,8 +2303,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 { @@ -2683,7 +2689,7 @@ mod announce_test { use crate::model::ProduceTest; use std::sync::Mutex; - type TestPublisher = Publisher; + type TestPublisher = Publisher; const VERSION: Version = Version::Lite06; @@ -2728,9 +2734,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(); @@ -2767,9 +2776,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(); @@ -2806,9 +2818,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(); @@ -2859,9 +2874,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(); @@ -2896,9 +2914,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!( @@ -3007,9 +3028,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(); @@ -3040,9 +3061,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(); @@ -3292,9 +3313,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(); @@ -3614,13 +3635,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, @@ -3628,7 +3645,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, @@ -3643,6 +3677,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 { @@ -3652,7 +3698,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 @@ -3735,16 +3794,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() @@ -3754,20 +3803,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 } } @@ -3775,8 +3825,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, @@ -3810,13 +3860,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)); @@ -3928,7 +3978,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()) } @@ -3938,7 +3992,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(); @@ -3948,7 +4002,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 { @@ -4091,7 +4145,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 { @@ -4144,7 +4198,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(()); @@ -4164,7 +4218,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. @@ -4181,7 +4238,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 @@ -4193,7 +4250,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 @@ -4254,7 +4311,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. @@ -4268,7 +4325,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, @@ -4279,18 +4336,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, @@ -4300,7 +4357,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, } @@ -4312,13 +4369,13 @@ struct GroupServe { reason = "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" ) )] -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, @@ -4329,18 +4386,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. @@ -4372,7 +4429,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(())); } @@ -4383,8 +4445,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 { @@ -4392,7 +4454,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); @@ -4469,7 +4531,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() } @@ -4479,7 +4541,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, @@ -4690,7 +4752,7 @@ impl GroupServe { } } -impl kio::Task for GroupServe { +impl kio::Task for GroupServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -4701,7 +4763,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) { @@ -4871,7 +4933,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(), @@ -4918,7 +4980,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(), @@ -4969,7 +5031,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(), @@ -5020,7 +5082,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(), @@ -5088,7 +5150,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(), @@ -5132,7 +5194,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; } @@ -5262,7 +5324,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(), @@ -5338,7 +5400,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(), @@ -5388,7 +5450,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(), @@ -5437,7 +5499,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(), @@ -5484,7 +5546,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) } @@ -5493,12 +5555,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(), @@ -5578,10 +5643,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); @@ -5632,13 +5697,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 @@ -5664,10 +5729,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()) @@ -5815,7 +5880,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 @@ -6521,7 +6590,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) @@ -6615,8 +6684,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, } @@ -6631,11 +6700,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(), @@ -6959,7 +7031,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, @@ -7020,11 +7092,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, @@ -7056,10 +7130,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, @@ -7090,7 +7166,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(); @@ -7120,12 +7198,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 { @@ -7151,11 +7229,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, @@ -7187,11 +7267,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, @@ -7208,7 +7290,7 @@ mod tests { struct Probing { estimate: kio::Producer, log: crate::lite::test_transport::Log, - server: ProbeServe, + server: ProbeServe, version: Version, _gate: kio::Producer, } @@ -7216,12 +7298,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, @@ -7396,7 +7480,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() @@ -7404,12 +7488,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. @@ -7430,7 +7509,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, @@ -7454,11 +7533,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. @@ -7525,7 +7604,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, @@ -7563,7 +7642,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, @@ -7596,11 +7675,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!( @@ -7652,7 +7737,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, @@ -7689,11 +7774,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 { @@ -7771,7 +7856,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, @@ -7806,11 +7891,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() @@ -7932,7 +8017,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), @@ -7973,7 +8058,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, @@ -8005,11 +8090,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. @@ -8038,9 +8123,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, @@ -8075,11 +8162,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); @@ -8100,7 +8187,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() @@ -8167,12 +8254,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" @@ -8200,12 +8294,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(), @@ -8238,11 +8339,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(); @@ -8283,12 +8391,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(); @@ -8299,7 +8416,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() @@ -8336,11 +8453,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(); @@ -8377,11 +8501,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(), @@ -8398,12 +8524,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(), @@ -8418,13 +8546,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, @@ -8436,22 +8566,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, @@ -8475,11 +8603,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() @@ -8503,8 +8631,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 19bb2ab16cc..8b8ddd095d9 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 @@ -567,26 +569,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); @@ -691,7 +697,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. @@ -701,15 +707,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 { @@ -754,36 +760,36 @@ impl UniAccept { } /// One accepted uni stream, dispatched on its first varint. -struct UniServe { - subscriber: Subscriber, - state: UniState, +struct UniServe { + subscriber: Subscriber, + state: UniState, } #[expect( clippy::large_enum_variant, reason = "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" )] -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<()> { @@ -800,7 +806,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 { @@ -892,9 +898,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, @@ -934,8 +940,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, @@ -1358,15 +1364,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 { @@ -1395,16 +1401,16 @@ 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, } #[expect( clippy::large_enum_variant, reason = "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" )] -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. @@ -1412,11 +1418,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, @@ -1478,20 +1484,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(), @@ -1538,34 +1544,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. @@ -1588,10 +1600,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, @@ -1821,29 +1833,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>, @@ -1861,9 +1873,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)?; } @@ -1930,8 +1942,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 @@ -2011,7 +2023,7 @@ impl SourceServe { } } -impl kio::Task for SourceServe { +impl kio::Task for SourceServe { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -2093,11 +2105,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, @@ -2208,7 +2222,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), @@ -2304,17 +2320,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, @@ -2498,12 +2506,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); @@ -2605,8 +2608,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, @@ -2649,12 +2654,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, @@ -2769,7 +2776,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 { @@ -2778,7 +2785,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); @@ -2788,7 +2797,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, @@ -2848,7 +2857,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, @@ -2879,7 +2888,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 => { @@ -2936,7 +2948,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, @@ -2972,7 +2984,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) } @@ -3119,7 +3134,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, @@ -3156,7 +3171,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) } @@ -3229,7 +3247,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, @@ -3263,7 +3281,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); @@ -3298,7 +3319,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, @@ -3370,7 +3391,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, @@ -3440,7 +3461,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, @@ -3499,7 +3520,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, @@ -3598,7 +3619,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, @@ -3671,7 +3692,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, @@ -3731,7 +3752,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, @@ -3783,10 +3804,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, @@ -3909,7 +3930,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, @@ -3968,7 +3989,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, @@ -4035,7 +4056,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, @@ -4081,7 +4102,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, @@ -4098,7 +4119,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, @@ -4167,7 +4188,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, @@ -4212,7 +4233,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, @@ -4580,7 +4601,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(); @@ -4630,7 +4651,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 @@ -4723,7 +4744,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, @@ -4778,7 +4799,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, @@ -4832,7 +4853,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, @@ -4860,9 +4881,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(); @@ -4901,7 +4922,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, @@ -4957,7 +4978,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, @@ -5016,7 +5037,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, @@ -5075,7 +5096,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, @@ -5142,7 +5163,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, @@ -5202,7 +5223,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, @@ -5249,7 +5270,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, @@ -5326,12 +5347,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, @@ -5440,7 +5461,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, @@ -5524,7 +5545,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, @@ -5587,15 +5608,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, @@ -5773,7 +5791,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, @@ -5846,8 +5864,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. @@ -5871,7 +5889,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. @@ -5897,9 +5915,9 @@ impl SubStream { reason = "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" ) )] -enum Sub { +enum Sub { None, - Active(SubStream), + Active(SubStream), } /// Every advertisement the peer currently has live on one announce stream. @@ -5964,12 +5982,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()) @@ -6053,7 +6066,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. @@ -6099,7 +6112,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() @@ -6212,18 +6225,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 { @@ -6277,10 +6290,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 @@ -6374,7 +6387,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 @@ -6420,7 +6433,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)); @@ -6443,7 +6456,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> { @@ -6474,19 +6487,16 @@ impl TrackServe { clippy::large_enum_variant, reason = "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" )] -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, @@ -6503,33 +6513,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 { @@ -6598,7 +6608,7 @@ impl Establish { } } - fn activate(&self, stream: Stream) -> SubStream { + fn activate(&self, stream: Stream) -> SubStream { SubStream { stream, id: self.id, @@ -6617,9 +6627,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, } @@ -6628,22 +6638,22 @@ struct TrackServeRun { clippy::large_enum_variant, reason = "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" )] -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), @@ -6687,7 +6697,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 @@ -6709,7 +6719,7 @@ impl TrackServeRun { } } -impl kio::Task for TrackServeRun { +impl kio::Task for TrackServeRun { type Output = (); fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> { @@ -6803,7 +6813,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. @@ -6820,31 +6830,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(), @@ -6856,9 +6866,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 @@ -6936,9 +6946,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(); } @@ -6948,7 +6958,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 @@ -6961,35 +6971,35 @@ 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, } #[expect( clippy::large_enum_variant, reason = "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" )] -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. @@ -7074,12 +7084,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); @@ -7161,8 +7166,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. @@ -7193,7 +7198,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() @@ -7500,33 +7505,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. @@ -7537,7 +7542,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 { @@ -7547,8 +7552,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 { @@ -7563,7 +7568,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. @@ -7605,7 +7610,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 18ce184814c..570068b5c9b 100644 --- a/rs/moq-uring/benches/worker_turns.rs +++ b/rs/moq-uring/benches/worker_turns.rs @@ -63,8 +63,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);