Skip to content

refactor(moq-net): make request_broadcast/subscribe/fetch_group infallible#1890

Merged
kixelated merged 1 commit into
devfrom
claude/loving-chatterjee-c99b8f
Jun 23, 2026
Merged

refactor(moq-net): make request_broadcast/subscribe/fetch_group infallible#1890
kixelated merged 1 commit into
devfrom
claude/loving-chatterjee-c99b8f

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Summary

Three consumer-side lookups in rs/moq-net each returned Result<kio::Pending<…>> — a synchronous Result wrapping a future that itself resolves to a Result. That double layer forced every caller into either x()?.await? or, when the synchronous error had to be translated into a wire/HTTP response rather than propagated, the awkward async { x()?.await }.await dance:

let broadcast = match async { self.origin.request_broadcast(&ns)?.await }.await {};

The synchronous error was never useful on its own: callers await the result anyway, and even the one register-then-select! caller (libmoq) just ?s it. So this collapses all three to return a bare kio::Pending<…> and bakes the former synchronous errors into the future, resolved on .await like every other outcome:

  • OriginConsumer::request_broadcast — new internal Requested::Failed(Error) variant carries Unroutable / Dropped.
  • TrackConsumer::subscribe — the closed-track error already surfaces via TrackSubscribe::poll_ok, so registration simply skips when the track is closed.
  • TrackConsumer::fetch_groupTrackFetch::poll already reports NotFound / abort, so the synchronous poll_fetch check was a pure duplicate; it now only decides whether to queue a request.

TrackConsumer::info() already worked this way, so this just makes the set consistent.

The gross call sites become a single .await:

let broadcast = match self.origin.request_broadcast(&ns).await {};

Public API changes (breaking)

In rs/moq-net:

  • OriginConsumer::request_broadcastkio::Pending<BroadcastRequested> (was Result<…, Error>)
  • TrackConsumer::subscribekio::Pending<TrackSubscribe> (was Result<…>)
  • TrackConsumer::fetch_groupkio::Pending<TrackFetch> (was Result<…>)

These are breaking, hence the dev base per the branch-targeting rules.

The remaining broadcast.track(name)? stays a plain ? — it is a synchronous accessor returning a handle, not a future-in-a-Result, so a single ? is idiomatic and not the wart being removed. The few surviving async { … } blocks (ietf publisher, relay serve_fetch) are now justified: they flatten a genuine track()? lookup plus a separate .await, not one call's double-Result.

Call-site sweep

Mechanical ?.await?.await? (and tests .unwrap().await.await) across: moq-net, moq-relay, moq-rtc, moq-ffi, libmoq, moq-mux, moq-audio, moq-boy, moq-gst, moq-bench, moq-native, hang.

Cross-package sync

  • js/net mirrors the rs/moq-net consumer surface (requestBroadcast / subscribe / fetchGroup). Not updated in this PR — flagging for a follow-up so the JS side can decide whether to reshape to match.

Test plan

  • cargo check --workspace --all-targets clean
  • cargo test -p moq-net — 389 passed
  • cargo test -p moq-mux -p moq-relay --lib — green
  • Re-run just fix against the pinned nix toolchain before merge — this branch was formatted with the system cargo fmt because nix develop couldn't allocate a pty in the dev environment.

(Written by Claude)

@kixelated kixelated force-pushed the claude/loving-chatterjee-c99b8f branch 2 times, most recently from 5132ce1 to 1128ecd Compare June 23, 2026 18:10
…lible

These three consumer-side lookups each returned `Result<kio::Pending<..>>`:
a synchronous Result wrapping a future that itself resolves to a Result. That
forced every caller into a double-unwrap (`x()?.await?`) or, when the synchronous
error had to be translated rather than propagated, the `async { x()?.await }.await`
dance. The synchronous error was never useful on its own: callers await the
result anyway, and even the one register-then-select caller (libmoq) just `?`s it.

Collapse all three to return a bare `kio::Pending<..>` and bake the former
synchronous errors into the future:

- `OriginConsumer::request_broadcast`: new internal `Requested::Failed(Error)`
  variant carries `Unroutable`/`Dropped`.
- `TrackConsumer::subscribe`: the closed-track error already surfaces via
  `TrackSubscribe::poll_ok`, so registration just skips when the track is closed.
- `TrackConsumer::fetch_group`: `TrackFetch::poll` already reports `NotFound`/abort,
  so the synchronous `poll_fetch` check was a pure duplicate; it now only decides
  whether to queue a request.

Call sites across moq-net, moq-relay, moq-rtc, moq-ffi, libmoq, moq-mux,
moq-audio, moq-boy, moq-gst, moq-bench, moq-native, and hang collapse from
`?.await?` to `.await?` (and tests from `.unwrap().await` to `.await`). The
remaining `broadcast.track(name)?` stays a plain `?`: it is a synchronous
accessor returning a handle, not a future, so a single `?` is idiomatic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated force-pushed the claude/loving-chatterjee-c99b8f branch from 1128ecd to 3cc8d5f Compare June 23, 2026 18:18
@kixelated kixelated merged commit 7f6eb4e into dev Jun 23, 2026
1 check passed
@kixelated kixelated deleted the claude/loving-chatterjee-c99b8f branch June 23, 2026 18:33
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