moq-net: reshape Track into TrackInfo + an async TrackConsumer handle#1631
Merged
Conversation
Complete the track-revamp prototype and update every consumer/test.
Model (rs/moq-net):
- Split `Track` (name + props) into `TrackInfo` (props only) and a name
carried separately on the handles. `Broadcast` -> `BroadcastInfo`.
- `BroadcastConsumer::consume_track` -> fallible `track(name)`; subscribing
is now `track(name)?.subscribe(sub)?.await` and resolves on SUBSCRIBE_OK
(or info), making room for FETCH. A `TrackRequest::accept(info)` locks in
the info and hands back a static `TrackProducer`.
- Add `TrackProducer::{consume, subscribe}` (sync in-process subscribe) and
sync `subscription()` snapshots; the async change-notifier is now
`subscription_changed()`.
Fixes found wiring it up end-to-end:
- TrackSubscriberPending/TrackInfoPending kept a temporary kio::Waiter, whose
weak waker died on poll return, so accept()'s wakeup was lost. Hold the
waiter across polls.
- poll_subscription_changed used retain_mut, tripping Mut's DerefMut and
flagging TrackState modified on no-op polls (draining unrelated waiters).
Iterate immutably via a shared helper; add kio::Consumer::is_closed.
hang catalog: replace the embedded `moq_net::Track` with a `{ name: String }`
type matching the JS `TrackSchema`; `default_track()` -> `default_track_info()`.
Allocation: track names are `Arc<str>` (handle clones are refcount bumps;
`impl Into<Arc<str>>` lets an existing Arc pass through free), and the
broadcast lookup maps key by the same shared `Arc<str>`.
Consumers/tests updated across hang, moq-mux, moq-relay, moq-audio, moq-cli,
moq-gst, moq-boy, moq-rtc, libmoq, moq-ffi, moq-native.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts: # rs/hang/src/catalog/chat.rs # rs/hang/src/catalog/mod.rs # rs/hang/src/catalog/root.rs
…dcast rename cargo doc -D warnings flagged links to the removed Track/Broadcast items. Point them at the new types (TrackInfo/BroadcastConsumer/TrackConsumer) and use crate:: paths where the type is no longer in scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks the track model so we don't have to know
TrackInfountil aSUBSCRIBE_OK/FETCH_OK/TRACK_STATUSarrives, which makes room for FETCH alongside SUBSCRIBE.TrackConsumeris now a cheap async handle yousubscribe/info(laterfetch); behind the scenes that resolves into a SUBSCRIBE, andTrackRequest::accept(info)locks the info in and returns a staticTrackProducer. Completes the prototype and updates every consumer/test across the workspace.Model (
rs/moq-net)Track(name + properties) intoTrackInfo(properties only); the name now lives on the handles.Broadcast→BroadcastInfo.BroadcastConsumer::consume_track→ fallibletrack(name). Subscribing istrack(name)?.subscribe(sub)?.await, resolving onSUBSCRIBE_OK.TrackRequest::accept(info)hands back aTrackProducerthat can't change the info.TrackProducer::{consume, subscribe}(synchronous in-process subscribe, since info is known at creation) and syncsubscription()snapshots; the async change-notifier is nowsubscription_changed().moq-litehas noTRACK_STATUSyet, so a standaloneinfo()would block — older versions still go through a real subscribe. Left as-is for now.Deadlock fixes found wiring it up end-to-end
Both surfaced via stack-sampling the hung
moq-ffi::server_client_roundtrip:accept()—TrackSubscriberPending/TrackInfoPendingpassed a temporarykio::Waiter; kio stores a weak waker, so it died onpollreturn andaccept()'s wake hit nobody. Now the waiter is held across polls.modified—poll_subscription_changedusedretain_mut, trippingMut'sDerefMutand flaggingTrackStatemodified on every no-op poll (draining unrelated waiters). Now a shared helper iterates immutably; addedkio::Consumer::is_closed.Catalog (
rs/hang)moq_net::Track, which no longer carries a name and shouldn't carrycompress/timescale/cacheanyway. Replaced with a{ name: String }type matching the JSTrackSchemaexactly (byte-identical wire, nojs/hangchange).default_track()→default_track_info() -> TrackInfo(it only ever configured the catalog.json producer).Allocation
Arc<str>(handle clones —weak/consume/subscribe/accept— are refcount bumps;impl Into<Arc<str>>lets an existingArcpass through free). The broadcast lookup maps key by the same sharedArc<str>.TrackInfostays a plainClonevalue (small, inline, no heap).Consumers updated
hang,moq-mux,moq-relay,moq-audio,moq-cli,moq-gst,moq-boy,moq-rtc,libmoq,moq-ffi,moq-native(+ their tests/examples).Test plan
cargo test --workspace— 941 passed, 0 failed (2 ignored)cargo fmt --all --checkclean (Nix-pinned toolchain)moq-ffi::server_client_roundtrippassesjs/not touched — this is an API-shape change, not a wire change (catalog JSON is identical); JS@moq/nethandle parity is a possible follow-up🤖 Generated with Claude Code
(Written by Claude)