Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ lands before the cut.
- [Subscribe ranges](/quest/m1/subscribe-ranges/README.md) - a lite-07 SUBSCRIBE asks for past and live ranges with absolute or relative ends, in either order, and replaces FETCH; merged ranges never starve a subscriber; relays fill misses by range, including over moq-transport
- [More tests under load](/quest/m1/test-flakes-2/README.md) - the second round of load-only failures, one quest per flake, fixed at the cause
- [A public model](/quest/m1/public-model/README.md) - every model item a built-in session reaches is public, unnecessary, or marked deliberately private, so a custom publisher, subscriber, or relay builds from the public model alone
- [An async QUIC driver without moq-net](/quest/m1/quic-driver.md) - `moq_tokio::quic::driver` is supported API that builds without moq-net, so other applications can embed moq-quic on tokio
- [Lazy discovery](/quest/m1/lazy-discovery/README.md) - a `consume` session requests announcements only for prefixes the origin is watching, in JS then Rust; `follow`, `broadcasts`, and the `discovery` option go away
- [Exact timestamps in every binding](/quest/m1/binding-timestamps.md) - bindings carry `{value, scale}` timestamps instead of lossy microseconds
- [JSON window timestamps](/quest/m1/json-window-timestamps.md) - Rust and JS window consumers return each event's frame timestamp like the snapshot and stream consumers
Expand Down
90 changes: 90 additions & 0 deletions quest/m1/quic-driver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# [M] An async QUIC driver without moq-net

## Goal

An application runs `moq-quic` on tokio without depending on moq-net:
`moq_tokio::quic::driver`'s endpoint, connection, and stream futures, with
send groups, `reset_at`, receive leases, and live `Limits`, become documented
public API that builds without moq-net. Any Rust MoQ implementation, or any
QUIC application, can embed the stack moq-dev ships, instead of forking
quinn's async layer again.

`cargo tree -e normal` on a driver-only build of moq-tokio
(`--no-default-features`, the driver feature, and a crypto provider) shows no
moq-net, kio, reqwest, or notify, and no crate from quinn, noq, or
moq-dev/web-transport. CI builds that feature set, and the driver's tests stay
in the merge gate.

## Plan

Where it stands:

- The driver is quinn's async layer on moq-quic, kept as moq-tokio modules,
tokio-only (decided 2026-10-06 in the fork epic, over `moq-quic-udp` and
`moq-quic-tokio` crates). The udp half is now `moq_sock::udp`.
- Its only moq-net type is `moq_net::transport::Wire`, a pair of byte
counters (`quic/driver/connection.rs`). `quic/backend.rs` also takes
`moq_net::Versions` for ALPN lists, but sits above the driver.
- moq-net is a required dependency of moq-tokio, even without the `quic`
feature that gates the driver, so a consumer cannot take the driver alone.
- The driver is public but `#[doc(hidden)]`, and is not on `release`.

Decided 2026-10-20 (maintainer): `moq-quic` powers qmux and WebTransport,
and moq takes no new work in, or dependency on, moq-dev/web-transport, noq
or quinn. The driver is that stack's tokio runtime, beside moq-uring's
driver and the planned in-tree qmux, so this quest moves no code out of the
tree. quinn stays the upstream the fork cherry-picks from, not a dependency.

Decided 2026-10-20 (maintainer): the driver stays in moq-tokio, at
`moq_tokio::quic::driver`, and moq-net becomes optional there. No new crate
and no feature on moq-quic: the driver keeps its home and its tests, and the
sans-IO core that moq-uring and qmux share gets no runtime. It stays a
`driver` submodule, since `quic::Connection` and `quic::Error` already name
the MoQ backend's types.

Rejected: a `moq-quic-tokio` crate (a new published crate and a reversal of
the 2026-10-06 decision) and a `tokio` feature on moq-quic (a runtime in the
sans-IO core, and the driver's tests behind a non-default gate).

The work:

- The first commit replaces `Wire` with counters owned by the driver.
moq-tokio converts at its boundary, and moq-net's wire stats do not change.
- moq-net moves behind a default feature, which every transport feature also
enables, since none works without it. `web-transport-trait` moves with it:
every user (`transport`, `server`, `tcp`, `quic::web`) is on the moq-net
side. Every moq-net use in moq-tokio, including the `moq_net` re-export,
gets the gate.
- A driver-only feature turns on `quic::driver` alone, and `quic` enables it
plus `quic::backend` and `quic::web`. `quic`'s other dependencies (reqwest,
notify through `watch`, kio, http, web-transport-proto,
rustls-native-certs, dns-lookup) stay on `quic`, so a driver-only build
drops them. Name both features in the implementing PR.
- Out of scope: moq-tokio's unconditional dependencies, which a driver-only
build still pulls through its `cli`, `tls`, and `settings` modules: tokio
`full`, rustls and rustls-platform-verifier, x509-parser, serde, toml,
tracing-subscriber, and usage-rs, plus rcgen and rustls-webpki from the
crypto-provider feature. None is MoQ code; splitting them is its own quest
if an embedder needs it.
- Drop the driver's `#[doc(hidden)]` and its "not a stable API" comment, and
document every exported item. The driver keeps quinn's rustfmt config.
- In-tree consumers with `default-features = false` and no transport feature
that use moq-net-backed modules (moq-room, moq-boy, moq-bench) enable the
new moq-net feature.
- `quic::web` and `quic::backend` keep their features and dependencies here.
[Drop web-transport-trait](/quest/m2/drop-web-transport-trait.md) owns their
API changes, such as `quic::web::Session` dropping its `Deref`, and proceeds
on top. Driver API changes that quest makes, such as aligning the stream
setters with moq-uring's, land in the driver here; neither quest waits on
the other.
- moq-uring's driver is out of scope. It is `!Send`, and coupled to moq-net
through `server::Activity` as well as `Wire`.

Decided 2026-10-20: m1, because making moq-net optional is a breaking change.
A build with `default-features = false` and no transport feature loses
`client`, `connect`, `connection`, `listen`, `origin`, `transport`, the root
re-exports built on them (`Client`, `Connection`, `Error`, ...), and the
`moq_net` re-export, so it lands before the cut. Add an entry under
`## Unreleased` in `rs/moq-tokio/MIGRATE.md`: enable the new moq-net feature
or a transport feature to keep them. Public API: the two new features, and
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
`quic::driver` becomes supported. Wire: none.
6 changes: 4 additions & 2 deletions quest/m2/drop-web-transport-trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ each gets its own impl:
`SendOptions` reach a new stream through its setters in both runtimes'
adapters. A native impl can pass them to the open, as moq-tokio's driver
`open_uni`/`open_bi` already accept.
- moq-tokio's `quic::driver` and `quic::web` modules are public but
`#[doc(hidden)]`. Decide whether they are API or should be private.
- moq-tokio's `quic::web` module is public but `#[doc(hidden)]`. Decide
whether it is API or should be private. `quic::driver` stays public:
[An async QUIC driver without moq-net](/quest/m1/quic-driver.md) makes it
supported API.

Notes from related quests:
- [qmux on moq-quic](/quest/m2/quic-qmux.md) planned to port qmux's
Expand Down