Skip to content

moq-lite-05: add TRACK stream, drop SUBSCRIBE_OK/FETCH_OK#1648

Open
kixelated wants to merge 1 commit into
devfrom
claude/vigorous-dirac-040547
Open

moq-lite-05: add TRACK stream, drop SUBSCRIBE_OK/FETCH_OK#1648
kixelated wants to merge 1 commit into
devfrom
claude/vigorous-dirac-040547

Conversation

@kixelated
Copy link
Copy Markdown
Collaborator

Implements moq-dev/drafts#25 for moq-lite-05-wip. The previous FETCH_OK was wrong anyway.

Targets dev (wire-protocol change under rs/moq-net, plus breaking JS API changes).

Wire protocol (rs/moq-net, gated to Lite05Wip; drafts 01–04 unchanged)

  • New Track stream (control type 0x6): a subscriber sends TRACK (broadcast path + track name); the publisher replies with a single TRACK_INFO (Publisher Priority, Ordered, Cache, Timescale, Compression) and FINs, or resets on error. These properties are immutable, so they're fetched once and cached instead of echoed on every response.
  • Removed SUBSCRIBE_OK and FETCH_OK. A subscription is accepted implicitly (rejection = stream reset); a FETCH returns bare FRAME messages.
  • Resolved range moved to SUBSCRIBE_START (0x0) / SUBSCRIBE_END (0x1); SUBSCRIBE_DROP renumbered to 0x2.
  • Added priority / ordered to crate::TrackInfo (serde-skipped, so the hang catalog is unchanged) so a relay round-trips the publisher's values.

The subscriber opens a TRACK stream immediately on a track request and accepts the producer up front (so downstream subscribers resolve and frames decode without blocking), then opens SUBSCRIBE / FETCH on demand. The relay drains START/END/DROP from the upstream subscribe stream (it previously only waited for FIN).

JS mirror (js/net)

Same wire changes, plus a consumer-side API matching Rust:

  • Track class renamed to TrackSubscriber; new TrackConsumer handle from broadcast.track(name) with subscribe() and info(). (fetch() is a follow-up PR.)
  • TrackRequest.accept(info): TrackSubscriber (mirrors Rust TrackRequest::accept) and an async Track.info(); the consumer wire commits TRACK_INFO so apps never see placeholder defaults.
  • Consumer call sites migrated to broadcast.track(name).subscribe({ priority }).

Cross-package sync

  • rs/moq-net wire ↔ js/net: done.
  • doc/concept (SUBSCRIBE_OK → TRACK_INFO): intentionally deferred while the draft is WIP.
  • JS fetch() support: follow-up PR (needs a publisher FETCH responder + group cache).

Known limitation

The JS publisher resolves a track's real TRACK_INFO via a cached probe (broadcast.subscribe(name)await track.info()). For a media track, the first such lookup briefly constructs and closes a VideoEncoder, because js/publish couples accept() and serve(). Bounded (cached, once per track per connection) and lite-05-wip is opt-in.

Test plan

  • just check green: Rust 332 tests + clippy/doc/shear/sort; all JS packages typecheck + test; biome/remark/shfmt/taplo/nixfmt.
  • rs/moq-native integration tests exercise lite-05 end-to-end over WebTransport: timestamp round-trip, bare-FRAME FETCH with Deflate matching TRACK_INFO, concurrent fetch+subscribe.

🤖 Generated with Claude Code

(Written by Claude)

@kixelated kixelated force-pushed the claude/vigorous-dirac-040547 branch 3 times, most recently from 8941496 to 89a6614 Compare June 8, 2026 16:10
@kixelated
Copy link
Copy Markdown
Collaborator Author

Addressed the TrackProducer/TrackConsumer split feedback in 89a6614.

The do-everything Track is now split, mirroring Rust:

  • TrackProducer (write: appendGroup/writeGroup/writeFrame/…) and TrackSubscriber (read: recvGroup/nextGroup/readFrame/…), sharing a TrackState.
  • TrackConsumer is the lazy handle from broadcast.track(name)subscribe() / info() (fetch() is the follow-up PR).
  • TrackRequest.accept(info) returns a TrackProducer. On the wire, the consume side writes via the producer while the app reads via the subscriber it got from subscribe(); the publish side is the mirror.

All call sites updated (publish serve fns → TrackProducer, watch/consumers → TrackSubscriber, json/hang/loc producer-vs-consumer typed accordingly). just check is green (Rust 332 + all JS packages incl. integration tests). Rebased on latest dev.

(Written by Claude)

Implements moq-dev/drafts#25 for moq-lite-05-wip.

Wire protocol (rs/moq-net, gated to Lite05Wip; older drafts unchanged):
- New Track stream (control type 0x6): a TRACK request answered with a single
  TRACK_INFO (publisher priority, ordered, cache, timescale, compression) then
  FIN, or reset on error. Properties are immutable and fetched once.
- Removed SUBSCRIBE_OK and FETCH_OK. A subscription is accepted implicitly
  (rejection = stream reset); FETCH returns bare FRAME messages.
- Moved the resolved range into SUBSCRIBE_START (0x0) / SUBSCRIBE_END (0x1);
  SUBSCRIBE_DROP renumbered to 0x2.
- Added priority/ordered to crate::TrackInfo (serde-skipped, so the catalog is
  unchanged) so a relay round-trips them.

Subscriber opens a TRACK stream immediately on a track request and accepts the
producer up front, then opens SUBSCRIBE / FETCH on demand. The relay drains
START/END/DROP from the upstream subscribe stream.

JS mirror (js/net): same wire changes, plus a Rust-style track API split:
- The do-everything Track is split into TrackProducer (write) and TrackSubscriber
  (read) sharing a TrackState, plus a lazy TrackConsumer handle from
  broadcast.track(name) with subscribe() and info() (fetch() is a follow-up PR).
- TrackRequest.accept(info) returns a TrackProducer; TrackSubscriber.info() is an
  async getter the wire commits TRACK_INFO into.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kixelated kixelated force-pushed the claude/vigorous-dirac-040547 branch from 89a6614 to 8d5f311 Compare June 8, 2026 16:20
@kixelated
Copy link
Copy Markdown
Collaborator Author

Heads up: CI also tripped on a brand-new advisory unrelated to this PRRUSTSEC-2026-0173 (proc-macro-error2 marked unmaintained, published 2026-06-08). It's a build-time proc-macro pulled in transitively via getset, with no runtime exposure, and it fails cargo deny repo-wide (dev included). I added it to deny.toml's ignore list alongside the existing entries. Happy to split that into its own PR if you'd prefer. (Written by Claude)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant