diff --git a/dart/moq/MIGRATE.md b/dart/moq/MIGRATE.md index 3a3ee2ab154..5cc86e51b4c 100644 --- a/dart/moq/MIGRATE.md +++ b/dart/moq/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `dynamic_()` on `OriginProducer`, `BroadcastProducer`, `TrackProducer`, and `TrackRequest` to `requests()`. +Their handles `OriginDynamic`, `BroadcastDynamic`, and `TrackDynamic` are `OriginRequests`, `BroadcastRequests`, and `TrackRequests`; their methods are unchanged. + ### `Allocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `Bandwidth` is `Allocator`, `bandwidth()` is `allocator()`, and `Reservation.grant()` is `rate()`. The producers' `bandwidth` option keeps its name. diff --git a/dart/moq/lib/src/aliases.dart b/dart/moq/lib/src/aliases.dart index 69e4f15118e..b4b13ca5e50 100644 --- a/dart/moq/lib/src/aliases.dart +++ b/dart/moq/lib/src/aliases.dart @@ -44,7 +44,7 @@ typedef OriginConfig = MoqOriginConfig; typedef OriginConsumer = MoqOriginConsumer; /// A served route: advertises a path prefix and yields broadcast requests beneath it. -typedef OriginDynamic = MoqOriginDynamic; +typedef OriginRequests = MoqOriginRequests; /// A requested broadcast not yet accepted: fulfill it with a producer or reject it. typedef BroadcastRequest = MoqBroadcastRequest; @@ -91,7 +91,7 @@ typedef BroadcastProducer = MoqBroadcastProducer; typedef BroadcastConsumer = MoqBroadcastConsumer; /// Receives tracks requested from a dynamically served broadcast. -typedef BroadcastDynamic = MoqBroadcastDynamic; +typedef BroadcastRequests = MoqBroadcastRequests; /// The write side of a raw track: append groups of frames. typedef TrackProducer = MoqTrackProducer; @@ -100,7 +100,7 @@ typedef TrackProducer = MoqTrackProducer; typedef TrackRequest = MoqTrackRequest; /// A stream of the fills readers of one track need: runs of groups the cache lacks. -typedef TrackDynamic = MoqTrackDynamic; +typedef TrackRequests = MoqTrackRequests; /// A watch-only handle to whether a published track has subscribers; holding it keeps nothing open. typedef TrackDemand = MoqTrackDemand; diff --git a/dart/moq/lib/src/client.dart b/dart/moq/lib/src/client.dart index 713434feebb..e807362638c 100644 --- a/dart/moq/lib/src/client.dart +++ b/dart/moq/lib/src/client.dart @@ -215,7 +215,7 @@ final class Moq { /// Create an unannounced broadcast at [path], invisible to everyone until announced. /// - /// Advertise it with `announce` after populating tracks. Create, `dynamic` + /// Advertise it with `announce` after populating tracks. Create, `requests` /// if tracks are served on demand, populate, then announce. BroadcastProducer createBroadcast(String path) => session.publish().createBroadcast(path: path); diff --git a/dart/moq/test/moq_test.dart b/dart/moq/test/moq_test.dart index 16fc6c33e86..f9b085bcbf1 100644 --- a/dart/moq/test/moq_test.dart +++ b/dart/moq/test/moq_test.dart @@ -497,7 +497,7 @@ void main() { test('dynamic serves a request under a prefix', () async { final origin = MoqOriginProducer(config: MoqOriginConfig()); - final dynamic = origin.dynamic_(prefix: 'live'); + final dynamic = origin.requests(prefix: 'live'); final pending = origin.consume().requestBroadcast(path: 'live/cam'); final request = await dynamic.requestedBroadcast().timeout(timeout); expect(request.path(), 'live/cam'); diff --git a/dart/moq_ffi/lib/src/moq.dart b/dart/moq_ffi/lib/src/moq.dart index 79e5421a936..d31bdf28c9f 100644 --- a/dart/moq_ffi/lib/src/moq.dart +++ b/dart/moq_ffi/lib/src/moq.dart @@ -12119,97 +12119,10 @@ class FfiConverterMoqOriginConsumer { } } -abstract class MoqOriginDynamicInterface { - void cancel(); - UniffiRustFuture requestedBroadcast(); -} - -final _MoqOriginDynamicFinalizer = Finalizer>((ptr) { - rustCall((status) => uniffi_moq_ffi_fn_free_moqorigindynamic(ptr, status)); -}); - -class MoqOriginDynamic implements MoqOriginDynamicInterface { - late final Pointer _ptr; - bool _isDisposed = false; - MoqOriginDynamic._(this._ptr) { - _MoqOriginDynamicFinalizer.attach(this, _ptr, detach: this); - } - factory MoqOriginDynamic.lift(Pointer ptr) { - return MoqOriginDynamic._(ptr); - } - Pointer uniffiClonePointer() { - if (_isDisposed) { - throw StateError("Object has already been disposed"); - } - return rustCall( - (status) => uniffi_moq_ffi_fn_clone_moqorigindynamic(_ptr, status), - ); - } - - void dispose() { - if (_isDisposed) { - return; - } - _isDisposed = true; - _MoqOriginDynamicFinalizer.detach(this); - rustCall((status) => uniffi_moq_ffi_fn_free_moqorigindynamic(_ptr, status)); - } - - void cancel() { - return rustCall((status) { - uniffi_moq_ffi_fn_method_moqorigindynamic_cancel( - uniffiClonePointer(), - status, - ); - }, null); - } - - UniffiRustFuture requestedBroadcast() { - return uniffiRustCallAsync( - () => uniffi_moq_ffi_fn_method_moqorigindynamic_requested_broadcast( - uniffiClonePointer(), - ), - ffi_moq_ffi_rust_future_poll_u64, - ffi_moq_ffi_rust_future_complete_u64, - ffi_moq_ffi_rust_future_cancel_u64, - ffi_moq_ffi_rust_future_free_u64, - (ptr) => - FfiConverterMoqBroadcastRequest.lift(Pointer.fromAddress(ptr)), - moqExceptionErrorHandler, - ); - } -} - -class FfiConverterMoqOriginDynamic { - static MoqOriginDynamic lift(Pointer ptr) { - return MoqOriginDynamic.lift(ptr); - } - - static Pointer lower(MoqOriginDynamic value) { - return value.uniffiClonePointer(); - } - - static int allocationSize(MoqOriginDynamic value) { - return 8; - } - - static LiftRetVal read(Uint8List buf) { - final handle = buf.buffer.asByteData(buf.offsetInBytes).getInt64(0); - final pointer = Pointer.fromAddress(handle); - return LiftRetVal(MoqOriginDynamic.lift(pointer), 8); - } - - static int write(MoqOriginDynamic value, Uint8List buf) { - final handle = lower(value); - buf.buffer.asByteData(buf.offsetInBytes).setInt64(0, handle.address); - return 8; - } -} - abstract class MoqOriginProducerInterface { MoqOriginConsumer consume(); MoqBroadcastProducer createBroadcast({required String path}); - MoqOriginDynamic dynamic_({required String prefix}); + MoqOriginRequests requests({required String prefix}); } final _MoqOriginProducerFinalizer = Finalizer>((ptr) { @@ -12278,14 +12191,14 @@ class MoqOriginProducer implements MoqOriginProducerInterface { ); } - MoqOriginDynamic dynamic_({required String prefix}) { + MoqOriginRequests requests({required String prefix}) { return rustCallWithLifter( - (status) => uniffi_moq_ffi_fn_method_moqoriginproducer_dynamic( + (status) => uniffi_moq_ffi_fn_method_moqoriginproducer_requests( uniffiClonePointer(), FfiConverterString.lower(prefix), status, ), - FfiConverterMoqOriginDynamic.lift, + FfiConverterMoqOriginRequests.lift, moqExceptionErrorHandler, ); } @@ -12317,30 +12230,30 @@ class FfiConverterMoqOriginProducer { } } -abstract class MoqBroadcastDynamicInterface { +abstract class MoqOriginRequestsInterface { void cancel(); - UniffiRustFuture requestedTrack(); + UniffiRustFuture requestedBroadcast(); } -final _MoqBroadcastDynamicFinalizer = Finalizer>((ptr) { - rustCall((status) => uniffi_moq_ffi_fn_free_moqbroadcastdynamic(ptr, status)); +final _MoqOriginRequestsFinalizer = Finalizer>((ptr) { + rustCall((status) => uniffi_moq_ffi_fn_free_moqoriginrequests(ptr, status)); }); -class MoqBroadcastDynamic implements MoqBroadcastDynamicInterface { +class MoqOriginRequests implements MoqOriginRequestsInterface { late final Pointer _ptr; bool _isDisposed = false; - MoqBroadcastDynamic._(this._ptr) { - _MoqBroadcastDynamicFinalizer.attach(this, _ptr, detach: this); + MoqOriginRequests._(this._ptr) { + _MoqOriginRequestsFinalizer.attach(this, _ptr, detach: this); } - factory MoqBroadcastDynamic.lift(Pointer ptr) { - return MoqBroadcastDynamic._(ptr); + factory MoqOriginRequests.lift(Pointer ptr) { + return MoqOriginRequests._(ptr); } Pointer uniffiClonePointer() { if (_isDisposed) { throw StateError("Object has already been disposed"); } return rustCall( - (status) => uniffi_moq_ffi_fn_clone_moqbroadcastdynamic(_ptr, status), + (status) => uniffi_moq_ffi_fn_clone_moqoriginrequests(_ptr, status), ); } @@ -12349,56 +12262,57 @@ class MoqBroadcastDynamic implements MoqBroadcastDynamicInterface { return; } _isDisposed = true; - _MoqBroadcastDynamicFinalizer.detach(this); + _MoqOriginRequestsFinalizer.detach(this); rustCall( - (status) => uniffi_moq_ffi_fn_free_moqbroadcastdynamic(_ptr, status), + (status) => uniffi_moq_ffi_fn_free_moqoriginrequests(_ptr, status), ); } void cancel() { return rustCall((status) { - uniffi_moq_ffi_fn_method_moqbroadcastdynamic_cancel( + uniffi_moq_ffi_fn_method_moqoriginrequests_cancel( uniffiClonePointer(), status, ); }, null); } - UniffiRustFuture requestedTrack() { + UniffiRustFuture requestedBroadcast() { return uniffiRustCallAsync( - () => uniffi_moq_ffi_fn_method_moqbroadcastdynamic_requested_track( + () => uniffi_moq_ffi_fn_method_moqoriginrequests_requested_broadcast( uniffiClonePointer(), ), ffi_moq_ffi_rust_future_poll_u64, ffi_moq_ffi_rust_future_complete_u64, ffi_moq_ffi_rust_future_cancel_u64, ffi_moq_ffi_rust_future_free_u64, - (ptr) => FfiConverterMoqTrackRequest.lift(Pointer.fromAddress(ptr)), + (ptr) => + FfiConverterMoqBroadcastRequest.lift(Pointer.fromAddress(ptr)), moqExceptionErrorHandler, ); } } -class FfiConverterMoqBroadcastDynamic { - static MoqBroadcastDynamic lift(Pointer ptr) { - return MoqBroadcastDynamic.lift(ptr); +class FfiConverterMoqOriginRequests { + static MoqOriginRequests lift(Pointer ptr) { + return MoqOriginRequests.lift(ptr); } - static Pointer lower(MoqBroadcastDynamic value) { + static Pointer lower(MoqOriginRequests value) { return value.uniffiClonePointer(); } - static int allocationSize(MoqBroadcastDynamic value) { + static int allocationSize(MoqOriginRequests value) { return 8; } - static LiftRetVal read(Uint8List buf) { + static LiftRetVal read(Uint8List buf) { final handle = buf.buffer.asByteData(buf.offsetInBytes).getInt64(0); final pointer = Pointer.fromAddress(handle); - return LiftRetVal(MoqBroadcastDynamic.lift(pointer), 8); + return LiftRetVal(MoqOriginRequests.lift(pointer), 8); } - static int write(MoqBroadcastDynamic value, Uint8List buf) { + static int write(MoqOriginRequests value, Uint8List buf) { final handle = lower(value); buf.buffer.asByteData(buf.offsetInBytes).setInt64(0, handle.address); return 8; @@ -12409,11 +12323,11 @@ abstract class MoqBroadcastProducerInterface { void announce({required MoqAnnounceRoute route}); void close(); MoqBroadcastConsumer consume(); - MoqBroadcastDynamic dynamic_(); MoqTrackProducer publishTrack({ required String name, required MoqTrackInfo? info, }); + MoqBroadcastRequests requests(); void unannounce(); } @@ -12490,17 +12404,6 @@ class MoqBroadcastProducer implements MoqBroadcastProducerInterface { ); } - MoqBroadcastDynamic dynamic_() { - return rustCallWithLifter( - (status) => uniffi_moq_ffi_fn_method_moqbroadcastproducer_dynamic( - uniffiClonePointer(), - status, - ), - FfiConverterMoqBroadcastDynamic.lift, - moqExceptionErrorHandler, - ); - } - MoqTrackProducer publishTrack({ required String name, required MoqTrackInfo? info, @@ -12517,6 +12420,17 @@ class MoqBroadcastProducer implements MoqBroadcastProducerInterface { ); } + MoqBroadcastRequests requests() { + return rustCallWithLifter( + (status) => uniffi_moq_ffi_fn_method_moqbroadcastproducer_requests( + uniffiClonePointer(), + status, + ), + FfiConverterMoqBroadcastRequests.lift, + moqExceptionErrorHandler, + ); + } + void unannounce() { return rustCall((status) { uniffi_moq_ffi_fn_method_moqbroadcastproducer_unannounce( @@ -12553,6 +12467,96 @@ class FfiConverterMoqBroadcastProducer { } } +abstract class MoqBroadcastRequestsInterface { + void cancel(); + UniffiRustFuture requestedTrack(); +} + +final _MoqBroadcastRequestsFinalizer = Finalizer>((ptr) { + rustCall( + (status) => uniffi_moq_ffi_fn_free_moqbroadcastrequests(ptr, status), + ); +}); + +class MoqBroadcastRequests implements MoqBroadcastRequestsInterface { + late final Pointer _ptr; + bool _isDisposed = false; + MoqBroadcastRequests._(this._ptr) { + _MoqBroadcastRequestsFinalizer.attach(this, _ptr, detach: this); + } + factory MoqBroadcastRequests.lift(Pointer ptr) { + return MoqBroadcastRequests._(ptr); + } + Pointer uniffiClonePointer() { + if (_isDisposed) { + throw StateError("Object has already been disposed"); + } + return rustCall( + (status) => uniffi_moq_ffi_fn_clone_moqbroadcastrequests(_ptr, status), + ); + } + + void dispose() { + if (_isDisposed) { + return; + } + _isDisposed = true; + _MoqBroadcastRequestsFinalizer.detach(this); + rustCall( + (status) => uniffi_moq_ffi_fn_free_moqbroadcastrequests(_ptr, status), + ); + } + + void cancel() { + return rustCall((status) { + uniffi_moq_ffi_fn_method_moqbroadcastrequests_cancel( + uniffiClonePointer(), + status, + ); + }, null); + } + + UniffiRustFuture requestedTrack() { + return uniffiRustCallAsync( + () => uniffi_moq_ffi_fn_method_moqbroadcastrequests_requested_track( + uniffiClonePointer(), + ), + ffi_moq_ffi_rust_future_poll_u64, + ffi_moq_ffi_rust_future_complete_u64, + ffi_moq_ffi_rust_future_cancel_u64, + ffi_moq_ffi_rust_future_free_u64, + (ptr) => FfiConverterMoqTrackRequest.lift(Pointer.fromAddress(ptr)), + moqExceptionErrorHandler, + ); + } +} + +class FfiConverterMoqBroadcastRequests { + static MoqBroadcastRequests lift(Pointer ptr) { + return MoqBroadcastRequests.lift(ptr); + } + + static Pointer lower(MoqBroadcastRequests value) { + return value.uniffiClonePointer(); + } + + static int allocationSize(MoqBroadcastRequests value) { + return 8; + } + + static LiftRetVal read(Uint8List buf) { + final handle = buf.buffer.asByteData(buf.offsetInBytes).getInt64(0); + final pointer = Pointer.fromAddress(handle); + return LiftRetVal(MoqBroadcastRequests.lift(pointer), 8); + } + + static int write(MoqBroadcastRequests value, Uint8List buf) { + final handle = lower(value); + buf.buffer.asByteData(buf.offsetInBytes).setInt64(0, handle.address); + return 8; + } +} + abstract class MoqFillInterface { MoqGroupProducer accept({required int sequence}); void dropGroups({required int start, required int end}); @@ -12888,92 +12892,6 @@ class FfiConverterMoqGroupProducer { } } -abstract class MoqTrackDynamicInterface { - void cancel(); - UniffiRustFuture requestedFill(); -} - -final _MoqTrackDynamicFinalizer = Finalizer>((ptr) { - rustCall((status) => uniffi_moq_ffi_fn_free_moqtrackdynamic(ptr, status)); -}); - -class MoqTrackDynamic implements MoqTrackDynamicInterface { - late final Pointer _ptr; - bool _isDisposed = false; - MoqTrackDynamic._(this._ptr) { - _MoqTrackDynamicFinalizer.attach(this, _ptr, detach: this); - } - factory MoqTrackDynamic.lift(Pointer ptr) { - return MoqTrackDynamic._(ptr); - } - Pointer uniffiClonePointer() { - if (_isDisposed) { - throw StateError("Object has already been disposed"); - } - return rustCall( - (status) => uniffi_moq_ffi_fn_clone_moqtrackdynamic(_ptr, status), - ); - } - - void dispose() { - if (_isDisposed) { - return; - } - _isDisposed = true; - _MoqTrackDynamicFinalizer.detach(this); - rustCall((status) => uniffi_moq_ffi_fn_free_moqtrackdynamic(_ptr, status)); - } - - void cancel() { - return rustCall((status) { - uniffi_moq_ffi_fn_method_moqtrackdynamic_cancel( - uniffiClonePointer(), - status, - ); - }, null); - } - - UniffiRustFuture requestedFill() { - return uniffiRustCallAsync( - () => uniffi_moq_ffi_fn_method_moqtrackdynamic_requested_fill( - uniffiClonePointer(), - ), - ffi_moq_ffi_rust_future_poll_u64, - ffi_moq_ffi_rust_future_complete_u64, - ffi_moq_ffi_rust_future_cancel_u64, - ffi_moq_ffi_rust_future_free_u64, - (ptr) => FfiConverterMoqFill.lift(Pointer.fromAddress(ptr)), - moqExceptionErrorHandler, - ); - } -} - -class FfiConverterMoqTrackDynamic { - static MoqTrackDynamic lift(Pointer ptr) { - return MoqTrackDynamic.lift(ptr); - } - - static Pointer lower(MoqTrackDynamic value) { - return value.uniffiClonePointer(); - } - - static int allocationSize(MoqTrackDynamic value) { - return 8; - } - - static LiftRetVal read(Uint8List buf) { - final handle = buf.buffer.asByteData(buf.offsetInBytes).getInt64(0); - final pointer = Pointer.fromAddress(handle); - return LiftRetVal(MoqTrackDynamic.lift(pointer), 8); - } - - static int write(MoqTrackDynamic value, Uint8List buf) { - final handle = lower(value); - buf.buffer.asByteData(buf.offsetInBytes).setInt64(0, handle.address); - return 8; - } -} - abstract class MoqTrackProducerInterface { void abort({required int errorCode}); int appendDatagram({required MoqFrame frame}); @@ -12981,9 +12899,9 @@ abstract class MoqTrackProducerInterface { MoqTrackConsumer consume({required MoqSubscription? subscription}); MoqGroupProducer createGroup({required int sequence}); MoqTrackDemand demand(); - MoqTrackDynamic dynamic_(); void finish(); void finishAt({required int finalSequence}); + MoqTrackRequests requests(); void writeFrame({required MoqFrame frame}); } @@ -13086,17 +13004,6 @@ class MoqTrackProducer implements MoqTrackProducerInterface { ); } - MoqTrackDynamic dynamic_() { - return rustCallWithLifter( - (status) => uniffi_moq_ffi_fn_method_moqtrackproducer_dynamic( - uniffiClonePointer(), - status, - ), - FfiConverterMoqTrackDynamic.lift, - moqExceptionErrorHandler, - ); - } - void finish() { return rustCall((status) { uniffi_moq_ffi_fn_method_moqtrackproducer_finish( @@ -13116,6 +13023,17 @@ class MoqTrackProducer implements MoqTrackProducerInterface { }, moqExceptionErrorHandler); } + MoqTrackRequests requests() { + return rustCallWithLifter( + (status) => uniffi_moq_ffi_fn_method_moqtrackproducer_requests( + uniffiClonePointer(), + status, + ), + FfiConverterMoqTrackRequests.lift, + moqExceptionErrorHandler, + ); + } + void writeFrame({required MoqFrame frame}) { return rustCall((status) { uniffi_moq_ffi_fn_method_moqtrackproducer_write_frame( @@ -13157,8 +13075,8 @@ abstract class MoqTrackRequestInterface { void abort({required int errorCode}); MoqTrackProducer accept({required MoqTrackInfo? info}); MoqTrackDemand demand(); - MoqTrackDynamic dynamic_(); String name(); + MoqTrackRequests requests(); } final _MoqTrackRequestFinalizer = Finalizer>((ptr) { @@ -13225,24 +13143,24 @@ class MoqTrackRequest implements MoqTrackRequestInterface { ); } - MoqTrackDynamic dynamic_() { + String name() { return rustCallWithLifter( - (status) => uniffi_moq_ffi_fn_method_moqtrackrequest_dynamic( + (status) => uniffi_moq_ffi_fn_method_moqtrackrequest_name( uniffiClonePointer(), status, ), - FfiConverterMoqTrackDynamic.lift, + FfiConverterString.lift, moqExceptionErrorHandler, ); } - String name() { + MoqTrackRequests requests() { return rustCallWithLifter( - (status) => uniffi_moq_ffi_fn_method_moqtrackrequest_name( + (status) => uniffi_moq_ffi_fn_method_moqtrackrequest_requests( uniffiClonePointer(), status, ), - FfiConverterString.lift, + FfiConverterMoqTrackRequests.lift, moqExceptionErrorHandler, ); } @@ -13274,6 +13192,92 @@ class FfiConverterMoqTrackRequest { } } +abstract class MoqTrackRequestsInterface { + void cancel(); + UniffiRustFuture requestedFill(); +} + +final _MoqTrackRequestsFinalizer = Finalizer>((ptr) { + rustCall((status) => uniffi_moq_ffi_fn_free_moqtrackrequests(ptr, status)); +}); + +class MoqTrackRequests implements MoqTrackRequestsInterface { + late final Pointer _ptr; + bool _isDisposed = false; + MoqTrackRequests._(this._ptr) { + _MoqTrackRequestsFinalizer.attach(this, _ptr, detach: this); + } + factory MoqTrackRequests.lift(Pointer ptr) { + return MoqTrackRequests._(ptr); + } + Pointer uniffiClonePointer() { + if (_isDisposed) { + throw StateError("Object has already been disposed"); + } + return rustCall( + (status) => uniffi_moq_ffi_fn_clone_moqtrackrequests(_ptr, status), + ); + } + + void dispose() { + if (_isDisposed) { + return; + } + _isDisposed = true; + _MoqTrackRequestsFinalizer.detach(this); + rustCall((status) => uniffi_moq_ffi_fn_free_moqtrackrequests(_ptr, status)); + } + + void cancel() { + return rustCall((status) { + uniffi_moq_ffi_fn_method_moqtrackrequests_cancel( + uniffiClonePointer(), + status, + ); + }, null); + } + + UniffiRustFuture requestedFill() { + return uniffiRustCallAsync( + () => uniffi_moq_ffi_fn_method_moqtrackrequests_requested_fill( + uniffiClonePointer(), + ), + ffi_moq_ffi_rust_future_poll_u64, + ffi_moq_ffi_rust_future_complete_u64, + ffi_moq_ffi_rust_future_cancel_u64, + ffi_moq_ffi_rust_future_free_u64, + (ptr) => FfiConverterMoqFill.lift(Pointer.fromAddress(ptr)), + moqExceptionErrorHandler, + ); + } +} + +class FfiConverterMoqTrackRequests { + static MoqTrackRequests lift(Pointer ptr) { + return MoqTrackRequests.lift(ptr); + } + + static Pointer lower(MoqTrackRequests value) { + return value.uniffiClonePointer(); + } + + static int allocationSize(MoqTrackRequests value) { + return 8; + } + + static LiftRetVal read(Uint8List buf) { + final handle = buf.buffer.asByteData(buf.offsetInBytes).getInt64(0); + final pointer = Pointer.fromAddress(handle); + return LiftRetVal(MoqTrackRequests.lift(pointer), 8); + } + + static int write(MoqTrackRequests value, Uint8List buf) { + final handle = lower(value); + buf.buffer.asByteData(buf.offsetInBytes).setInt64(0, handle.address); + return 8; + } +} + abstract class MoqRequestInterface { UniffiRustFuture accept({ MoqOriginProducer? publish = null, @@ -18521,36 +18525,6 @@ uniffi_moq_ffi_fn_method_moqoriginconsumer_request_broadcast( RustBuffer path, ); -@Native Function(Pointer, Pointer)>( - assetId: _uniffiAssetId, -) -external Pointer uniffi_moq_ffi_fn_clone_moqorigindynamic( - Pointer handle, - Pointer uniffiStatus, -); - -@Native, Pointer)>( - assetId: _uniffiAssetId, -) -external void uniffi_moq_ffi_fn_free_moqorigindynamic( - Pointer handle, - Pointer uniffiStatus, -); - -@Native, Pointer)>( - assetId: _uniffiAssetId, -) -external void uniffi_moq_ffi_fn_method_moqorigindynamic_cancel( - Pointer ptr, - Pointer uniffiStatus, -); - -@Native Function(Pointer)>(assetId: _uniffiAssetId) -external Pointer -uniffi_moq_ffi_fn_method_moqorigindynamic_requested_broadcast( - Pointer ptr, -); - @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) @@ -18596,7 +18570,7 @@ uniffi_moq_ffi_fn_method_moqoriginproducer_create_broadcast( @Native< Pointer Function(Pointer, RustBuffer, Pointer) >(assetId: _uniffiAssetId) -external Pointer uniffi_moq_ffi_fn_method_moqoriginproducer_dynamic( +external Pointer uniffi_moq_ffi_fn_method_moqoriginproducer_requests( Pointer ptr, RustBuffer prefix, Pointer uniffiStatus, @@ -18605,7 +18579,7 @@ external Pointer uniffi_moq_ffi_fn_method_moqoriginproducer_dynamic( @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) -external Pointer uniffi_moq_ffi_fn_clone_moqbroadcastdynamic( +external Pointer uniffi_moq_ffi_fn_clone_moqoriginrequests( Pointer handle, Pointer uniffiStatus, ); @@ -18613,7 +18587,7 @@ external Pointer uniffi_moq_ffi_fn_clone_moqbroadcastdynamic( @Native, Pointer)>( assetId: _uniffiAssetId, ) -external void uniffi_moq_ffi_fn_free_moqbroadcastdynamic( +external void uniffi_moq_ffi_fn_free_moqoriginrequests( Pointer handle, Pointer uniffiStatus, ); @@ -18621,14 +18595,16 @@ external void uniffi_moq_ffi_fn_free_moqbroadcastdynamic( @Native, Pointer)>( assetId: _uniffiAssetId, ) -external void uniffi_moq_ffi_fn_method_moqbroadcastdynamic_cancel( +external void uniffi_moq_ffi_fn_method_moqoriginrequests_cancel( Pointer ptr, Pointer uniffiStatus, ); @Native Function(Pointer)>(assetId: _uniffiAssetId) external Pointer -uniffi_moq_ffi_fn_method_moqbroadcastdynamic_requested_track(Pointer ptr); +uniffi_moq_ffi_fn_method_moqoriginrequests_requested_broadcast( + Pointer ptr, +); @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, @@ -18678,14 +18654,6 @@ external Pointer uniffi_moq_ffi_fn_method_moqbroadcastproducer_consume( Pointer uniffiStatus, ); -@Native Function(Pointer, Pointer)>( - assetId: _uniffiAssetId, -) -external Pointer uniffi_moq_ffi_fn_method_moqbroadcastproducer_dynamic( - Pointer ptr, - Pointer uniffiStatus, -); - @Native< Pointer Function( Pointer, @@ -18702,6 +18670,14 @@ uniffi_moq_ffi_fn_method_moqbroadcastproducer_publish_track( Pointer uniffiStatus, ); +@Native Function(Pointer, Pointer)>( + assetId: _uniffiAssetId, +) +external Pointer uniffi_moq_ffi_fn_method_moqbroadcastproducer_requests( + Pointer ptr, + Pointer uniffiStatus, +); + @Native, Pointer)>( assetId: _uniffiAssetId, ) @@ -18710,6 +18686,36 @@ external void uniffi_moq_ffi_fn_method_moqbroadcastproducer_unannounce( Pointer uniffiStatus, ); +@Native Function(Pointer, Pointer)>( + assetId: _uniffiAssetId, +) +external Pointer uniffi_moq_ffi_fn_clone_moqbroadcastrequests( + Pointer handle, + Pointer uniffiStatus, +); + +@Native, Pointer)>( + assetId: _uniffiAssetId, +) +external void uniffi_moq_ffi_fn_free_moqbroadcastrequests( + Pointer handle, + Pointer uniffiStatus, +); + +@Native, Pointer)>( + assetId: _uniffiAssetId, +) +external void uniffi_moq_ffi_fn_method_moqbroadcastrequests_cancel( + Pointer ptr, + Pointer uniffiStatus, +); + +@Native Function(Pointer)>(assetId: _uniffiAssetId) +external Pointer +uniffi_moq_ffi_fn_method_moqbroadcastrequests_requested_track( + Pointer ptr, +); + @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) @@ -18887,35 +18893,6 @@ external void uniffi_moq_ffi_fn_method_moqgroupproducer_write_frame( Pointer uniffiStatus, ); -@Native Function(Pointer, Pointer)>( - assetId: _uniffiAssetId, -) -external Pointer uniffi_moq_ffi_fn_clone_moqtrackdynamic( - Pointer handle, - Pointer uniffiStatus, -); - -@Native, Pointer)>( - assetId: _uniffiAssetId, -) -external void uniffi_moq_ffi_fn_free_moqtrackdynamic( - Pointer handle, - Pointer uniffiStatus, -); - -@Native, Pointer)>( - assetId: _uniffiAssetId, -) -external void uniffi_moq_ffi_fn_method_moqtrackdynamic_cancel( - Pointer ptr, - Pointer uniffiStatus, -); - -@Native Function(Pointer)>(assetId: _uniffiAssetId) -external Pointer uniffi_moq_ffi_fn_method_moqtrackdynamic_requested_fill( - Pointer ptr, -); - @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) @@ -18984,28 +18961,28 @@ external Pointer uniffi_moq_ffi_fn_method_moqtrackproducer_demand( Pointer uniffiStatus, ); -@Native Function(Pointer, Pointer)>( +@Native, Pointer)>( assetId: _uniffiAssetId, ) -external Pointer uniffi_moq_ffi_fn_method_moqtrackproducer_dynamic( +external void uniffi_moq_ffi_fn_method_moqtrackproducer_finish( Pointer ptr, Pointer uniffiStatus, ); -@Native, Pointer)>( +@Native, Uint64, Pointer)>( assetId: _uniffiAssetId, ) -external void uniffi_moq_ffi_fn_method_moqtrackproducer_finish( +external void uniffi_moq_ffi_fn_method_moqtrackproducer_finish_at( Pointer ptr, + int final_sequence, Pointer uniffiStatus, ); -@Native, Uint64, Pointer)>( +@Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) -external void uniffi_moq_ffi_fn_method_moqtrackproducer_finish_at( +external Pointer uniffi_moq_ffi_fn_method_moqtrackproducer_requests( Pointer ptr, - int final_sequence, Pointer uniffiStatus, ); @@ -19060,22 +19037,51 @@ external Pointer uniffi_moq_ffi_fn_method_moqtrackrequest_demand( Pointer uniffiStatus, ); +@Native, Pointer)>( + assetId: _uniffiAssetId, +) +external RustBuffer uniffi_moq_ffi_fn_method_moqtrackrequest_name( + Pointer ptr, + Pointer uniffiStatus, +); + @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) -external Pointer uniffi_moq_ffi_fn_method_moqtrackrequest_dynamic( +external Pointer uniffi_moq_ffi_fn_method_moqtrackrequest_requests( Pointer ptr, Pointer uniffiStatus, ); -@Native, Pointer)>( +@Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) -external RustBuffer uniffi_moq_ffi_fn_method_moqtrackrequest_name( +external Pointer uniffi_moq_ffi_fn_clone_moqtrackrequests( + Pointer handle, + Pointer uniffiStatus, +); + +@Native, Pointer)>( + assetId: _uniffiAssetId, +) +external void uniffi_moq_ffi_fn_free_moqtrackrequests( + Pointer handle, + Pointer uniffiStatus, +); + +@Native, Pointer)>( + assetId: _uniffiAssetId, +) +external void uniffi_moq_ffi_fn_method_moqtrackrequests_cancel( Pointer ptr, Pointer uniffiStatus, ); +@Native Function(Pointer)>(assetId: _uniffiAssetId) +external Pointer uniffi_moq_ffi_fn_method_moqtrackrequests_requested_fill( + Pointer ptr, +); + @Native Function(Pointer, Pointer)>( assetId: _uniffiAssetId, ) @@ -20296,13 +20302,6 @@ uniffi_moq_ffi_checksum_method_moqoriginconsumer_announced_broadcast(); external int uniffi_moq_ffi_checksum_method_moqoriginconsumer_request_broadcast(); -@Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqorigindynamic_cancel(); - -@Native(assetId: _uniffiAssetId) -external int -uniffi_moq_ffi_checksum_method_moqorigindynamic_requested_broadcast(); - @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqoriginproducer_consume(); @@ -20311,14 +20310,14 @@ external int uniffi_moq_ffi_checksum_method_moqoriginproducer_create_broadcast(); @Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqoriginproducer_dynamic(); +external int uniffi_moq_ffi_checksum_method_moqoriginproducer_requests(); @Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqbroadcastdynamic_cancel(); +external int uniffi_moq_ffi_checksum_method_moqoriginrequests_cancel(); @Native(assetId: _uniffiAssetId) external int -uniffi_moq_ffi_checksum_method_moqbroadcastdynamic_requested_track(); +uniffi_moq_ffi_checksum_method_moqoriginrequests_requested_broadcast(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_announce(); @@ -20329,16 +20328,23 @@ external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_close(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_consume(); -@Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_dynamic(); - @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_publish_track(); +@Native(assetId: _uniffiAssetId) +external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_requests(); + @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqbroadcastproducer_unannounce(); +@Native(assetId: _uniffiAssetId) +external int uniffi_moq_ffi_checksum_method_moqbroadcastrequests_cancel(); + +@Native(assetId: _uniffiAssetId) +external int +uniffi_moq_ffi_checksum_method_moqbroadcastrequests_requested_track(); + @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqfill_accept(); @@ -20393,12 +20399,6 @@ external int uniffi_moq_ffi_checksum_method_moqgroupproducer_sequence(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqgroupproducer_write_frame(); -@Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqtrackdynamic_cancel(); - -@Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqtrackdynamic_requested_fill(); - @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqtrackproducer_abort(); @@ -20417,15 +20417,15 @@ external int uniffi_moq_ffi_checksum_method_moqtrackproducer_create_group(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqtrackproducer_demand(); -@Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqtrackproducer_dynamic(); - @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqtrackproducer_finish(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqtrackproducer_finish_at(); +@Native(assetId: _uniffiAssetId) +external int uniffi_moq_ffi_checksum_method_moqtrackproducer_requests(); + @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqtrackproducer_write_frame(); @@ -20439,10 +20439,16 @@ external int uniffi_moq_ffi_checksum_method_moqtrackrequest_accept(); external int uniffi_moq_ffi_checksum_method_moqtrackrequest_demand(); @Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqtrackrequest_dynamic(); +external int uniffi_moq_ffi_checksum_method_moqtrackrequest_name(); + +@Native(assetId: _uniffiAssetId) +external int uniffi_moq_ffi_checksum_method_moqtrackrequest_requests(); @Native(assetId: _uniffiAssetId) -external int uniffi_moq_ffi_checksum_method_moqtrackrequest_name(); +external int uniffi_moq_ffi_checksum_method_moqtrackrequests_cancel(); + +@Native(assetId: _uniffiAssetId) +external int uniffi_moq_ffi_checksum_method_moqtrackrequests_requested_fill(); @Native(assetId: _uniffiAssetId) external int uniffi_moq_ffi_checksum_method_moqrequest_accept(); @@ -21024,28 +21030,21 @@ void _checkApiChecksums() { 54627) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqorigindynamic_cancel() != 47453) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } - if (uniffi_moq_ffi_checksum_method_moqorigindynamic_requested_broadcast() != - 54021) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } if (uniffi_moq_ffi_checksum_method_moqoriginproducer_consume() != 52357) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } if (uniffi_moq_ffi_checksum_method_moqoriginproducer_create_broadcast() != - 45756) { + 38558) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqoriginproducer_dynamic() != 17765) { + if (uniffi_moq_ffi_checksum_method_moqoriginproducer_requests() != 8499) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqbroadcastdynamic_cancel() != 25875) { + if (uniffi_moq_ffi_checksum_method_moqoriginrequests_cancel() != 18954) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqbroadcastdynamic_requested_track() != - 5884) { + if (uniffi_moq_ffi_checksum_method_moqoriginrequests_requested_broadcast() != + 31253) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_announce() != 3965) { @@ -21057,17 +21056,24 @@ void _checkApiChecksums() { if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_consume() != 27634) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_dynamic() != 55635) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_publish_track() != 44452) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } + if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_requests() != 27464) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } if (uniffi_moq_ffi_checksum_method_moqbroadcastproducer_unannounce() != 49647) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } + if (uniffi_moq_ffi_checksum_method_moqbroadcastrequests_cancel() != 44028) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } + if (uniffi_moq_ffi_checksum_method_moqbroadcastrequests_requested_track() != + 49236) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } if (uniffi_moq_ffi_checksum_method_moqfill_accept() != 63990) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } @@ -21122,13 +21128,6 @@ void _checkApiChecksums() { if (uniffi_moq_ffi_checksum_method_moqgroupproducer_write_frame() != 42053) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqtrackdynamic_cancel() != 15841) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } - if (uniffi_moq_ffi_checksum_method_moqtrackdynamic_requested_fill() != - 22958) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } if (uniffi_moq_ffi_checksum_method_moqtrackproducer_abort() != 37537) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } @@ -21148,15 +21147,15 @@ void _checkApiChecksums() { if (uniffi_moq_ffi_checksum_method_moqtrackproducer_demand() != 7311) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqtrackproducer_dynamic() != 58584) { - throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); - } if (uniffi_moq_ffi_checksum_method_moqtrackproducer_finish() != 63940) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } if (uniffi_moq_ffi_checksum_method_moqtrackproducer_finish_at() != 24581) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } + if (uniffi_moq_ffi_checksum_method_moqtrackproducer_requests() != 60252) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } if (uniffi_moq_ffi_checksum_method_moqtrackproducer_write_frame() != 32196) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } @@ -21169,10 +21168,17 @@ void _checkApiChecksums() { if (uniffi_moq_ffi_checksum_method_moqtrackrequest_demand() != 3618) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqtrackrequest_dynamic() != 24801) { + if (uniffi_moq_ffi_checksum_method_moqtrackrequest_name() != 56715) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } - if (uniffi_moq_ffi_checksum_method_moqtrackrequest_name() != 56715) { + if (uniffi_moq_ffi_checksum_method_moqtrackrequest_requests() != 23724) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } + if (uniffi_moq_ffi_checksum_method_moqtrackrequests_cancel() != 43316) { + throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); + } + if (uniffi_moq_ffi_checksum_method_moqtrackrequests_requested_fill() != + 55377) { throw UniffiInternalError.panicked("UniFFI API checksum mismatch"); } if (uniffi_moq_ffi_checksum_method_moqrequest_accept() != 55136) { diff --git a/doc/lib/dart/index.md b/doc/lib/dart/index.md index 4b953d06caa..8743963cb28 100644 --- a/doc/lib/dart/index.md +++ b/doc/lib/dart/index.md @@ -140,7 +140,7 @@ The rest of the [shared feature list](/lib/#what-every-binding-can-do) maps one to one; the API reference has the names, and [Layers](/lib/layers) shows which module holds each. -- **Names.** Types drop the `Moq` prefix (`Session`, `BroadcastProducer`) as aliases, so the generated names still work. `Container`, `Route`, and the exceptions keep it, since Flutter owns those names. `dynamic` is reserved, so the origin method is `dynamic_`. +- **Names.** Types drop the `Moq` prefix (`Session`, `BroadcastProducer`) as aliases, so the generated names still work. `Container`, `Route`, and the exceptions keep it, since Flutter owns those names. - **Audio needs cuts.** Video groups at its keyframes, but audio forms a group only where you call `cut()`: after every frame, or at a segment cadence to align with video. - **Timeline breaks.** On a seek or pause, call `discontinuity()`, then keep timestamps moving forward and resume video on a keyframe. - **Decoder reads.** `audio.Consumer` and `video.Consumer` return a `Read` in order: a `ReadFrame`, a `ReadGap` where media was lost, or a `ReadEnd` where the publisher stopped its encoder. What follows a gap or an end does not continue what came before. diff --git a/doc/lib/go/index.md b/doc/lib/go/index.md index ef667359e1f..c2fe8c0a968 100644 --- a/doc/lib/go/index.md +++ b/doc/lib/go/index.md @@ -126,7 +126,7 @@ one to one; the API reference has the names, and [Layers](/lib/layers) shows which module holds each. - **Context cancellation.** Every call that can block takes a `context.Context` first, and cancelling it tears down the native work, not just your wait. A one-shot call (`RequestBroadcast`, `FetchGroup`, `Server.Accept`) aborts alone; a stream read (`Next`, `ReadFrame`, and the iterators over them) cancels the stream it reads. -- **Keep owners reachable.** An origin from `moq.NewOriginProducer` has no `Close`. It ends when the garbage collector reaches its last owner (each producer, published broadcast, and `OriginDynamic`), and its consumers then fail with `moq.ErrClosed`. +- **Keep owners reachable.** An origin from `moq.NewOriginProducer` has no `Close`. It ends when the garbage collector reaches its last owner (each producer, published broadcast, and `OriginRequests`), and its consumers then fail with `moq.ErrClosed`. - **Bandwidth ownership.** An encoder you manage can reserve a share of the session's bandwidth. Reuse its reservation when the ceiling changes; before abandoning or replacing it, call `Update(0)` to return its share and automatic probe ceiling without waiting for garbage collection. The track can stay subscribed and the reservation can be reused. - **Audio needs cuts.** Video groups at its keyframes, but audio forms a group only where you call `Cut()`: after every frame, or at a segment cadence to align with video. - **Timeline breaks.** On a seek or pause, call `Discontinuity()`, then keep timestamps moving forward and resume video on a keyframe. diff --git a/doc/lib/js/net.md b/doc/lib/js/net.md index f40ea29e942..e587877952c 100644 --- a/doc/lib/js/net.md +++ b/doc/lib/js/net.md @@ -38,7 +38,7 @@ publication.announce(); ``` - **The origin holds the broadcasts, not the connection.** Closing a session unannounces them and leaves them created for the next one. A publication controls announcements; its `broadcast` fills tracks. The broadcast is invisible, locally and remotely, until the publication calls `announce()`. -- **Answer claimed paths with `using`.** `dynamic(prefix)` claims a prefix and yields each requested path. Use `using prepared = request.prepare(epoch)`, fill its broadcast, then `prepared.publish()` to answer with a new publisher instance and keep the `Publication` it returns. Leaving the scope without publishing, including on a throw, refuses the request as unroutable. Explicit `prepared.close()` or closing its unpublished broadcast does the same; disposal after publishing leaves the returned publication and its fill broadcast live. Reject before preparing with `request.reject(err)`. A retained, unclosed prepared answer keeps the request pending; JavaScript garbage collection provides no prompt cleanup guarantee. +- **Answer claimed paths with `using`.** `requests(prefix)` claims a prefix and yields each requested path. Use `using prepared = request.prepare(epoch)`, fill its broadcast, then `prepared.publish()` to answer with a new publisher instance and keep the `Publication` it returns. Leaving the scope without publishing, including on a throw, refuses the request as unroutable. Explicit `prepared.close()` or closing its unpublished broadcast does the same; disposal after publishing leaves the returned publication and its fill broadcast live. Reject before preparing with `request.reject(err)`. A retained, unclosed prepared answer keeps the request pending; JavaScript garbage collection provides no prompt cleanup guarantee. - **End content by finishing tracks.** A broadcast has no finished state. When the input ends, `finish()` each track, then `close()` it; closing a track without finishing aborts it. The broadcast stays announced and keeps serving them until you `close()` it. How long to keep it up for late readers is yours to decide. - **Requests can pin an epoch.** `consumer.request(path, { epoch })` resolves only through a route announcing that [publisher epoch](/concept/moq-lite#publisher-epochs). The resolved broadcast's `epoch` names the route it came through, pinned or not. - **Follow restarts.** `origin.request(path, { announced: true })` follows whichever publisher instance serves the path: its `active` changes to a fresh broadcast on a restart, clears on an end, and resolves again on the next start, so read it reactively and close the request when done. Instances are never stitched, so subscribe again to each new broadcast. Another route of the same epoch taking over (epochs travel only on `moq-lite-07-wip`) keeps `active` as is, and each track subscription resumes there from the first group it lacks. A refusal ends the request. Add `epoch` to pin one instance; a plain `request(path)` keeps its accepted instance, can resolve blindly, and ends once that instance stops serving. To list what is live, iterate `announced(scope)`. diff --git a/doc/lib/kt/index.md b/doc/lib/kt/index.md index 016ab280086..21c2258c4c1 100644 --- a/doc/lib/kt/index.md +++ b/doc/lib/kt/index.md @@ -97,7 +97,7 @@ The rest of the [shared feature list](/lib/#what-every-binding-can-do) maps one to one; the API reference has the names, and [Layers](/lib/layers) shows which module holds each. -- **`end`, not `close`.** `broadcast.end()` ends a broadcast for good. `close()`, or leaving `use { }`, releases the handle, which ends the broadcast only once no `dynamic()` handle remains. +- **`end`, not `close`.** `broadcast.end()` ends a broadcast for good. `close()`, or leaving `use { }`, releases the handle, which ends the broadcast only once no `requests()` handle remains. - **Audio needs cuts.** Video groups at its keyframes, but audio forms a group only where you call `cut()`: after every frame, or at a segment cadence to align with video. - **Timeline breaks.** On a seek or pause, call `discontinuity()`, then keep timestamps moving forward and resume video on a keyframe. - **Decoder reads.** `dev.moq.audio.Consumer` and `dev.moq.video.Consumer` return a `Read` in order: `ReadFrame`, a `ReadGap` where media was lost, or a `ReadEnd` where the publisher stopped its encoder. What follows a gap or an end does not continue what came before. diff --git a/doc/lib/rs/index.md b/doc/lib/rs/index.md index 57804d0618f..ba5dbdab825 100644 --- a/doc/lib/rs/index.md +++ b/doc/lib/rs/index.md @@ -79,7 +79,7 @@ while let Some(event) = announced.next().await { let mut broadcast = origin.publish("my-stream.hang", Default::default())?; // moq-mux (from a container) or moq-video / moq-audio (from a device) fill it. // The route retracts on `unannounce()` or when the broadcast ends. To serve a whole -// subtree on demand instead, `origin.dynamic("room")?` yields each requested path: +// subtree on demand instead, `origin.requests("room")?` yields each requested path: // `prepare(Epoch::mint())`, fill its broadcast, then `publish()`, or reject it. ``` diff --git a/go/wrapper/MIGRATE.md b/go/wrapper/MIGRATE.md index 3791436c1eb..1f47be3393c 100644 --- a/go/wrapper/MIGRATE.md +++ b/go/wrapper/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `Requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `Dynamic()` on `OriginProducer`, `BroadcastProducer`, `TrackProducer`, and `TrackRequest` to `Requests()`. +Their handles `OriginDynamic`, `BroadcastDynamic`, and `TrackDynamic` are `OriginRequests`, `BroadcastRequests`, and `TrackRequests`; their methods are unchanged. + ### `Allocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `Bandwidth` is `Allocator`, `Session.Bandwidth()` is `Session.Allocator()`, and `Reservation.Grant()` is `Reservation.Rate()`. The `Bandwidth` field of `ProducerOptions` keeps its name and takes a `*moq.Allocator`. diff --git a/go/wrapper/README.md b/go/wrapper/README.md index e4a288fdbb9..034eea4ddf4 100644 --- a/go/wrapper/README.md +++ b/go/wrapper/README.md @@ -99,7 +99,7 @@ and track themselves. `NewGroupConsumer` decodes a raw group, such as one from `moq.TrackConsumer.RecvGroup` for arrival-order reads. Frames and `Flush` use `time.Duration`; `Demand()` owns track names and subscriber waits. -`BroadcastProducer.Dynamic()` accepts subscriber-requested tracks. Call +`BroadcastProducer.Requests()` accepts subscriber-requested tracks. Call `TrackRequest.Accept()` for raw tracks, or pass the request as `media.Requested` so the media importer selects the timescale. diff --git a/go/wrapper/moq_test.go b/go/wrapper/moq_test.go index 0f24deccc50..18795f006e4 100644 --- a/go/wrapper/moq_test.go +++ b/go/wrapper/moq_test.go @@ -46,7 +46,7 @@ func TestDynamicBroadcastRequest(t *testing.T) { defer cancel() origin := newOrigin(t) - dynamic, err := origin.Dynamic("") + dynamic, err := origin.Requests("") if err != nil { t.Fatal(err) } @@ -566,7 +566,7 @@ func TestFetchGroupAndServeDynamicMiss(t *testing.T) { t.Fatal("a negative fetch max delay was accepted, want an error") } - dynamic, err := track.Dynamic() + dynamic, err := track.Requests() if err != nil { t.Fatal(err) } @@ -926,7 +926,7 @@ func TestDynamicTrackRequest(t *testing.T) { } defer broadcast.Close() - dynamic, err := broadcast.Dynamic() + dynamic, err := broadcast.Requests() if err != nil { t.Fatal(err) } @@ -1002,7 +1002,7 @@ func TestDynamicTrackRequestCanPublishAudio(t *testing.T) { } defer broadcast.Close() - dynamic, err := broadcast.Dynamic() + dynamic, err := broadcast.Requests() if err != nil { t.Fatal(err) } @@ -1153,7 +1153,7 @@ func TestConsumerCancelConcurrent(t *testing.T) { // that one request rather than the consumer it was made on. func TestRequestBroadcastCancelKeepsTheOrigin(t *testing.T) { origin := newOrigin(t) - dynamic, err := origin.Dynamic("") + dynamic, err := origin.Requests("") if err != nil { t.Fatal(err) } @@ -1229,7 +1229,7 @@ func TestSubscribeTrackCancelKeepsTheBroadcast(t *testing.T) { } defer broadcast.Close() - dynamic, err := broadcast.Dynamic() + dynamic, err := broadcast.Requests() if err != nil { t.Fatal(err) } @@ -1349,7 +1349,7 @@ func TestCancelDoesNotLeakGoroutines(t *testing.T) { } defer broadcast.Close() - dynamic, err := broadcast.Dynamic() + dynamic, err := broadcast.Requests() if err != nil { t.Fatal(err) } @@ -1599,7 +1599,7 @@ func TestDynamicServesARequestUnderAPrefix(t *testing.T) { defer cancel() origin := newOrigin(t) - dynamic, err := origin.Dynamic("live") + dynamic, err := origin.Requests("live") if err != nil { t.Fatal(err) } @@ -1639,7 +1639,7 @@ func TestClosingAPreparedAnswerRefusesTheRequest(t *testing.T) { defer cancel() origin := newOrigin(t) - dynamic, err := origin.Dynamic("live") + dynamic, err := origin.Requests("live") if err != nil { t.Fatal(err) } diff --git a/go/wrapper/origin.go b/go/wrapper/origin.go index d0a60966b63..7e41b497f03 100644 --- a/go/wrapper/origin.go +++ b/go/wrapper/origin.go @@ -13,7 +13,7 @@ import ( // consume sink for a full-duplex peer. // // There is no Close: the origin ends once the collector reaches every owner -// (each producer, published broadcast, and [OriginDynamic]), and its consumers +// (each producer, published broadcast, and [OriginRequests]), and its consumers // then fail with [ErrClosed]. Keep an owner reachable for as long as the origin // should live. type OriginProducer struct { @@ -35,18 +35,18 @@ func (o *OriginProducer) Consume() *OriginConsumer { return &OriginConsumer{inner: o.inner.Consume()} } -// Dynamic advertises prefix and serves the requests beneath it. +// Requests advertises prefix and serves the requests beneath it. // // A route claims prefix and every path beneath it ("" claims every path). A // service that only serves some of them rejects the rest as they are requested. -// Create, Dynamic if tracks are served on demand, populate, then +// Create, Requests if tracks are served on demand, populate, then // [BroadcastProducer.Announce]. -func (o *OriginProducer) Dynamic(prefix string) (*OriginDynamic, error) { - inner, err := o.inner.Dynamic(prefix) +func (o *OriginProducer) Requests(prefix string) (*OriginRequests, error) { + inner, err := o.inner.Requests(prefix) if err != nil { return nil, err } - return &OriginDynamic{inner: inner}, nil + return &OriginRequests{inner: inner}, nil } // CreateBroadcast creates a broadcast at the given path, returning the producer @@ -64,14 +64,14 @@ func (o *OriginProducer) CreateBroadcast(path string) (*BroadcastProducer, error return &BroadcastProducer{inner: inner}, nil } -// OriginDynamic streams requests for paths with no existing exact-path broadcast. -type OriginDynamic struct { - inner *ffi.MoqOriginDynamic +// OriginRequests streams requests for paths with no existing exact-path broadcast. +type OriginRequests struct { + inner *ffi.MoqOriginRequests } // RequestedBroadcast blocks until a consumer requests a path with no existing // exact-path broadcast. -func (d *OriginDynamic) RequestedBroadcast(ctx context.Context) (*BroadcastRequest, error) { +func (d *OriginRequests) RequestedBroadcast(ctx context.Context) (*BroadcastRequest, error) { inner, err := bridge.CallHandle(ctx, d.inner.Cancel, d.inner.RequestedBroadcast) if err != nil { return nil, err @@ -81,12 +81,12 @@ func (d *OriginDynamic) RequestedBroadcast(ctx context.Context) (*BroadcastReque // All ranges over requested broadcasts until the stream errors or the loop // breaks. -func (d *OriginDynamic) All(ctx context.Context) iter.Seq2[*BroadcastRequest, error] { +func (d *OriginRequests) All(ctx context.Context) iter.Seq2[*BroadcastRequest, error] { return bridge.Seq(ctx, d.RequestedBroadcast) } // Cancel stops serving requested broadcasts and retracts the route. -func (d *OriginDynamic) Cancel() { +func (d *OriginRequests) Cancel() { d.inner.Cancel() } diff --git a/go/wrapper/origin_internal_test.go b/go/wrapper/origin_internal_test.go index 467d0d018ea..933909daca3 100644 --- a/go/wrapper/origin_internal_test.go +++ b/go/wrapper/origin_internal_test.go @@ -35,15 +35,15 @@ func TestOriginEndsWithItsProducer(t *testing.T) { } } -// An OriginDynamic owns its origin: once the collector finalizes the last +// An OriginRequests owns its origin: once the collector finalizes the last // OriginProducer, the route still serves and a consumer made earlier still // resolves through it. -func TestDynamicKeepsTheOrigin(t *testing.T) { +func TestRequestsKeepTheOrigin(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() origin := NewOriginProducer() - dynamic, err := origin.Dynamic("") + dynamic, err := origin.Requests("") if err != nil { t.Fatal(err) } diff --git a/go/wrapper/publish.go b/go/wrapper/publish.go index d03ebd52516..9d7722985c9 100644 --- a/go/wrapper/publish.go +++ b/go/wrapper/publish.go @@ -27,13 +27,13 @@ func NewBroadcastProducer() (*BroadcastProducer, error) { return &BroadcastProducer{inner: inner}, nil } -// Dynamic accepts requests for tracks that are not published yet. -func (b *BroadcastProducer) Dynamic() (*BroadcastDynamic, error) { - inner, err := b.inner.Dynamic() +// Requests accepts requests for tracks that are not published yet. +func (b *BroadcastProducer) Requests() (*BroadcastRequests, error) { + inner, err := b.inner.Requests() if err != nil { return nil, err } - return &BroadcastDynamic{inner: inner}, nil + return &BroadcastRequests{inner: inner}, nil } // Announce advertises this broadcast's exact path as a route. @@ -82,13 +82,13 @@ func (b *BroadcastProducer) Close() error { return b.inner.Close() } -// BroadcastDynamic is a stream of subscriber-requested tracks. -type BroadcastDynamic struct { - inner *ffi.MoqBroadcastDynamic +// BroadcastRequests is a stream of subscriber-requested tracks. +type BroadcastRequests struct { + inner *ffi.MoqBroadcastRequests } // RequestedTrack waits for the next subscriber-requested track. -func (d *BroadcastDynamic) RequestedTrack(ctx context.Context) (*TrackRequest, error) { +func (d *BroadcastRequests) RequestedTrack(ctx context.Context) (*TrackRequest, error) { inner, err := bridge.CallHandle(ctx, d.inner.Cancel, d.inner.RequestedTrack) if err != nil { return nil, err @@ -97,12 +97,12 @@ func (d *BroadcastDynamic) RequestedTrack(ctx context.Context) (*TrackRequest, e } // All ranges over subscriber-requested tracks until the dynamic source ends. -func (d *BroadcastDynamic) All(ctx context.Context) iter.Seq2[*TrackRequest, error] { +func (d *BroadcastRequests) All(ctx context.Context) iter.Seq2[*TrackRequest, error] { return bridge.Seq(ctx, d.RequestedTrack) } // Cancel stops the dynamic request stream. -func (d *BroadcastDynamic) Cancel() { +func (d *BroadcastRequests) Cancel() { d.inner.Cancel() } @@ -125,13 +125,13 @@ func (r *TrackRequest) Demand() (*TrackDemand, error) { return &TrackDemand{inner: inner}, nil } -// Dynamic creates a fetch handler before accepting this requested track. -func (r *TrackRequest) Dynamic() (*TrackDynamic, error) { - inner, err := r.inner.Dynamic() +// Requests creates a fetch handler before accepting this requested track. +func (r *TrackRequest) Requests() (*TrackRequests, error) { + inner, err := r.inner.Requests() if err != nil { return nil, err } - return &TrackDynamic{inner: inner}, nil + return &TrackRequests{inner: inner}, nil } // Accept accepts the request as a raw track. For media, pass the request as media.Requested to an importer constructor. @@ -191,13 +191,13 @@ func (t *TrackProducer) Demand() (*TrackDemand, error) { return &TrackDemand{inner: inner}, nil } -// Dynamic serves fetches for groups that are not currently cached. -func (t *TrackProducer) Dynamic() (*TrackDynamic, error) { - inner, err := t.inner.Dynamic() +// Requests serves fetches for groups that are not currently cached. +func (t *TrackProducer) Requests() (*TrackRequests, error) { + inner, err := t.inner.Requests() if err != nil { return nil, err } - return &TrackDynamic{inner: inner}, nil + return &TrackRequests{inner: inner}, nil } // AppendGroup starts a new group; write frames into it, then Finish. @@ -305,13 +305,13 @@ func (g *GroupProducer) Abort(errorCode uint16) error { return g.inner.Abort(errorCode) } -// TrackDynamic yields the fills readers of one track need: runs of groups the cache lacks. -type TrackDynamic struct { - inner *ffi.MoqTrackDynamic +// TrackRequests yields the fills readers of one track need: runs of groups the cache lacks. +type TrackRequests struct { + inner *ffi.MoqTrackRequests } // RequestedFill waits for the next fill. -func (d *TrackDynamic) RequestedFill(ctx context.Context) (*Fill, error) { +func (d *TrackRequests) RequestedFill(ctx context.Context) (*Fill, error) { inner, err := bridge.CallHandle(ctx, d.inner.Cancel, d.inner.RequestedFill) if err != nil { return nil, err @@ -320,16 +320,16 @@ func (d *TrackDynamic) RequestedFill(ctx context.Context) (*Fill, error) { } // All ranges over fills until the dynamic source ends. -func (d *TrackDynamic) All(ctx context.Context) iter.Seq2[*Fill, error] { +func (d *TrackRequests) All(ctx context.Context) iter.Seq2[*Fill, error] { return bridge.Seq(ctx, d.RequestedFill) } // Cancel stops current and future requested-fill waits. -func (d *TrackDynamic) Cancel() { +func (d *TrackRequests) Cancel() { d.inner.Cancel() } -// Fill is a run of groups readers miss, for a TrackDynamic to serve. +// Fill is a run of groups readers miss, for a TrackRequests to serve. // // Accept each group you have and DropGroups the rest; Next names what is still // owed, in the fill's order. Releasing the fill names whatever is left as dropped diff --git a/js/net/MIGRATE.md b/js/net/MIGRATE.md index 155be7ef6c2..84e2ac0ac8f 100644 --- a/js/net/MIGRATE.md +++ b/js/net/MIGRATE.md @@ -4,6 +4,10 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `Origin.Producer.dynamic(prefix)` to `requests(prefix)`, and the `Origin.Dynamic` handle it returns to `Origin.Requests`; its methods are unchanged. + ### Names say one thing ([#6751](https://github.com/moq-dev/moq/pull/6751)) `Auth.Auth` is `Auth.Credential`, and `Reservation.grant` is `Reservation.rate`. diff --git a/js/net/api/index.api.md b/js/net/api/index.api.md index 436ff1aaf28..6d910943399 100644 --- a/js/net/api/index.api.md +++ b/js/net/api/index.api.md @@ -271,13 +271,6 @@ class Duplicate extends Error { constructor(message?: string); } -class Dynamic { - close(): void; - readonly prefix: Path.Valid; - requested(): AsyncIterableIterator; - get route(): Route; -} - function empty(): Valid; function encode(path: Valid): Valid; @@ -502,7 +495,7 @@ declare namespace Origin_2 { Producer_4 as Producer, Requesting, Consumer_5 as Consumer, - Dynamic, + Requests, Request_3 as Request, Publication, Prepared @@ -609,8 +602,8 @@ class Producer_4 implements Table { consume(): Consumer_5; createBroadcast(path: Path.Valid): Publication; get discovery(): Getter; - dynamic(prefix: Path.Valid): Dynamic; request(path: Path.Valid, options?: RequestOptions): Requesting; + requests(prefix: Path.Valid): Requests; scope(root: Path.Valid, patterns: Path.Patterns): Producer_4; } @@ -687,6 +680,13 @@ interface RequestOptions { epoch?: Epoch.Valid; } +class Requests { + close(): void; + readonly prefix: Path.Valid; + requested(): AsyncIterableIterator; + get route(): Route; +} + class Reservation implements Disposable { [Symbol.dispose](): void; close(): void; @@ -830,8 +830,8 @@ interface Table { readonly closed: GetPromise; createBroadcast(path: Path.Valid): Publication; readonly discovery: Getter; - dynamic(prefix: Path.Valid): Dynamic; request(path: Path.Valid, options?: RequestOptions): Requesting; + requests(prefix: Path.Valid): Requests; } declare namespace Time { diff --git a/js/net/bench/broadcasts.ts b/js/net/bench/broadcasts.ts index b841afdeb93..9e6825289b4 100644 --- a/js/net/bench/broadcasts.ts +++ b/js/net/bench/broadcasts.ts @@ -31,7 +31,7 @@ for (const scope of ["unscoped", "distinct-scopes", "producer-scopes", "rooted-p for (const observerCount of observerCounts) { const origin = new Producer(); const handles = Array.from({ length: routeCount }, (_, index) => - origin.dynamic(Path.from(`room/${index}`)), + origin.requests(Path.from(`room/${index}`)), ); const touched = Path.from(scope === "rooted-producers" ? "0" : "room/0"); let notifications = 0; @@ -248,7 +248,7 @@ const nextEpoch = Epoch.parse("01900000-0000-7000-8000-000000000002"); for (const pathCount of routeCounts) { for (const readerCount of observerCounts) { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room"), { epoch }); + const dynamic = origin.requestsRoute(Path.from("room"), { epoch }); const pending = dynamic.requested(); const requests = Array.from({ length: pathCount }, (_, index) => Array.from({ length: readerCount }, () => origin.consume().request(Path.from(`room/${index}`))), diff --git a/js/net/bench/requests.ts b/js/net/bench/requests.ts index d37c8f69f68..8eef8d04a73 100644 --- a/js/net/bench/requests.ts +++ b/js/net/bench/requests.ts @@ -74,7 +74,7 @@ console.log("unrelated,waiters,cancel_us"); for (const unrelated of [8, 128, 2048]) for (const waiters of [1, 8, 32]) { const origin = new Producer(); - origin.dynamicRoute(Path.from("pending")); + origin.requestsRoute(Path.from("pending")); const held = Array.from({ length: unrelated }, (_, i) => origin.request(Path.from(`pending/${i}`))); const wire = wireOf(origin.consume()); const samples: number[] = []; @@ -108,9 +108,9 @@ for (const failovers of [0, 1, 16, 128]) const sources: Broadcast[] = []; for (let i = 0; i < failovers; i++) { const epoch = Epoch.mint(); - const primary = origin.dynamicRoute(prefix, { epoch, cost: 0n }); + const primary = origin.requestsRoute(prefix, { epoch, cost: 0n }); const ar = primary.requested(); - const br = origin.dynamicRoute(prefix, { epoch, cost: 1n }).requested(); + const br = origin.requestsRoute(prefix, { epoch, cost: 1n }).requested(); const held = origin.request(path); const source = new Broadcast(); sources.push(source); @@ -120,8 +120,8 @@ for (const failovers of [0, 1, 16, 128]) entries.push({ primary, ar, br, held }); } const epoch = Epoch.mint(); - origin.dynamicRoute(prefix, { epoch }); - for (let i = 0; i < extraRoutes; i++) origin.dynamicRoute(prefix, { epoch, cost: BigInt(i + 1) }); + origin.requestsRoute(prefix, { epoch }); + for (let i = 0; i < extraRoutes; i++) origin.requestsRoute(prefix, { epoch, cost: BigInt(i + 1) }); const pending = []; for (const entry of entries) { entry.primary.close(); @@ -183,7 +183,7 @@ for (const operation of ["cancel-forward", "cancel-reverse", "drain-local"]) const settled: number[] = []; for (let round = 0; round < 4; round++) { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("pending")); + const dynamic = origin.requestsRoute(Path.from("pending")); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const names = Array.from({ length: paths }, (_, i) => Path.from(`pending/${i}`)); @@ -241,7 +241,7 @@ for (const survivor of [false, true]) const origin = new Producer(); const prefix = Path.from("competing"); const path = Path.from("competing/touched"); - for (let i = 0; i < routes; i++) origin.dynamicRoute(prefix, { cost: BigInt(i) }); + for (let i = 0; i < routes; i++) origin.requestsRoute(prefix, { cost: BigInt(i) }); const wire = wireOf(origin.consume()); const kept = survivor ? new AbortController() : undefined; const remaining = kept ? wire.demand(path, undefined, kept.signal).catch(() => {}) : undefined; diff --git a/js/net/src/broadcast.ts b/js/net/src/broadcast.ts index 453c665076d..fb652688be4 100644 --- a/js/net/src/broadcast.ts +++ b/js/net/src/broadcast.ts @@ -59,7 +59,7 @@ class BroadcastState { requests = new Map(); lookups = new WeakMap(); // Whether something answers on-demand track requests: a wire layer's consumed broadcast, or a - // publisher that has started pulling them. The counterpart of a live Rust `broadcast::Dynamic`; + // publisher that has started pulling them. The counterpart of a live Rust `broadcast::Requests`; // without one, a track nobody publishes is `NotFound` rather than a request nobody will answer. served = false; // Live consumer handles sharing this state (see {@link Consumer.clone}). diff --git a/js/net/src/connection/forward.ts b/js/net/src/connection/forward.ts index 505b3f972cd..664ec4f8a02 100644 --- a/js/net/src/connection/forward.ts +++ b/js/net/src/connection/forward.ts @@ -9,7 +9,7 @@ import { type Dispose, race } from "@moq/signals"; import type * as Announce from "../announced.ts"; import { type Route, routesEqual } from "../hop.ts"; import { coveringPrefixes, hooks } from "../internal.ts"; -import type { Dynamic, Producer as OriginProducer, RequestSlot } from "../origin.ts"; +import type { Producer as OriginProducer, RequestSlot, Requests } from "../origin.ts"; import * as Path from "../path.ts"; import { after } from "../util/timer.ts"; import { wireOf } from "../wire.ts"; @@ -39,7 +39,7 @@ interface Interest { * request handing over to another never retracts it. The first reporter drives it. */ interface Reported { - handle: Dynamic; + handle: Requests; /** Each request's latest route for the prefix. */ readonly reporters: Map; } @@ -289,7 +289,7 @@ export function forwardAnnounced(conn: Established, origin: OriginProducer): voi } /** Answer the requests under a received route by consuming them from the session. */ -async function drive(handle: Dynamic, conn: Established): Promise { +async function drive(handle: Requests, conn: Established): Promise { const session = wireOf(conn); try { for await (const request of handle.requested()) { diff --git a/js/net/src/connection/pool.test.ts b/js/net/src/connection/pool.test.ts index e971e1d6af6..9479bd6d6a5 100644 --- a/js/net/src/connection/pool.test.ts +++ b/js/net/src/connection/pool.test.ts @@ -263,7 +263,7 @@ test("a borrowed connection origin exposes live routes and dynamic serving", asy announcement = event; }); const prefix = Path.from("on-demand"); - const route = table.dynamicRoute(prefix); + const route = table.requestsRoute(prefix); await advance(); expect(announcement).toMatchObject({ kind: "start", prefix }); let withdrawal: unknown; diff --git a/js/net/src/hop.ts b/js/net/src/hop.ts index b28e22e4473..f48c4e5e64d 100644 --- a/js/net/src/hop.ts +++ b/js/net/src/hop.ts @@ -91,7 +91,7 @@ export const Cost = { /** * The path a route took through the mesh and what using it costs. * - * The metadata half of an advertisement: an origin `dynamic()` pairs it with the + * The metadata half of an advertisement: an origin `requests()` pairs it with the * pattern it covers, a broadcast `announce()` with the broadcast's exact path, and * an announce event carries it so consumers can read it back. */ diff --git a/js/net/src/ietf/publisher.test.ts b/js/net/src/ietf/publisher.test.ts index c6bf8a7bf72..93725115f6d 100644 --- a/js/net/src/ietf/publisher.test.ts +++ b/js/net/src/ietf/publisher.test.ts @@ -339,7 +339,7 @@ test("TRACK_STATUS outside the grant is refused on every draft", async () => { const session = new NativeSession(pair.server, version, true); const grant = new Signal(nothing()); const { pub, origin } = publisher(pair.server, { session, grant }); - const requests = origin.dynamicRoute(Path.from("room")).requested(); + const requests = origin.requestsRoute(Path.from("room")).requested(); const outside = requestStream(version); await pub.runTrackStatusRequest(trackStatus("room"), outside.stream); @@ -366,7 +366,7 @@ test("a second GOAWAY on an unanswered SUBSCRIBE closes the session", async () = const pair = createMockTransportPair(ALPNS[version]); const session = new NativeSession(pair.server, version, true); const { pub, origin } = publisher(pair.server, { session }); - const requests = origin.dynamic(Path.from("room")).requested(); + const requests = origin.requests(Path.from("room")).requested(); const held = requestStream(version); const task = pub.runSubscribe( @@ -422,7 +422,7 @@ test("a cancelled TRACK_STATUS releases its demand on every draft", async () => const pair = createMockTransportPair(ALPNS[version]); const session = new NativeSession(pair.server, version, true); const { pub, origin } = publisher(pair.server, { session }); - const requests = origin.dynamicRoute(Path.from("room")).requested(); + const requests = origin.requestsRoute(Path.from("room")).requested(); // The broadcast is still resolving: its handler never answers. const early = requestStream(version); @@ -472,7 +472,7 @@ test("a SUBSCRIBE withdrawn during setup releases its demand on every draft", as const pair = createMockTransportPair(ALPNS[version]); const session = new NativeSession(pair.server, version, true); const { pub, origin } = publisher(pair.server, { session }); - const requests = origin.dynamicRoute(Path.from("room")).requested(); + const requests = origin.requestsRoute(Path.from("room")).requested(); // The broadcast is still resolving: its handler never answers. const early = requestStream(version); @@ -667,7 +667,7 @@ test("reserved namespace requests get DOES_NOT_EXIST while other dot namespaces // Navigation segments cannot be published. A covering application // route still proves these reserved requests are refused before lookup. const navigation = path.split("/")[0] === "."; - const claim = navigation ? origin.dynamic(Path.empty()) : undefined; + const claim = navigation ? origin.requests(Path.empty()) : undefined; const requested = claim?.requested().next(); const broadcast = navigation ? undefined : publish(origin, Path.from(path)); const track = broadcast?.createTrack("video", { timescale: Timescale.MILLI }); @@ -1215,7 +1215,7 @@ test("a subscription outside a covering route's claim does not hear it", async ( const pair = createMockTransportPair(ALPN.DRAFT_18); const { pub, origin } = publisher(pair.server, { requiresSolicitation: true }); const chat = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.subtree(Path.from("room/chat"))])); - const dynamic = chat.dynamicRoute(Path.from("room")); + const dynamic = chat.requestsRoute(Path.from("room")); const subscription = await Stream.open(pair.client, { version: VERSION }); const accepted = await Stream.accept(pair.server, VERSION); @@ -1247,8 +1247,8 @@ test("a subscription hears the best covering route its claim allows", async () = const { pub, origin } = publisher(pair.server, { requiresSolicitation: true }); const scoped = (path: string) => origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.subtree(Path.from(path))])); - const chat = scoped("room/chat").dynamicRoute(Path.from("room"), { cost: 1n }); - const video = scoped("room/video").dynamicRoute(Path.from("room"), { cost: 5n }); + const chat = scoped("room/chat").requestsRoute(Path.from("room"), { cost: 1n }); + const video = scoped("room/video").requestsRoute(Path.from("room"), { cost: 5n }); const subscription = await Stream.open(pair.client, { version: VERSION }); const accepted = await Stream.accept(pair.server, VERSION); @@ -1288,8 +1288,8 @@ test("a subscription hears a broader covering route when the narrowest cannot se }); const chat = origin .scope(Path.empty(), new Path.Patterns([Path.Pattern.subtree(Path.from("tenant/chat"))])) - .dynamicRoute(Path.from("tenant")); - const broad = origin.dynamicRoute(Path.empty(), { cost: 5n }); + .requestsRoute(Path.from("tenant")); + const broad = origin.requestsRoute(Path.empty(), { cost: 5n }); const subscription = await Stream.open(pair.client, { version: VERSION }); const accepted = await Stream.accept(pair.server, VERSION); @@ -1326,7 +1326,7 @@ test("a covering route's claim is compared relative to the served root", async ( requiresSolicitation: true, }); const chat = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.subtree(Path.from("tenant/room/chat"))])); - const dynamic = chat.dynamicRoute(Path.from("tenant/room")); + const dynamic = chat.requestsRoute(Path.from("tenant/room")); const subscription = await Stream.open(pair.client, { version: VERSION }); const accepted = await Stream.accept(pair.server, VERSION); diff --git a/js/net/src/integration.test.ts b/js/net/src/integration.test.ts index fd087c7d256..d653c0040d2 100644 --- a/js/net/src/integration.test.ts +++ b/js/net/src/integration.test.ts @@ -962,7 +962,7 @@ test("integration: a peer is served the cheaper route it was offered, not the lo const localPublication = origin.createBroadcast(path); const local = localPublication.broadcast; localPublication.announce({ epoch, cost: 5n }); - const dynamic = origin.dynamicRoute(path, { epoch, cost: 1n }); + const dynamic = origin.requestsRoute(path, { epoch, cost: 1n }); const [client, server] = await Promise.all([ connect(url, { transport: pair.client }), @@ -2727,7 +2727,7 @@ test("create then announce is discoverable on the wire", async () => { test("a handle serves a request under live/** over the wire", async () => { const pair = createMockTransportPair(Lite.ALPN_06); const origin = new OriginProducer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const serving = (async () => { for await (const request of handle.requested()) { diff --git a/js/net/src/lite/publisher.test.ts b/js/net/src/lite/publisher.test.ts index a4f98abb92a..6087e2a02c4 100644 --- a/js/net/src/lite/publisher.test.ts +++ b/js/net/src/lite/publisher.test.ts @@ -666,7 +666,7 @@ async function servedSubscription( broadcast = new BroadcastProducer(); const front = new Front(); front.serve(broadcast.consume()); - const dynamic = origin.dynamicRoute(Path.from("test")); + const dynamic = origin.requestsRoute(Path.from("test")); void (async () => { for await (const request of dynamic.requested()) hooks.acceptRequest(request, front.consumer); })(); @@ -2518,7 +2518,7 @@ test("lite draft-06: closing while announces wait for the setup grant does not h test("lite draft-06: a grant that shrinks while a TRACK resolves refuses it", async () => { const pair = createMockTransportPair(ALPN_06); const origin = new OriginProducer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const requests = handle.requested(); const grant = new Signal(grantOf("live")); const publisher = new Publisher(pair.server, Version.DRAFT_06, randomHop(), origin.consume(), { @@ -2559,7 +2559,7 @@ test("lite draft-06: a grant that shrinks while a TRACK resolves refuses it", as test("lite draft-06: a grant that shrinks while TRACK_INFO is blocked resets it", async () => { const pair = createMockTransportPair(ALPN_06); const origin = new OriginProducer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const requests = handle.requested(); const grant = new Signal(grantOf("live")); const publisher = new Publisher(pair.server, Version.DRAFT_06, randomHop(), origin.consume(), { @@ -2622,7 +2622,7 @@ test("lite draft-06: a grant that shrinks while TRACK_INFO is blocked resets it" test("lite draft-06: a grant that shrinks while the broadcast resolves resets the subscription", async () => { const pair = createMockTransportPair(ALPN_06); const origin = new OriginProducer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const requests = handle.requested(); const grant = new Signal(grantOf("live")); const publisher = new Publisher(pair.server, Version.DRAFT_06, randomHop(), origin.consume(), { diff --git a/js/net/src/lite/tracks.test.ts b/js/net/src/lite/tracks.test.ts index 9574c45028e..036b8180c94 100644 --- a/js/net/src/lite/tracks.test.ts +++ b/js/net/src/lite/tracks.test.ts @@ -411,7 +411,7 @@ test("a newer listing of a broadcast on one session replaces the older", async ( test("a path served through a covering prefix route is NOT_FOUND", async () => { const origin = new OriginProducer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); void (async () => { for await (const request of dynamic.requested()) { const served = new BroadcastProducer(); @@ -428,7 +428,7 @@ test("a path served through a covering prefix route is NOT_FOUND", async () => { test("a local read through a covering prefix route is NOT_FOUND, and through its exact route lists", async () => { const origin = new OriginProducer(); for (const prefix of ["room", "room/bob"]) { - const dynamic = origin.dynamicRoute(Path.from(prefix)); + const dynamic = origin.requestsRoute(Path.from(prefix)); void (async () => { for await (const request of dynamic.requested()) { const served = new BroadcastProducer(); @@ -528,7 +528,7 @@ test("an epoch-pinned front lists its serving route's tracks", async () => { test("an epoch-pinned front served through a covering prefix route is NOT_FOUND", async () => { const origin = new OriginProducer(); - const dynamic = origin.dynamicRoute(Path.from("room"), { + const dynamic = origin.requestsRoute(Path.from("room"), { epoch: Epoch.parse("01900000-0000-7000-8000-000000000001"), }); void (async () => { diff --git a/js/net/src/origin-demand.test.ts b/js/net/src/origin-demand.test.ts index 0b5fb78344d..f8a947dd9d9 100644 --- a/js/net/src/origin-demand.test.ts +++ b/js/net/src/origin-demand.test.ts @@ -28,7 +28,7 @@ test.each(["lite", "ietf", "fetch", "track"] as const)( async (kind) => { const pair = createMockTransportPair(); const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const publisher = kind === "ietf" ? new IetfPublisher({ @@ -107,7 +107,7 @@ test.each(["lite", "ietf", "fetch", "track"] as const)( test("last cancellation finishes the internal wait and discards a late consumer", async () => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const hold = new AbortController(); const wait = wireOf(origin.consume()).demand(path, undefined, hold.signal); @@ -150,7 +150,7 @@ test.each([true, false])( "shared local/remote demand is withdrawn whichever leaves last (local first: %s)", async (localFirst) => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const hold = new AbortController(); const wait = wireOf(origin.consume()) @@ -194,7 +194,7 @@ test.each([ ] as const)("cancelling one waiter preserves a second %s requester across %i routes", async (other, routes) => { const origin = new Producer(); const prefix = Path.from("room"); - const dynamics = Array.from({ length: routes }, (_, i) => origin.dynamicRoute(prefix, { cost: BigInt(i) })); + const dynamics = Array.from({ length: routes }, (_, i) => origin.requestsRoute(prefix, { cost: BigInt(i) })); const hold = new AbortController(); const wire = wireOf(origin.consume()); const first = wire.demand(path, undefined, hold.signal).catch(() => undefined); @@ -223,7 +223,7 @@ test.each([ test("an already cancelled signal never enqueues or subscribes to abort", async () => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const hold = new AbortController(); hold.abort(); @@ -245,7 +245,7 @@ test.each(["accept", "reject", "cancel"] as const)( "%s releases the abort listener without closing a shared producer", async (action) => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const source = new Broadcast(); const keeper = source.consume(); @@ -281,12 +281,12 @@ test.each(["accept", "reject", "cancel"] as const)( test("a pending local request changing routes withdraws the old route's work", async () => { const origin = new Producer(); - const first = origin.dynamicRoute(Path.from("room"), { cost: 5n }); + const first = origin.requestsRoute(Path.from("room"), { cost: 5n }); const a = first.requested(); const local = origin.request(path); const old = (await a.next()).value; if (!old) throw new Error("expected a pending request"); - const second = origin.dynamicRoute(Path.from("room"), { cost: 1n }); + const second = origin.requestsRoute(Path.from("room"), { cost: 1n }); const b = second.requested(); const fresh = (await b.next()).value; if (!fresh) throw new Error("expected a pending request"); @@ -314,7 +314,7 @@ test("a pending local request changing routes withdraws the old route's work", a test("cancelling an old epoch waiter does not decrement a new epoch's demand", async () => { const origin = new Producer(); const epoch = Epoch.mint(); - const dynamic = origin.dynamicRoute(Path.from("room"), { epoch }); + const dynamic = origin.requestsRoute(Path.from("room"), { epoch }); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const hold = new AbortController(); @@ -346,8 +346,8 @@ test.each(["answer", "release"] as const)( const origin = new Producer(); const epoch = Epoch.mint(); const prefix = Path.from("room"); - const a = origin.dynamicRoute(prefix, { epoch, cost: 1n }); - const b = origin.dynamicRoute(prefix, { epoch, cost: 5n }); + const a = origin.requestsRoute(prefix, { epoch, cost: 1n }); + const b = origin.requestsRoute(prefix, { epoch, cost: 5n }); const ar = a.requested(); const br = b.requested(); const held = origin.request(path); @@ -355,7 +355,7 @@ test.each(["answer", "release"] as const)( hooks.acceptRequest((await ar.next()).value, source); await settle(); // Another instance wins new requests. The old handle stays on its own epoch. - const c = origin.dynamicRoute(prefix, { epoch: Epoch.mint(), cost: 0n }); + const c = origin.requestsRoute(prefix, { epoch: Epoch.mint(), cost: 0n }); a.close(); await settle(); const pending = (await br.next()).value; @@ -405,8 +405,8 @@ test.each([0, 1])( const sources: Broadcast[] = []; for (let i = 0; i < 2; i++) { const epoch = Epoch.parse(`00000000-0000-7000-8000-00000000000${i + 1}`); - const primary = origin.dynamicRoute(prefix, { epoch, cost: 0n }); - const standby = origin.dynamicRoute(prefix, { epoch, cost: 1n }); + const primary = origin.requestsRoute(prefix, { epoch, cost: 0n }); + const standby = origin.requestsRoute(prefix, { epoch, cost: 1n }); const ar = primary.requested(); const br = standby.requested(); const held = origin.request(path); @@ -416,7 +416,7 @@ test.each([0, 1])( await settle(); entries.push({ primary, ar, br, held }); } - origin.dynamicRoute(prefix, { epoch: Epoch.parse("00000000-0000-7000-8000-000000000003") }); + origin.requestsRoute(prefix, { epoch: Epoch.parse("00000000-0000-7000-8000-000000000003") }); const pending = []; for (const entry of entries) { entry.primary.close(); @@ -457,7 +457,7 @@ test.each([0, 1])( test("a normal FETCH request FIN keeps unanswered origin demand alive", async () => { const pair = createMockTransportPair(); const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const publisher = new LitePublisher(pair.server, LiteVersion.DRAFT_06, randomHop(), origin.consume()); let input!: ReadableStreamDefaultController; @@ -498,7 +498,7 @@ test.each(["accept", "reject"] as const)( "cancellation racing %s releases only the cancelled waiter", async (answer) => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const hold = new AbortController(); @@ -527,7 +527,7 @@ test.each(["accept", "reject"] as const)( test.each([true, false])("last waiter cancellation and accept in one turn (cancel first: %s)", async (cancelFirst) => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const hold = new AbortController(); @@ -568,7 +568,7 @@ test.each([true, false])("last waiter cancellation and accept in one turn (cance test.each([true, false])("local demand survives same-turn cancellation only when rejoined: %s", async (rejoin) => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const local = origin.request(path); const hold = new AbortController(); @@ -614,7 +614,7 @@ test.each([true, false])("local demand survives same-turn cancellation only when test("queued cancellation preserves order, replacement identity, and empty-queue wakeup", async () => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const holds = Array.from({ length: 4 }, () => new AbortController()); @@ -640,7 +640,7 @@ test("queued cancellation preserves order, replacement identity, and empty-queue test("reset clears queued work while a handler is suspended and admits the new epoch", async () => { const origin = new Producer(); const epoch = Epoch.mint(); - const dynamic = origin.dynamicRoute(Path.from("room"), { epoch }); + const dynamic = origin.requestsRoute(Path.from("room"), { epoch }); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); const waits = [path, Path.from("room/obsolete")].map((name) => wire.demand(name, epoch).catch(() => {})); @@ -664,7 +664,7 @@ test("reset clears queued work while a handler is suspended and admits the new e test("concurrent handlers consume queued requests once across empty batches", async () => { const origin = new Producer(); - const dynamic = origin.dynamicRoute(Path.from("room")); + const dynamic = origin.requestsRoute(Path.from("room")); const handlers = [dynamic.requested(), dynamic.requested()]; const wire = wireOf(origin.consume()); const waits: Promise[] = []; diff --git a/js/net/src/origin-request.test.ts b/js/net/src/origin-request.test.ts index fb6f1315128..019e3e68530 100644 --- a/js/net/src/origin-request.test.ts +++ b/js/net/src/origin-request.test.ts @@ -150,7 +150,7 @@ test("announced requests follow the serving prefix, ignoring descendants and re- const origin = new Producer(); const source = new BroadcastProducer(); const keeper = source.consume(); - const prefix = origin.dynamicRoute(Path.from("pool")); + const prefix = origin.requestsRoute(Path.from("pool")); const serving = (async () => { for await (const request of prefix.requested()) hooks.acceptRequest(request, source.consume()); })(); @@ -188,7 +188,7 @@ test("announced requests follow the serving prefix, ignoring descendants and re- test("an announced request ignores a covering route whose scope excludes its path", async () => { const origin = new Producer(); const scoped = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("room/*/chat")])); - const prefix = scoped.dynamicRoute(Path.from("room/alice")); + const prefix = scoped.requestsRoute(Path.from("room/alice")); const exactPublication = origin.createBroadcast(Path.from("room/alice")); const exact = exactPublication.broadcast; exactPublication.announce({ cost: 5n }); @@ -206,7 +206,7 @@ test("an announced request follows an epochless route replaced by an identical o const origin = new Producer(); const path = Path.from("room"); const serve = (source: BroadcastProducer) => { - const route = origin.dynamicRoute(path); + const route = origin.requestsRoute(path); void (async () => { for await (const request of route.requested()) hooks.acceptRequest(request, source.consume()); })(); @@ -237,7 +237,7 @@ test("an origin closing settles an announced request a served route resolved", a const origin = new Producer(); const path = Path.from("room"); const source = new BroadcastProducer(); - const route = origin.dynamicRoute(path); + const route = origin.requestsRoute(path); void (async () => { for await (const request of route.requested()) hooks.acceptRequest(request, source.consume()); })(); @@ -256,7 +256,7 @@ test("an origin closing settles an announced request a served route resolved", a test("an announced request keeps a refusal that lands with a re-price", async () => { const origin = new Producer(); const path = Path.from("room"); - const route = origin.dynamicRoute(path); + const route = origin.requestsRoute(path); const requested = route.requested(); const request = origin.request(path, { announced: true }); const pending = (await requested.next()).value; @@ -287,7 +287,7 @@ for (const received of [false, true]) { const events: string[] = []; const stop = wireOf(origin).interests((prefix, wanted) => events.push(`${prefix} ${wanted}`)); const source = new BroadcastProducer(); - const route = received ? wireOf(origin).receive(path, Route.default) : origin.dynamicRoute(path); + const route = received ? wireOf(origin).receive(path, Route.default) : origin.requestsRoute(path); void (async () => { for await (const request of route.requested()) hooks.acceptRequest(request, source.consume()); })(); @@ -311,7 +311,7 @@ for (const received of [false, true]) { test("a claim answer is hidden until published under its own epoch", async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(path); const pending = (await requests.next()).value; @@ -333,7 +333,7 @@ test("a claim answer is hidden until published under its own epoch", async () => test("a prepared answer cannot announce itself before publish", async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(path); const pending = (await requests.next()).value; @@ -356,7 +356,7 @@ test("a prepared answer cannot announce itself before publish", async () => { test("an application claim cannot accept an arbitrary broadcast", async () => { const origin = new Producer(); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(Path.from("room/alice")); const pending: Request | undefined = (await requests.next()).value; @@ -370,7 +370,7 @@ test("an application claim cannot accept an arbitrary broadcast", async () => { test("closing a prepared answer refuses the request and closes its broadcast", async () => { const origin = new Producer(); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(Path.from("room/alice")); const pending = (await requests.next()).value; @@ -389,7 +389,7 @@ test("closing a prepared answer refuses the request and closes its broadcast", a test("an answer prepared for an abandoned claim is never announced", async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(path); const pending = (await requests.next()).value; @@ -409,7 +409,7 @@ for (const cleanup of ["close", "dispose", "broadcast"] as const) { test(`prepared ${cleanup} releases shared requesters and admits a new request`, async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const first = origin.request(path); const pending = (await requests.next()).value; @@ -445,7 +445,7 @@ for (const cleanup of ["close", "dispose", "broadcast"] as const) { test("a throwing handler disposes its prepared answer and leaves the claim answerable", async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const failed = (async () => { for await (const request of claim.requested()) { using prepared = request.prepare(Epoch.mint()); @@ -474,7 +474,7 @@ test("a throwing handler disposes its prepared answer and leaves the claim answe test("using transfers a published answer without closing it on disposal", async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const request = origin.request(path); const pending = (await requests.next()).value; @@ -503,7 +503,7 @@ for (const cleanup of ["close", "dispose", "broadcast", "publish"] as const) { test(`an old prepared ${cleanup} cannot refuse the next request for its path`, async () => { const origin = new Producer(); const path = Path.from("room/alice"); - const claim = origin.dynamic(Path.from("room")); + const claim = origin.requests(Path.from("room")); const requests = claim.requested(); const first = origin.request(path); const pending = (await requests.next()).value; @@ -538,7 +538,7 @@ for (const cleanup of ["close", "dispose", "broadcast", "publish"] as const) { test("a forwarded request cannot be prepared by setting a publisher property", async () => { const origin = new Producer(); - const route = origin.dynamicRoute(Path.from("room")); + const route = origin.requestsRoute(Path.from("room")); const requests = route.requested(); const request = origin.request(Path.from("room/alice")); const pending = (await requests.next()).value; diff --git a/js/net/src/origin.test.ts b/js/net/src/origin.test.ts index 8d0d18706fa..33c4e7d0179 100644 --- a/js/net/src/origin.test.ts +++ b/js/net/src/origin.test.ts @@ -93,7 +93,7 @@ test("a borrowed table exposes dynamic serving and a live scoped broadcast map", expect(changes.some((value) => value.get(localPath)?.cost === 4n)).toBe(true); const prefix = Path.from("room"); - const dynamic = table.dynamicRoute(prefix, { cost: 2n }); + const dynamic = table.requestsRoute(prefix, { cost: 2n }); await new Promise((resolve) => setImmediate(resolve)); expect(live.peek().get(prefix)).toEqual(Route.normalize({ cost: 2n })); dynamic.updateRoute({ cost: 3n }); @@ -1083,7 +1083,7 @@ test("the cheapest received route competes with the local broadcast, not the new test("a handle serves a request under live", async () => { const origin = new Producer(); const consumer = origin.consume(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); expect(await consumer.announced().next()).toMatchObject({ prefix: Path.from("live"), kind: "start" }); @@ -1110,7 +1110,7 @@ test("a handle serves a request under live", async () => { test("an originated route refuses a broadcast a session delivered", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const it = handle.requested(); const pending = wireOf(origin.consume()).demand(Path.from("live/cam")); const { value: req } = await it.next(); @@ -1153,7 +1153,7 @@ test("a received route still serves a broadcast a session delivered", async () = test("a re-priced route is delivered as an update", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const announced = origin.consume().announced(); expect(await announced.next()).toMatchObject({ prefix: Path.from("live"), kind: "start" }); handle.updateRoute({ cost: 5n }); @@ -1166,7 +1166,7 @@ test("a re-priced route is delivered as an update", async () => { test("an accepted dynamic broadcast is retired when it closes", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const path = Path.from("live/cam"); const request = origin.request(path); const it = handle.requested(); @@ -1198,7 +1198,7 @@ test("an accepted dynamic broadcast is retired when it closes", async () => { test("reject surfaces the error from demand", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const consumer = origin.consume(); const it = handle.requested(); const pending = wireOf(consumer).demand(Path.from("live/cam")); @@ -1215,8 +1215,8 @@ test("a peer is offered and served the cheapest originated route", async () => { const origin = new Producer(); const consumer = origin.consume(); const prefix = Path.from("live"); - const cheap = origin.dynamicRoute(prefix, { epoch: EPOCH, cost: 1n }); - const pricey = origin.dynamicRoute(prefix, { epoch: EPOCH, cost: 10n }); + const cheap = origin.requestsRoute(prefix, { epoch: EPOCH, cost: 1n }); + const pricey = origin.requestsRoute(prefix, { epoch: EPOCH, cost: 10n }); expect(wireOf(consumer).advertised.peek()?.get(prefix)?.[0]?.route).toEqual( Route.normalize({ epoch: EPOCH, cost: 1n }), @@ -1248,7 +1248,7 @@ test("a peer is offered and served the cheapest originated route", async () => { test("a shared reject still surfaces from demand", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const consumer = origin.consume(); const it = handle.requested(); @@ -1270,7 +1270,7 @@ test("a shared reject still surfaces from demand", async () => { test("a request refusal does not keep demand from asking again", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const consumer = origin.consume(); const it = handle.requested(); @@ -1294,7 +1294,7 @@ test("a request refusal does not keep demand from asking again", async () => { test("advancing requested without settling rejects the previous request", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const consumer = origin.consume(); const it = handle.requested(); @@ -1318,7 +1318,7 @@ test("advancing requested without settling rejects the previous request", async test("a rejected request is not asked of the same route again", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const it = handle.requested(); const request = origin.request(Path.from("live/cam")); @@ -1633,8 +1633,8 @@ test("a request ends when its winning source goes, even with a standby", async ( test("a refusal is terminal, never falling through to a broader route", async () => { const origin = new Producer(); const consumer = origin.consume(); - const narrow = origin.dynamicRoute(Path.from("live")); - const wide = origin.dynamicRoute(Path.from("")); + const narrow = origin.requestsRoute(Path.from("live")); + const wide = origin.requestsRoute(Path.from("")); const wideRequests = wide.requested(); const wideAsked = wideRequests.next(); @@ -1670,8 +1670,8 @@ test("a better route's refusal ends a served request", async () => { // The narrower route is asked while the broad one keeps serving, then says no. A // costlier sibling at the same prefix could serve, but is never asked. - const narrow = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH, cost: 1n }); - const sibling = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH, cost: 2n }); + const narrow = origin.requestsRoute(Path.from("live"), { epoch: EPOCH, cost: 1n }); + const sibling = origin.requestsRoute(Path.from("live"), { epoch: EPOCH, cost: 2n }); const siblingRequests = sibling.requested(); const siblingAsked = siblingRequests.next(); const { value: req } = await narrow.requested().next(); @@ -1696,14 +1696,14 @@ test("a better route's refusal ends a served request", async () => { test("a refusal from a superseded route does not end the request", async () => { const origin = new Producer(); const consumer = origin.consume(); - const wide = origin.dynamicRoute(Path.from("")); + const wide = origin.requestsRoute(Path.from("")); const wideRequests = wide.requested(); const request = consumer.request(Path.from("live/cam")); const { value: stale } = await wideRequests.next(); // A narrower route takes over the pending request before the broad one answers. - const narrow = origin.dynamicRoute(Path.from("live")); + const narrow = origin.requestsRoute(Path.from("live")); const { value: req } = await narrow.requested().next(); stale?.reject(new Error("unserved")); await settle(); @@ -1725,7 +1725,7 @@ test("a refusal from a superseded route does not end the request", async () => { test("a refusal from a route a local broadcast superseded does not end the request", async () => { const origin = new Producer(); const consumer = origin.consume(); - const wide = origin.dynamicRoute(Path.from("live")); + const wide = origin.requestsRoute(Path.from("live")); const wideRequests = wide.requested(); const request = consumer.request(Path.from("live/cam")); @@ -1751,7 +1751,7 @@ test("a refusal from a route a local broadcast superseded does not end the reque test("close rejects queued requests as unroutable", async () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live")); + const handle = origin.requestsRoute(Path.from("live")); const waiting = handle.requested().next(); const request = origin.request(Path.from("live/cam")); const { value: req } = await waiting; @@ -1910,7 +1910,7 @@ test("a rooted producer shares the table and enforces its pattern union", async await new Promise((resolve) => setImmediate(resolve)); expect(() => scoped.request(Path.from("room/alice/deep"))).toThrow("outside the origin scope"); await new Promise((resolve) => setImmediate(resolve)); - expect(() => scoped.dynamicRoute(Path.from("other"))).toThrow("outside the origin scope"); + expect(() => scoped.requestsRoute(Path.from("other"))).toThrow("outside the origin scope"); await new Promise((resolve) => setImmediate(resolve)); expect(() => scoped.scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("other/**")]))).toThrow( "do not overlap", @@ -1938,8 +1938,8 @@ test("closing a derived handle releases only what it registered", async () => { const scoped = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.subtree(Path.from("room"))])); const wide = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.all()])); const inside = publish(scoped, Path.from("room/alice")); - const claim = scoped.dynamic(Path.from("room/claim")); - const ranked = wide.dynamic(Path.from("ranked")); + const claim = scoped.requests(Path.from("room/claim")); + const ranked = wide.requests(Path.from("ranked")); const peer = serve(scoped, Path.from("room/peer"), provider(new BroadcastProducer())); scoped.close(); @@ -1953,7 +1953,7 @@ test("closing a derived handle releases only what it registered", async () => { // A released handle refuses new work, so a borrower notices instead of publishing into nothing. expect(() => scoped.createBroadcast(Path.from("room/late")).broadcast).toThrow("origin handle is closed"); - scoped.dynamic(Path.from("room/late")).close(); + scoped.requests(Path.from("room/late")).close(); expect((await announcedView(origin)).peek().has(Path.from("room/late"))).toBe(false); // The owner and fresh handles keep working. @@ -2051,7 +2051,7 @@ test("closing a derived handle withdraws the sessions and answers attached throu test("a scoped dynamic only serves allowed paths and presents relative requests", async () => { const origin = new Producer(); const scoped = origin.scope(Path.from("tenant"), new Path.Patterns([Path.Pattern.parse("room/*/chat")])); - const dynamic = scoped.dynamicRoute(Path.from("room")); + const dynamic = scoped.requestsRoute(Path.from("room")); await new Promise((resolve) => setImmediate(resolve)); expect(dynamic.prefix).toBe(Path.from("room")); const denied = origin.request(Path.from("tenant/room/alice/video")); @@ -2099,7 +2099,7 @@ test("a scoped dynamic is announced only to readers its scope can serve", async const origin = new Producer(); const dynamic = origin .scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("*/chat")])) - .dynamicRoute(Path.empty()); + .requestsRoute(Path.empty()); const chat = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("room/chat")])); const video = origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("room/video")])); await new Promise((resolve) => setImmediate(resolve)); @@ -2116,8 +2116,8 @@ test("a scoped dynamic is announced only to readers its scope can serve", async test("a rooted reader presents the most specific covering route", async () => { const origin = new Producer(); - const narrow = origin.dynamicRoute(Path.from("room/alice"), { cost: 9n }); - const broad = origin.dynamicRoute(Path.from("room"), { cost: 1n }); + const narrow = origin.requestsRoute(Path.from("room/alice"), { cost: 9n }); + const broad = origin.requestsRoute(Path.from("room"), { cost: 1n }); const rooted = origin.scope(Path.from("room/alice"), new Path.Patterns([Path.Pattern.all()])); await new Promise((resolve) => setImmediate(resolve)); expect((await announcedView(rooted)).peek().get(Path.empty())?.cost).toBe(9n); @@ -2131,8 +2131,8 @@ test("a rooted reader presents the most specific covering route", async () => { test("a scoped reader picks the best route its scope can see at a prefix", async () => { const origin = new Producer(); const scoped = (pattern: string) => origin.scope(Path.empty(), new Path.Patterns([Path.Pattern.parse(pattern)])); - const chat = scoped("*/chat").dynamicRoute(Path.empty(), { cost: 1n }); - const video = scoped("*/video").dynamicRoute(Path.empty(), { cost: 5n }); + const chat = scoped("*/chat").requestsRoute(Path.empty(), { cost: 1n }); + const video = scoped("*/video").requestsRoute(Path.empty(), { cost: 5n }); const reader = scoped("room/video"); await new Promise((resolve) => setImmediate(resolve)); @@ -2159,7 +2159,7 @@ test("a scoped reader sees a local broadcast that only loses to a route outside const origin = new Producer(); const chat = origin .scope(Path.empty(), new Path.Patterns([Path.Pattern.parse("room/*/chat")])) - .dynamicRoute(Path.from("room/alice"), { epoch: EPOCH, cost: 0n }); + .requestsRoute(Path.from("room/alice"), { epoch: EPOCH, cost: 0n }); const localPublication = origin.createBroadcast(Path.from("room/alice")); const local = localPublication.broadcast; localPublication.announce({ epoch: EPOCH, cost: 5n }); @@ -2194,7 +2194,7 @@ test("broadcast handles carry the path they were created or requested at", async expect(clone?.path).toBe(Path.from("room/alice")); // A dynamic handler's standalone broadcast is named by the request, too. - const dynamic = origin.dynamicRoute(Path.from("live")); + const dynamic = origin.requestsRoute(Path.from("live")); const request = origin.request(Path.from("live/bob")); const pending = await dynamic.requested().next(); const served = new BroadcastProducer(); @@ -2238,7 +2238,7 @@ test("demand held across an epoch change asks again, unless it named the old epo const origin = new Producer(); const consumer = origin.consume(); const path = Path.from("live/cam"); - const handle = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const handle = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const it = handle.requested(); const pinned = wireOf(consumer).demand(path, EPOCH); const unpinned = wireOf(consumer).demand(path); @@ -2267,7 +2267,7 @@ test("a demand refused across an epoch change does not lose the carried demand's const origin = new Producer(); const consumer = origin.consume(); const path = Path.from("live/cam"); - const handle = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const handle = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const it = handle.requested(); const unpinned = wireOf(consumer).demand(path); const pinned = wireOf(consumer).demand(path, EPOCH); @@ -2287,7 +2287,7 @@ test("a demand refused across an epoch change does not lose the carried demand's test("demand held across an epoch round trip still asks again", async () => { const origin = new Producer(); const path = Path.from("live/cam"); - const handle = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const handle = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const it = handle.requested(); const demanded = wireOf(origin.consume()).demand(path); const { value: req } = await it.next(); @@ -2313,7 +2313,7 @@ test("demand held across an epoch round trip still asks again", async () => { test("re-pricing from the current route keeps the epoch", () => { const origin = new Producer(); - const handle = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH, cost: 5n }); + const handle = origin.requestsRoute(Path.from("live"), { epoch: EPOCH, cost: 5n }); handle.updateRoute({ ...handle.route, cost: 1n }); expect(handle.route).toEqual(Route.normalize({ epoch: EPOCH, cost: 1n })); @@ -2382,7 +2382,7 @@ test("a request held across an epoch change asks again and never takes the old h const origin = new Producer(); const prefix = Path.from("room"); const path = Path.from("room/cam"); - const dynamic = origin.dynamicRoute(prefix, { epoch: EPOCH }); + const dynamic = origin.requestsRoute(prefix, { epoch: EPOCH }); const unpinned = origin.consume().request(path); const pinned = origin.consume().request(path, { epoch: EPOCH }); const requests = dynamic.requested(); @@ -2416,7 +2416,7 @@ test.each([ const origin = new Producer(); const prefix = Path.from("live"); const path = Path.from("live/cam"); - const dynamic = origin.dynamicRoute(prefix, { epoch: from }); + const dynamic = origin.requestsRoute(prefix, { epoch: from }); const requests = dynamic.requested(); const announced = origin.consume().announced(); expect(await announced.next()).toMatchObject({ prefix, kind: "start" }); @@ -2498,7 +2498,7 @@ test.each([ test("an epoch update does not retain an answer that already closed", async () => { const origin = new Producer(); const path = Path.from("live/cam"); - const dynamic = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const dynamic = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const requests = dynamic.requested(); const held = origin.consume().request(path); const old = new BroadcastProducer(); @@ -2526,7 +2526,7 @@ test("an epoch update does not retain an answer that already closed", async () = test("an unread resolved request retains its broadcast until its last handle closes", async () => { const origin = new Producer(); const path = Path.from("live/cam"); - const dynamic = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const dynamic = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const requests = dynamic.requested(); const held = origin.consume().request(path); const old = new SessionBroadcast(); @@ -2546,7 +2546,7 @@ test("an unread resolved request retains its broadcast until its last handle clo test("a session's re-request after an epoch update asks the handler again", async () => { const origin = new Producer(); const path = Path.from("live/cam"); - const dynamic = origin.dynamicRoute(Path.from("live"), { epoch: EPOCH }); + const dynamic = origin.requestsRoute(Path.from("live"), { epoch: EPOCH }); const requests = dynamic.requested(); const wire = wireOf(origin.consume()); @@ -2576,8 +2576,8 @@ test("an update does not override route selection: another claim at the epoch ke const origin = new Producer(); const prefix = Path.from("live"); const path = Path.from("live/cam"); - const first = origin.dynamicRoute(prefix, { epoch: EPOCH, cost: 1n }); - const second = origin.dynamicRoute(prefix, { epoch: EPOCH, cost: 5n }); + const first = origin.requestsRoute(prefix, { epoch: EPOCH, cost: 1n }); + const second = origin.requestsRoute(prefix, { epoch: EPOCH, cost: 5n }); const firstRequests = first.requested(); const secondRequests = second.requested(); @@ -2651,7 +2651,7 @@ test("published names refuse navigation segments", () => { for (const name of ["room/./cam", "room/../cam", ".", ".."]) { const path = Path.from(name); expect(() => origin.createBroadcast(path).broadcast).toThrow(); - expect(() => origin.dynamic(path)).toThrow(); + expect(() => origin.requests(path)).toThrow(); expect(() => wireOf(origin).receive(path, Route.default)).toThrow(); } const scoped = origin.scope(Path.from("room/.."), new Path.Patterns([Path.Pattern.all()])); diff --git a/js/net/src/origin.ts b/js/net/src/origin.ts index ae96f898108..36c8cd4f930 100644 --- a/js/net/src/origin.ts +++ b/js/net/src/origin.ts @@ -335,7 +335,7 @@ function unroutable(): StreamError { return new StreamError(StreamCode.Unroutable, { message: "unroutable" }); } -/** A served route from {@link Producer.dynamic}: the queue a handler drains. */ +/** A served route from {@link Producer.requests}: the queue a handler drains. */ class ServeState { readonly root: Path.Valid; /** The prefix the route claims; every served path is at or beneath it. */ @@ -1080,14 +1080,14 @@ export interface Table { /** The available broadcasts under `scope`, as a live stream; see {@link Consumer.announced}. */ announced(scope?: Path.Pattern, options?: Announce.Options): Announce.Consumer; - /** Advertise a prefix and serve requests under it; see {@link Producer.dynamic}. */ - dynamic(prefix: Path.Valid): Dynamic; + /** Advertise a prefix and serve requests under it; see {@link Producer.requests}. */ + requests(prefix: Path.Valid): Requests; /** Insert a route with protocol metadata. @internal */ - dynamicRoute( + requestsRoute( prefix: Path.Valid, route?: Route | { epoch?: Route["epoch"]; hops?: Route["hops"]; cost?: Route["cost"]; auth?: Route["auth"] }, - ): Dynamic; + ): Requests; } /** Options for resolving a broadcast path. */ @@ -1113,7 +1113,7 @@ export interface RequestOptions { * Create a broadcast, populate its tracks, then {@link Publication.announce}: an * exact-path subscribe before the tracks exist is refused, and nobody can see or reach a * broadcast until it announces. To publish broadcasts on demand instead, claim a prefix with - * {@link dynamic} and answer the requests beneath it. + * {@link requests} and answer the requests beneath it. * * @public */ @@ -1284,15 +1284,15 @@ export class Producer implements Table { * advertises the covering prefix and rejects the rest as they are requested; * consumers narrow with a {@link Path.Pattern} locally. The advertisement is * visible to {@link Consumer.announced} and forwarded by sessions for as long as - * the returned {@link Dynamic} lives. A consumer resolving a path under it that + * the returned {@link Requests} lives. A consumer resolving a path under it that * no announced local broadcast wins is handed to the handle as a {@link Request}. */ - dynamic(prefix: Path.Valid): Dynamic { + requests(prefix: Path.Valid): Requests { return this.#insertRoute(prefix, Route.default, true, true); } /** Insert an originated claim with route metadata that answers through `hooks.acceptRequest`, for tests and benches. @internal */ - dynamicRoute( + requestsRoute( prefix: Path.Valid, route: | Route @@ -1302,13 +1302,13 @@ export class Producer implements Table { cost?: Route["cost"]; auth?: Route["auth"]; } = Route.default, - ): Dynamic { + ): Requests { return this.#insertRoute(prefix, Route.normalize(route), true, false); } /** * Land a route a peer announced, served through the returned handle. Same as - * {@link dynamic} but not originated, so a session never announces it back. + * {@link requests} but not originated, so a session never announces it back. * * @internal */ @@ -1322,11 +1322,11 @@ export class Producer implements Table { cost?: Route["cost"]; auth?: Route["auth"]; } = Route.default, - ): Dynamic { + ): Requests { return this.#insertRoute(prefix, Route.normalize(route), false, false); } - #insertRoute(prefix: Path.Valid, route: Route, originated: boolean, publishes: boolean): Dynamic { + #insertRoute(prefix: Path.Valid, route: Route, originated: boolean, publishes: boolean): Requests { prefix = this.#scope.prefix(prefix); publishPath(prefix); const server = new ServeState(this.#scope.root, prefix, originated); @@ -1557,7 +1557,7 @@ let makeDynamic: ( state: OriginState, retract: Dispose, publisher?: Producer, -) => Dynamic; +) => Requests; let makeRequest: (path: Path.Valid, server: ServeState) => Request; let finishRequest: (request: Request, err: Error) => void; @@ -2189,7 +2189,7 @@ export class Consumer { } /** - * A served route from {@link Producer.dynamic}: advertises a prefix and answers the + * A served route from {@link Producer.requests}: advertises a prefix and answers the * requests beneath it. * * Drop it (or {@link close}) to retract the route and reject anything still waiting @@ -2197,7 +2197,7 @@ export class Consumer { * * @public */ -export class Dynamic { +export class Requests { /** The prefix this handle advertises. */ readonly prefix: Path.Valid; @@ -2223,7 +2223,7 @@ export class Dynamic { static { makeDynamic = (prefix, entry, state, retract, publisher) => - new Dynamic(prefix, entry, state, retract, publisher); + new Requests(prefix, entry, state, retract, publisher); } /** The route this handle advertises. */ @@ -2306,7 +2306,7 @@ export class Dynamic { /** * A pending request for a broadcast to be served on demand. * - * Yielded by {@link Dynamic.requested}. {@link prepare} then {@link Prepared.publish} + * Yielded by {@link Requests.requested}. {@link prepare} then {@link Prepared.publish} * resolves it with a new exact-path broadcast; {@link reject} resolves it with an error. * Advancing the iterator or closing it without either rejects the request. * diff --git a/js/net/src/untimed.test.ts b/js/net/src/untimed.test.ts index 1a18e72115e..afcd35bb48a 100644 --- a/js/net/src/untimed.test.ts +++ b/js/net/src/untimed.test.ts @@ -131,7 +131,7 @@ test("a forwarded untimed track stays untimed", async () => { // Serve the downstream session from the upstream one. A JS origin refuses to serve a // broadcast a session delivered, so the forwarding node republishes a copy it produced. - const dynamic = relay.dynamicRoute(Path.from("test")); + const dynamic = relay.requestsRoute(Path.from("test")); const inputs: BroadcastConsumer[] = []; const forwarding = (async () => { for await (const request of dynamic.requested()) { diff --git a/js/net/src/wire.ts b/js/net/src/wire.ts index a572480e92d..9d16631d831 100644 --- a/js/net/src/wire.ts +++ b/js/net/src/wire.ts @@ -57,7 +57,7 @@ export interface OriginProducer { receive( prefix: Path.Valid, route?: Route | { epoch?: Route["epoch"]; hops?: Route["hops"]; cost?: Route["cost"]; auth?: Route["auth"] }, - ): origin.Dynamic; + ): origin.Requests; attach(discovery: boolean): Dispose; /** * Hold the origin's announcement streams overlapping `prefix` unsynced until diff --git a/js/watch/src/broadcast.test.ts b/js/watch/src/broadcast.test.ts index ed76cf9a62f..c0cbc91bbcb 100644 --- a/js/watch/src/broadcast.test.ts +++ b/js/watch/src/broadcast.test.ts @@ -36,7 +36,7 @@ function broadcast(name: string, paths: string[] = [name]): { source: Broadcast; } // Answer every request `claim` receives with a new exact broadcast, returning the answers. -function serve(claim: Origin.Dynamic, epoch?: Moq.Epoch.Valid): Moq.Broadcast.Producer[] { +function serve(claim: Origin.Requests, epoch?: Moq.Epoch.Valid): Moq.Broadcast.Producer[] { const answers: Moq.Broadcast.Producer[] = []; void (async () => { for await (const request of claim.requested()) @@ -494,7 +494,7 @@ describe("blind resolution", () => { await settle(); // Stand in for a claim answering the request. - const route = owner.dynamic(Path.from("blind.hang")); + const route = owner.requests(Path.from("blind.hang")); const requests = route.requested(); const next = await requests.next(); if (!next.value) throw new Error("expected a request"); @@ -607,7 +607,7 @@ describe("restart", () => { it("moves to a more specific announcement of another instance", async () => { const owner = new Origin.Producer(); const name = Path.from("pool/job.hang"); - const pool = owner.dynamic(Path.from("pool")); + const pool = owner.requests(Path.from("pool")); const answers = serve(pool); const source = new Broadcast({ origin: owner, name, enabled: true, announced: true, catalogFormat: "manual" }); await settle(); @@ -651,7 +651,7 @@ describe("restart", () => { // The exact route goes, which ends the request on it, and a prefix answers under the same // epoch before the table is read again. The player still has to ask again. exact.close(); - const pool = owner.dynamic(Path.from("pool")); + const pool = owner.requests(Path.from("pool")); const answers = serve(pool, epoch); await settle(); const resumed = source.out.active.peek(); @@ -669,7 +669,7 @@ describe("restart", () => { it("falls back to a covering prefix when the exact route ends", async () => { const owner = new Origin.Producer(); const name = Path.from("pool/job.hang"); - const pool = owner.dynamic(Path.from("pool")); + const pool = owner.requests(Path.from("pool")); const answers = serve(pool); const exact = publish(owner, name); const source = new Broadcast({ origin: owner, name, enabled: true, announced: true, catalogFormat: "manual" }); @@ -702,7 +702,7 @@ describe("refusal", () => { it("reports an unroutable refusal of a restarted publisher", async () => { const owner = new Origin.Producer(); const name = Path.from("room/live.hang"); - const first = owner.dynamic(Path.from("room")); + const first = owner.requests(Path.from("room")); const answers = serve(first); const source = new Broadcast({ origin: owner, name, enabled: true, announced: true, catalogFormat: "manual" }); await settle(); @@ -711,7 +711,7 @@ describe("refusal", () => { // The publisher restarts, and refuses with the same code an ended instance reports. first.close(); for (const answer of answers) answer.close(); - const second = owner.dynamic(Path.from("room")); + const second = owner.requests(Path.from("room")); const refused = await second.requested().next(); refused.value?.reject(new Moq.Error.Stream(Moq.StreamCode.Unroutable, { message: "refused" })); await settle(); @@ -747,7 +747,7 @@ describe("refusal", () => { for (const announced of [true, false]) { it(`reports a refusal until a fresh request (announced: ${announced})`, async () => { const owner = new Origin.Producer(); - const route = owner.dynamic(Path.from("room")); + const route = owner.requests(Path.from("room")); const requests = route.requested(); const name = new Signal(Path.from("room/refused.hang")); const enabled = new Signal(true); @@ -1029,7 +1029,7 @@ describe("wildcard renditions", () => { await settle(); expect(videoRenditions(source)).toEqual(["source"]); - const worker = owner.dynamic(Path.from(".pro/transcode")); + const worker = owner.requests(Path.from(".pro/transcode")); const requests = worker.requested(); await settle(); expect(videoRenditions(source)).toEqual(["source", "transcode"]); @@ -1075,8 +1075,8 @@ describe("wildcard renditions", () => { try { // A catch-all (an archive) and a narrower pool both cover the derived path. - const archive = owner.dynamic(Path.empty()); - const worker = owner.dynamic(Path.from(".pro/transcode")); + const archive = owner.requests(Path.empty()); + const worker = owner.requests(Path.from(".pro/transcode")); await settle(); expect(videoRenditions(source)).toEqual(["source", "transcode"]); diff --git a/kt/moq/MIGRATE.md b/kt/moq/MIGRATE.md index 747ce1a5343..459ae34e936 100644 --- a/kt/moq/MIGRATE.md +++ b/kt/moq/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `dynamic()` on `OriginProducer`, `BroadcastProducer`, `TrackProducer`, and `TrackRequest` to `requests()`. +Their handles `OriginDynamic`, `BroadcastDynamic`, and `TrackDynamic` are `OriginRequests`, `BroadcastRequests`, and `TrackRequests`; their methods and flows are unchanged. + ### `Allocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `Bandwidth` is `Allocator`, `bandwidth()` is `allocator()`, and `Reservation.grant()` is `rate()`. The producers' `bandwidth` option keeps its name. diff --git a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Aliases.kt b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Aliases.kt index 7ad1b9f750e..19d384bf4c8 100644 --- a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Aliases.kt +++ b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Aliases.kt @@ -42,7 +42,7 @@ typealias OriginConfig = uniffi.moq.MoqOriginConfig /** The subscribe side of an origin: discover and request published broadcasts. */ typealias OriginConsumer = uniffi.moq.MoqOriginConsumer /** A served route: advertises a path prefix and yields broadcast requests beneath it. */ -typealias OriginDynamic = uniffi.moq.MoqOriginDynamic +typealias OriginRequests = uniffi.moq.MoqOriginRequests /** A requested broadcast not yet accepted: fulfill it with a producer or reject it. */ typealias BroadcastRequest = uniffi.moq.MoqBroadcastRequest /** A claim answer being filled before its exact route is announced. */ @@ -76,13 +76,13 @@ typealias BroadcastProducer = uniffi.moq.MoqBroadcastProducer /** The read side of a broadcast: subscribe to its catalog and tracks. */ typealias BroadcastConsumer = uniffi.moq.MoqBroadcastConsumer /** Receives tracks requested from a dynamically served broadcast. */ -typealias BroadcastDynamic = uniffi.moq.MoqBroadcastDynamic +typealias BroadcastRequests = uniffi.moq.MoqBroadcastRequests /** The write side of a raw track: append groups of frames. */ typealias TrackProducer = uniffi.moq.MoqTrackProducer /** A subscriber-requested track not yet accepted: accept it for a [TrackProducer] or abort it. */ typealias TrackRequest = uniffi.moq.MoqTrackRequest /** A stream of the fills readers of one track need: runs of groups the cache lacks. */ -typealias TrackDynamic = uniffi.moq.MoqTrackDynamic +typealias TrackRequests = uniffi.moq.MoqTrackRequests /** A watch-only handle to whether a published track has subscribers; holding it keeps nothing open. */ typealias TrackDemand = uniffi.moq.MoqTrackDemand /** The read side of a raw track: yields groups in sequence order, skipping ahead if it falls behind. */ diff --git a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Flows.kt b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Flows.kt index dec8f893fc6..b9103ab4cf6 100644 --- a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Flows.kt +++ b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Flows.kt @@ -40,13 +40,13 @@ fun TrackConsumer.frames(): Flow = pull({ cancel() }) { readFrame() } fun TrackConsumer.datagrams(): Flow = pull({ cancel() }) { recvDatagram() } /** Stream of tracks requested by subscribers. */ -fun BroadcastDynamic.requestedTracks(): Flow = pull({ cancel() }) { requestedTrack() } +fun BroadcastRequests.requestedTracks(): Flow = pull({ cancel() }) { requestedTrack() } /** Stream of the fills readers of one track need. */ -fun TrackDynamic.requestedFills(): Flow = pull({ cancel() }) { requestedFill() } +fun TrackRequests.requestedFills(): Flow = pull({ cancel() }) { requestedFill() } /** Stream of broadcasts requested by consumers. */ -fun OriginDynamic.requestedBroadcasts(): Flow = pull({ cancel() }) { requestedBroadcast() } +fun OriginRequests.requestedBroadcasts(): Flow = pull({ cancel() }) { requestedBroadcast() } /** Stream of timestamped raw frames within a group. */ fun GroupConsumer.frames(): Flow = pull({ cancel() }) { readFrame() } diff --git a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Moq.kt b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Moq.kt index 98b3f114505..570222dcc99 100644 --- a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Moq.kt +++ b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Moq.kt @@ -20,7 +20,7 @@ class Moq internal constructor( * Create an unannounced broadcast at [path], invisible to everyone until announced. * * Advertise it with `announce` after populating tracks. `end()` ends it for good; `close()` - * (or `use`) releases the handle, which ends it once no `dynamic()` handle remains. + * (or `use`) releases the handle, which ends it once no `requests()` handle remains. */ fun createBroadcast(path: String): BroadcastProducer = session.publish().createBroadcast(path) diff --git a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Server.kt b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Server.kt index 52e52f55469..0a348f61763 100644 --- a/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Server.kt +++ b/kt/moq/src/jvmAndAndroidMain/kotlin/dev/moq/Server.kt @@ -29,7 +29,7 @@ class Server internal constructor( * * Advertise it with `announce` after populating tracks. `end()` ends it for * good; `close()` (or `use`) releases the handle, which ends it once no - * `dynamic()` handle remains. + * `requests()` handle remains. */ fun createBroadcast(path: String): BroadcastProducer { val origin = publishOrigin ?: throw IllegalStateException("no publish origin configured") diff --git a/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt b/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt index a8523b23e15..a5517c84cbe 100644 --- a/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt +++ b/kt/moq/src/jvmAndAndroidTest/kotlin/dev/moq/SmokeTest.kt @@ -176,7 +176,7 @@ class SmokeTest { fun `origin alias constructs and consumes`() = runTest { OriginProducer(OriginConfig()).use { origin -> origin.consume().use { /* lifecycle smoke */ } - origin.dynamic("").use { /* dynamic origin smoke */ } + origin.requests("").use { /* dynamic origin smoke */ } } } @@ -229,7 +229,7 @@ class SmokeTest { @Test fun `ending a broadcast ends it while a dynamic handle remains`() = runTest { BroadcastProducer().use { broadcast -> - broadcast.dynamic().use { + broadcast.requests().use { val consumer = broadcast.consume() // Releasing the producer alone would leave the dynamic handle holding it open. broadcast.end() @@ -615,7 +615,7 @@ class SmokeTest { @Test fun `dynamic serves a request under a prefix`() = runTest { OriginProducer(OriginConfig()).use { origin -> - origin.dynamic("live").use { dynamic -> + origin.requests("live").use { dynamic -> val pending = async { origin.consume().requestBroadcast("live/cam") } diff --git a/py/moq-rs/MIGRATE.md b/py/moq-rs/MIGRATE.md index 1340c48bad7..42d00562300 100644 --- a/py/moq-rs/MIGRATE.md +++ b/py/moq-rs/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `dynamic()` on `OriginProducer`, `BroadcastProducer`, `TrackProducer`, and `TrackRequest` to `requests()`. +Their handles `OriginDynamic`, `BroadcastDynamic`, and `TrackDynamic` are `OriginRequests`, `BroadcastRequests`, and `TrackRequests`; their methods are unchanged. + ### `Allocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `moq.Bandwidth` is `moq.Allocator`, `Session.bandwidth()` is `allocator()`, and `Reservation.grant()` is `rate()`. `Bandwidth.Consumer`, returned by `recv_bandwidth()`, is the top-level `moq.BandwidthConsumer`. The producers' `bandwidth=` argument keeps its name. diff --git a/py/moq-rs/README.md b/py/moq-rs/README.md index 7755e3b4eaa..4bfa7afd239 100644 --- a/py/moq-rs/README.md +++ b/py/moq-rs/README.md @@ -165,11 +165,11 @@ client = moq.Client( ### Publishing - **`BroadcastProducer()`**. Create a broadcast to publish tracks into. - - `.dynamic() → BroadcastDynamic` + - `.requests() → BroadcastRequests` - `moq.video.Producer(media.CatalogProducer(broadcast), input, output, *, track=None, bandwidth=None)`. Encode raw video frames inside the binding. - `moq.audio.Producer(media.CatalogProducer(broadcast), input, output, *, track=None, bandwidth=None)`. Encode raw PCM frames. A zero frame duration uses the codec's own frame. - `.close()` ends the broadcast for good; a second call is a no-op. -- **`BroadcastDynamic`**. Async source of tracks requested by subscribers. +- **`BroadcastRequests`**. Async source of tracks requested by subscribers. - `await .requested_track() → TrackRequest`. Call `.accept()` on it for a `TrackProducer`, or `.abort(code)` to reject. - Async iterator yielding `TrackRequest` - **`TrackProducer` / `GroupProducer`**. Write raw payloads with no codec parsing. @@ -239,15 +239,15 @@ Omitting time leaves data untimed; choose the track's `timescale` to match. - **`GroupConsumer`**. Async iterator of raw `Frame`s. - `.read_frame() -> Frame | None` returns a raw frame with optional capture time. -Every handle whose cleanup is `cancel()` is an async context manager, so exiting `async with` releases it: the consumers (`media.CatalogConsumer`, `media.TrackConsumer`, `media.GroupConsumer`, `TrackConsumer`, `audio.Consumer`, `video.Consumer`, `GroupConsumer`, `json.SnapshotConsumer`, `json.StreamConsumer`, `json.WindowConsumer`, `AnnounceConsumer`, `AnnouncedBroadcast`) and the dynamic sources (`OriginDynamic`, `BroadcastDynamic`, `TrackDynamic`). +Every handle whose cleanup is `cancel()` is an async context manager, so exiting `async with` releases it: the consumers (`media.CatalogConsumer`, `media.TrackConsumer`, `media.GroupConsumer`, `TrackConsumer`, `audio.Consumer`, `video.Consumer`, `GroupConsumer`, `json.SnapshotConsumer`, `json.StreamConsumer`, `json.WindowConsumer`, `AnnounceConsumer`, `AnnouncedBroadcast`) and the dynamic sources (`OriginRequests`, `BroadcastRequests`, `TrackRequests`). ### Origin (advanced) - **`OriginProducer(*, cache_capacity_bytes=None)`**. Manage broadcast announcements. Set `cache_capacity_bytes` to bound cached groups under this origin. - `.consume() → OriginConsumer` - - `.dynamic(prefix) → OriginDynamic` + - `.requests(prefix) → OriginRequests` - `.create_broadcast(path) → BroadcastProducer` -- **`OriginDynamic`**. Async source of broadcasts requested by consumers. +- **`OriginRequests`**. Async source of broadcasts requested by consumers. - `await .requested_broadcast() → BroadcastRequest`. Call `.prepare(mint_epoch())`, fill its `.broadcast`, then `.publish()` to serve it under a new epoch, or `.reject(code)` to fail the requester. - Async iterator yielding `BroadcastRequest` - **`OriginConsumer`**. Discover broadcasts. diff --git a/py/moq-rs/docs/index.md b/py/moq-rs/docs/index.md index df19611b688..cd334e75dad 100644 --- a/py/moq-rs/docs/index.md +++ b/py/moq-rs/docs/index.md @@ -59,11 +59,11 @@ asyncio.run(main()) :nosignatures: BroadcastProducer - BroadcastDynamic + BroadcastRequests BroadcastRequest TrackProducer TrackDemand - TrackDynamic + TrackRequests TrackRequest GroupProducer Fill @@ -179,7 +179,7 @@ broadcast, and producers advertise it in the catalog. OriginProducer OriginConsumer - OriginDynamic + OriginRequests AnnounceConsumer AnnouncedBroadcast Announce diff --git a/py/moq-rs/moq/__init__.py b/py/moq-rs/moq/__init__.py index 239fc062969..169fa743a5d 100644 --- a/py/moq-rs/moq/__init__.py +++ b/py/moq-rs/moq/__init__.py @@ -27,18 +27,18 @@ BroadcastPrepared, BroadcastRequest, OriginConsumer, - OriginDynamic, OriginProducer, + OriginRequests, ) from .publish import ( - BroadcastDynamic, BroadcastProducer, + BroadcastRequests, Fill, GroupProducer, TrackDemand, - TrackDynamic, TrackProducer, TrackRequest, + TrackRequests, ) from .server import Request, Server, Transport from .session import Allocator, BandwidthConsumer, GrantConsumer, Reservation, Session, Tokens @@ -98,7 +98,7 @@ "Backoff", "BandwidthConsumer", "BroadcastConsumer", - "BroadcastDynamic", + "BroadcastRequests", "BroadcastPrepared", "BroadcastProducer", "BroadcastRequest", @@ -122,7 +122,7 @@ "GroupConsumer", "GroupProducer", "OriginConsumer", - "OriginDynamic", + "OriginRequests", "OriginProducer", "Order", "Range", @@ -135,7 +135,7 @@ "Tokens", "TrackConsumer", "TrackDemand", - "TrackDynamic", + "TrackRequests", "TrackInfo", "TrackProducer", "TrackRequest", diff --git a/py/moq-rs/moq/origin.py b/py/moq-rs/moq/origin.py index df807b6f019..f8647bcd68d 100644 --- a/py/moq-rs/moq/origin.py +++ b/py/moq-rs/moq/origin.py @@ -12,8 +12,8 @@ MoqBroadcastRequest, MoqOriginConfig, MoqOriginConsumer, - MoqOriginDynamic, MoqOriginProducer, + MoqOriginRequests, ) from ._stream import _Stream @@ -138,13 +138,13 @@ def publish(self) -> BroadcastProducer: return BroadcastProducer._from_inner(self._inner.publish()) -class OriginDynamic(_Stream[BroadcastRequest]): +class OriginRequests(_Stream[BroadcastRequest]): """A served route: advertises a prefix and yields requests beneath it. Usable as an async context manager that cancels the route on exit. """ - def __init__(self, inner: MoqOriginDynamic) -> None: + def __init__(self, inner: MoqOriginRequests) -> None: self._inner = inner async def _next(self) -> BroadcastRequest: @@ -202,8 +202,8 @@ class OriginProducer: """The publishing side of an origin: announce broadcasts for consumers to discover. Call :meth:`create_broadcast` to publish at a path, :meth:`consume` for a - matching :class:`OriginConsumer`, or :meth:`dynamic` to advertise a prefix - and serve on-demand requests. Create, :meth:`dynamic` if tracks are served + matching :class:`OriginConsumer`, or :meth:`requests` to advertise a prefix + and serve on-demand requests. Create, :meth:`requests` if tracks are served on demand, populate, then :meth:`BroadcastProducer.announce`. """ @@ -221,7 +221,7 @@ def consume(self) -> OriginConsumer: """Create a consumer that discovers the broadcasts this origin publishes.""" return OriginConsumer(self._inner.consume()) - def dynamic(self, prefix: str) -> OriginDynamic: + def requests(self, prefix: str) -> OriginRequests: """Advertise ``prefix`` and serve the requests beneath it. A route claims ``prefix`` and every path beneath it (``""`` claims every @@ -229,7 +229,7 @@ def dynamic(self, prefix: str) -> OriginDynamic: are requested. Hold the returned handle while the route should stay advertised. """ - return OriginDynamic(self._inner.dynamic(prefix)) + return OriginRequests(self._inner.requests(prefix)) def create_broadcast(self, path: str) -> BroadcastProducer: """Create a broadcast at ``path``, returning the producer that feeds it. @@ -237,7 +237,7 @@ def create_broadcast(self, path: str) -> BroadcastProducer: The broadcast is invisible and unroutable, for this origin's consumers and peers alike, until :meth:`BroadcastProducer.announce`. Announce it after populating tracks. Create, - :meth:`dynamic` if tracks are served on demand, populate, then announce. + :meth:`requests` if tracks are served on demand, populate, then announce. :meth:`BroadcastProducer.close` ends it for good; dropping the last handle does the same. """ diff --git a/py/moq-rs/moq/publish.py b/py/moq-rs/moq/publish.py index 38fff546fcc..3cb61709077 100644 --- a/py/moq-rs/moq/publish.py +++ b/py/moq-rs/moq/publish.py @@ -6,15 +6,15 @@ from typing import TYPE_CHECKING from moq_ffi import ( - MoqBroadcastDynamic, MoqBroadcastProducer, + MoqBroadcastRequests, MoqFill, MoqGroupProducer, MoqOrder, MoqTrackDemand, - MoqTrackDynamic, MoqTrackProducer, MoqTrackRequest, + MoqTrackRequests, ) from ._records import _subscription, _track_info @@ -105,9 +105,9 @@ def demand(self) -> TrackDemand: """A watch-only handle to this track's name and whether it has subscribers.""" return TrackDemand(self._inner.demand()) - def dynamic(self) -> TrackDynamic: + def requests(self) -> TrackRequests: """Serve fetches for groups that are not currently cached.""" - return TrackDynamic(self._inner.dynamic()) + return TrackRequests(self._inner.requests()) def append_group(self) -> GroupProducer: """Start a new group; write frames into it, then finish().""" @@ -181,9 +181,9 @@ def demand(self) -> TrackDemand: """Watch this track's subscribers, including after accepting it.""" return TrackDemand(self._inner.demand()) - def dynamic(self) -> TrackDynamic: + def requests(self) -> TrackRequests: """Create a fetch handler before accepting this requested track.""" - return TrackDynamic(self._inner.dynamic()) + return TrackRequests(self._inner.requests()) def abort(self, error_code: int) -> None: """Reject the request with an application error code.""" @@ -191,7 +191,7 @@ def abort(self, error_code: int) -> None: class Fill: - """A run of groups readers miss, for a :class:`TrackDynamic` to serve. + """A run of groups readers miss, for a :class:`TrackRequests` to serve. Call :meth:`accept` for each group you have and :meth:`drop_groups` for the rest; :meth:`next` names what is still owed, in the fill's order. Dropping the fill names @@ -268,13 +268,13 @@ async def unwanted(self, sequence: int) -> None: await self._inner.unwanted(sequence) -class TrackDynamic(_Stream[Fill]): +class TrackRequests(_Stream[Fill]): """Async source of the fills readers of one track need: runs of groups the cache lacks. Usable as an async context manager that cancels on exit. """ - def __init__(self, inner: MoqTrackDynamic) -> None: + def __init__(self, inner: MoqTrackRequests) -> None: self._inner = inner async def _next(self) -> Fill: @@ -289,14 +289,14 @@ def cancel(self) -> None: self._inner.cancel() -class BroadcastDynamic(_Stream[TrackRequest]): +class BroadcastRequests(_Stream[TrackRequest]): """Async source of tracks requested by subscribers. Hold this object while subscriptions to unknown tracks should be accepted. Usable as an async context manager that cancels on exit. """ - def __init__(self, inner: MoqBroadcastDynamic) -> None: + def __init__(self, inner: MoqBroadcastRequests) -> None: self._inner = inner async def _next(self) -> TrackRequest: @@ -329,9 +329,9 @@ def _from_inner(cls, inner: MoqBroadcastProducer) -> BroadcastProducer: self._inner = inner return self - def dynamic(self) -> BroadcastDynamic: + def requests(self) -> BroadcastRequests: """Accept subscriptions to tracks that are not published yet.""" - return BroadcastDynamic(self._inner.dynamic()) + return BroadcastRequests(self._inner.requests()) def announce(self, route: AnnounceRoute | None = None) -> None: """Advertise this broadcast's exact path as a route. diff --git a/py/moq-rs/tests/test_local.py b/py/moq-rs/tests/test_local.py index 68dba7ca505..0800bf84e1d 100644 --- a/py/moq-rs/tests/test_local.py +++ b/py/moq-rs/tests/test_local.py @@ -105,7 +105,7 @@ def h264_init() -> bytes: async def test_fetch_of_a_dropped_group_is_not_found(): broadcast = moq.BroadcastProducer() track = broadcast.publish_track("events") - dynamic = track.dynamic() + dynamic = track.requests() consumer = broadcast.consume() async def reject(): @@ -464,7 +464,7 @@ def test_string_sequences_refuse_a_bare_string(): async def test_fetch_group_and_serve_dynamic_miss(): - """Fetch a cached group, then serve an uncached sequence through TrackDynamic.""" + """Fetch a cached group, then serve an uncached sequence through TrackRequests.""" broadcast = moq.BroadcastProducer() track = broadcast.publish_track("events", moq.TrackInfo(timescale=1_000_000)) consumer = broadcast.consume() @@ -477,7 +477,7 @@ async def test_fetch_group_and_serve_dynamic_miss(): assert fetched.sequence == 0 assert [frame.payload async for frame in fetched] == [b"cached"] - dynamic = track.dynamic() + dynamic = track.requests() pending = asyncio.create_task(consumer.fetch_group("events", 7, moq.FetchGroupOptions(priority=11))) fill = await asyncio.wait_for(dynamic.requested_fill(), timeout=5.0) assert (fill.start_group, fill.start_frame, fill.end_group) == (7, 0, 8) @@ -642,7 +642,7 @@ async def test_json_producers_report_demand(): async def test_dynamic_track_request(): broadcast = moq.BroadcastProducer() - dynamic = broadcast.dynamic() + dynamic = broadcast.requests() consumer = broadcast.consume() # The subscribe stays pending until the request is accepted below; run it concurrently. @@ -681,7 +681,7 @@ async def test_media_subscribe_refuses_a_non_rendition(): async def test_dynamic_track_request_can_publish_media(): broadcast = moq.BroadcastProducer() - dynamic = broadcast.dynamic() + dynamic = broadcast.requests() consumer = broadcast.consume() catalog_consumer = await moq.media.CatalogConsumer.subscribe(consumer) @@ -735,7 +735,7 @@ async def test_dynamic_track_request_can_publish_media(): async def test_dynamic_broadcast_request(): origin = moq.OriginProducer(cache_capacity_bytes=4096) - dynamic = origin.dynamic("") + dynamic = origin.requests("") consumer = origin.consume() request_broadcast = asyncio.create_task(consumer.request_broadcast("dynamic/broadcast")) @@ -764,7 +764,7 @@ async def test_dynamic_broadcast_request(): async def test_dynamic_broadcast_request_can_reject(): origin = moq.OriginProducer() - dynamic = origin.dynamic("") + dynamic = origin.requests("") consumer = origin.consume() request_broadcast = asyncio.create_task(consumer.request_broadcast("missing")) @@ -1591,7 +1591,7 @@ async def test_announced_pattern_captures(): consumer = origin.consume() announced = consumer.announced("room", filter="*/chat") - dynamic = origin.dynamic("room") + dynamic = origin.requests("room") overlap = await next_route(announced) assert isinstance(overlap, moq.AnnounceEventStart) assert overlap.announce.prefix == "room" @@ -1612,7 +1612,7 @@ async def test_announced_pattern_captures(): async def test_dynamic_serves_a_request_under_a_prefix(): origin = moq.OriginProducer() - dynamic = origin.dynamic("live") + dynamic = origin.requests("live") consumer = origin.consume() pending = asyncio.create_task(consumer.request_broadcast("live/cam")) @@ -1633,17 +1633,17 @@ async def assert_cancelled(awaitable) -> None: assert moq.is_shutdown(excinfo.value) origin = moq.OriginProducer() - async with origin.dynamic("live") as origin_dynamic: + async with origin.requests("live") as origin_dynamic: pass await assert_cancelled(origin_dynamic.requested_broadcast()) broadcast = moq.BroadcastProducer() - async with broadcast.dynamic() as broadcast_dynamic: + async with broadcast.requests() as broadcast_dynamic: pass await assert_cancelled(broadcast_dynamic.requested_track()) track = broadcast.publish_track("events") - async with track.dynamic() as track_dynamic: + async with track.requests() as track_dynamic: pass await assert_cancelled(track_dynamic.requested_fill()) diff --git a/quest/m1/api-audit/README.md b/quest/m1/api-audit/README.md index ff9a774268a..17977c51806 100644 --- a/quest/m1/api-audit/README.md +++ b/quest/m1/api-audit/README.md @@ -78,7 +78,6 @@ Rejected in planning: - [Binding publications](/quest/m1/api-audit/binding-publication.md) - moq-ffi, the C ABI, and every wrapper hand out a publication handle that announces, replacing the private adapters - [Encoded consumers read gaps and ends](/quest/m1/api-audit/encoded-read-bindings.md) - moq-ffi, moq-c, and every wrapper read encoded media with the tagged-record shape the decoded consumers use - [One lifecycle vocabulary in @moq/e2ee](/quest/m1/api-audit/lifecycle.md) - @moq/e2ee ends tracks and groups with finish and abort, as @moq/net does -- [Request handlers are named requests](/quest/m1/api-audit/requests.md) - `dynamic()` and `Dynamic` become `requests()` and `Requests` at every layer - [Demand is wanted, everywhere](/quest/m1/api-audit/wanted.md) - every `used`/`unused` pair becomes `wanted()` and `wanted_changed()`, and unused ones go - [One meaning for Credential](/quest/m1/api-audit/dial-credential.md) - the internal dial type gets its own name in JS and moq-tokio, and the `Presented` alias goes diff --git a/quest/m1/api-audit/requests.md b/quest/m1/api-audit/requests.md deleted file mode 100644 index ec5e03df6e9..00000000000 --- a/quest/m1/api-audit/requests.md +++ /dev/null @@ -1,26 +0,0 @@ -# [L] Request handlers are named requests - -## Goal - -The handle that answers incoming requests is named for its role at every -layer: `origin`, `broadcast`, and `track` producers have `requests()` -returning `Requests`, which yields `Request`s, in Rust, JS, and the bindings. - -## Plan - -Decided 2026-10-23 (API audit follow-up, maintainer): `dynamic()` names the -mechanism; `auth::Handle::requests() -> auth::Requests` is the precedent. - -- Rename `{origin,broadcast,track}::Producer::dynamic()` (and - `track::Request::dynamic()`) to `requests()`, and each `Dynamic` type to - `Requests`. JS `dynamic()`/`Dynamic` mirror it. moq-ffi, its wrappers, - and moq-c (`moq_origin_dynamic*`) follow, since moq-c takes the same breaks - (decided 2026-10-25). -- Rename the crate-private peer-route hatches (`dynamic_route`, - `update_route`) with the rest. -- Quests that say `Dynamic` (subscribe ranges, archive) switch - to the new name in this PR. - -About 240 Rust, 30 binding, and 10 JS call sites; land it in one sweep. - -Public API: moq-net, `@moq/net`, moq-ffi, wrappers, and moq-c renamed. Wire: none. diff --git a/quest/m1/archive/README.md b/quest/m1/archive/README.md index 5f64b877d27..4302334a932 100644 --- a/quest/m1/archive/README.md +++ b/quest/m1/archive/README.md @@ -57,7 +57,7 @@ archive (per-track `.timeline.z` records named by the catalog's root every rendition) and size-based cuts. The `archive::Producer` records the rest. - **Hosts serve archives, relays do not.** `archive::Consumer` serves a stored - prefix through `broadcast::Dynamic` and `track::Dynamic`, the archived + prefix through `broadcast::Requests` and `track::Requests`, the archived catalog included as an ordinary track, and a host publishes it at a path of its choosing. Rejected: a moq-relay storage fallback. Also rejected: serving the archive as a covering-prefix route under the original path, which diff --git a/quest/m1/subscribe-ranges/README.md b/quest/m1/subscribe-ranges/README.md index 55cb20151f4..4c7fe240906 100644 --- a/quest/m1/subscribe-ranges/README.md +++ b/quest/m1/subscribe-ranges/README.md @@ -34,7 +34,7 @@ relay bounds a sparse FETCH only if the model can request ranges: publisher delivers what it has and fills the rest as upstream answers. - **Model.** `Subscription` gains `ranges` beside its `order`, mirroring the wire; `request_groups` as a separate API was rejected. A publisher's - `track::Dynamic` receives a `track::Fill` per run of misses (landed), and + `track::Requests` receives a `track::Fill` per run of misses (landed), and `fetch_group` becomes a one-range subscription or is removed. This breaks published moq-net APIs. - **moq-transport.** Some deployments use non-contiguous group numbers, so a relay never probes upstream one group at a time. Upstream, each run of @@ -64,7 +64,7 @@ relay bounds a sparse FETCH only if the model can request ranges: - **Time ends** (maintainer, 2026-10-17, for DVR seek in the [archive line](/quest/m1/archive/README.md)). A range end may also be `Time(pts)`, in the track's timescale. Whoever holds the track resolves it: - the cache from its groups' timestamps, or a `track::Dynamic` handler such as + the cache from its groups' timestamps, or a `track::Requests` handler such as an archive consumer. A start resolves to the group containing pts, and an end to just after that group. A lite-07 relay that cannot resolve one forwards it upstream unchanged. An untimed track refuses a time end, and a diff --git a/quest/m1/unbounded-groups/README.md b/quest/m1/unbounded-groups/README.md index f28c3d294d7..946e2155e85 100644 --- a/quest/m1/unbounded-groups/README.md +++ b/quest/m1/unbounded-groups/README.md @@ -99,7 +99,7 @@ Decided 2026-10-16 (maintainer interview): draft's 32 MiB interop cap. The [m1 compression migration](/quest/m1/compress/migrate.md) deletes the flate packages. There is no new page. -The refill API is the `track::Dynamic` fill (`track::Fill`). A handler serves a range by writing into a +The refill API is the `track::Requests` fill (`track::Fill`). A handler serves a range by writing into a group producer bounded to that range, the same API as a live write, so an origin can regenerate data from disk or an archive. diff --git a/quest/m1/unbounded-groups/front-eviction.md b/quest/m1/unbounded-groups/front-eviction.md index 5b1050df2f6..7a7122d79cb 100644 --- a/quest/m1/unbounded-groups/front-eviction.md +++ b/quest/m1/unbounded-groups/front-eviction.md @@ -6,7 +6,7 @@ A group grows without a frame-count or byte cap. When the cache pool is over budget and the group can't go whole, because it is the live edge or is being read, it sheds whole frames from its front. A reader that needs an evicted frame gets it refilled in place. The refill comes from upstream over a -frame-precise range, or from the publisher's `track::Dynamic` handler, and +frame-precise range, or from the publisher's `track::Requests` handler, and the reader gets `Error::Evicted` only when neither exists. `MAX_GROUP_FRAMES` and the group byte cap are removed. The frame cap stays until [Byte holes](/quest/m1/unbounded-groups/byte-holes.md). A moq-json @@ -58,7 +58,7 @@ See the [epic](/quest/m1/unbounded-groups/README.md) for the decisions. the first victim, so merging would also thrash under steady pressure. - A refill must not evict what it was fetched for before the waiting reader takes it: hand its first demanded frame to that reader. Test a - `track::Dynamic` handler that writes more than the pool synchronously, so + `track::Requests` handler that writes more than the pool synchronously, so the reader still progresses. - A refill of frames `0..N` refreshes the recency of the group's frames from `N+1` on (decided 2026-10-24, maintainer). Pressure then sheds the @@ -70,7 +70,7 @@ See the [epic](/quest/m1/unbounded-groups/README.md) for the decisions. - When nothing serves the hole, the reader gets `Error::Evicted`, and a join onto a group whose first frame is evicted asks for a new group as if it were over the `Info::refresh` ratio, on tracks that opt into - refresh (decided 2026-10-24, maintainer). The origin's `track::Dynamic` + refresh (decided 2026-10-24, maintainer). The origin's `track::Requests` handler decides whether to serve old content; refresh is the fallback. - The live edge is paced by its fastest reader (decided 2026-10-25, maintainer, superseding 2026-10-24's "never paced by a reader"): @@ -86,7 +86,7 @@ See the [epic](/quest/m1/unbounded-groups/README.md) for the decisions. allocated. Storing a group as flat header and payload bytes was rejected: it copies every small frame, and lite and IETF encode headers differently. -- Refill goes through a `track::Dynamic` fill. Over +- Refill goes through a `track::Requests` fill. Over moq-transport, a hole that covers whole objects refills; one inside an object is `Evicted`. - Downstream encoders that roll groups by the removed constants (moq-json, diff --git a/quest/m2/archive-time-ranges.md b/quest/m2/archive-time-ranges.md index 88096dfdb80..2814a22664d 100644 --- a/quest/m2/archive-time-ranges.md +++ b/quest/m2/archive-time-ranges.md @@ -23,7 +23,7 @@ handler. [moq-dev/moq#6171](https://github.com/moq-dev/moq/pull/6171) deferred c landed without it. - `moq-net` passes a time anchor the cache can't resolve to the - `track::Dynamic` handler, unresolved, in its fill. + `track::Requests` handler, unresolved, in its fill. - The consumer resolves it from its index: every object key carries its first frame's pts, so the object holding pts is one lookup, and the group within it comes from the stored group timestamps. diff --git a/quest/m2/e2ee/README.md b/quest/m2/e2ee/README.md index ffeb6a6c4f3..dad5be242c1 100644 --- a/quest/m2/e2ee/README.md +++ b/quest/m2/e2ee/README.md @@ -46,7 +46,7 @@ The Rust and TypeScript cores expose the same surface, and nothing else: ### Dynamic names -Physical names are reversible (decided with the maintainer on 2026-10-24 in [#6623](https://github.com/moq-dev/moq/pull/6623)). A physical track name is a 12-byte nonce, the first 12 bytes of an HMAC-SHA-256 of the semantic name padded to a multiple of 16 bytes, followed by the AES-128-GCM encryption of that padded name under that nonce, with both keys derived from the generation (the draft's Key Derivation section). It needs only HMAC-SHA-256 and AES-128-GCM, so it runs on aws-lc-rs, graviola, and WebCrypto with no new dependency (maintainer, 2026-10-24, over AES-GCM-SIV, which graviola lacks). A publisher opens a requested name and recomputes its nonce to recover its semantic name, so the e2ee `requests()` handler (`dynamic()` until [named requests](/quest/m1/api-audit/requests.md)) answers undeclared names through the [moq-net traits](/quest/m2/net-wrap/README.md) unchanged, and a name that does not open is answered as missing with no state kept. Equal names under one generation still share one physical name, so relays dedupe and cache them, and names stay unlinkable across epochs. AEAD keys bind the semantic name. The cost is that a relay learns each name's length rounded up to 16 bytes: every name up to 15 bytes looks alike, and a longer one leaks its length to within 16 bytes (maintainer, 2026-10-24, over power-of-two buckets that leak less but can double a long name). Broadcast paths stay one-way: e2ee wraps no origin, so nothing requests an undeclared protected broadcast. +Physical names are reversible (decided with the maintainer on 2026-10-24 in [#6623](https://github.com/moq-dev/moq/pull/6623)). A physical track name is a 12-byte nonce, the first 12 bytes of an HMAC-SHA-256 of the semantic name padded to a multiple of 16 bytes, followed by the AES-128-GCM encryption of that padded name under that nonce, with both keys derived from the generation (the draft's Key Derivation section). It needs only HMAC-SHA-256 and AES-128-GCM, so it runs on aws-lc-rs, graviola, and WebCrypto with no new dependency (maintainer, 2026-10-24, over AES-GCM-SIV, which graviola lacks). A publisher opens a requested name and recomputes its nonce to recover its semantic name, so the e2ee `requests()` answers undeclared names through the [moq-net traits](/quest/m2/net-wrap/README.md) unchanged, and a name that does not open is answered as missing with no state kept. Equal names under one generation still share one physical name, so relays dedupe and cache them, and names stay unlinkable across epochs. AEAD keys bind the semantic name. The cost is that a relay learns each name's length rounded up to 16 bytes: every name up to 15 bytes looks alike, and a longer one leaks its length to within 16 bytes (maintainer, 2026-10-24, over power-of-two buckets that leak less but can double a long name). Broadcast paths stay one-way: e2ee wraps no origin, so nothing requests an undeclared protected broadcast. Rejected: diff --git a/quest/m2/e2ee/js-undeclared-names.md b/quest/m2/e2ee/js-undeclared-names.md index 795e6156f6c..82d12ccc6b8 100644 --- a/quest/m2/e2ee/js-undeclared-names.md +++ b/quest/m2/e2ee/js-undeclared-names.md @@ -15,10 +15,9 @@ Decided with the maintainer on 2026-10-24: - One quest, both halves. Today the JS broadcast's request pull (`requested()` in `js/net/src/broadcast.ts`) is reachable only by wire - layers, and only the origin has a public `dynamic()`. Expose the - broadcast's handler under the name and shape that - [named requests](/quest/m1/api-audit/requests.md) gives Rust's - (`requests()` returning `Requests`), and keep the internal wire path on it. + layers, and only the origin has a public `requests()`. Expose the + broadcast's handler under Rust's name and shape (`requests()` returning + `Requests`), and keep the internal wire path on it. - `@moq/e2ee` mirrors the Rust handler exactly: it opens each request's physical name, claims it, and yields a request whose `name` is semantic. A name that does not open is answered as missing and keeps no state. A @@ -38,6 +37,5 @@ handler on `@moq/e2ee`'s broadcast producer. Wire: none. ## Required -- [Named requests](/quest/m1/api-audit/requests.md) - the handler name and shape this exposes - [Undeclared track names](/quest/m2/e2ee/undeclared-names.md) - the Rust handler this mirrors - [JS mirror](/quest/m2/net-wrap/js.md) - the `@moq/net` interfaces the `@moq/e2ee` wrappers implement diff --git a/quest/m2/e2ee/undeclared-names.md b/quest/m2/e2ee/undeclared-names.md index 6e7c0b2ac41..a685b027c7b 100644 --- a/quest/m2/e2ee/undeclared-names.md +++ b/quest/m2/e2ee/undeclared-names.md @@ -4,8 +4,7 @@ An encrypted broadcast producer answers requests for track names it never created or reserved, as a plaintext `moq-net` broadcast does. Its request -handler (`dynamic()` today, `requests()` after -[named requests](/quest/m1/api-audit/requests.md)) mirrors moq-net's and +handler (`requests()`) mirrors moq-net's and yields requests named by their semantic name, so a handler such as moq-stats' or moq-transcode's serves an encrypted broadcast unchanged. A request whose physical name does not open under the generation is answered diff --git a/quest/m2/net-wrap/README.md b/quest/m2/net-wrap/README.md index 3fc95ca25ff..013f0b1880a 100644 --- a/quest/m2/net-wrap/README.md +++ b/quest/m2/net-wrap/README.md @@ -32,8 +32,7 @@ and its trait-versus-bridge comparison: that spawns adds the bound at its spawn site. - **Mirror moq-net's current API exactly.** The trait methods are the methods writers and readers call today, with the same names, arguments, - and errors: `create_track`, `reserve_track`, `requests` (renamed from - `dynamic` by [named requests](/quest/m1/api-audit/requests.md)), `demand`, + and errors: `create_track`, `reserve_track`, `requests`, `demand`, `create_group(group::Info)`, `append_group`, `append_datagram`, `insert_datagram`, `write_frame`, `create_frame`, `write`, `finish`, `abort(self, Error)`, `closed`, `track(name)` then `.subscribe(..)`, diff --git a/quest/m2/net-wrap/traits.md b/quest/m2/net-wrap/traits.md index 087ddfb46d3..4e1a47d236c 100644 --- a/quest/m2/net-wrap/traits.md +++ b/quest/m2/net-wrap/traits.md @@ -14,7 +14,7 @@ with moq-net's types as the default, no `Send` bounds wasm can't meet, and the methods exactly as moq-net has them today. - Every handle a writer or reader can get from moq-net's public API, - including pending operations (`track::Subscribing`, `Querying`, + including pending operations (`track::Subscribing`, `Resolving`, `Fetching`), requests, and adapters, has an associated type, so no trait method returns a concrete moq-net type and a wrapper never leaks its physical handle. Examples of what the rule covers: @@ -27,16 +27,14 @@ the methods exactly as moq-net has them today. `frame::Producer<'_>` borrows its group, so its associated type is generic over that lifetime. - Requests: a broadcast producer's `requests` returns its own - `broadcast::Requests` (`dynamic` and `Dynamic` until - [named requests](/quest/m1/api-audit/requests.md) renames them before - the cut this waits on), whose `requested_track` yields its own + `broadcast::Requests`, whose `requested_track` yields its own `track::Request`, so generic code serves undeclared names (as - [E2EE undeclared names](/quest/m2/e2ee/undeclared-names.md) needs). A track - `Requests`'s `requested_fill` yields its own `track::Fill`, whose + [E2EE undeclared names](/quest/m2/e2ee/undeclared-names.md) needs). A + `track::Requests`'s `requested_fill` yields its own `track::Fill`, whose `accept` returns its own group producer and whose `drop_groups` names the rest dropped. - Pending operations: `track::Consumer::subscribe` resolves to the - wrapper's own subscriber, so E2EE decrypts behind it; `Querying` and + wrapper's own subscriber, so E2EE decrypts behind it; `Resolving` and `Fetching` resolve to the wrapper's logical metadata and groups. - Adapters: a subscriber's `ordered` returns its own `track::Ordered` with the same group, datagram, and control surface. moq-json's snapshot diff --git a/rs/moq-archive/src/consumer/mod.rs b/rs/moq-archive/src/consumer/mod.rs index 133eec41327..5786bcc3ca8 100644 --- a/rs/moq-archive/src/consumer/mod.rs +++ b/rs/moq-archive/src/consumer/mod.rs @@ -4,7 +4,7 @@ //! stored track on a `moq_net` broadcast, the archived catalog included, with its stored //! timescale and priority and no max age: the store's retention bounds what it holds. Each //! track's live feed starts at its newest stored sequence, and every older group is served on -//! demand from the store through [`track::Dynamic`](moq_net::track::Dynamic) fills, each sequence in its recorded form: a +//! demand from the store through [`track::Requests`](moq_net::track::Requests) fills, each sequence in its recorded form: a //! group as a group, a datagram as a datagram. //! //! A growing archive is followed: every [`Config::refresh`], one delimiter LIST of the prefix @@ -83,7 +83,7 @@ pub struct Consumer { shared: Arc>, broadcast: broadcast::Producer, /// Answers requests for names the archive does not hold, and says when the broadcast closed. - requests: broadcast::Dynamic, + requests: broadcast::Requests, refresh: Duration, tracks: HashMap, /// Whether the prefix held `.end`, so every track ended and nothing is refreshed. @@ -98,7 +98,7 @@ struct Shared { struct Track { index: Arc>, live: track::Live, - dynamic: moq_net::track::Dynamic, + dynamic: moq_net::track::Requests, } /// What one refresh found, applied to the served tracks at once. @@ -137,7 +137,7 @@ impl Consumer { }); let mut consumer = Self { shared, - requests: broadcast.dynamic(), + requests: broadcast.requests(), broadcast, refresh: config.refresh, tracks: HashMap::new(), @@ -237,7 +237,7 @@ impl Consumer { fn apply(&mut self, refreshed: Refreshed) -> Result<()> { for (name, info, index) in refreshed.added { let producer = self.broadcast.create_track(name.as_str(), info)?; - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); self.tracks.insert( name, Track { diff --git a/rs/moq-c/MIGRATE.md b/rs/moq-c/MIGRATE.md index b2a27577807..038c7ca1fbf 100644 --- a/rs/moq-c/MIGRATE.md +++ b/rs/moq-c/MIGRATE.md @@ -4,6 +4,13 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are named requests ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +The request-handler functions are renamed to match moq-net's `requests()`; their arguments and callbacks are unchanged: +`moq_origin_dynamic` and `moq_origin_dynamic_cancel` are `moq_origin_requests` and `moq_origin_requests_cancel`, +`moq_publish_dynamic`, `moq_publish_track_dynamic`, and `moq_track_request_dynamic` are `moq_publish_requests`, `moq_publish_track_requests`, and `moq_track_request_requests`, +and `moq_publish_dynamic_cancel` is `moq_publish_requests_cancel`. + ### Session allocator ([#6751](https://github.com/moq-dev/moq/pull/6751)) `moq_session_bandwidth` is `moq_session_allocator`, `moq_bandwidth_reserve` is `moq_allocator_reserve`, and `moq_bandwidth_close` is `moq_allocator_close`, matching `moq_net::bandwidth::Allocator`. `moq_reservation_grant` is `moq_reservation_rate`, matching `moq_net::bandwidth::Reservation::rate()`. Signatures are unchanged. The receive estimate keeps its names (`moq_session_recv_bandwidth`, `moq_bandwidth_consumer_*`). diff --git a/rs/moq-c/README.md b/rs/moq-c/README.md index 3c0e691e569..8b5b8ca9141 100644 --- a/rs/moq-c/README.md +++ b/rs/moq-c/README.md @@ -92,10 +92,10 @@ int32_t moq_publish_demand_cancel(uint32_t watcher); int32_t moq_publish_demand_wanted(uint32_t watcher, uint64_t *group, bool *present); // Publishing: Requests -int32_t moq_publish_dynamic(uint32_t broadcast, moq_status_callback on_request, void *user_data); -int32_t moq_publish_track_dynamic(uint32_t track, moq_status_callback on_group, void *user_data); -int32_t moq_track_request_dynamic(uint32_t request, moq_status_callback on_group, void *user_data); -int32_t moq_publish_dynamic_cancel(uint32_t dynamic); +int32_t moq_publish_requests(uint32_t broadcast, moq_status_callback on_request, void *user_data); +int32_t moq_publish_track_requests(uint32_t track, moq_status_callback on_group, void *user_data); +int32_t moq_track_request_requests(uint32_t request, moq_status_callback on_group, void *user_data); +int32_t moq_publish_requests_cancel(uint32_t dynamic); int32_t moq_track_request_name(uint32_t request, moq_string *dst); int32_t moq_track_request_accept(uint32_t request, const moq_track_info *info); int32_t moq_track_request_video(uint32_t request, const moq_video_init *config); diff --git a/rs/moq-c/src/api.rs b/rs/moq-c/src/api.rs index 7a110523115..3233de41f61 100644 --- a/rs/moq-c/src/api.rs +++ b/rs/moq-c/src/api.rs @@ -736,7 +736,7 @@ pub struct moq_section { /// A route advertisement: hops and a static cost. /// -/// Pair with [moq_publish_announce] or [moq_origin_dynamic]. Zeroed (NULL hops, +/// Pair with [moq_publish_announce] or [moq_origin_requests]. Zeroed (NULL hops, /// hops_len 0, cost 0) is the default route. `hops` is borrowed for the duration /// of the call that reads it. /// @@ -1815,7 +1815,7 @@ pub unsafe extern "C" fn moq_origin_create_broadcast(origin: u32, path: *const c /// required: a NULL callback is refused before the route is advertised. It is /// invoked with a positive request handle for each /// pending broadcast, then exactly once more with a terminal code: `0` (stopped -/// cleanly, including after [moq_origin_dynamic_cancel]) or a negative error. +/// cleanly, including after [moq_origin_requests_cancel]) or a negative error. /// After the terminal (`<= 0`) callback, `user_data` is never touched again. /// /// Returns a non-zero handle on success, or a negative code on failure. @@ -1825,7 +1825,7 @@ pub unsafe extern "C" fn moq_origin_create_broadcast(origin: u32, path: *const c /// - `on_request` must be non-NULL; a missing callback is refused before the route is advertised. /// - The caller must keep `user_data` valid until the terminal (`<= 0`) `on_request` callback. #[unsafe(no_mangle)] -pub unsafe extern "C" fn moq_origin_dynamic( +pub unsafe extern "C" fn moq_origin_requests( origin: u32, prefix: *const c_char, prefix_len: usize, @@ -1843,18 +1843,18 @@ pub unsafe extern "C" fn moq_origin_dynamic( /// Stop serving and retract the route. /// /// Returns immediately: zero on success, or a negative code if already closed. -/// The [moq_origin_dynamic] `on_request` callback still fires once more with a +/// The [moq_origin_requests] `on_request` callback still fires once more with a /// terminal `0` (or a negative error), and that final callback is where /// `user_data` should be released. #[unsafe(no_mangle)] -pub extern "C" fn moq_origin_dynamic_cancel(dynamic: u32) -> i32 { +pub extern "C" fn moq_origin_requests_cancel(dynamic: u32) -> i32 { ffi::enter(move || { let dynamic = ffi::parse_id(dynamic)?; State::lock().origin.dynamic_close(dynamic) }) } -/// The path of a broadcast request delivered to a [moq_origin_dynamic] callback. +/// The path of a broadcast request delivered to a [moq_origin_requests] callback. /// /// The destination borrows the request's storage: copy it out before accept, /// reject, or [moq_broadcast_request_free]. @@ -2116,7 +2116,7 @@ pub extern "C" fn moq_origin_announced_broadcast_cancel(task: u32) -> i32 { /// Resolves against what is announced *now*, where [moq_origin_announced_broadcast] waits /// indefinitely: it returns an announced broadcast at once, and fails when none is reachable, /// including a broadcast created but not announced. It does NOT wait for a later -/// announcement. Serve on-demand paths with [moq_origin_dynamic]. A client session only +/// announcement. Serve on-demand paths with [moq_origin_requests]. A client session only /// asks its peer about paths something watches, through [moq_origin_announced] or /// [moq_origin_announced_broadcast], so a path nothing watches is unreachable on it. /// @@ -2164,7 +2164,7 @@ pub extern "C" fn moq_origin_request_cancel(task: u32) -> i32 { /// Close an origin and clean up its resources. /// /// The origin keeps running while a broadcast published on it or a -/// [moq_origin_dynamic] handler lives; close or cancel those to end it. +/// [moq_origin_requests] handler lives; close or cancel those to end it. /// /// Returns a zero on success, or a negative code on failure. #[unsafe(no_mangle)] @@ -2945,7 +2945,7 @@ pub unsafe extern "C" fn moq_publish_track_demand( /// Without a live handler a subscription to an unknown track name is refused. While one /// is live, `on_request` is invoked with a positive request handle for each pending /// track, then exactly once more with a terminal code: `0` (the broadcast finished, or -/// [moq_publish_dynamic_cancel] was called) or a negative error. After the terminal +/// [moq_publish_requests_cancel] was called) or a negative error. After the terminal /// (`<= 0`) callback, `user_data` is never touched again. Answer each request with /// [moq_track_request_accept], [moq_track_request_video], [moq_track_request_audio], /// or [moq_track_request_abort]; the subscriber waits until you do. @@ -2956,7 +2956,7 @@ pub unsafe extern "C" fn moq_publish_track_demand( /// - `on_request` must be non-NULL. /// - The caller must keep `user_data` valid until the terminal (`<= 0`) `on_request` callback. #[unsafe(no_mangle)] -pub unsafe extern "C" fn moq_publish_dynamic( +pub unsafe extern "C" fn moq_publish_requests( broadcast: u32, on_request: ffi::moq_status_callback, user_data: *mut c_void, @@ -2973,7 +2973,7 @@ pub unsafe extern "C" fn moq_publish_dynamic( /// Without a live handler a fetch that misses the cache fails as not found. While one is /// live, `on_group` is invoked with a positive group-request handle for each miss, then /// exactly once more with a terminal code: `0` (the track ended, or -/// [moq_publish_dynamic_cancel] was called) or a negative error. After the terminal +/// [moq_publish_requests_cancel] was called) or a negative error. After the terminal /// (`<= 0`) callback, `user_data` is never touched again. Cached groups never reach the /// handler. Answer each request with [moq_group_request_accept] or [moq_group_request_abort]. /// A request whose group nobody reads any more is withdrawn: answering it then fails as not @@ -2985,7 +2985,7 @@ pub unsafe extern "C" fn moq_publish_dynamic( /// - `on_group` must be non-NULL. /// - The caller must keep `user_data` valid until the terminal (`<= 0`) `on_group` callback. #[unsafe(no_mangle)] -pub unsafe extern "C" fn moq_publish_track_dynamic( +pub unsafe extern "C" fn moq_publish_track_requests( track: u32, on_group: ffi::moq_status_callback, user_data: *mut c_void, @@ -2997,21 +2997,21 @@ pub unsafe extern "C" fn moq_publish_track_dynamic( }) } -/// Stop a request handler from [moq_publish_dynamic], [moq_publish_track_dynamic], or -/// [moq_track_request_dynamic]. Requests not yet delivered are rejected. +/// Stop a request handler from [moq_publish_requests], [moq_publish_track_requests], or +/// [moq_track_request_requests]. Requests not yet delivered are rejected. /// /// Returns immediately: zero on success, or a negative code if already closed. The /// handler's callback still fires once more with a terminal `0`, and that final /// callback is where `user_data` should be released. #[unsafe(no_mangle)] -pub extern "C" fn moq_publish_dynamic_cancel(dynamic: u32) -> i32 { +pub extern "C" fn moq_publish_requests_cancel(dynamic: u32) -> i32 { ffi::enter(move || { let dynamic = ffi::parse_id(dynamic)?; State::lock().publish.dynamic_close(dynamic) }) } -/// The name of a track request delivered to a [moq_publish_dynamic] callback. +/// The name of a track request delivered to a [moq_publish_requests] callback. /// /// The destination borrows the request's storage: copy it out before accepting, /// aborting, or freeing the request. @@ -3033,7 +3033,7 @@ pub unsafe extern "C" fn moq_track_request_name(request: u32, dst: *mut moq_stri /// /// A track requested by a fetch has that group pending from birth. Register the /// handler here, before [moq_track_request_accept], so the request survives the -/// transition; the callback contract is that of [moq_publish_track_dynamic]. +/// transition; the callback contract is that of [moq_publish_track_requests]. /// /// Returns a non-zero handle on success, or a negative code on failure. /// @@ -3041,7 +3041,7 @@ pub unsafe extern "C" fn moq_track_request_name(request: u32, dst: *mut moq_stri /// - `on_group` must be non-NULL. /// - The caller must keep `user_data` valid until the terminal (`<= 0`) `on_group` callback. #[unsafe(no_mangle)] -pub unsafe extern "C" fn moq_track_request_dynamic( +pub unsafe extern "C" fn moq_track_request_requests( request: u32, on_group: ffi::moq_status_callback, user_data: *mut c_void, diff --git a/rs/moq-c/src/origin.rs b/rs/moq-c/src/origin.rs index e58dd2a1e63..8daea7d5fc7 100644 --- a/rs/moq-c/src/origin.rs +++ b/rs/moq-c/src/origin.rs @@ -118,7 +118,7 @@ impl AnnouncedRecord { struct DynamicEntry { task: Task, - inner: Option, + inner: Option, } impl Origin { @@ -338,7 +338,7 @@ impl Origin { let origin = self.active.get(origin).ok_or(Error::OriginNotFound)?; origin.driver.check()?; let driver = origin.driver.clone(); - let result = origin.producer.dynamic(prefix); + let result = origin.producer.requests(prefix); origin.driver.check()?; let inner = result?; let (task, close) = Task::new(on_request); diff --git a/rs/moq-c/src/publish.rs b/rs/moq-c/src/publish.rs index 9fa64eebb3d..1f1c4c227d1 100644 --- a/rs/moq-c/src/publish.rs +++ b/rs/moq-c/src/publish.rs @@ -43,9 +43,9 @@ struct GroupRequest { /// What a request handler serves. enum Dynamic { /// Track requests on a broadcast, remembered so media can be published onto them. - Broadcast(moq_net::broadcast::Dynamic, Id, Children), + Broadcast(moq_net::broadcast::Requests, Id, Children), /// Group requests (fetches of uncached groups) on a track. - Track(moq_net::track::Dynamic), + Track(moq_net::track::Requests), } /// A published broadcast: its producer, its catalog, and the renditions the caller authored by @@ -828,7 +828,7 @@ impl Publish { /// /// Without a live handler an unknown track name is refused, as before. pub fn dynamic(&mut self, broadcast: Id, on_request: OnStatus) -> Result { - let dynamic = self.producer(broadcast)?.dynamic(); + let dynamic = self.producer(broadcast)?.requests(); let Broadcast { driver, children, .. } = self.broadcast(broadcast)?; let dynamic = Dynamic::Broadcast(dynamic, broadcast, children.clone()); self.spawn_dynamic(dynamic, on_request, driver.clone()) @@ -837,7 +837,7 @@ impl Publish { /// Serve fetches of uncached groups on a raw track, delivering each as a group-request /// handle via `on_group`. pub fn track_dynamic(&mut self, track: Id, on_group: OnStatus) -> Result { - let dynamic = self.tracks.get(track).ok_or(Error::TrackNotFound)?.dynamic(); + let dynamic = self.tracks.get(track).ok_or(Error::TrackNotFound)?.requests(); self.spawn_dynamic(Dynamic::Track(dynamic), on_group, Default::default()) } @@ -851,7 +851,7 @@ impl Publish { .get(request) .ok_or(Error::NotFound)? .request - .dynamic(); + .requests(); self.spawn_dynamic(Dynamic::Track(dynamic), on_group, Default::default()) } @@ -1545,7 +1545,7 @@ mod supervision_tests { #[tokio::test(start_paused = true)] async fn admission_must_match_the_broadcast_it_filled() { let origin = moq_tokio::origin::spawn(); - let claim = origin.dynamic("room").unwrap(); + let claim = origin.requests("room").unwrap(); let pending = origin.consume().request_broadcast("room/first", None); let prepared = claim .requested_broadcast() @@ -1627,7 +1627,7 @@ mod supervision_tests { .unwrap(); let producer = &state.publish.broadcast(broadcast).unwrap().producer; // A dynamic handle outlives the consumed broadcast, so only an explicit close ends it. - let _dynamic = producer.dynamic(); + let _dynamic = producer.requests(); let consumer = producer.consume(); *trigger .write() diff --git a/rs/moq-c/src/test.rs b/rs/moq-c/src/test.rs index a60a47b61dc..fd40b354646 100644 --- a/rs/moq-c/src/test.rs +++ b/rs/moq-c/src/test.rs @@ -2747,7 +2747,7 @@ fn dynamic_serves_a_request_under_a_prefix() { let cb = Callback::new(); let prefix = b"live"; let dynamic = id(unsafe { - moq_origin_dynamic( + moq_origin_requests( origin, prefix.as_ptr() as *const c_char, prefix.len(), @@ -2785,8 +2785,8 @@ fn dynamic_serves_a_request_under_a_prefix() { assert!(req_cb.recv() > 0); req_cb.recv_terminal(); - assert_eq!(moq_origin_dynamic_cancel(dynamic), 0); - assert!(moq_origin_dynamic_cancel(dynamic) < 0, "double-cancel should fail"); + assert_eq!(moq_origin_requests_cancel(dynamic), 0); + assert!(moq_origin_requests_cancel(dynamic) < 0, "double-cancel should fail"); assert_eq!(cb.recv_terminal(), 0); assert_eq!(moq_publish_close(served), 0); assert_eq!(moq_origin_close(origin), 0); @@ -2797,7 +2797,7 @@ fn dynamic_refuses_a_missing_callback() { let origin = id(moq_origin_create()); let prefix = b"live"; let code = unsafe { - moq_origin_dynamic( + moq_origin_requests( origin, prefix.as_ptr() as *const c_char, prefix.len(), @@ -3105,11 +3105,11 @@ fn dynamic_serves_track_requests() { let broadcast = publish_broadcast(origin, b"dynamic-tracks"); assert!( - unsafe { moq_publish_dynamic(broadcast, None, std::ptr::null_mut()) } < 0, + unsafe { moq_publish_requests(broadcast, None, std::ptr::null_mut()) } < 0, "a missing on_request must be refused" ); let request_cb = Callback::new(); - let dynamic = id(unsafe { moq_publish_dynamic(broadcast, Some(channel_callback), request_cb.ptr) }); + let dynamic = id(unsafe { moq_publish_requests(broadcast, Some(channel_callback), request_cb.ptr) }); // The subscribe stays pending until the request is answered. let consume = consume_local(broadcast); @@ -3189,9 +3189,9 @@ fn dynamic_serves_track_requests() { assert_eq!(moq_track_request_free(request), 0); assert!(freed_cb.recv_terminal() < 0, "a freed request fails its subscriber"); - assert_eq!(moq_publish_dynamic_cancel(dynamic), 0); + assert_eq!(moq_publish_requests_cancel(dynamic), 0); assert_eq!(request_cb.recv_terminal(), 0); - assert!(moq_publish_dynamic_cancel(dynamic) < 0, "double-close should fail"); + assert!(moq_publish_requests_cancel(dynamic) < 0, "double-close should fail"); assert_eq!(moq_consume_track_cancel(consumer), 0); assert_eq!(frame_cb.recv_terminal(), 0); @@ -3208,7 +3208,7 @@ fn dynamic_track_request_publishes_media() { let origin = id(moq_origin_create()); let broadcast = publish_broadcast(origin, b"dynamic-media"); let request_cb = Callback::new(); - let _dynamic = id(unsafe { moq_publish_dynamic(broadcast, Some(channel_callback), request_cb.ptr) }); + let _dynamic = id(unsafe { moq_publish_requests(broadcast, Some(channel_callback), request_cb.ptr) }); let consume = consume_local(broadcast); let frame_cb = Callback::new(); @@ -3256,7 +3256,7 @@ fn track_request_accepted_after_the_broadcast_closes_is_refused() { let origin = id(moq_origin_create()); let broadcast = publish_broadcast(origin, b"dynamic-closed"); let request_cb = Callback::new(); - let _dynamic = id(unsafe { moq_publish_dynamic(broadcast, Some(channel_callback), request_cb.ptr) }); + let _dynamic = id(unsafe { moq_publish_requests(broadcast, Some(channel_callback), request_cb.ptr) }); let consume = consume_local(broadcast); let frame_cb = Callback::new(); @@ -3313,7 +3313,7 @@ fn track_dynamic_serves_a_fetch_miss() { id(unsafe { moq_publish_track(broadcast, name.as_ptr() as *const c_char, name.len(), std::ptr::null()) }); let group_cb = Callback::new(); - let dynamic = id(unsafe { moq_publish_track_dynamic(track, Some(channel_callback), group_cb.ptr) }); + let dynamic = id(unsafe { moq_publish_track_requests(track, Some(channel_callback), group_cb.ptr) }); let fetch = fetch_group(broadcast, "data", 5, 11); let request = id(group_cb.recv()); @@ -3347,7 +3347,7 @@ fn track_dynamic_serves_a_fetch_miss() { .expect_err("a rejected fetch fails"); assert!(matches!(err, moq_net::Error::NotFound), "got {err:?}"); - assert_eq!(moq_publish_dynamic_cancel(dynamic), 0); + assert_eq!(moq_publish_requests_cancel(dynamic), 0); assert_eq!(group_cb.recv_terminal(), 0); assert_eq!(moq_publish_track_finish(track), 0); assert_eq!(moq_publish_close(broadcast), 0); @@ -3364,7 +3364,7 @@ fn a_group_request_nobody_reads_is_withdrawn() { let track = id(unsafe { moq_publish_track(broadcast, name.as_ptr() as *const c_char, name.len(), std::ptr::null()) }); let group_cb = Callback::new(); - let dynamic = id(unsafe { moq_publish_track_dynamic(track, Some(channel_callback), group_cb.ptr) }); + let dynamic = id(unsafe { moq_publish_track_requests(track, Some(channel_callback), group_cb.ptr) }); let ascending = |start, end| { moq_net::track::Subscription::default() @@ -3401,7 +3401,7 @@ fn a_group_request_nobody_reads_is_withdrawn() { assert_eq!(moq_group_request_free(next), 0); drop(reader); - assert_eq!(moq_publish_dynamic_cancel(dynamic), 0); + assert_eq!(moq_publish_requests_cancel(dynamic), 0); assert_eq!(group_cb.recv_terminal(), 0); assert_eq!(moq_publish_track_finish(track), 0); assert_eq!(moq_publish_close(broadcast), 0); @@ -3418,7 +3418,7 @@ fn a_rejected_group_request_binds_only_its_readers() { let track = id(unsafe { moq_publish_track(broadcast, name.as_ptr() as *const c_char, name.len(), std::ptr::null()) }); let group_cb = Callback::new(); - let dynamic = id(unsafe { moq_publish_track_dynamic(track, Some(channel_callback), group_cb.ptr) }); + let dynamic = id(unsafe { moq_publish_track_requests(track, Some(channel_callback), group_cb.ptr) }); // The live feed ran from 10 and ended, so only a fill can serve group 6. { @@ -3471,7 +3471,7 @@ fn a_rejected_group_request_binds_only_its_readers() { assert_eq!(group.sequence, 6); drop(reader); - assert_eq!(moq_publish_dynamic_cancel(dynamic), 0); + assert_eq!(moq_publish_requests_cancel(dynamic), 0); assert_eq!(group_cb.recv_terminal(), 0); assert_eq!(moq_publish_track_finish(track), 0); assert_eq!(moq_publish_close(broadcast), 0); @@ -3483,13 +3483,13 @@ fn track_request_dynamic_survives_accept() { let origin = id(moq_origin_create()); let broadcast = publish_broadcast(origin, b"request-dynamic"); let request_cb = Callback::new(); - let _dynamic = id(unsafe { moq_publish_dynamic(broadcast, Some(channel_callback), request_cb.ptr) }); + let _dynamic = id(unsafe { moq_publish_requests(broadcast, Some(channel_callback), request_cb.ptr) }); // A fetch of a track the broadcast has not declared requests the track first. let fetch = fetch_group(broadcast, "archive", 9, 0); let request = id(request_cb.recv()); let group_cb = Callback::new(); - let track_dynamic = id(unsafe { moq_track_request_dynamic(request, Some(channel_callback), group_cb.ptr) }); + let track_dynamic = id(unsafe { moq_track_request_requests(request, Some(channel_callback), group_cb.ptr) }); let track = id(unsafe { moq_track_request_accept(request, std::ptr::null()) }); let group_request = id(group_cb.recv()); @@ -3505,7 +3505,7 @@ fn track_request_dynamic_survives_accept() { assert_eq!(moq_publish_group_finish(group), 0); assert_eq!(fetch.recv_timeout(TIMEOUT).unwrap().unwrap(), (0, payload.to_vec())); - assert_eq!(moq_publish_dynamic_cancel(track_dynamic), 0); + assert_eq!(moq_publish_requests_cancel(track_dynamic), 0); assert_eq!(group_cb.recv_terminal(), 0); assert_eq!(moq_publish_track_finish(track), 0); assert_eq!(moq_publish_close(broadcast), 0); @@ -3856,7 +3856,7 @@ fn consume_announced_delivers_a_takeover_once(dynamic_at: &str) { let dynamic = { let _runtime = crate::ffi::RUNTIME.enter(); let origin = crate::Id::try_from(origin).unwrap(); - State::lock().origin.get(origin).unwrap().dynamic(dynamic_at).unwrap() + State::lock().origin.get(origin).unwrap().requests(dynamic_at).unwrap() }; let cb = Callback::new(); let path = b"live"; @@ -3899,10 +3899,10 @@ fn consume_announced_delivers_a_held_takeover_once() { } /// Serve `prefix` on `origin` dynamically. -fn serve_dynamic(origin: u32, prefix: &str) -> moq_net::origin::Dynamic { +fn serve_dynamic(origin: u32, prefix: &str) -> moq_net::origin::Requests { let _runtime = crate::ffi::RUNTIME.enter(); let origin = crate::Id::try_from(origin).unwrap(); - State::lock().origin.get(origin).unwrap().dynamic(prefix).unwrap() + State::lock().origin.get(origin).unwrap().requests(prefix).unwrap() } /// Wait for the broadcast at `path` on `origin`, delivering each instance through `cb`. diff --git a/rs/moq-cli/src/play/media.rs b/rs/moq-cli/src/play/media.rs index d0379a43532..91c856b5621 100644 --- a/rs/moq-cli/src/play/media.rs +++ b/rs/moq-cli/src/play/media.rs @@ -1632,7 +1632,7 @@ mod tests { /// Answer the next request through `claim` with one `audio` rendition, under `route`'s epoch. async fn answer( - claim: &moq_net::origin::Dynamic, + claim: &moq_net::origin::Requests, route: &moq_net::origin::Route, ) -> ( moq_net::origin::Publication, @@ -1720,7 +1720,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn a_refused_broadcast_ends_the_player() { let origin = moq_tokio::origin::spawn(); - let handler = origin.dynamic("").unwrap(); + let handler = origin.requests("").unwrap(); let recorder = Recorder::default(); let player = tokio::spawn(media(&origin, Duration::from_millis(50), recorder.clone()).run()); let request = handler.requested_broadcast().await.unwrap(); @@ -1884,7 +1884,7 @@ mod tests { // The broadcast ends while its route stands, so the player goes idle. tokio::time::sleep(Duration::from_secs(60)).await; - let pool = origin.dynamic("").unwrap(); + let pool = origin.requests("").unwrap(); drop(exact); let (served, served_catalog, mut new) = answer(&pool, &route).await; write(&mut new, 10, NEW).await; @@ -1921,7 +1921,7 @@ mod tests { } exact.unannounce(); - let pool = origin.dynamic("").unwrap(); + let pool = origin.requests("").unwrap(); let (mirror, mirror_catalog, mut copy) = answer(&pool, &route).await; for index in 50..60 { copy.write(packet(index, NEW)).unwrap(); diff --git a/rs/moq-cli/src/transcode.rs b/rs/moq-cli/src/transcode.rs index 8a22ec0a890..50cf6667c32 100644 --- a/rs/moq-cli/src/transcode.rs +++ b/rs/moq-cli/src/transcode.rs @@ -227,7 +227,7 @@ mod tests { } }; let old = origin.publish("source", route()).unwrap(); - let _old_dynamic = old.dynamic(); + let _old_dynamic = old.requests(); let mut derivatives = moq_mux::follow::Instances::new(&publish.consume(), "derived", None).unwrap(); let following = Following { origin: origin.consume(), @@ -245,7 +245,7 @@ mod tests { .await .unwrap(); let new = origin.publish("source", route()).unwrap(); - let _new_dynamic = new.dynamic(); + let _new_dynamic = new.requests(); let second = next(&mut derivatives).await; assert!(!first.is_clone(&second)); assert_ne!(first.info().epoch, second.info().epoch); @@ -293,7 +293,7 @@ mod tests { assert!(!task.is_finished(), "a clean end stopped following"); let new = origin.publish("source", route()).unwrap(); - let _new_dynamic = new.dynamic(); + let _new_dynamic = new.requests(); let second = next(&mut derivatives).await; assert!(!first.is_clone(&second)); task.abort(); diff --git a/rs/moq-ffi/MIGRATE.md b/rs/moq-ffi/MIGRATE.md index 7180e7123a9..ee4d98e19a9 100644 --- a/rs/moq-ffi/MIGRATE.md +++ b/rs/moq-ffi/MIGRATE.md @@ -5,6 +5,11 @@ These are the UniFFI names; each language wrapper has its own `MIGRATE.md` in it ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `dynamic()` on `MoqOriginProducer`, `MoqBroadcastProducer`, `MoqTrackProducer`, and `MoqTrackRequest` to `requests()`. +Their handles `MoqOriginDynamic`, `MoqBroadcastDynamic`, and `MoqTrackDynamic` are `MoqOriginRequests`, `MoqBroadcastRequests`, and `MoqTrackRequests`; their methods are unchanged. + ### `MoqAllocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `MoqBandwidth` is `MoqAllocator`, and `MoqSession::bandwidth()` is `allocator()`, matching `moq_net::bandwidth::Allocator`. `MoqReservation::grant()` is `rate()`, matching `moq_net::bandwidth::Reservation::rate()`. The `bandwidth` option field on audio and video producers keeps its name. diff --git a/rs/moq-ffi/src/origin.rs b/rs/moq-ffi/src/origin.rs index ffffbf609fc..307e146d44b 100644 --- a/rs/moq-ffi/src/origin.rs +++ b/rs/moq-ffi/src/origin.rs @@ -67,7 +67,7 @@ impl TryFrom for moq_net::origin::Route { /// Carried by `MoqAnnounceConsumer` events. A route claims capability, not /// inventory: by convention a publisher announces each broadcast's exact path, /// so subscribers can enumerate broadcasts, while a service advertises a prefix -/// with `MoqOriginProducer::dynamic` and answers whatever is requested beneath it. +/// with `MoqOriginProducer::requests` and answers whatever is requested beneath it. #[derive(Clone, Debug, PartialEq, Eq, uniffi::Record)] pub struct MoqRoute { /// Hop ids of the relay hops the route traversed, oldest first. 0 is the @@ -137,9 +137,9 @@ pub struct MoqAnnounceConsumer { /// /// Keeps its origin running, like a published broadcast, after every /// `MoqOriginProducer` is gone. -pub struct MoqOriginDynamic { +pub struct MoqOriginRequests { slot: Slot, - task: std::sync::Mutex>>>, + task: std::sync::Mutex>>>, } #[derive(uniffi::Object)] @@ -162,17 +162,17 @@ struct Announced { driver: Background, } -/// The served route behind one `MoqOriginProducer::dynamic` handle, shared +/// The served route behind one `MoqOriginProducer::requests` handle, shared /// between the handle and the task draining it. Emptied by the handle's cancel, /// which retracts the route: the task sees the empty slot and ends. -type Slot = Arc>>; +type Slot = Arc>>; -struct OriginDynamic { +struct OriginRequests { slot: Slot, driver: Background, } -impl OriginDynamic { +impl OriginRequests { async fn requested_broadcast(&mut self) -> Result, MoqError> { let request = self .driver @@ -386,16 +386,16 @@ impl MoqOriginProducer { /// the covering prefix and rejects the rest as they are requested. Hold /// the returned handle while the route should stay advertised and missing /// broadcasts should be served. - pub fn dynamic(&self, prefix: String) -> Result, MoqError> { + pub fn requests(&self, prefix: String) -> Result, MoqError> { let _guard = crate::ffi::enter(); self.inner.driver.check()?; - let result = self.inner.dynamic(prefix); + let result = self.inner.requests(prefix); self.inner.driver.check()?; let dynamic = result?; let slot = Arc::new(std::sync::Mutex::new(Some(dynamic))); - Ok(Arc::new(MoqOriginDynamic { + Ok(Arc::new(MoqOriginRequests { slot: slot.clone(), - task: std::sync::Mutex::new(Some(Arc::new(Task::new(OriginDynamic { + task: std::sync::Mutex::new(Some(Arc::new(Task::new(OriginRequests { slot, driver: self.inner.driver.clone(), })))), @@ -407,11 +407,11 @@ impl MoqOriginProducer { /// The broadcast exists for nobody, on this origin or its peers, until /// [`MoqBroadcastProducer::announce`]: until then announcement streams skip it /// and requests for its path are unroutable. Announce after populating - /// tracks; an on-demand handler is [`Self::dynamic`]. Create, `dynamic()` if + /// tracks; an on-demand handler is [`Self::requests`]. Create, `requests()` if /// tracks are served on demand, populate, then announce. /// /// [`MoqBroadcastProducer::close`] ends it for good; dropping its last handle, - /// `dynamic()` included, does the same. + /// `requests()` included, does the same. pub fn create_broadcast(&self, path: String) -> Result, MoqError> { let _guard = crate::ffi::enter(); self.inner.driver.check()?; @@ -497,10 +497,10 @@ impl MoqOriginConsumer { } } -// ---- MoqOriginDynamic ---- +// ---- MoqOriginRequests ---- #[uniffi::export] -impl MoqOriginDynamic { +impl MoqOriginRequests { /// Wait for the next broadcast requested through this handle's prefix. /// /// Returns a [`MoqBroadcastRequest`]: accept it with a broadcast producer or reject @@ -669,7 +669,7 @@ mod supervision_tests { driver: completion.clone(), }); let broadcast = origin.create_broadcast("retained".into()).unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); drop(origin); *trigger .write() @@ -698,7 +698,7 @@ mod supervision_tests { }); let broadcast = origin.create_broadcast("retained".into()).unwrap(); // A dynamic handle outlives the consumed producer, so only an explicit close ends it. - let _dynamic = broadcast.dynamic().unwrap(); + let _dynamic = broadcast.requests().unwrap(); let consumer = broadcast.state.lock().unwrap().as_ref().unwrap().broadcast.consume(); let catalog = crate::media::MoqMediaCatalogProducer::new(broadcast.clone()).unwrap(); *trigger diff --git a/rs/moq-ffi/src/producer.rs b/rs/moq-ffi/src/producer.rs index 6b44d445ccb..d622bdc1925 100644 --- a/rs/moq-ffi/src/producer.rs +++ b/rs/moq-ffi/src/producer.rs @@ -216,36 +216,36 @@ pub struct MoqBroadcastProducer { /// A handler for requests for tracks in a broadcast. #[derive(uniffi::Object)] -pub struct MoqBroadcastDynamic { - task: Task, +pub struct MoqBroadcastRequests { + task: Task, } /// Serves on-demand fetches of uncached groups for one track. #[derive(uniffi::Object)] -pub struct MoqTrackDynamic { +pub struct MoqTrackRequests { task: Task, } -impl MoqTrackDynamic { - fn new(inner: moq_net::track::Dynamic) -> Self { +impl MoqTrackRequests { + fn new(inner: moq_net::track::Requests) -> Self { Self { task: Task::new(TrackDynamicProducer { inner }), } } } -struct DynamicProducer { - inner: moq_net::broadcast::Dynamic, +struct RequestsProducer { + inner: moq_net::broadcast::Requests, children: Children, } struct TrackDynamicProducer { - inner: moq_net::track::Dynamic, + inner: moq_net::track::Requests, } -impl DynamicProducer { +impl RequestsProducer { async fn requested_track(&mut self) -> Result, MoqError> { - // Hand back the un-accepted request, mirroring `moq_net::broadcast::Dynamic`: the caller + // Hand back the un-accepted request, mirroring `moq_net::broadcast::Requests`: the caller // accepts it (raw, at a chosen timescale) or publishes media onto it (importer accepts). // The subscriber's subscribe stays pending until then. let request = self.inner.requested_track().await?; @@ -335,12 +335,12 @@ impl MoqBroadcastProducer { /// /// Hold the returned object for as long as missing track requests should be /// accepted. Dropping it makes future subscriptions to unknown tracks fail. - pub fn dynamic(&self) -> Result, MoqError> { + pub fn requests(&self) -> Result, MoqError> { let _guard = crate::ffi::enter(); self.with_state(|state| { - Ok(Arc::new(MoqBroadcastDynamic { - task: Task::new(DynamicProducer { - inner: state.broadcast.dynamic(), + Ok(Arc::new(MoqBroadcastRequests { + task: Task::new(RequestsProducer { + inner: state.broadcast.requests(), children: state.children.clone(), }) .supervised(state.driver.clone()), @@ -431,10 +431,10 @@ impl MoqBroadcastProducer { } } -// ---- Dynamic Broadcast Producer ---- +// ---- Broadcast Requests ---- #[uniffi::export] -impl MoqBroadcastDynamic { +impl MoqBroadcastRequests { /// Wait for the next subscriber-requested track. /// /// Returns a [`MoqTrackRequest`]: accept it for raw writes with @@ -458,10 +458,10 @@ impl MoqBroadcastDynamic { } } -// ---- Dynamic Track Producer ---- +// ---- Track Requests ---- #[uniffi::export] -impl MoqTrackDynamic { +impl MoqTrackRequests { /// Wait for the next run of groups readers miss: a fetch of an uncached group, or /// history a subscription reads that the cache no longer holds. /// @@ -628,11 +628,11 @@ impl MoqTrackRequest { /// Obtain and retain this handle before `accept()` when the track itself was /// requested by a fetch. This keeps the pending group request serviceable across /// the transition from request to producer. - pub fn dynamic(&self) -> Result, MoqError> { + pub fn requests(&self) -> Result, MoqError> { let _guard = crate::ffi::enter(); let guard = self.inner.lock().unwrap(); let request = guard.as_ref().ok_or(MoqError::Closed)?; - Ok(Arc::new(MoqTrackDynamic::new(request.dynamic()))) + Ok(Arc::new(MoqTrackRequests::new(request.requests()))) } /// Accept the request as a raw track, fixing its [`MoqTrackInfo`] (timescale, etc.). @@ -744,11 +744,11 @@ impl MoqTrackProducer { /// /// Hold the returned object for as long as cache misses should wait to be /// served. Without a live dynamic handler, a missing group fails with `NotFound`. - pub fn dynamic(&self) -> Result, MoqError> { + pub fn requests(&self) -> Result, MoqError> { let _guard = crate::ffi::enter(); let guard = self.inner.lock().unwrap(); let track = guard.as_ref().ok_or(MoqError::Closed)?; - Ok(Arc::new(MoqTrackDynamic::new(track.dynamic()))) + Ok(Arc::new(MoqTrackRequests::new(track.requests()))) } /// A watch-only handle to this track's name and whether it has subscribers. diff --git a/rs/moq-ffi/src/test.rs b/rs/moq-ffi/src/test.rs index 6dff709cd1b..1cae13b3b35 100644 --- a/rs/moq-ffi/src/test.rs +++ b/rs/moq-ffi/src/test.rs @@ -1860,7 +1860,7 @@ async fn json_stream_roundtrip() { #[tokio::test] async fn json_on_requested_track() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let config = MoqJsonStreamConfig { compression: false }; // The subscribe stays pending until the request is accepted, so run it concurrently. @@ -1925,7 +1925,7 @@ async fn json_consumer_takes_an_unread_track() { #[tokio::test] async fn track_request_demand_survives_accept() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let subscribe = tokio::spawn(async move { consumer.subscribe_track("events".into(), None).await }); let request = dynamic.requested_track().await.unwrap(); @@ -1958,7 +1958,7 @@ async fn track_request_demand_survives_accept() { #[tokio::test] async fn track_request_demand_ends_on_rejection() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let subscribe = tokio::spawn(async move { consumer.subscribe_track("events".into(), None).await }); let request = dynamic.requested_track().await.unwrap(); @@ -1972,7 +1972,7 @@ async fn track_request_demand_ends_on_rejection() { #[tokio::test] async fn dynamic_track_request() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); // The subscribe stays pending until the request is accepted below, so run it on a @@ -2190,7 +2190,7 @@ async fn raw_group_abort_reaches_consumer() { #[tokio::test] async fn dynamic_track_request_can_abort() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); // The subscribe stays pending until the request is resolved; aborting an @@ -2551,7 +2551,7 @@ async fn media_group_fails_loudly_on_bad_containers() { async fn dynamic_track_serves_fetch_miss_and_priority() { let broadcast = MoqBroadcastProducer::new().unwrap(); let track = broadcast.publish_track("events".into(), Some(timed_info())).unwrap(); - let dynamic = track.dynamic().unwrap(); + let dynamic = track.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let fetch = tokio::spawn(async move { @@ -2602,7 +2602,7 @@ async fn dynamic_track_serves_fetch_miss_and_priority() { async fn fill_goes_unused_when_the_fetcher_leaves() { let broadcast = MoqBroadcastProducer::new().unwrap(); let track = broadcast.publish_track("events".into(), None).unwrap(); - let dynamic = track.dynamic().unwrap(); + let dynamic = track.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let fetch = tokio::spawn(async move { consumer.fetch_group("events".into(), 5, None).await }); @@ -2631,7 +2631,7 @@ async fn fill_goes_unused_when_the_fetcher_leaves() { async fn dynamic_track_rejects_fetch_miss() { let broadcast = MoqBroadcastProducer::new().unwrap(); let track = broadcast.publish_track("events".into(), None).unwrap(); - let dynamic = track.dynamic().unwrap(); + let dynamic = track.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let fetch = tokio::spawn(async move { consumer.fetch_group("events".into(), 5, None).await }); @@ -2672,7 +2672,7 @@ async fn fetch_unknown_track_is_not_found() { #[tokio::test] async fn requested_track_dynamic_survives_accept() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let broadcast_dynamic = broadcast.dynamic().unwrap(); + let broadcast_dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let fetch = tokio::spawn(async move { consumer.fetch_group("archive".into(), 9, None).await }); @@ -2680,7 +2680,7 @@ async fn requested_track_dynamic_survives_accept() { .await .expect("timed out waiting for track request") .unwrap(); - let track_dynamic = request.dynamic().unwrap(); + let track_dynamic = request.requests().unwrap(); let _track = request.accept(Some(timed_info())).unwrap(); let fill = tokio::time::timeout(TIMEOUT, track_dynamic.requested_fill()) @@ -2792,7 +2792,7 @@ async fn track_stream_producer_publishes_its_last_access_unit() { #[tokio::test] async fn requested_track_keeps_its_name() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let subscribe = tokio::spawn(async move { MoqMediaTrackConsumer::subscribe( @@ -2825,7 +2825,7 @@ async fn requested_track_keeps_its_name() { #[tokio::test] async fn dynamic_track_request_can_publish_media() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let catalog_consumer = MoqMediaCatalogConsumer::subscribe(&consumer).await.unwrap(); @@ -3257,7 +3257,7 @@ async fn announced_filters_patterns_and_reports_captures() { }) .unwrap(); - let _broad = origin.dynamic("room".into()).unwrap(); + let _broad = origin.requests("room".into()).unwrap(); let overlap = next_announced(&announced).await; assert_eq!(overlap.prefix, "room"); assert_eq!(overlap.captures, None, "an overlap does not pin the wildcard"); @@ -4495,7 +4495,7 @@ async fn a_failed_finish_ends_the_track_with_its_cause() { #[tokio::test(start_paused = true)] async fn accepting_a_request_after_close_is_refused() { let broadcast = MoqBroadcastProducer::new().unwrap(); - let dynamic = broadcast.dynamic().unwrap(); + let dynamic = broadcast.requests().unwrap(); let consumer = broadcast.consume().unwrap(); let subscribe = tokio::spawn(async move { consumer.subscribe_track("late".into(), None).await }); let request = dynamic.requested_track().await.unwrap(); @@ -4524,8 +4524,8 @@ async fn announced_broadcast() { _broadcast.close().unwrap(); } -fn serve(origin: &MoqOriginProducer, prefix: &str) -> Arc { - origin.dynamic(prefix.into()).unwrap() +fn serve(origin: &MoqOriginProducer, prefix: &str) -> Arc { + origin.requests(prefix.into()).unwrap() } #[tokio::test] @@ -5790,7 +5790,7 @@ async fn announced_broadcast_hands_out_the_instance_again_after_an_end() { .unwrap(); // A covering claim answering under the same epoch. - let dynamic = origin.inner().inner.dynamic("").unwrap(); + let dynamic = origin.inner().inner.requests("").unwrap(); broadcast.unannounce().unwrap(); let again = tokio::spawn(async move { followed.available().await }); let request = tokio::time::timeout(TIMEOUT, dynamic.requested_broadcast()) diff --git a/rs/moq-ffi/uniffi.toml b/rs/moq-ffi/uniffi.toml index 4dda0865a5a..eba2c541b3d 100644 --- a/rs/moq-ffi/uniffi.toml +++ b/rs/moq-ffi/uniffi.toml @@ -1,5 +1,5 @@ # Kotlin objects are AutoCloseable, and `close()` there releases the handle, -# which ends the broadcast only once no `dynamic()` handle remains. The +# which ends the broadcast only once no `requests()` handle remains. The # generated forced end is `end()` so it doesn't collide with it. [bindings.kotlin.rename] "MoqBroadcastProducer.close" = "end" diff --git a/rs/moq-gst/src/source/imp.rs b/rs/moq-gst/src/source/imp.rs index b88ce22eb5e..9c2916f8bef 100644 --- a/rs/moq-gst/src/source/imp.rs +++ b/rs/moq-gst/src/source/imp.rs @@ -2231,7 +2231,7 @@ mod session_tests { /// Block until a consumer asks the broadcast for a track, returning the request unanswered so /// its subscriber stays parked. Bounded so a session that never subscribes fails the test. - fn await_request(dynamic: &mut moq_net::broadcast::Dynamic) -> moq_net::track::Request { + fn await_request(dynamic: &mut moq_net::broadcast::Requests) -> moq_net::track::Request { super::RUNTIME .block_on(async { tokio::time::timeout(Duration::from_secs(10), dynamic.requested_track()).await }) .expect("no track was ever requested") @@ -2256,11 +2256,11 @@ mod session_tests { let element = element(); let origin = origin(); let catalog_broadcast = origin.create_broadcast("room/catalog").unwrap(); - let mut local = catalog_broadcast.dynamic(); + let mut local = catalog_broadcast.requests(); let left = origin.create_broadcast("room/left").unwrap(); - let mut remote = left.dynamic(); + let mut remote = left.requests(); let right = origin.create_broadcast("room/right").unwrap(); - let mut replacement = right.dynamic(); + let mut replacement = right.requests(); let mut catalog = moq_mux::catalog::Producer::new(&mut catalog_broadcast.broadcast().clone(), Default::default()).unwrap(); let mut config = video_rendition(); @@ -2320,7 +2320,7 @@ mod session_tests { let mut broadcast = moq_net::broadcast::Info::new().produce(); // A live handler is what makes an unserved name park rather than resolve `NotFound`, // which is how it behaves over the wire: the publisher just never answers. - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let mut catalog = moq_mux::catalog::Producer::new(&mut broadcast, moq_mux::catalog::Config::default()).unwrap(); // First update announces audio only, and no producer ever answers for it. @@ -2396,7 +2396,7 @@ mod session_tests { let element = element(); let mut broadcast = moq_net::broadcast::Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let mut catalog = moq_mux::catalog::Producer::new(&mut broadcast, moq_mux::catalog::Config::default()).unwrap(); { @@ -2947,7 +2947,7 @@ mod session_tests { let element = element(); let mut broadcast = moq_net::broadcast::Info::new().produce(); - let _dynamic = broadcast.dynamic(); + let _dynamic = broadcast.requests(); let mut catalog = moq_mux::catalog::Producer::new(&mut broadcast, moq_mux::catalog::Config::default()).unwrap(); // A video rendition nobody serves, alongside an audio one that arrives. The audio pad @@ -3520,7 +3520,7 @@ mod session_tests { let recorder = Recorder::attach(&element); let origin = origin(); - let claim = origin.dynamic("").unwrap(); + let claim = origin.requests("").unwrap(); let (answers, answered) = std::sync::mpsc::channel(); let handler = super::RUNTIME.spawn(async move { while let Ok(request) = claim.requested_broadcast().await { @@ -3553,7 +3553,7 @@ mod session_tests { let element = element(); let recorder = Recorder::attach(&element); let origin = origin(); - let pool = origin.dynamic("").unwrap(); + let pool = origin.requests("").unwrap(); let session = follow(&element, &origin); let pending = super::RUNTIME.block_on(async { tokio::time::timeout(Duration::from_secs(10), pool.requested_broadcast()) diff --git a/rs/moq-hls/src/export/mod.rs b/rs/moq-hls/src/export/mod.rs index ad0cf40ac89..ded016b871a 100644 --- a/rs/moq-hls/src/export/mod.rs +++ b/rs/moq-hls/src/export/mod.rs @@ -5262,7 +5262,7 @@ mod tests { async fn a_pending_timeline_subscription_ends_with_the_broadcast() { let test = Timelines::new(); // A handler keeps the unpublished timelines' requests waiting rather than refused. - let _handler = test.broadcast.dynamic(); + let _handler = test.broadcast.requests(); tokio::time::sleep(Duration::from_secs(60)).await; assert!(!test.rendition("video0").snapshot().finished); diff --git a/rs/moq-hls/src/export/rendition.rs b/rs/moq-hls/src/export/rendition.rs index 1f5e0251ec1..be87738cde9 100644 --- a/rs/moq-hls/src/export/rendition.rs +++ b/rs/moq-hls/src/export/rendition.rs @@ -1491,13 +1491,13 @@ mod tests { async fn pending_reads_preserve_a_later_authorization_refusal() { let origin = moq_tokio::origin::spawn(); let broadcast = origin.create_broadcast("room/live").unwrap(); - let dynamic = origin.dynamic("room/secret").unwrap(); + let dynamic = origin.requests("room/secret").unwrap(); let source = moq_mux::Source::new(origin.consume(), broadcast.consume()); let mut config = VideoConfig::new(hang::catalog::VideoCodec::VP8); config.broadcast = Some(moq_net::path::Relative::new("./secret").to_owned()); let rendition = Arc::new(Rendition::video("video".into(), &config, &source, Archive::default(), None).unwrap()); let request = dynamic.requested_broadcast().await.unwrap(); - let other = origin.dynamic("room/hidden").unwrap(); + let other = origin.requests("room/hidden").unwrap(); config.broadcast = Some(moq_net::path::Relative::new("./hidden").to_owned()); let resolving = Arc::new(Rendition::video("video".into(), &config, &source, Archive::default(), None).unwrap()); let other_request = other.requested_broadcast().await.unwrap(); @@ -1553,7 +1553,7 @@ mod tests { fn capture_keeps_the_queried_track_when_end_lands_during_the_query() { struct Serve { broadcast: moq_net::broadcast::Producer, - dynamic: std::sync::Mutex, + dynamic: std::sync::Mutex, track: std::sync::Mutex>, // Kept alive here, since a list only holds it weakly. waiter: std::sync::OnceLock, @@ -1582,7 +1582,7 @@ mod tests { let broadcast = moq_net::broadcast::Info::new().produce(); let serve = Arc::new(Serve { - dynamic: std::sync::Mutex::new(broadcast.dynamic()), + dynamic: std::sync::Mutex::new(broadcast.requests()), broadcast, track: Default::default(), waiter: Default::default(), diff --git a/rs/moq-mux/src/catalog/hang/consumer.rs b/rs/moq-mux/src/catalog/hang/consumer.rs index 30b60a948f4..0de524d4b78 100644 --- a/rs/moq-mux/src/catalog/hang/consumer.rs +++ b/rs/moq-mux/src/catalog/hang/consumer.rs @@ -163,7 +163,7 @@ mod test { /// takes when it answers an origin request. async fn publish_catalog_served(published: Catalog<()>) -> Result> { let origin = crate::source::produce_origin(); - let dynamic = origin.dynamic("").unwrap(); + let dynamic = origin.requests("").unwrap(); let requesting = origin.consume().request_broadcast("a/pub", None); // The handler hands its route back: dropping it would retract the route and end // the broadcast it just served. diff --git a/rs/moq-mux/src/container/ts/export_test.rs b/rs/moq-mux/src/container/ts/export_test.rs index cb093dd2d4d..496adde0b1b 100644 --- a/rs/moq-mux/src/container/ts/export_test.rs +++ b/rs/moq-mux/src/container/ts/export_test.rs @@ -9312,7 +9312,7 @@ async fn a_follower_awaits_a_replacement_catalog_past_the_follow() { moq_net::origin::Route::default().with_epoch(moq_net::Epoch::mint()), ) .unwrap(); - let unanswered = second.dynamic(); + let unanswered = second.requests(); assert!( tokio::time::timeout(follow * 3, follower.next()).await.is_err(), "awaiting the replacement's catalog past the follow" @@ -9382,7 +9382,7 @@ async fn a_follower_keeps_following_when_a_return_goes_before_it_resolves() { let second = origin .publish("live", moq_net::origin::Route::default().with_epoch(epoch)) .unwrap(); - let unanswered = second.dynamic(); + let unanswered = second.requests(); assert!( tokio::time::timeout(Duration::from_secs(1), follower.next()) .await @@ -9404,7 +9404,7 @@ fn publish_refusing(origin: &moq_net::origin::Producer, epoch: &moq_net::Epoch) let broadcast = origin .publish("live", moq_net::origin::Route::default().with_epoch(epoch.clone())) .unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); tokio::spawn(async move { let _broadcast = broadcast; while let Ok(request) = dynamic.requested_track().await { @@ -9498,7 +9498,7 @@ async fn a_follower_stitches_onto_the_next_replacement_when_one_goes_before_it_r // Replaced, but the replacement's catalog request is never answered before it goes. let second = origin.publish("live", route()).unwrap(); - let unanswered = second.dynamic(); + let unanswered = second.requests(); assert!( tokio::time::timeout(Duration::from_secs(1), follower.next()) .await @@ -9560,7 +9560,7 @@ async fn a_follower_keeps_a_return_awaiting_its_catalog_when_a_stitch_goes() { moq_net::origin::Route::default().with_epoch(moq_net::Epoch::mint()), ) .unwrap(); - let unanswered = third.dynamic(); + let unanswered = third.requests(); assert!( tokio::time::timeout(Duration::from_secs(1), follower.next()) .await @@ -9865,10 +9865,10 @@ async fn a_follower_ignores_a_covering_prefix_while_the_exact_route_serves() { let mut follower = super::Follower::new(open_export(source).await.unwrap()).unwrap(); let quiet = Duration::from_secs(1); - let pool = origin.dynamic("pool").unwrap(); + let pool = origin.requests("pool").unwrap(); assert!(tokio::time::timeout(quiet, follower.next()).await.is_err(), "a start"); drop(pool); - let pool = origin.dynamic("pool").unwrap(); + let pool = origin.requests("pool").unwrap(); assert!(tokio::time::timeout(quiet, follower.next()).await.is_err(), "a restart"); drop(pool); assert!(tokio::time::timeout(quiet, follower.next()).await.is_err(), "an end"); @@ -9931,7 +9931,7 @@ async fn a_midstream_stitch_keeps_the_old_instance_playing_until_it_switches() { moq_net::origin::Route::default().with_epoch(moq_net::Epoch::mint()), ) .unwrap(); - let _unanswered = second.dynamic(); + let _unanswered = second.requests(); for ms in (0..200).step_by(20) { write_aac(&mut track, ms); } @@ -9968,7 +9968,7 @@ async fn a_nested_stitch_keeps_awaiting_the_pending_replacement() { moq_net::origin::Route::default().with_epoch(moq_net::Epoch::mint()), ) .unwrap(); - let unanswered = third.dynamic(); + let unanswered = third.requests(); assert!( tokio::time::timeout(Duration::from_secs(1), follower.next()) .await diff --git a/rs/moq-mux/src/source.rs b/rs/moq-mux/src/source.rs index f68afe5663a..fbd2bbf2586 100644 --- a/rs/moq-mux/src/source.rs +++ b/rs/moq-mux/src/source.rs @@ -475,7 +475,7 @@ mod tests { let _catalog = origin.publish("pub", Default::default()).unwrap(); settle().await; let source = resolved(&origin, "pub").await; - let dynamic = origin.dynamic("media").unwrap(); + let dynamic = origin.requests("media").unwrap(); let binding = source.bind(Some(&Relative::new("media")), None).unwrap(); let request = dynamic.requested_broadcast().await.unwrap(); diff --git a/rs/moq-net-tests/tests/integration/ietf_conformance.rs b/rs/moq-net-tests/tests/integration/ietf_conformance.rs index 6dabda5e069..6548b8c5cbe 100644 --- a/rs/moq-net-tests/tests/integration/ietf_conformance.rs +++ b/rs/moq-net-tests/tests/integration/ietf_conformance.rs @@ -22,7 +22,7 @@ async fn routing(version: &str, cluster: bool) { let publisher = origin(1); let relay = origin(2); let reader = origin(4); - let prefix = Arc::new(moq_net::fuzz::dynamic_route(&publisher, PREFIX, Default::default()).unwrap()); + let prefix = Arc::new(moq_net::fuzz::requests_route(&publisher, PREFIX, Default::default()).unwrap()); let broadcast = broadcast::Info::new().produce(); let track = broadcast.create_track("test", moq_net::track::Info::default()).unwrap(); let serving = prefix.clone(); diff --git a/rs/moq-net-tests/tests/integration/restart.rs b/rs/moq-net-tests/tests/integration/restart.rs index 6e5f300a1dc..dec1ba05a49 100644 --- a/rs/moq-net-tests/tests/integration/restart.rs +++ b/rs/moq-net-tests/tests/integration/restart.rs @@ -174,14 +174,14 @@ relay_chain_tests! { /// the hidden `fuzz` module as a session lands it, so its answers carry no exact route. struct Worker { origin: origin::Producer, - _claim: Rc, + _claim: Rc, _outputs: Rc>>, } impl Worker { fn new(hop: u64) -> Self { let origin = produce_origin(hop); - let claim = Rc::new(moq_net::fuzz::dynamic_route(&origin, "pool", origin::Route::default()).unwrap()); + let claim = Rc::new(moq_net::fuzz::requests_route(&origin, "pool", origin::Route::default()).unwrap()); let outputs = Rc::new(RefCell::new(Vec::new())); let (handler, served) = (claim.clone(), outputs.clone()); drop(moq_clock::sim::spawn(async move { @@ -258,7 +258,7 @@ async fn prefix_pool_lite07() { /// claim carries an epoch or re-prices, so it lands through the hidden `fuzz` module as /// a session lands it. struct Claim { - dynamic: Rc, + dynamic: Rc, outputs: Rc>>, } @@ -266,7 +266,7 @@ impl Claim { fn new(origin: &origin::Producer, epoch: Option) -> Self { let mut route = origin::Route::default(); route.epoch = epoch; - let dynamic = Rc::new(moq_net::fuzz::dynamic_route(origin, "live", route).unwrap()); + let dynamic = Rc::new(moq_net::fuzz::requests_route(origin, "live", route).unwrap()); let outputs = Rc::new(RefCell::new(Vec::new())); let (handler, served) = (dynamic.clone(), outputs.clone()); drop(moq_clock::sim::spawn(async move { @@ -655,14 +655,14 @@ async fn a_more_specific_source_cannot_fill_a_held_covering_track() { /// A worker claiming `pool` through the public API: each request is prepared under a /// fresh epoch and published at its exact path, and `outputs[path]` holds the latest. struct Pool { - _claim: Rc, + _claim: Rc, outputs: Rc>>, answered: Rc>, } impl Pool { fn new(origin: &origin::Producer) -> Self { - let claim = Rc::new(origin.dynamic("pool").unwrap()); + let claim = Rc::new(origin.requests("pool").unwrap()); let outputs = Rc::new(RefCell::new(std::collections::HashMap::new())); let answered = Rc::new(RefCell::new(0)); let (handler, served, count) = (claim.clone(), outputs.clone(), answered.clone()); diff --git a/rs/moq-net/MIGRATE.md b/rs/moq-net/MIGRATE.md index 445d0636ff6..98b92dcbd1c 100644 --- a/rs/moq-net/MIGRATE.md +++ b/rs/moq-net/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `origin::Producer::dynamic(prefix)`, `broadcast::Producer::dynamic()`, `track::Producer::dynamic()`, and `track::Request::dynamic()` to `requests`. +Their handles `origin::Dynamic`, `broadcast::Dynamic`, and `track::Dynamic` are `origin::Requests`, `broadcast::Requests`, and `track::Requests`; their methods are unchanged. + ### Names say one thing ([#6751](https://github.com/moq-dev/moq/pull/6751)) Rename these, which kept their behavior: diff --git a/rs/moq-net/benches/group.rs b/rs/moq-net/benches/group.rs index bd4ee030743..d15477f693e 100644 --- a/rs/moq-net/benches/group.rs +++ b/rs/moq-net/benches/group.rs @@ -392,7 +392,7 @@ fn bench_stamp(c: &mut Criterion) { let ctx = filled_track(n, &payload); // A pending fetch keeps the landing index occupied beyond this batch, // separating the no-reader fast path from an unrelated parked read. - let dynamic = waiting.then(|| ctx.track.dynamic()); + let dynamic = waiting.then(|| ctx.track.requests()); let mut fetching = dynamic .as_ref() .map(|_| ctx.track.consume().fetch_group((2 * n + 1) as u64, None)); diff --git a/rs/moq-net/benches/origin.rs b/rs/moq-net/benches/origin.rs index 5f2e9135453..6900c88adbb 100644 --- a/rs/moq-net/benches/origin.rs +++ b/rs/moq-net/benches/origin.rs @@ -168,7 +168,7 @@ fn bench_withdraw(c: &mut Criterion) { .unwrap(); let routes: Vec<_> = (0..publishers) .map(|i| { - moq_net::fuzz::dynamic_route(&producer, format!("room/{i}"), peer_route(9, 1)).unwrap() + moq_net::fuzz::requests_route(&producer, format!("room/{i}"), peer_route(9, 1)).unwrap() }) .collect(); let mut cursors: Vec<_> = (0..subscribers).map(|_| producer.consume().announced()).collect(); @@ -224,12 +224,13 @@ fn bench_withdraw_wave(c: &mut Criterion) { .unwrap(); let near: Vec<_> = (0..broadcasts) .map(|i| { - moq_net::fuzz::dynamic_route(&producer, format!("room/{i}"), route(&[9, 2])).unwrap() + moq_net::fuzz::requests_route(&producer, format!("room/{i}"), route(&[9, 2])).unwrap() }) .collect(); let far: Vec<_> = (0..broadcasts) .map(|i| { - moq_net::fuzz::dynamic_route(&producer, format!("room/{i}"), route(&[9, 3, 4])).unwrap() + moq_net::fuzz::requests_route(&producer, format!("room/{i}"), route(&[9, 3, 4])) + .unwrap() }) .collect(); let mut cursors: Vec<_> = (0..subscribers).map(|_| producer.consume().announced()).collect(); @@ -274,13 +275,13 @@ fn bench_route_churn(c: &mut Criterion) { group.bench_function(id, |b| { let (producer, _driver) = origin::Producer::new(origin::Config::default()); let _routes: Vec<_> = (0..broadcasts) - .map(|i| moq_net::fuzz::dynamic_route(&producer, format!("room/{i}"), peer_route(1, 1)).unwrap()) + .map(|i| moq_net::fuzz::requests_route(&producer, format!("room/{i}"), peer_route(1, 1)).unwrap()) .collect(); let mut cursors: Vec<_> = (0..subscribers).map(|_| producer.consume().announced()).collect(); for cursor in &mut cursors { while cursor.try_next().is_some() {} } - b.iter(|| drop(moq_net::fuzz::dynamic_route(&producer, "room/0", peer_route(2, 5)).unwrap())); + b.iter(|| drop(moq_net::fuzz::requests_route(&producer, "room/0", peer_route(2, 5)).unwrap())); for cursor in &mut cursors { assert!(cursor.try_next().is_none(), "the winner is unchanged"); } @@ -405,7 +406,7 @@ fn bench_announce_duplicate(c: &mut Criterion) { // the entries are distinct routes rather than one re-priced in place. let _routes: Vec<_> = (1..=duplicates) .map(|peer| { - moq_net::fuzz::dynamic_route(&producer, PATH, peer_route(peer as u64, INCUMBENT_COST)).unwrap() + moq_net::fuzz::requests_route(&producer, PATH, peer_route(peer as u64, INCUMBENT_COST)).unwrap() }) .collect(); let mut cursors: Vec = (0..subscribers) @@ -416,7 +417,7 @@ fn bench_announce_duplicate(c: &mut Criterion) { } b.iter(|| { - let handle = moq_net::fuzz::dynamic_route( + let handle = moq_net::fuzz::requests_route( &producer, PATH, peer_route(duplicates as u64 + 1, INCUMBENT_COST - 1), @@ -456,12 +457,12 @@ fn bench_reprice_duplicate(c: &mut Criterion) { &Patterns::from(Pattern::subtree(&format!("{PATH}/p{}", (peer - 1) % 2)).unwrap()), ) .unwrap(); - moq_net::fuzz::dynamic_route(&scoped, PATH, peer_route(peer as u64, incumbent_cost)).unwrap() + moq_net::fuzz::requests_route(&scoped, PATH, peer_route(peer as u64, incumbent_cost)).unwrap() }) .collect(); let challenger = duplicates as u64 + 1; let route = - moq_net::fuzz::dynamic_route(&producer, PATH, peer_route(challenger, incumbent_cost + 1)).unwrap(); + moq_net::fuzz::requests_route(&producer, PATH, peer_route(challenger, incumbent_cost + 1)).unwrap(); let mut cursors: Vec = (0..subscribers) .map(|peer| { producer @@ -522,7 +523,7 @@ fn bench_announce_fronts(c: &mut Criterion) { let (producer, mut driver) = origin::Producer::new(origin::Config::default()); let consumer = producer.consume(); // Served but never answered: every request under it parks a front. - let _served = producer.dynamic("room").unwrap(); + let _served = producer.requests("room").unwrap(); let _requests: Vec<_> = (0..fronts) .map(|i| consumer.request_broadcast(format!("room/{i}"), None)) .collect(); @@ -562,7 +563,7 @@ fn bench_serve_idle(c: &mut Criterion) { let (producer, _driver) = origin::Producer::new(origin::Config::default()); // One route per announced path, exactly as a session lands a peer's. let dynamics: Vec<_> = (0..routes) - .map(|i| producer.dynamic(format!(".stats/p{}/node/edge{i}", i % 8)).unwrap()) + .map(|i| producer.requests(format!(".stats/p{}/node/edge{i}", i % 8)).unwrap()) .collect(); b.iter(|| { // A fresh waiter per sweep, so every poll pays a real registration: a @@ -717,9 +718,10 @@ fn bench_unroutable_churn(c: &mut Criterion) { group.bench_function(id, |b| { let (producer, mut driver) = origin::Producer::new(origin::Config::default()); let consumer = producer.consume(); - let server = moq_net::fuzz::dynamic_route(&producer, "room", origin::Route::default()).unwrap(); + let server = + moq_net::fuzz::requests_route(&producer, "room", origin::Route::default()).unwrap(); let unrelated = - moq_net::fuzz::dynamic_route(&producer, "other", origin::Route::default()).unwrap(); + moq_net::fuzz::requests_route(&producer, "other", origin::Route::default()).unwrap(); let mut waiting = Waiting::new( (0..requesters) .map(|i| { @@ -823,7 +825,7 @@ const POOL_HOP: u64 = 1_000; struct Pool { producer: origin::Producer, driver: origin::Driver, - _members: Vec, + _members: Vec, _producers: Vec, _consumers: Vec, cursors: Vec, @@ -843,7 +845,7 @@ fn pool(members: usize, paths: usize, cursors: usize) -> Pool { let consumer = producer.consume(); let cursors = (0..cursors).map(|_| consumer.announced()).collect(); let members: Vec<_> = (0..members) - .map(|i| moq_net::fuzz::dynamic_route(&producer, "pool", pool_route(POOL_HOP + i as u64)).unwrap()) + .map(|i| moq_net::fuzz::requests_route(&producer, "pool", pool_route(POOL_HOP + i as u64)).unwrap()) .collect(); let waiter = kio::Waiter::noop(); @@ -902,7 +904,7 @@ fn bench_pool_churn(c: &mut Criterion) { let waiter = kio::Waiter::noop(); let hop = POOL_HOP + members as u64; b.iter(|| { - let joined = moq_net::fuzz::dynamic_route(&pool.producer, "pool", pool_route(hop)).unwrap(); + let joined = moq_net::fuzz::requests_route(&pool.producer, "pool", pool_route(hop)).unwrap(); pool.driver.poll(moq_net::time::Instant::now(), &waiter).unwrap(); drop(joined); pool.driver.poll(moq_net::time::Instant::now(), &waiter).unwrap(); @@ -930,7 +932,7 @@ fn bench_pool_cursors(c: &mut Criterion) { let waiter = kio::Waiter::noop(); let hop = POOL_HOP + members as u64; b.iter(|| { - let joined = moq_net::fuzz::dynamic_route(&pool.producer, "pool", pool_route(hop)).unwrap(); + let joined = moq_net::fuzz::requests_route(&pool.producer, "pool", pool_route(hop)).unwrap(); pool.driver.poll(moq_net::time::Instant::now(), &waiter).unwrap(); drop(joined); pool.driver.poll(moq_net::time::Instant::now(), &waiter).unwrap(); diff --git a/rs/moq-net/benches/retirement.rs b/rs/moq-net/benches/retirement.rs index fdc5281f03a..365ec2b6a00 100644 --- a/rs/moq-net/benches/retirement.rs +++ b/rs/moq-net/benches/retirement.rs @@ -22,7 +22,7 @@ fn retirement(c: &mut Criterion) { || { let (origin, driver) = origin::Producer::new(origin::Config::default()); let routes: Vec<_> = (0..routes) - .map(|i| origin.dynamic(format!("route/{i}")).unwrap()) + .map(|i| origin.requests(format!("route/{i}")).unwrap()) .collect(); let mut watches = Vec::new(); let mut controls = Vec::new(); @@ -46,7 +46,7 @@ fn retirement(c: &mut Criterion) { (origin, driver, routes, watches, controls, pending) }, |fixture| { - let replacement = fixture.0.dynamic("route/0/jobs").unwrap(); + let replacement = fixture.0.requests("route/0/jobs").unwrap(); let refused = fixture .5 .iter() diff --git a/rs/moq-net/benches/track.rs b/rs/moq-net/benches/track.rs index 40d84446c0f..fe62dd2252c 100644 --- a/rs/moq-net/benches/track.rs +++ b/rs/moq-net/benches/track.rs @@ -1751,7 +1751,7 @@ fn bench_time_end(c: &mut Criterion) { struct Fills { _broadcast: broadcast::Producer, _track: track::Producer, - dynamic: track::Dynamic, + dynamic: track::Requests, readers: Vec, runs: u64, } @@ -1760,7 +1760,7 @@ impl Fills { fn new(readers: usize, runs: u64) -> Self { let broadcast = broadcast::Info::default().produce(); let mut track = broadcast.create_track("bench", timed()).unwrap(); - let dynamic = track.dynamic(); + let dynamic = track.requests(); // The feed starts past every run, so each is a miss asked at once. let start = runs * 2; track.start_at(start).unwrap(); @@ -1835,7 +1835,7 @@ fn bench_fill(c: &mut Criterion) { struct RangeFills { _broadcast: broadcast::Producer, _track: track::Producer, - dynamic: track::Dynamic, + dynamic: track::Requests, reader: track::Subscriber, groups: u64, } @@ -1844,7 +1844,7 @@ impl RangeFills { fn new(ranges: u64, span: u64) -> Self { let broadcast = broadcast::Info::default().produce(); let mut track = broadcast.create_track("bench", timed()).unwrap(); - let dynamic = track.dynamic(); + let dynamic = track.requests(); // The feed starts past every range, so each is a miss asked at once. A gap between // neighbors keeps every range its own fill. let start = ranges * (span + 1); diff --git a/rs/moq-net/benches/viewers.rs b/rs/moq-net/benches/viewers.rs index 48b1744a7b4..adb8a73378a 100644 --- a/rs/moq-net/benches/viewers.rs +++ b/rs/moq-net/benches/viewers.rs @@ -181,7 +181,7 @@ fn bench_churn(c: &mut Criterion) { room.leave(subscription); } b.iter(|| { - let covering = room.producer.dynamic("room").unwrap(); + let covering = room.producer.requests("room").unwrap(); room.poll(); drop(covering); room.poll(); diff --git a/rs/moq-net/src/fuzz.rs b/rs/moq-net/src/fuzz.rs index 08d7d213eae..f9dce155e8e 100644 --- a/rs/moq-net/src/fuzz.rs +++ b/rs/moq-net/src/fuzz.rs @@ -321,16 +321,16 @@ pub fn excluding(origin: crate::origin::Consumer, peer: crate::Hop) -> crate::or } /// Land a claim with a peer's wire route, as a session does, for the origin bench. -pub fn dynamic_route( +pub fn requests_route( origin: &crate::origin::Producer, prefix: impl crate::AsPath, route: crate::origin::Route, -) -> Result { - origin.dynamic_route(prefix, route) +) -> Result { + origin.requests_route(prefix, route) } /// Replace a peer claim's route in place, as a session does on a route update. -pub fn update_route(dynamic: &crate::origin::Dynamic, route: crate::origin::Route) -> Result<(), crate::Error> { +pub fn update_route(dynamic: &crate::origin::Requests, route: crate::origin::Route) -> Result<(), crate::Error> { dynamic.update_route(route) } @@ -1468,7 +1468,7 @@ pub struct RequestValidity(crate::model::broadcast::RequestValidity); impl RequestValidity { /// Watch which instance this route's peer selects for a path. - pub fn new(route: &crate::origin::Dynamic, path: &crate::Path) -> Self { + pub fn new(route: &crate::origin::Requests, path: &crate::Path) -> Self { Self(crate::model::broadcast::RequestValidity::for_source(route, path)) } diff --git a/rs/moq-net/src/ietf/publisher.rs b/rs/moq-net/src/ietf/publisher.rs index 4573e6eea00..411f9cb7726 100644 --- a/rs/moq-net/src/ietf/publisher.rs +++ b/rs/moq-net/src/ietf/publisher.rs @@ -1475,7 +1475,7 @@ impl Publisher { }; // We just received a subscribe for this exact namespace, so the peer must have // already seen the announcement. `request_broadcast` resolves it immediately, or - // falls back to the route covering it (an `origin::Dynamic`), if any. Pinned to + // falls back to the route covering it (an `origin::Requests`), if any. Pinned to // the instance it names, if any: another is refused, never served. let requesting = origin.request_broadcast(&msg.track_namespace, msg.epoch.clone()); let broadcast = match self @@ -9648,7 +9648,7 @@ mod serve_tests { let mut h = serve(version); let claim = h ._origin - .dynamic_route("live", crate::origin::Route::default()) + .requests_route("live", crate::origin::Route::default()) .unwrap(); let auth = crate::auth::Link::new(false); auth.handle().authorize(¬hing()); @@ -9671,7 +9671,7 @@ mod serve_tests { let mut h = serve(version); let claim = h ._origin - .dynamic_route("live", crate::origin::Route::default()) + .requests_route("live", crate::origin::Route::default()) .unwrap(); let auth = crate::auth::Link::new(false); h.publisher = h.publisher.clone().with_auth(auth.clone()); @@ -10006,7 +10006,7 @@ mod serve_tests { let version = Version::Draft22; for path in [".", "./child", ".session", ".session/extension"] { let h = serve(version); - let claim = h._origin.dynamic_route("", crate::origin::Route::default()).unwrap(); + let claim = h._origin.requests_route("", crate::origin::Route::default()).unwrap(); settle().await; let stream = Stream::open(&mut crate::driver::Transport::new(h.session.clone()), version) .await @@ -12177,7 +12177,7 @@ mod serve_tests { for version in FETCH_DRAFTS { let h = serve(version); let request = h._broadcast.reserve_track("cam").unwrap(); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let fetching = request.consume().fetch_group(1, None); let mut fetched = dynamic.requested_fill_group().await.unwrap().accept(None).unwrap(); fetched.write_frame(None, b"1-0".to_vec()).unwrap(); @@ -12207,7 +12207,7 @@ mod serve_tests { let version = Version::Draft22; let h = serve(version); let request = h._broadcast.reserve_track("cam").unwrap(); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let fetching = request.consume().fetch_group(4, None); let mut fetched = dynamic.requested_fill_group().await.unwrap().accept(None).unwrap(); for object in 0..2 { @@ -13061,7 +13061,7 @@ mod serve_tests { let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let (claim, published) = match parked { Parked::Resolving => ( - Some(origin.dynamic_route("room", crate::origin::Route::default()).unwrap()), + Some(origin.requests_route("room", crate::origin::Route::default()).unwrap()), None, ), Parked::Acking | Parked::Ending => { @@ -13251,7 +13251,7 @@ mod serve_tests { let mut idle = None; match setup { Setup::Resolving => { - let route = origin.dynamic_route("room", crate::origin::Route::default()).unwrap(); + let route = origin.requests_route("room", crate::origin::Route::default()).unwrap(); let request = { let requested = std::pin::pin!(route.requested_broadcast()); match futures::future::select(requested, serving.as_mut()).await { @@ -13263,7 +13263,7 @@ mod serve_tests { } Setup::Subscribing => { let broadcast = origin.publish("room", crate::origin::Route::default()).unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let request = { let requested = std::pin::pin!(dynamic.requested_track()); match futures::future::select(requested, serving.as_mut()).await { diff --git a/rs/moq-net/src/ietf/subscriber.rs b/rs/moq-net/src/ietf/subscriber.rs index ff359bafc5c..54de30565d6 100644 --- a/rs/moq-net/src/ietf/subscriber.rs +++ b/rs/moq-net/src/ietf/subscriber.rs @@ -731,7 +731,7 @@ fn largest_group(track: &track::Producer, answer: Option) -> Opt struct Idle { track: track::Producer, /// Serves its cache misses with a group FETCH, subscribed or not. - dynamic: track::Dynamic, + dynamic: track::Requests, demand: track::Demand, timescale: Option, /// The publisher ended the track, so a returning subscriber reads the copy as it is. @@ -828,7 +828,7 @@ struct BroadcastState { // The served route: dropping it (and the serve task's clone) retracts the // route and rejects its queued requests. `None` while the session's limit holds // it back, though the peer still advertises it. - dynamic: Option, + dynamic: Option, // Bumped each time the route attaches, so a serve task outlived by a limit that // took the route away and gave it back ends rather than serve beside the new one. @@ -2604,7 +2604,7 @@ impl Subscriber { if self.going_away.is_set() { route.cost = crate::origin::Cost::DRAIN; } - entry.dynamic = Some(self.origin.dynamic_route(path, route)?); + entry.dynamic = Some(self.origin.requests_route(path, route)?); entry.generation += 1; tracing::info!(route = %self.origin.absolute(path), "namespace authorized again"); Ok(Some(entry.generation)) @@ -2696,7 +2696,7 @@ impl Subscriber { return Ok(()); } // Propagates Error::Unauthorized if the namespace is out of scope. - let dynamic = self.origin.dynamic_route(&path, route.clone())?; + let dynamic = self.origin.requests_route(&path, route.clone())?; entry.insert(BroadcastState { route: route.clone(), @@ -2877,7 +2877,7 @@ impl Subscriber { let source = crate::model::broadcast::SourceGuard::new(self.origin.create_source(&requested, validity)); // The handler exists before the requester sees the source, so a track it asks // for before `run_broadcast` first polls queues instead of failing `NotFound`. - let dynamic = source.dynamic(); + let dynamic = source.requests(); request.accept(&*source); // The namespace's token closes the source as it is retracted. If it was @@ -2932,7 +2932,7 @@ impl Subscriber { &self, path: Path<'_>, source: crate::model::broadcast::SourceGuard, - mut broadcast: broadcast::Dynamic, + mut broadcast: broadcast::Requests, route: Option>, ) -> Result<(), Error> { let mut subscribes = TaskSet::owned(); @@ -3039,7 +3039,7 @@ impl Subscriber { broadcast_path: Path<'_>, // Held for the subscription's lifetime but never watched: the broadcast ending // is a retraction, which does not disturb a subscription the scope allows. - _broadcast: broadcast::Dynamic, + _broadcast: broadcast::Requests, // Open while the namespace stays announced and authorized, which its own token may // have done in place of the scope. `None` once retracted. route: Option>, @@ -3612,7 +3612,7 @@ impl Subscriber { let request = request.request_start(start); // Serves cache misses with a group FETCH. Registered before accepting, so a // miss queued meanwhile waits for it rather than failing for want of a handler. - let dynamic = request.dynamic(); + let dynamic = request.requests(); let copy = request.stage(info); let track = track::Producer::clone(©); staged = Some(copy); @@ -4685,7 +4685,7 @@ impl Subscriber { }; tracing::debug!(broadcast = %self.origin.absolute(broadcast_path), track = %track_name, "track status known"); - let dynamic = request.dynamic(); + let dynamic = request.requests(); // Nothing feeds this copy live: what it caches is fetched, never the live edge. Idle // from the accept, so no reader takes it as live in between. let track = request.idle().stage(accepted_info(&ok.properties, self.version)); @@ -6701,7 +6701,7 @@ mod tests { #[moq_clock::test] async fn session_death_rejects_a_subscribe_still_setting_up() { let broadcast = crate::broadcast::Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let mut waiting = std::pin::pin!(consumer.track("video").unwrap().subscribe(None)); assert!(poll!(&mut waiting).is_pending()); @@ -7771,7 +7771,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -7844,7 +7844,7 @@ mod tests { let (mut subscriber, log, _auth, _tokens, _task_set) = waiting_on_auth(VERSION); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -7883,7 +7883,7 @@ mod tests { let (mut subscriber, log, _auth, _tokens, _task_set) = waiting_on_auth(VERSION); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -7943,7 +7943,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8015,7 +8015,7 @@ mod tests { .with_auth(auth.clone()); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8080,7 +8080,7 @@ mod tests { .with_auth(auth.clone()); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8147,7 +8147,7 @@ mod tests { subscriber.validity = crate::model::broadcast::RequestValidity::token(Some(route.consume())); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8232,7 +8232,7 @@ mod tests { assert!(gate.poll_denied(&waiter).is_pending()); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let mut subscription = Box::pin(track.subscribe(None)); @@ -8264,7 +8264,7 @@ mod tests { }), _ => { let track = request.accept(track::Info::default().with_timescale(None)); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let mut pending = Box::pin(track.consume().fetch_group(0, None)); assert!(futures::poll!(pending.as_mut()).is_pending()); let request = dynamic.requested_fill().await.expect("group request"); @@ -8425,7 +8425,7 @@ mod tests { subscriber.validity = crate::model::broadcast::RequestValidity::token(Some(route.consume())); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let _subscription = track.subscribe(None); @@ -8457,7 +8457,7 @@ mod tests { "video", track::Info::default().with_timescale(None), ); - let requested = track.dynamic(); + let requested = track.requests(); let mut pending = Box::pin(track.consume().fetch_group(0, None)); assert!(futures::poll!(pending.as_mut()).is_pending()); let group = requested.requested_fill().await.expect("group request"); @@ -8565,7 +8565,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8639,7 +8639,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let _low = track.subscribe(track::Subscription::default().with_priority(1)); @@ -8718,7 +8718,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let _short = track.subscribe(track::Subscription::default().with_max_delay(Duration::from_secs(1))); @@ -8856,7 +8856,7 @@ mod tests { // A consumer asking for a track is what dispatches a request to the session. let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = track.subscribe(None); @@ -8943,7 +8943,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let _subscription = track.subscribe(None); @@ -9009,7 +9009,7 @@ mod tests { struct Peer { version: Version, - dynamic: Mutex>, + dynamic: Mutex>, park: Mutex, log: Mutex>, } @@ -9091,7 +9091,7 @@ mod tests { let resolved = origin.consume().request_broadcast("broadcast", None).await.unwrap(); let peer = Arc::new(Peer { version, - dynamic: Mutex::new(Some(source.dynamic())), + dynamic: Mutex::new(Some(source.requests())), park: Default::default(), log: Default::default(), }); @@ -9161,7 +9161,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let mut pending = Box::pin(async { @@ -9247,7 +9247,7 @@ mod tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); // Demand with nobody subscribing learns the track from TRACK_STATUS. @@ -10159,7 +10159,7 @@ mod tests { let (subscriber, origin) = cluster_subscriber(crate::Hop::new(1).unwrap()); let run = |route: &kio::Producer<()>| { let source = crate::model::broadcast::SourceGuard::new(origin.create_source("pool/p", Default::default())); - let (holder, dynamic) = (source.consume(), source.dynamic()); + let (holder, dynamic) = (source.consume(), source.requests()); let (this, route) = (subscriber.clone(), route.consume()); let task = moq_clock::sim::spawn(async move { this.run_broadcast(crate::Path::new("pool/p"), source, dynamic, Some(route)) @@ -16098,7 +16098,7 @@ mod stitch_tests { for objects in [Vec::new(), group_fetch_objects(SEQUENCE, 0, &[b"a"])] { let empty = objects.is_empty(); let mut run = GroupFetchRun::new(version, objects).await; - let dynamic = run.track.dynamic(); + let dynamic = run.track.requests(); let consumer = run.track.consume(); let mut filling = Box::pin(consumer.fill_groups(SEQUENCE..last + 1, 0)); assert!(futures::poll!(filling.as_mut()).is_pending()); @@ -16266,7 +16266,7 @@ mod stitch_tests { // The next relay's fill of the same run reads that one stream. let mut run = GroupFetchRun::new(version, decoder.rest().to_vec()).await; - let dynamic = run.track.dynamic(); + let dynamic = run.track.requests(); let consumer = run.track.consume(); let mut filling = Box::pin(consumer.fill_groups(3..7, 0)); assert!(futures::poll!(filling.as_mut()).is_pending()); @@ -16470,7 +16470,7 @@ mod stitch_tests { kio::Producer, std::pin::Pin>>, ) { - let dynamic = self.track.dynamic(); + let dynamic = self.track.requests(); let mut fetch = Box::pin(self.track.consume().fetch_group(SEQUENCE, None)); assert!(futures::poll!(fetch.as_mut()).is_pending()); let fill = dynamic.requested_fill().await.expect("group request"); @@ -16664,7 +16664,7 @@ mod joining_fetch_tests { ); let producer = crate::broadcast::Info::default().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("video").unwrap(); let subscription = match start { @@ -16796,7 +16796,7 @@ mod joining_fetch_tests { ); let auth = subscriber.auth.clone(); let broadcast = crate::broadcast::Info::default().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let track = consumer.track("video").unwrap(); let mut subscribing = Box::pin(track.subscribe(None)); @@ -17274,7 +17274,7 @@ mod joining_fetch_tests { "video", track::Info::default().with_timescale(None), ); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let consumer = track.consume(); let mut fetch = Box::pin(consumer.fetch_group(GROUP, None)); assert!(futures::poll!(fetch.as_mut()).is_pending()); @@ -17555,7 +17555,7 @@ mod joining_fetch_tests { "video", track::Info::default().with_timescale(None), ); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let consumer = track.consume(); let mut fetch = std::pin::pin!(consumer.fetch_group(GROUP, None)); assert!(futures::poll!(fetch.as_mut()).is_pending()); @@ -17621,7 +17621,7 @@ mod joining_fetch_tests { "video", track::Info::default().with_timescale(None), ); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let consumer = track.consume(); let mut fetch = std::pin::pin!(consumer.fetch_group( GROUP, @@ -17763,7 +17763,7 @@ mod joining_fetch_tests { "video", track::Info::default().with_timescale(None), ); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let consumer = track.consume(); let mut fetch = std::pin::pin!(consumer.fetch_group( GROUP, @@ -17884,7 +17884,7 @@ mod new_group_tests { Default::default(), ); let broadcast = crate::broadcast::Info::default().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let track = broadcast.consume().track("video").unwrap(); let first = track.subscribe(None); let request = dynamic.requested_track().await.expect("no track requested"); @@ -18225,7 +18225,7 @@ mod track_property_tests { Default::default(), ); let broadcast = crate::broadcast::Info::default().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let track = broadcast.consume().track("video").unwrap(); let subscribing = track.subscribe(None); let request = dynamic.requested_track().await.expect("no track requested"); diff --git a/rs/moq-net/src/ietf/subscriber/tracks.rs b/rs/moq-net/src/ietf/subscriber/tracks.rs index 8c4a037dbf3..1bf0899eeae 100644 --- a/rs/moq-net/src/ietf/subscriber/tracks.rs +++ b/rs/moq-net/src/ietf/subscriber/tracks.rs @@ -1278,7 +1278,7 @@ mod tests { Default::default(), ); let broadcast = crate::broadcast::Info::default().produce(); - let lister = Arc::new(broadcast.dynamic().lister().unwrap()); + let lister = Arc::new(broadcast.requests().lister().unwrap()); let tracks = broadcast.consume().tracks().unwrap(); let listening = subscriber.listen(PathOwned::from("bcast"), lister); Harness { @@ -1364,7 +1364,7 @@ mod tests { kio::Pending, moq_clock::sim::JoinHandle<()>, ) { - let mut dynamic = self._broadcast.dynamic(); + let mut dynamic = self._broadcast.requests(); let track = self._broadcast.consume().track(name).unwrap(); let reader = track.subscribe(None); let request = dynamic.requested_track().await.expect("no track requested"); diff --git a/rs/moq-net/src/lite/publisher.rs b/rs/moq-net/src/lite/publisher.rs index 9c074712e60..fa356ded43e 100644 --- a/rs/moq-net/src/lite/publisher.rs +++ b/rs/moq-net/src/lite/publisher.rs @@ -1679,7 +1679,7 @@ impl RequestServe { if requesting.is_none() { // The peer requested this exact path, so it has already seen an // announcement for it. `request_broadcast` resolves it immediately, is - // served on demand by the route covering it (an `origin::Dynamic`), or + // served on demand by the route covering it (an `origin::Requests`), or // errors when there is none. let origin = ready!(self.shared.poll_serving_origin(waiter)); let path = R::target(msg).0.clone(); @@ -7156,7 +7156,7 @@ mod tests { let mut echoed_hops = Hops::new(); echoed_hops.push(crate::Hop::UNKNOWN).unwrap(); let _echoed = origin - .dynamic_route( + .requests_route( "echoed", crate::origin::Route::default() .with_hops(echoed_hops) @@ -7167,7 +7167,7 @@ mod tests { let mut local_hops = Hops::new(); local_hops.push(upstream).unwrap(); let _local = origin - .dynamic_route("local", crate::origin::Route::default().with_hops(local_hops)) + .requests_route("local", crate::origin::Route::default().with_hops(local_hops)) .unwrap(); // A SETUP that declares no origin of its own, so only the assigned one applies. @@ -7639,10 +7639,10 @@ mod tests { let mut _route = None; let mut held = None; match wait { - Wait::Broadcast => _route = Some(origin.dynamic_route("room", crate::origin::Route::default()).unwrap()), + Wait::Broadcast => _route = Some(origin.requests_route("room", crate::origin::Route::default()).unwrap()), Wait::Track => { let broadcast = origin.create_broadcast("room").unwrap(); - let dynamic = broadcast.dynamic(); + let dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); held = Some((broadcast, dynamic)); } @@ -7867,7 +7867,7 @@ mod tests { async fn a_subscribe_update_is_not_a_close() { let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let broadcast = origin.create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let peer_setup = crate::lite::PeerSetup::new(false, crate::transport::Address::Setup); @@ -7978,7 +7978,7 @@ mod tests { let origin = crate::origin::Config::new(crate::Hop::new(1).unwrap()).produce(); let broadcast = origin.create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let peer_setup = crate::lite::PeerSetup::new(false, crate::transport::Address::Setup); @@ -8244,7 +8244,7 @@ mod tests { for version in [Version::Lite05, Version::Lite06, Version::Lite07] { let origin = crate::origin::Config::new(Hop::random()).produce(); let broadcast = origin.create_broadcast("room").unwrap(); - let _dynamic = broadcast.dynamic(); + let _dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let request = lite::Subscribe { order: crate::track::Order::Descending, @@ -8355,7 +8355,7 @@ mod tests { for version in [Version::Lite05, Version::Lite06, Version::Lite07] { let origin = crate::origin::Config::new(Hop::random()).produce(); let broadcast = origin.create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let request = lite::Subscribe { order: crate::track::Order::Descending, @@ -8487,7 +8487,7 @@ mod tests { /// with `info`, until the subscription runs. async fn subscribe_at( publisher: &Publisher, - dynamic: &mut broadcast::Dynamic, + dynamic: &mut broadcast::Requests, broadcast: &'static str, track: &'static str, priority: i8, @@ -8539,7 +8539,7 @@ mod tests { async fn send_group_ranks_by_the_subscriber_then_the_publisher() { let origin = crate::origin::Config::new(Hop::new(1).unwrap()).produce(); let broadcast = origin.create_broadcast("a").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let (publisher, log) = grouped_publisher(origin.consume()); diff --git a/rs/moq-net/src/lite/subscriber.rs b/rs/moq-net/src/lite/subscriber.rs index 005f3b57bb7..29f1067ebd5 100644 --- a/rs/moq-net/src/lite/subscriber.rs +++ b/rs/moq-net/src/lite/subscriber.rs @@ -1842,7 +1842,7 @@ struct MintedSource { epoch: Option, source: crate::model::broadcast::SourceGuard, /// The source's track handler, registered before its requester could ask for a track. - dynamic: crate::broadcast::Dynamic, + dynamic: crate::broadcast::Requests, /// Closes when the route that minted the source goes. route: kio::Consumer<()>, } @@ -1858,7 +1858,7 @@ struct SourceServe { path: PathOwned, epoch: Option, source: crate::model::broadcast::SourceGuard, - dynamic: crate::broadcast::Dynamic, + dynamic: crate::broadcast::Requests, route: kio::Consumer<()>, // A dedicated close-watch handle, since each pending operation needs its own. closed: Transport, @@ -2121,7 +2121,7 @@ mod tests { fn feed_fetch(sequence: u64) -> (track::Producer, kio::Pending, track::Fill) { let info = track::Info::default().with_timescale(None); let track = track::Producer::new(std::sync::Arc::new(crate::broadcast::Info::default()), "video", info); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let fetching = track.consume().fetch_group(sequence, None); let req = dynamic.requested_fill().now_or_never().expect("queued").unwrap(); (track, fetching, req) @@ -2323,7 +2323,7 @@ mod tests { ) -> (track::Producer, Vec>, Vec) { let info = track::Info::default().with_timescale(None); let track = track::Producer::new(Arc::new(crate::broadcast::Info::default()), "video", info); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let mut callers = Vec::new(); let mut requests = Vec::new(); for sequence in sequences { @@ -2495,7 +2495,7 @@ mod tests { let sub = feed_sub(&tail).await; let info = track::Info::default().with_timescale(None); let mut track = track::Producer::new(Arc::new(crate::broadcast::Info::default()), "video", info); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let mut reader = track.subscribe( Subscription::default() .with_range(0..) @@ -2549,7 +2549,7 @@ mod tests { let tail = kio::Producer::new(Tail::default()); let sub = feed_sub(&tail).await; let (track, caller, req) = feed_fetch(1); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let mut fetches = FeedFetches::new(&clock); fetches.push(req, &track.consume()); fetches.poll(&sub, start, &kio::Waiter::noop()); @@ -2577,7 +2577,7 @@ mod tests { let tail = kio::Producer::new(Tail::default()); let sub = feed_sub(&tail).await; let (track, mut callers, requests) = feed_batch([1, 2]); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let mut fetches = FeedFetches::new(&clock); fetches.max = 2; for req in requests { @@ -3936,7 +3936,7 @@ mod tests { }); let broadcast = crate::broadcast::Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let mut waiting = std::pin::pin!(consumer.track("video").unwrap().subscribe(None)); assert!( @@ -4030,7 +4030,7 @@ mod tests { }; let info = track::Info::default().with_timescale(None); let track = track::Producer::new(Arc::new(crate::broadcast::Info::default()), "video", info.clone()); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let fetch = track.consume().fetch_group(4, None); let request = dynamic.requested_fill_group().await.unwrap(); let mut run = FetchServeRun::new(serve, request, info); @@ -4083,7 +4083,7 @@ mod tests { }); let broadcast = crate::broadcast::Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let mut waiting = Box::pin(consumer.track("video").unwrap().subscribe(None)); assert!( @@ -4138,7 +4138,7 @@ mod tests { }); let broadcast = crate::broadcast::Info::new().produce().with_validity(validity); let consumer = broadcast.consume(); - let dynamic = broadcast.dynamic(); + let dynamic = broadcast.requests(); let route = kio::Producer::new(()); let serve = SourceServe::new( subscriber, @@ -4284,7 +4284,7 @@ mod tests { }); let broadcast = crate::broadcast::Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let mut waiting = Box::pin(consumer.track("video").unwrap().subscribe(None)); assert!(futures::poll!(waiting.as_mut()).is_pending()); @@ -4515,7 +4515,7 @@ mod tests { if !dynamic_first { // Isolate the subscription-changed arm, which can observe a concurrent // abort after the dynamic-request poll returned Pending. - serving.dynamic = other.dynamic(); + serving.dynamic = other.requests(); } serving.serving.clone().abort(Error::ProtocolViolation).unwrap(); assert!(matches!( @@ -6330,7 +6330,7 @@ impl Announced { } /// Attach a route, queued for its first serve pass. - fn attach(&mut self, path: PathOwned, route: crate::origin::Route, dynamic: crate::origin::Dynamic) { + fn attach(&mut self, path: PathOwned, route: crate::origin::Route, dynamic: crate::origin::Requests) { let wake = crate::util::QueueWake::new(path.clone(), self.ready.clone()); let route = AnnouncedRoute::new(route, dynamic, wake); route.waker.wake_by_ref(); @@ -6350,7 +6350,7 @@ impl Announced { return false; } // An error means the prefix is outside our origin's scope, so don't serve it. - match subscriber.origin.dynamic_route(&path, route.clone()) { + match subscriber.origin.requests_route(&path, route.clone()) { Ok(dynamic) => { self.attach(path, route, dynamic); true @@ -6455,7 +6455,7 @@ impl Announced { // asks for before the serve machine first runs queues instead of failing // `NotFound`. Accepted before the push, so the requester holds the source // before its serve machine can see it unheld. - let dynamic = source.dynamic(); + let dynamic = source.requests(); request.accept(&source); let _ = subscriber.sources.try_push(MintedSource { path, @@ -6518,7 +6518,7 @@ struct AnnouncedRoute { /// without recomputing the chain. route: crate::origin::Route, /// Dropping it retracts the route and rejects its queued requests. - dynamic: crate::origin::Dynamic, + dynamic: crate::origin::Requests, /// Closes as the route goes, which closes every source it minted. live: kio::Producer<()>, /// Whether the GOAWAY drain already re-priced this route. @@ -6533,7 +6533,7 @@ struct AnnouncedRoute { impl AnnouncedRoute { fn new( route: crate::origin::Route, - dynamic: crate::origin::Dynamic, + dynamic: crate::origin::Requests, wake: Arc>, ) -> Self { Self { @@ -7337,7 +7337,7 @@ struct ServeLoop { /// Watches `serving`'s subscribers, to release the copy once nobody reads it. demand: track::Demand, /// Serve on-demand fetches of uncached groups from this session. - dynamic: track::Dynamic, + dynamic: track::Requests, sub: Sub, fetches: kio::Tasks, /// Fetches a pre-lite-05 upstream has no FETCH for, held for the live feed. @@ -7597,7 +7597,7 @@ impl ServeLoop { // 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. - let dynamic = request.dynamic(); + let dynamic = request.requests(); // Lite-06+ resolves each subscription's start from its budget, so the floor // the SUBSCRIBE asks for is not where delivery begins until SUBSCRIBE_START says. let request = match serve.subscriber.version.resolves_start() { diff --git a/rs/moq-net/src/model/broadcast.rs b/rs/moq-net/src/model/broadcast.rs index 76922008349..c1af9979672 100644 --- a/rs/moq-net/src/model/broadcast.rs +++ b/rs/moq-net/src/model/broadcast.rs @@ -18,7 +18,7 @@ use crate::Error; use crate::origin::Route; use super::origin_impl::Announcer; -use super::{Requests, WeakCache}; +use super::{RequestQueue, WeakCache}; #[path = "listing.rs"] mod listing; @@ -112,7 +112,7 @@ struct BroadcastState { // and waiting for a dynamic handler to accept or deny them. A request leaves // here once handed out (the handler caches it in `tracks`, so lookups keep // coalescing onto it there). - requests: Requests, track::Request>, + requests: RequestQueue, track::Request>, // The tracks the broadcast lists, and the readers listing them; see [`Tracks`]. listing: listing::ListingState, @@ -136,7 +136,7 @@ impl BroadcastState { /// [`track::Info`] that can no longer arrive fail with `err` instead of parking. /// /// Covers a reservation nobody accepted and a request still queued for a handler. - /// A request a [`Dynamic`] already took is left alone: it may be in flight to a peer + /// A request a [`Requests`] already took is left alone: it may be in flight to a peer /// still serving it, and the handler answers or drops it. So is a track that carries /// its info: an end there is that publisher's call, and its cache stays readable. fn reject_unserved(&mut self, err: Error) { @@ -173,12 +173,12 @@ impl BroadcastState { /// /// Create tracks up front with [Self::create_track], reserve a name to fill in /// later with [Self::reserve_track], or handle on-demand consumer requests via -/// [Self::dynamic]. +/// [Self::requests]. /// /// # Lifetime /// /// A broadcast lives until [`Self::close`] or until the last [`Producer`] (or -/// [`Dynamic`]) drops, whichever comes first; both end it the same way. A publisher +/// [`Requests`]) drops, whichever comes first; both end it the same way. A publisher /// whose input ended cleanly finishes its tracks first: a subscriber still catching up /// drains them after the close. Children /// do *not* keep it alive: cloning a [`Consumer`] or holding a [`track::Producer`] @@ -189,7 +189,7 @@ pub struct Producer { // handle (threaded down by [`Self::create_track`] / [`Self::reserve_track`]). info: Arc, - // Broadcast liveness, shared with every `Dynamic`. Consumers watch it (read-only) + // Broadcast liveness, shared with every `Requests`. Consumers watch it (read-only) // for close; the guard ends the broadcast when the last of those handles drops. alive: Arc, @@ -325,7 +325,7 @@ impl Producer { let mut state = self.state.lock(); // A consumer may have requested this name before it existed (a live - // [`Dynamic`] queues such requests). Creating the track fulfills that + // [`Requests`] queues such requests). Creating the track fulfills that // request: its consumers resolve against this very producer. Without // this they would be stranded, since the name is taken the moment the // track exists, so no handler could ever serve their queue entry. @@ -351,7 +351,7 @@ impl Producer { /// [`track::Request::accept`] to set its info and start producing. Use this when /// the producer can't pick the track's properties (e.g. timescale) until it has /// inspected the media, the same shape as a consumer-driven - /// [`Dynamic::poll_requested_track`]. + /// [`Requests::poll_requested_track`]. /// /// Subscribers wait on the name until it is accepted, so a reservation the producer /// ends up never filling has to be dropped or rejected. Ending the broadcast @@ -404,8 +404,8 @@ impl Producer { } /// Create a dynamic producer that handles on-demand track requests from consumers. - pub fn dynamic(&self) -> Dynamic { - Dynamic::new( + pub fn requests(&self) -> Requests { + Requests::new( self.info.clone(), self.alive.clone(), self.state.clone(), @@ -433,7 +433,7 @@ impl Producer { /// with [`Error::Closed`]. Tracks already handed out carry on and end with their /// own finish or abort. Every later [`Consumer::track`], and every name reserved or /// still queued for a handler, answers [`Error::Unroutable`]: the same answer an - /// origin gives for a path nobody publishes. A request a [`Dynamic`] already took is + /// origin gives for a path nobody publishes. A request a [`Requests`] already took is /// left for that handler to answer. /// /// Dropping the last producer does the same. Closing twice is a no-op. @@ -470,7 +470,7 @@ impl Producer { } /// Ends the broadcast on [`Producer::close`] or when the last [`Producer`] or -/// [`Dynamic`] drops, closing the liveness channel every [`Consumer`] watches. +/// [`Requests`] drops, closing the liveness channel every [`Consumer`] watches. /// /// A refcount rather than a "am I the last one?" check inside `Drop`: that answer is /// a snapshot, and acting on it is exactly what invalidates it. @@ -586,7 +586,7 @@ impl RequestValidity { } #[cfg_attr(not(feature = "async"), allow(dead_code, reason = "async-only"))] - pub(crate) fn for_source(route: &crate::origin::Dynamic, path: &crate::Path) -> Self { + pub(crate) fn for_source(route: &crate::origin::Requests, path: &crate::Path) -> Self { route .request_validity(path) .map(|selected| Self::Selected(std::sync::Arc::new(selected))) @@ -646,7 +646,7 @@ impl Producer { } /// A session-owned source broadcast, closed on drop even while the session's -/// serve machines still hold its [`Dynamic`]. +/// serve machines still hold its [`Requests`]. /// /// A peer's retraction and a dead session end the source the same way: a broadcast /// carries no end cause past this hop. Shared by the lite and IETF subscribers. @@ -682,7 +682,7 @@ impl Drop for SourceGuard { /// [`track::Request::reject`]s it. Dropped when no longer needed; pending requests /// are automatically aborted. #[derive(Clone)] -pub struct Dynamic { +pub struct Requests { info: Arc, // Keeps the broadcast alive while a handler exists (mirrors a producer). alive: Arc, @@ -696,7 +696,7 @@ pub struct Dynamic { _handler: Handler, } -/// Counts one live [`Dynamic`], rejecting the queued requests when the last one drops. +/// Counts one live [`Requests`], rejecting the queued requests when the last one drops. struct Handler(kio::Shared); impl Handler { @@ -729,7 +729,7 @@ impl Drop for Handler { } } -impl Dynamic { +impl Requests { fn new(info: Arc, alive: Arc, state: kio::Shared, stats: stats::Scope) -> Self { Self { info, @@ -831,7 +831,7 @@ use futures::FutureExt; #[cfg(test)] #[expect(missing_docs, reason = "test-only assertion helpers")] -impl Dynamic { +impl Requests { pub fn assert_request(&mut self) -> track::Request { kio::wait(|waiter| self.poll_requested_track(waiter)) .now_or_never() @@ -921,7 +921,7 @@ impl Consumer { /// Nothing is requested until the handle queries, subscribes, or fetches, each of /// which looks the name up again. Fails with [`Error::Unroutable`] once the broadcast /// has ended, and [`Error::NotFound`] when nothing publishes the track and no - /// [`Dynamic`] would serve a request for it. + /// [`Requests`] would serve a request for it. pub fn track(&self, name: &str) -> Result { let current = { let mut state = self.state.lock(); @@ -947,7 +947,7 @@ impl Consumer { ) } - /// Join the demand of the track serving `name`, requesting it from a [`Dynamic`] + /// Join the demand of the track serving `name`, requesting it from a [`Requests`] /// when nothing serves it yet. Registers the subscription before exposing demand. /// Errors as [`Self::track`] does. pub(super) fn resolve_track( @@ -1129,7 +1129,7 @@ mod test { #[test] fn a_subscription_is_registered_before_its_request_is_visible() { struct Serve { - dynamic: std::sync::Mutex, + dynamic: std::sync::Mutex, request: std::sync::Mutex>, subscription: std::sync::Mutex>>, } @@ -1149,7 +1149,7 @@ mod test { let producer = Info::new().produce(); let serve = Arc::new(Serve { - dynamic: std::sync::Mutex::new(producer.dynamic()), + dynamic: std::sync::Mutex::new(producer.requests()), request: Default::default(), subscription: Default::default(), }); @@ -1368,7 +1368,7 @@ mod test { #[cfg(feature = "async")] async fn closed() { let mut producer = Info::new().produce(); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); consumer.assert_not_closed(); @@ -1423,7 +1423,7 @@ mod test { #[moq_clock::test] #[cfg(feature = "async")] async fn requests() { - let mut producer = Info::new().produce().dynamic(); + let mut producer = Info::new().produce().requests(); let consumer = producer.consume(); let consumer2 = consumer.clone(); @@ -1464,7 +1464,7 @@ mod test { #[moq_clock::test] #[cfg(feature = "async")] async fn stale_producer() { - let mut broadcast = Info::new().produce().dynamic(); + let mut broadcast = Info::new().produce().requests(); let consumer = broadcast.consume(); // Subscribe to a track and serve it. @@ -1503,7 +1503,7 @@ mod test { fn replacement_starts_over() { let at = |millis| crate::Timestamp::from_millis(millis).unwrap(); let producer = Info::new().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let track = consumer.track("media").unwrap().subscribe(None); @@ -1530,7 +1530,7 @@ mod test { #[test] fn gone_names_are_forgotten() { let producer = Info::new().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); for i in 0..1000 { let track = consumer.track(&format!("requested/{i}")).unwrap().subscribe(None); @@ -1553,7 +1553,7 @@ mod test { #[moq_clock::test] #[cfg(feature = "async")] async fn requested_unused() { - let mut broadcast = Info::new().produce().dynamic(); + let mut broadcast = Info::new().produce().requests(); let bc = broadcast.consume(); // Subscribe to a track that doesn't exist yet, then serve it. @@ -1608,7 +1608,7 @@ mod test { #[cfg(feature = "async")] async fn create_track_fulfills_queued_request() { let producer = Info::new().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let bc = dynamic.consume(); // Queue a request for a track that doesn't exist yet. @@ -1628,14 +1628,14 @@ mod test { again.assert_is_clone(&track.subscribe(None)); } - // Cloning a `Dynamic` and dropping the clone must not flip the handler + // Cloning a `Requests` and dropping the clone must not flip the handler // count to zero. The relay's lite subscriber clones the // dynamic per spawned subscribe; if Clone skipped the increment, the // first finished subscribe would tear down the broadcast and any // follow-up `track` would return `NotFound`. #[test] fn dynamic_clone_keeps_alive() { - let broadcast = Info::new().produce().dynamic(); + let broadcast = Info::new().produce().requests(); let consumer = broadcast.consume(); let clone = broadcast.clone(); @@ -1652,7 +1652,7 @@ mod test { #[test] fn close_unheld_yields_to_holders() { let producer = Info::new().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let weak = consumer.weak(); assert!(producer.is_held()); @@ -1697,7 +1697,7 @@ mod test { #[cfg(feature = "async")] async fn close_resolves_a_queued_request() { let producer = Info::new().produce(); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = dynamic.consume(); let pending = subscribe_pending!(consumer, "track1"); @@ -1708,11 +1708,11 @@ mod test { } /// A queued request answers the same when the broadcast ends by its last handle - /// dropping, even when that handle is the `Dynamic` that would have served it. + /// dropping, even when that handle is the `Requests` that would have served it. #[moq_clock::test] #[cfg(feature = "async")] async fn dropping_the_last_handle_resolves_a_queued_request() { - let dynamic = Info::new().produce().dynamic(); + let dynamic = Info::new().produce().requests(); let consumer = dynamic.consume(); let pending = subscribe_pending!(consumer, "track1"); @@ -1731,7 +1731,7 @@ mod test { let producer = Info::new() .produce() .with_validity(RequestValidity::Route(route.consume())); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = producer.consume(); let pending = subscribe_pending!(consumer, "accepted"); @@ -1754,7 +1754,7 @@ mod test { #[cfg(feature = "async")] async fn dropping_the_last_handler_resolves_a_queued_request_dropped() { let producer = Info::new().produce(); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = dynamic.consume(); let pending = subscribe_pending!(consumer, "track1"); @@ -1771,7 +1771,7 @@ mod test { #[cfg(feature = "async")] async fn close_leaves_a_claimed_request_to_its_handler() { let producer = Info::new().produce(); - let mut dynamic = producer.dynamic(); + let mut dynamic = producer.requests(); let consumer = dynamic.consume(); let accepted = subscribe_pending!(consumer, "track1"); @@ -1807,7 +1807,7 @@ mod test { let consumer = producer.consume(); let request = producer.reserve_track("track1").unwrap(); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let track = consumer.track("track1").unwrap(); let pending_fetch = track.fetch_group(0, None); let fetch = dynamic.requested_fill_group().await.unwrap(); diff --git a/rs/moq-net/src/model/follow.rs b/rs/moq-net/src/model/follow.rs index e26d92af015..696dee7d29e 100644 --- a/rs/moq-net/src/model/follow.rs +++ b/rs/moq-net/src/model/follow.rs @@ -335,7 +335,7 @@ mod tests { let epoch = Epoch::mint(); // A prefix above the path covers it. - let pool = origin.dynamic_route("pool", route(&epoch)).unwrap(); + let pool = origin.requests_route("pool", route(&epoch)).unwrap(); assert_eq!(followed(&mut follow).await, ("start", "pool".into())); // A route beneath the path serves another broadcast. @@ -370,7 +370,7 @@ mod tests { #[moq_clock::test] async fn follow_starts_on_the_serving_route_when_joining_late() { let origin = Hop::new(1).unwrap().produce(); - let _pool = origin.dynamic_route("pool", Route::default()).unwrap(); + let _pool = origin.requests_route("pool", Route::default()).unwrap(); let _exact = origin.publish("pool/job", Route::default()).unwrap(); let mut follow = origin.consume().follow("pool/job").unwrap(); @@ -391,7 +391,7 @@ mod tests { // Both land before the follower reads again, and the cursor delivers the prefix's start // ahead of the path's end, but the path went unserved in between. drop(exact); - let _pool = origin.dynamic_route("pool", route(&epoch)).unwrap(); + let _pool = origin.requests_route("pool", route(&epoch)).unwrap(); assert_eq!(followed(&mut follow).await, ("end", "pool/job".into())); assert_eq!(followed(&mut follow).await, ("start", "pool".into())); @@ -412,7 +412,7 @@ mod tests { assert_eq!(followed(&mut follow).await, ("start", "pool/job".into())); let epoch = Epoch::mint(); - let _pool = origin.dynamic_route("pool", route(&epoch)).unwrap(); + let _pool = origin.requests_route("pool", route(&epoch)).unwrap(); exact.announce(route(&epoch)).unwrap(); assert_eq!(followed(&mut follow).await, ("restart", "pool/job".into())); @@ -426,7 +426,7 @@ mod tests { let origin = Hop::new(1).unwrap().produce(); let mut follow = origin.consume().follow("pool/job").unwrap(); - let _pool = origin.dynamic_route("pool", Route::default()).unwrap(); + let _pool = origin.requests_route("pool", Route::default()).unwrap(); assert_eq!(followed(&mut follow).await, ("start", "pool".into())); let _exact = origin.publish("pool/job", Route::default()).unwrap(); @@ -442,7 +442,7 @@ mod tests { let _chat = origin .scope("", &chat) .unwrap() - .dynamic_route("room/alice", Route::default()) + .requests_route("room/alice", Route::default()) .unwrap(); let mut follow = origin.consume().follow("room/alice").unwrap(); @@ -489,7 +489,7 @@ mod tests { } /// The next request a dynamic route receives for its path. - async fn requested(dynamic: &crate::origin::Dynamic) -> crate::origin::Request { + async fn requested(dynamic: &crate::origin::Requests) -> crate::origin::Request { moq_clock::timeout(Duration::from_secs(1), dynamic.requested_broadcast()) .await .expect("never asked") @@ -501,7 +501,7 @@ mod tests { #[moq_clock::test] async fn announced_hands_out_a_held_takeover_once() { let origin = Hop::new(1).unwrap().produce(); - let dynamic = origin.dynamic("live").unwrap(); + let dynamic = origin.requests("live").unwrap(); let mut announced = origin.consume().announced_broadcast("live", None).unwrap(); // The wait is on the dynamic route's answer when the exact path takes over without an epoch. @@ -517,7 +517,7 @@ mod tests { #[moq_clock::test] async fn announced_hands_out_a_dropped_takeover_again() { let origin = Hop::new(1).unwrap().produce(); - let dynamic = origin.dynamic("live").unwrap(); + let dynamic = origin.requests("live").unwrap(); let mut announced = origin.consume().announced_broadcast("live", None).unwrap(); let (dropped, _publish) = futures::join!(available(&mut announced), async { @@ -537,7 +537,7 @@ mod tests { #[moq_clock::test] async fn announced_hands_out_a_gap_while_resolving_once() { let origin = Hop::new(1).unwrap().produce(); - let dynamic = origin.dynamic("").unwrap(); + let dynamic = origin.requests("").unwrap(); let mut announced = origin.consume().announced_broadcast("live", None).unwrap(); let (_arrival, _publish) = futures::join!(available(&mut announced), async { @@ -560,7 +560,7 @@ mod tests { let exact = origin.publish("live", route(&epoch)).unwrap(); let first = available(&mut announced).await; - let dynamic = origin.dynamic_route("", route(&epoch)).unwrap(); + let dynamic = origin.requests_route("", route(&epoch)).unwrap(); exact.unannounce(); let served = broadcast::Info::new().produce(); let (again, ()) = futures::join!(available(&mut announced), async { diff --git a/rs/moq-net/src/model/listing.rs b/rs/moq-net/src/model/listing.rs index 71dd0bc4c5c..a61b1ab96a8 100644 --- a/rs/moq-net/src/model/listing.rs +++ b/rs/moq-net/src/model/listing.rs @@ -559,7 +559,7 @@ impl Consumer { } } -/// A handler's answer to the broadcast's listings, from [`Dynamic::lister`](super::Dynamic::lister). +/// A handler's answer to the broadcast's listings, from [`Requests::lister`](super::Requests::lister). /// /// A broadcast has at most one. While it exists, readers wait for it to /// [`sync`](Self::synced) before reporting [`TracksEvent::Synced`]. Answer while [`poll_used`](Self::poll_used): list what the @@ -797,7 +797,7 @@ mod tests { #[test] fn a_lister_finishes_or_removes_a_track() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); lister.add("up", track::Info::default()).unwrap(); lister.add("gone", track::Info::default()).unwrap(); lister.synced(); @@ -829,7 +829,7 @@ mod tests { // The producer's finished track is what a handler's answer of its name served. let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); lister.add("a", track::Info::default()).unwrap(); lister.synced(); let a = broadcast.create_track("a", None).unwrap(); @@ -842,7 +842,7 @@ mod tests { // A handler's end is clean too, and its abort is not. for abort in [false, true] { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); lister.add("up", track::Info::default()).unwrap(); lister.synced(); let mut tracks = broadcast.consume().tracks().unwrap(); @@ -900,7 +900,7 @@ mod tests { #[test] fn a_track_served_on_request_is_never_listed() { let broadcast = Info::new().produce(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let consumer = broadcast.consume(); let mut tracks = consumer.tracks().unwrap(); assert_eq!(drain(&mut tracks), ["synced"]); @@ -983,7 +983,7 @@ mod tests { fn readers_wait_for_the_lister_to_sync() { let broadcast = Info::new().produce(); let _own = broadcast.create_track("own", None).unwrap(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); let waiter = kio::Waiter::noop(); assert!(lister.poll_used(&waiter).is_pending()); @@ -1011,7 +1011,7 @@ mod tests { fn a_name_listed_by_both_is_reported_once() { let broadcast = Info::new().produce(); let own = broadcast.create_track("a", None).unwrap(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); lister.add("a", track::Info::default()).unwrap(); lister.synced(); let mut tracks = broadcast.consume().tracks().unwrap(); @@ -1025,7 +1025,7 @@ mod tests { #[test] fn an_aborted_answer_fails_its_readers_and_a_later_reader_asks_again() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); let waiter = kio::Waiter::noop(); let mut tracks = broadcast.consume().tracks().unwrap(); lister.add("up", track::Info::default()).unwrap(); @@ -1051,7 +1051,7 @@ mod tests { #[test] fn a_dropped_lister_withdraws_its_answer_and_syncs() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); lister.add("up", track::Info::default()).unwrap(); let mut tracks = broadcast.consume().tracks().unwrap(); assert_eq!(drain(&mut tracks), ["+up"]); @@ -1118,16 +1118,16 @@ mod tests { #[test] fn a_broadcast_has_one_lister() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); - assert!(matches!(broadcast.dynamic().lister(), Err(Error::Duplicate))); + let lister = broadcast.requests().lister().unwrap(); + assert!(matches!(broadcast.requests().lister(), Err(Error::Duplicate))); drop(lister); - broadcast.dynamic().lister().expect("the first lister left"); + broadcast.requests().lister().expect("the first lister left"); } #[test] fn an_ended_answer_ends_its_readers_and_a_later_reader_asks_again() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); let waiter = kio::Waiter::noop(); let mut tracks = broadcast.consume().tracks().unwrap(); lister.add("up", track::Info::default()).unwrap(); @@ -1145,7 +1145,7 @@ mod tests { #[test] fn a_cleared_answer_unsyncs_a_reader_still_waiting() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); let _a = broadcast.create_track("a", None).unwrap(); let _b = broadcast.create_track("b", None).unwrap(); lister.synced(); @@ -1160,7 +1160,7 @@ mod tests { #[test] fn a_lister_sees_the_broadcast_end() { let broadcast = Info::new().produce(); - let lister = broadcast.dynamic().lister().unwrap(); + let lister = broadcast.requests().lister().unwrap(); broadcast.close(); assert!(matches!( lister.poll_used(&kio::Waiter::noop()), diff --git a/rs/moq-net/src/model/mod.rs b/rs/moq-net/src/model/mod.rs index ea6c3debb60..53e8f8a2143 100644 --- a/rs/moq-net/src/model/mod.rs +++ b/rs/moq-net/src/model/mod.rs @@ -26,7 +26,7 @@ mod skipped; // The DEFLATE codec behind compressed tracks. mod flate; pub(crate) mod object; -mod requests; +mod request_queue; mod resume; mod subscription; mod time; @@ -36,7 +36,7 @@ mod weak_cache; #[cfg(test)] mod test_tracing; -use requests::Requests; +use request_queue::RequestQueue; use weak_cache::{WeakCache, WeakEntry}; pub use bytes::*; @@ -50,8 +50,8 @@ pub use timed::Timed; pub mod origin { pub use super::follow::AnnouncedBroadcast; pub use super::origin_impl::{ - Config, Consumer, Cost, Driver, Dynamic, HopLimit, Link, Preference, Prepared, Producer, Publication, Request, - Requesting, Route, Routing, Source, + Config, Consumer, Cost, Driver, HopLimit, Link, Preference, Prepared, Producer, Publication, Request, + Requesting, Requests, Route, Routing, Source, }; } diff --git a/rs/moq-net/src/model/origin.rs b/rs/moq-net/src/model/origin.rs index cb455f97a14..295019a37a6 100644 --- a/rs/moq-net/src/model/origin.rs +++ b/rs/moq-net/src/model/origin.rs @@ -13,7 +13,7 @@ use std::{ use rand::RngExt; use super::{ - Requests, WeakCache, WeakEntry, + RequestQueue, WeakCache, WeakEntry, follow::AnnouncedBroadcast, front::{Action, Candidate, Event, Front, Refusal}, }; @@ -470,7 +470,7 @@ impl From for Preference { /// The path a route took through the mesh and what using it costs. /// -/// The metadata half of an advertisement: [`Producer::dynamic`] pairs it with +/// The metadata half of an advertisement: [`Producer::requests`] pairs it with /// the prefix it covers, [`Publication::announce`] with the /// broadcast's exact path, and [`Consumer::announced`] yields both. A route /// claims capability, not inventory: it says paths under its prefix are @@ -603,7 +603,7 @@ impl Route { /// Where the route entered this origin, as delivered by [`Consumer::announced`]. /// /// Set by the origin, not the announcer: a route handed to - /// [`Producer::dynamic`] reports [`Source::Local`] until the origin delivers it. + /// [`Producer::requests`] reports [`Source::Local`] until the origin delivers it. pub fn source(&self) -> Source { self.source } @@ -1249,7 +1249,7 @@ struct RouteEntry { /// The link the entry arrived on, from the handle that inserted it. link: Link, /// The queue requests under this route are served from, when the announcer - /// serves content on demand (a [`Dynamic`]). `None` for an advertise-only + /// serves content on demand (a [`Requests`]). `None` for an advertise-only /// announcement ([`Producer::announce`]) and for a local broadcast. server: Option>, /// The broadcast published on this origin at exactly `prefix`, when the @@ -1262,7 +1262,7 @@ struct RouteEntry { advertised: bool, /// Whether a peer the chain passes through has since withdrawn this prefix. /// The route was derived from that peer's advertisement, so it serves nobody - /// until the peer announces again. See [`Dynamic::withdrawn`]. + /// until the peer announces again. See [`Requests::withdrawn`]. stale: bool, /// [`prefix_claim`] of [`Self::prefix`], built once at announce time. /// @@ -1377,12 +1377,12 @@ fn prefix_claim(prefix: &Path) -> Result { /// A served route's request queue: what materializes a requested path on demand. /// /// Shared by every requester resolving through the owning route and the -/// [`Dynamic`] draining it, so both sides work under one lock. +/// [`Requests`] draining it, so both sides work under one lock. #[derive(Default)] struct ServeState { // Result channels for pending requests, keyed by absolute path so concurrent // `request_broadcast` calls for the same path coalesce onto one channel. - requests: Requests>, + requests: RequestQueue>, // Broadcasts the handler has already served, kept weakly so a repeat request for the // same path resolves to a shared clone instead of re-invoking the handler (which would @@ -2073,7 +2073,7 @@ impl Producer { /// Rank the link this handle (and any handle derived from it) is given to: /// higher wins, and every handle starts at the neutral [`Preference::default`]. /// - /// Applies to what [`Self::dynamic`] advertises, which is how a session lands its + /// Applies to what [`Self::requests`] advertises, which is how a session lands its /// peer's routes, not to a broadcast published here. A route with a newer epoch still wins, /// but among the rest preference decides before cost, so links to different /// operators rank by this instead of comparing their metrics. Hand each CDN's @@ -2149,11 +2149,11 @@ impl Producer { /// until then no announce cursor lists it and a request for its path fails /// with [`Error::Unroutable`], for a consumer of this origin exactly as for a /// peer. Announce once the tracks a subscriber needs first exist. To serve - /// paths on demand without publishing each one, use [`Self::dynamic`]. + /// paths on demand without publishing each one, use [`Self::requests`]. /// /// Announcing is visible to local consumers before it returns; only /// lifecycle work (track serving, teardown) waits for the [`Driver`] to be - /// polled. Register a [`broadcast::Producer::dynamic`] handler before + /// polled. Register a [`broadcast::Producer::requests`] handler before /// announcing, so the first consumer finds the tracks it serves. /// /// End the broadcast with [`broadcast::Producer::close`] or by dropping it; @@ -2244,7 +2244,7 @@ impl Producer { /// Mint a standalone source broadcast for a served-route request: it carries /// this origin's cache policy and ingress attribution, but /// is *not* entered into the route table. Sessions answer - /// [`Dynamic`] requests with one of these; the requester already holds + /// [`Requests`] requests with one of these; the requester already holds /// the request's result channel, so the table never needs to resolve it. /// The source takes new tracks only while `validity` holds. #[cfg_attr(not(feature = "async"), allow(dead_code, reason = "async-only"))] @@ -2272,10 +2272,10 @@ impl Producer { /// can be served, answered by nothing. /// /// A request under an advertise-only route resolves [`Error::Unroutable`] - /// unless an announced broadcast or a served route ([`Self::dynamic`]) covers + /// unless an announced broadcast or a served route ([`Self::requests`]) covers /// the path too. Tests use it to shape the route table; everything else /// advertises through a broadcast ([`Publication::announce`]) or a - /// [`Dynamic`] handler, which serve what they claim. + /// [`Requests`] handler, which serve what they claim. #[cfg(test)] pub(crate) fn announce(&self, prefix: impl AsPath, route: Route) -> Result { Announcing::new(self, prefix)?.announce( @@ -2354,7 +2354,7 @@ impl Producer { /// thing on every hop. /// /// The advertisement is visible to [`Consumer::announced`] and forwarded by - /// sessions for as long as the returned [`Dynamic`] (and every clone) lives. + /// sessions for as long as the returned [`Requests`] (and every clone) lives. /// A consumer resolving a path under it through this route is handed to the /// handler as a [`Request`] to materialize on demand: [`Request::prepare`] /// under a new epoch, fill, then [`Prepared::publish`] the exact path. Each @@ -2367,17 +2367,17 @@ impl Producer { /// /// The prefix must overlap this producer's pattern scope. Individual requests /// remain authoritative and are refused when they do not match the scope. - pub fn dynamic(&self, prefix: impl AsPath) -> Result { - self.dynamic_inner(prefix, Route::default(), true) + pub fn requests(&self, prefix: impl AsPath) -> Result { + self.requests_inner(prefix, Route::default(), true) } /// Land a peer's claim with its wire route metadata. #[cfg(any(feature = "async", test))] - pub(crate) fn dynamic_route(&self, prefix: impl AsPath, route: Route) -> Result { - self.dynamic_inner(prefix, route, false) + pub(crate) fn requests_route(&self, prefix: impl AsPath, route: Route) -> Result { + self.requests_inner(prefix, route, false) } - fn dynamic_inner(&self, prefix: impl AsPath, route: Route, publishes: bool) -> Result { + fn requests_inner(&self, prefix: impl AsPath, route: Route, publishes: bool) -> Result { let announcing = Announcing::new(self, prefix)?; let serve = kio::Shared::::default(); serve.lock().requests.add_handler(); @@ -2389,7 +2389,7 @@ impl Producer { advertised: true, }, )?; - Ok(Dynamic { + Ok(Requests { announcement, state: serve, publisher: publishes.then(|| self.clone()), @@ -2516,7 +2516,7 @@ impl Producer { } /// What it takes to insert a route: the prefixes it covers and the origin table -/// to insert them into. Built by [`Producer::announce`], [`Producer::dynamic`], +/// to insert them into. Built by [`Producer::announce`], [`Producer::requests`], /// and [`Announcer`], which is the same advertisement re-issued from a broadcast. struct Announcing { hop: Hop, @@ -2715,7 +2715,7 @@ impl Announcer { /// The write half of an advertisement: a live claim that paths under a /// [`Pattern`] can be served. /// -/// Held by a [`Dynamic`] and by a broadcast's [`Announcer`]; dropping it +/// Held by a [`Requests`] and by a broadcast's [`Announcer`]; dropping it /// retracts the route, which [`AnnounceConsumer`]s observe and sessions withdraw /// from their peers. #[must_use = "dropping an announcement retracts the route"] @@ -2729,7 +2729,7 @@ pub(crate) struct AnnounceProducer { } impl AnnounceProducer { - /// Replace the route in place, epoch included; see [`Dynamic::update_route`]. + /// Replace the route in place, epoch included; see [`Requests::update_route`]. /// /// The prefix is fixed at announce time and a [`Route`] cannot name one: to /// move an advertisement, drop this and announce again. Fails with @@ -2892,7 +2892,7 @@ impl Drop for AnnounceProducer { /// /// It holds no [`Producer`] clone, so it never keeps the origin alive. It /// finishes once every owner is gone: each [`Producer`] clone, published -/// broadcast, and [`Dynamic`]. Read handles ([`Consumer`], [`AnnounceConsumer`]) +/// broadcast, and [`Requests`]. Read handles ([`Consumer`], [`AnnounceConsumer`]) /// are not owners. Dropping it aborts active fronts, rejects pending requests, /// ends announcements, and makes subsequent producer mutations fail with /// [`Error::Closed`]. @@ -2924,7 +2924,7 @@ impl Driver { /// /// See [`crate::time::Driver`] for the contract. Finishes with /// [`Error::Closed`] once every owner (a [`Producer`] clone, published - /// broadcast, or [`Dynamic`]) has dropped and the remaining lifecycle work + /// broadcast, or [`Requests`]) has dropped and the remaining lifecycle work /// has drained. pub fn poll(&mut self, now: Instant, waiter: &kio::Waiter) -> Result, Error> { waiter.batch(|| { @@ -3267,7 +3267,7 @@ async fn serve_front(task: FrontTask) -> Vec { // The front serves its broadcast on demand: every track a reader names is // handed here, and its readers read it from whichever source serves the path. - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let lister = dynamic .lister() .expect("only the front answers its broadcast's listings"); @@ -4901,7 +4901,7 @@ struct OriginState { fronts: WeakCache, // Peers that withdrew a prefix while routes there still passed through them, - // which are stale. See [`Dynamic::withdrawn`]. + // which are stale. See [`Requests::withdrawn`]. withdrawn: HashMap>, // Set when the origin's driver dropped: new requests fail with `Closed` @@ -5414,10 +5414,10 @@ impl Resolution { } } -/// A served route, from [`Producer::dynamic`]: advertises a path prefix and +/// A served route, from [`Producer::requests`]: advertises a path prefix and /// answers the [`Consumer::request_broadcast`] calls beneath it. /// -/// The origin-level analogue of [`broadcast::Dynamic`]: where that serves tracks +/// The origin-level analogue of [`broadcast::Requests`]: where that serves tracks /// on demand within a broadcast, this serves whole broadcasts on demand within /// an origin. A relay holds one per route a peer announces to it, materializing /// a requested path from that peer; an application holds one to answer a @@ -5428,8 +5428,8 @@ impl Resolution { /// /// It keeps the origin's [`Driver`] running, like a published broadcast: a /// handler can drop every [`Producer`] and keep serving. -#[must_use = "dropping an origin::Dynamic retracts the route"] -pub struct Dynamic { +#[must_use = "dropping an origin::Requests retracts the route"] +pub struct Requests { /// The advertisement, retracted on drop. announcement: AnnounceProducer, state: kio::Shared, @@ -5441,7 +5441,7 @@ pub struct Dynamic { _keepalive: Keepalive, } -impl Dynamic { +impl Requests { #[cfg_attr(not(feature = "async"), allow(dead_code, reason = "async-only"))] pub(super) fn request_validity(&self, path: &Path) -> Option { let shared = &self.announcement.shared; @@ -5519,7 +5519,7 @@ impl Dynamic { /// `dynamic.update_route(dynamic.route().with_cost(cost))`. /// /// The prefix is fixed at announce time: to move a route, drop this and call - /// [`Producer::dynamic`] again. Fails with [`Error::Closed`] once the origin's + /// [`Producer::requests`] again. Fails with [`Error::Closed`] once the origin's /// [`Driver`] has been dropped. #[cfg(any(feature = "async", test))] pub(crate) fn update_route(&self, route: Route) -> Result<(), Error> { @@ -5658,7 +5658,7 @@ impl ServeState { /// A pending request for a broadcast to be served on demand. /// -/// Yielded by [`Dynamic::poll_requested_broadcast`]. The requester is awaiting inside +/// Yielded by [`Requests::poll_requested_broadcast`]. The requester is awaiting inside /// [`Consumer::request_broadcast`]; [`prepare`](Self::prepare) then [`Prepared::publish`] /// resolves it with a new exact-path broadcast, and [`reject`](Self::reject) resolves it /// with an error. Dropping the request without either rejects it. @@ -5785,7 +5785,7 @@ impl Drop for Request { /// The pollable result of [`Consumer::request_broadcast`]. /// /// Awaited via the [`kio::Pending`] wrapper; resolves to the [`broadcast::Consumer`] -/// immediately when the broadcast was already announced, or once an [`Dynamic`] +/// immediately when the broadcast was already announced, or once a [`Requests`] /// handler serves the request. Resolves to an error if the request is rejected or every /// handler drops before serving it. pub struct Requesting { @@ -7222,8 +7222,8 @@ impl ProduceTest for Hop { #[cfg(all(test, feature = "async"))] pub(crate) struct TestSelection { origin: Producer, - route: Option, - replacement: Option, + route: Option, + replacement: Option, } #[cfg(all(test, feature = "async"))] @@ -7233,7 +7233,7 @@ impl TestSelection { pub(crate) fn new() -> Self { let origin = Hop::new(1).unwrap().produce(); let route = origin - .dynamic_route("room", Route::default().with_via(Hop::new(Self::PEER).unwrap())) + .requests_route("room", Route::default().with_via(Hop::new(Self::PEER).unwrap())) .unwrap(); Self { origin, @@ -7255,7 +7255,7 @@ impl TestSelection { /// Another instance of the peer takes the path. pub(crate) fn replace(&mut self) { let route = Route::default().with_via(Hop::new(Self::PEER).unwrap()); - self.replacement = Some(self.origin.dynamic_route("room/a", route).unwrap()); + self.replacement = Some(self.origin.requests_route("room/a", route).unwrap()); } } @@ -7387,7 +7387,7 @@ mod tests { /// Yield to the driver until the server's front watcher delivers a request. #[cfg(feature = "async")] - async fn queued(server: &Dynamic) -> Request { + async fn queued(server: &Requests) -> Request { let mut request = None; settle(|| match server.poll_requested_broadcast(&kio::Waiter::noop()) { Poll::Ready(Ok(popped)) => { @@ -7724,7 +7724,7 @@ mod tests { #[cfg(feature = "async")] async fn mount_resolves_on_the_target_front() { let producer = origin(1).produce(); - let server = producer.dynamic_route(".svc", Route::default()).unwrap(); + let server = producer.requests_route(".svc", Route::default()).unwrap(); let project = mounted(&producer, "p1", &["**"]); let through = project.request_broadcast(".svc/foo", None); @@ -7907,11 +7907,11 @@ mod tests { .unwrap(); assert!(matches!(project.create_broadcast(".svc/foo"), Err(Error::Unauthorized))); assert!(matches!( - project.dynamic_route(".svc", Route::default()), + project.requests_route(".svc", Route::default()), Err(Error::Unauthorized) )); assert!(matches!( - project.dynamic_route(".svc/foo", Route::default()), + project.requests_route(".svc/foo", Route::default()), Err(Error::Unauthorized) )); project.publish("cam", Route::default()).unwrap(); @@ -8186,10 +8186,10 @@ mod tests { // arrived in `order`. fn winners(order: impl Iterator) -> Vec { let producer = origin(1).produce(); - let _pool: Vec = order + let _pool: Vec = order .map(|id| { producer - .dynamic_route("pool", Route::default().with_hops(hops(&[id])).with_cost(3)) + .requests_route("pool", Route::default().with_hops(hops(&[id])).with_cost(3)) .unwrap() }) .collect(); @@ -8259,7 +8259,7 @@ mod tests { async fn a_reprice_is_an_update() { let producer = origin(1).produce(); let mut announced = producer.consume().announced(); - let route = producer.dynamic_route("room", Route::default().with_cost(3)).unwrap(); + let route = producer.requests_route("room", Route::default().with_cost(3)).unwrap(); announced.expect_next_active("room").await; route.update_route(Route::default().with_cost(5)).unwrap(); @@ -8280,7 +8280,7 @@ mod tests { let producer = origin(1).produce(); let mut announced = producer.consume().announced(); let route = producer - .dynamic_route("room", Route::default().with_auth(first.clone())) + .requests_route("room", Route::default().with_auth(first.clone())) .unwrap(); assert_eq!(announced.expect_next_active("room").await.auth, Some(first)); @@ -8309,12 +8309,12 @@ mod tests { let mut announced = consumer.announced(); let peer = producer.clone().with_link(Link::Peer); let old = peer - .dynamic_route("pool/job-0", Route::default().with_hops(hops(&[11]))) + .requests_route("pool/job-0", Route::default().with_hops(hops(&[11]))) .unwrap(); announced.expect_next_active("pool/job-0").await; let new = peer - .dynamic_route("pool/job-0", Route::default().with_hops(hops(&[10]))) + .requests_route("pool/job-0", Route::default().with_hops(hops(&[10]))) .unwrap(); announced.assert_next_wait(); @@ -8351,12 +8351,12 @@ mod tests { let consumer = producer.consume(); let mut announced = consumer.announced(); let _old = producer - .dynamic_route("pool/job-0", Route::default().with_hops(hops(&[old_hop]))) + .requests_route("pool/job-0", Route::default().with_hops(hops(&[old_hop]))) .unwrap(); announced.expect_next_active("pool/job-0").await; let new = producer - .dynamic_route("pool/job-0", Route::default().with_hops(hops(&[new_hop]))) + .requests_route("pool/job-0", Route::default().with_hops(hops(&[new_hop]))) .unwrap(); assert_eq!( announced.expect_next_restarted("pool/job-0").await.hops, @@ -8372,7 +8372,7 @@ mod tests { /// An origin delivering restarts at once, and a way to claim `prefix` with a /// producer scoped to `scope`, from `hop` at `cost`. #[cfg(feature = "async")] - fn scoped_pool() -> (Producer, impl Fn(&str, &str, u64, u64) -> Dynamic) { + fn scoped_pool() -> (Producer, impl Fn(&str, &str, u64, u64) -> Requests) { let producer = Config { update_hold: Duration::ZERO, ..Config::new(origin(1)) @@ -8383,7 +8383,7 @@ mod tests { claims .scope("", &scopes(&[scope])) .unwrap() - .dynamic_route(prefix, Route::default().with_hops(hops(&[hop])).with_cost(cost)) + .requests_route(prefix, Route::default().with_hops(hops(&[hop])).with_cost(cost)) .unwrap() }; (producer, claim) @@ -8392,7 +8392,7 @@ mod tests { /// Request `path` from `consumer` and have `server` answer it: the answer, and /// the requester's broadcast. #[cfg(feature = "async")] - async fn hold(consumer: &Consumer, path: &str, server: &Dynamic) -> (broadcast::Producer, broadcast::Consumer) { + async fn hold(consumer: &Consumer, path: &str, server: &Requests) -> (broadcast::Producer, broadcast::Consumer) { let pending = consumer.request_broadcast(path, None); let answer = broadcast::Info::new().produce(); queued(server).await.accept(&answer); @@ -8481,7 +8481,7 @@ mod tests { let _sticky = hold(&consumer, "room/job", &a).await; let c = producer - .dynamic_route("room", Route::default().with_hops(hops(&[12])).with_cost(1)) + .requests_route("room", Route::default().with_hops(hops(&[12])).with_cost(1)) .unwrap(); assert_eq!(announced.expect_next_restarted("room").await.cost, Cost::new(1)); quiet(&mut announced).await; @@ -8614,10 +8614,10 @@ mod tests { let consumer = producer.consume(); let anonymous = producer - .dynamic_route("room", Route::default().with_hops(hops(&[0])).with_cost(1)) + .requests_route("room", Route::default().with_hops(hops(&[0])).with_cost(1)) .unwrap(); let identified = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10])).with_cost(5)) + .requests_route("room", Route::default().with_hops(hops(&[10])).with_cost(5)) .unwrap(); let _pending = consumer.request_broadcast("room/alice", None); @@ -8638,10 +8638,10 @@ mod tests { let demoted = producer .clone() .with_preference(Preference::new(-1)) - .dynamic_route("room", Route::default().with_hops(hops(&[10])).with_cost(1)) + .requests_route("room", Route::default().with_hops(hops(&[10])).with_cost(1)) .unwrap(); let unranked = producer - .dynamic_route("room", Route::default().with_hops(hops(&[11])).with_cost(5)) + .requests_route("room", Route::default().with_hops(hops(&[11])).with_cost(5)) .unwrap(); let _pending = consumer.request_broadcast("room/alice", None); @@ -8673,7 +8673,7 @@ mod tests { let mut announced = producer.consume().announced(); let dynamic = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_cost(5)) + .requests_route("room", Route::default().with_epoch(epoch()).with_cost(5)) .unwrap(); announced.expect_next_active("room").await; dynamic.update_route(dynamic.route().with_cost(1)).unwrap(); @@ -8800,7 +8800,7 @@ mod tests { assert_eq!(announced.expect_next_active("room/alice").await.cost, Cost::new(5)); let server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default().with_epoch(epoch()).with_hops(hops(&[10])).with_cost(1), ) @@ -8853,7 +8853,7 @@ mod tests { .expect("resolves locally"); let server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default().with_epoch(epoch()).with_hops(hops(&[10])).with_cost(1), ) @@ -8936,7 +8936,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let source = producer.publish("room/alice", Route::default()).unwrap(); - let lister = source.dynamic().lister().unwrap(); + let lister = source.requests().lister().unwrap(); lister.add("video", crate::track::Info::default()).unwrap(); lister.synced(); @@ -8970,7 +8970,7 @@ mod tests { assert_eq!(listed(&mut tracks).await, "synced"); let server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default().with_epoch(epoch()).with_hops(hops(&[10])).with_cost(1), ) @@ -8991,7 +8991,7 @@ mod tests { async fn a_front_through_a_covering_prefix_lists_nothing() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let pending = consumer.request_broadcast("room/alice", None); let upstream = broadcast::Info::new().produce(); let _video = upstream.create_track("video", None).unwrap(); @@ -9012,7 +9012,7 @@ mod tests { let consumer = producer.consume(); let _local = producer.publish("room/alice", Route::default()).unwrap(); - let server = producer.dynamic_route("room/alice", Route::default()).unwrap(); + let server = producer.requests_route("room/alice", Route::default()).unwrap(); // Were the claim to win, the request would park on its handler forever. let resolved = moq_clock::timeout(Duration::from_secs(1), consumer.request_broadcast("room/alice", None)) @@ -9067,7 +9067,7 @@ mod tests { let mut announced = consumer.announced(); let server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default().with_epoch(epoch()).with_hops(hops(&[10])).with_cost(2), ) @@ -9122,7 +9122,7 @@ mod tests { let consumer = producer.consume(); let broadcast = producer.publish("room/alice", Route::default()).unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let resolved = consumer.request_broadcast("room/alice", None).await.expect("resolves"); let track = resolved.track("video").unwrap(); let subscribing = moq_clock::sim::spawn(async move { track.subscribe(None).await }); @@ -9149,15 +9149,15 @@ mod tests { /// A front resolved through a served route, as a relay's upstream session serves /// one: the upstream broadcast's track requests arrive on the returned handle. #[cfg(feature = "async")] - async fn served_front() -> (Dynamic, broadcast::Producer, broadcast::Dynamic, broadcast::Consumer) { + async fn served_front() -> (Requests, broadcast::Producer, broadcast::Requests, broadcast::Consumer) { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room/alice", Route::default().with_hops(hops(&[10]))) + .requests_route("room/alice", Route::default().with_hops(hops(&[10]))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let upstream = broadcast::Info::new().produce(); - let dynamic = upstream.dynamic(); + let dynamic = upstream.requests(); queued(&server).await.accept(&upstream); let resolved = pending.await.expect("resolves"); (server, upstream, dynamic, resolved) @@ -9234,7 +9234,7 @@ mod tests { let producer = origin(1).produce(); // A prefix route, which resolves any path beneath it optimistically. let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let upstream = broadcast::Info::new().produce(); let source = upstream.create_track("video", crate::track::Info::timed()).unwrap(); @@ -9286,7 +9286,7 @@ mod tests { async fn a_hop_in_a_chain_gets_its_own_front() { let producer = origin(1).produce(); let _incumbent = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let fronts = || producer.shared.lock().fronts.len(); @@ -9297,7 +9297,7 @@ mod tests { // The same publisher, now also reached through the peer. let _echo = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10, 7]))) + .requests_route("room", Route::default().with_hops(hops(&[10, 7]))) .unwrap(); let _filtered = peer.request_broadcast("room/alice", None); assert_eq!(fronts(), 2, "the peer still shares the plain front"); @@ -9316,7 +9316,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let upstream = broadcast::Info::new().produce(); let source = upstream.create_track("video", crate::track::Info::timed()).unwrap(); @@ -9383,7 +9383,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let upstream = broadcast::Info::new().produce(); let source = upstream.create_track("video", None).unwrap(); @@ -9450,11 +9450,11 @@ mod tests { async fn a_peers_filtered_front_ends_once_unread() { let producer = origin(1).produce(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); // The same publisher, also reached through the peer, at a price the plain front skips. let _echo = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10, 7])).with_cost(100)) + .requests_route("room", Route::default().with_hops(hops(&[10, 7])).with_cost(100)) .unwrap(); let upstream = broadcast::Info::new().produce(); let source = upstream.create_track("video", crate::track::Info::timed()).unwrap(); @@ -9490,7 +9490,7 @@ mod tests { let peer = producer.consume().excluding(origin(7)); let mut view = peer.announced(); let incumbent = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) .unwrap(); view.expect_next_active("room").await; @@ -9501,7 +9501,7 @@ mod tests { // The same publisher, now also reached through the peer, outlives the incumbent. let echo = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10, 7]))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10, 7]))) .unwrap(); drop(incumbent); drop(source); @@ -9530,14 +9530,14 @@ mod tests { async fn takeover_keeps_the_open_group_head(dies_first: bool) { let producer = origin(1).produce(); let first_server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default().with_epoch(epoch()).with_hops(hops(&[10])).with_cost(5), ) .unwrap(); let pending = producer.consume().request_broadcast("room/alice", None); let upstream = broadcast::Info::new().produce(); - let mut dynamic = upstream.dynamic(); + let mut dynamic = upstream.requests(); queued(&first_server).await.accept(&upstream); let resolved = pending.await.unwrap(); @@ -9585,7 +9585,7 @@ mod tests { } let cost = if dies_first { 5 } else { 0 }; let replacement_server = producer - .dynamic_route( + .requests_route( "room/alice", Route::default() .with_epoch(epoch()) @@ -9594,14 +9594,14 @@ mod tests { ) .unwrap(); let replacement = broadcast::Info::new().produce(); - let mut replacement_dynamic = replacement.dynamic(); + let mut replacement_dynamic = replacement.requests(); queued(&replacement_server).await.accept(&replacement); let request = moq_clock::timeout(Duration::from_secs(1), replacement_dynamic.requested_track()) .await .expect("the front asked the replacement") .unwrap(); // The replacement serves the whole group to a fetch, frames still to come included. - let fetches = request.dynamic(); + let fetches = request.requests(); let fetched = Arc::new(crate::sync::Mutex::new(Vec::::new())); let serving = fetched.clone(); let _fetching = moq_clock::sim::spawn(async move { @@ -9699,7 +9699,7 @@ mod tests { let consumer = producer.consume(); let broadcast = producer.publish("room/alice", Route::default()).unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let resolved = consumer.request_broadcast("room/alice", None).await.expect("resolves"); let track = resolved.track("video").unwrap(); let subscribing = moq_clock::sim::spawn(async move { track.subscribe(None).await }); @@ -9815,8 +9815,8 @@ mod tests { #[cfg(feature = "async")] async fn duplicate_routes_aggregate_until_the_last_leaves() { let producer = origin(1).produce(); - let first = producer.dynamic_route("live", Route::default().with_cost(3)).unwrap(); - let second = producer.dynamic_route("live", Route::default().with_cost(1)).unwrap(); + let first = producer.requests_route("live", Route::default().with_cost(3)).unwrap(); + let second = producer.requests_route("live", Route::default().with_cost(1)).unwrap(); let mut announced = producer.consume().announced(); let Some(Some(AnnounceEvent::Start(update))) = announced.next().now_or_never() else { @@ -9840,25 +9840,25 @@ mod tests { let producer = origin(1).produce(); let scoped = producer.scope("", &scopes(&["room"])).unwrap(); let _broad = scoped - .dynamic_route("", Route::default()) + .requests_route("", Route::default()) .expect("an overlapping prefix is accepted"); let _ok = scoped - .dynamic_route("room/alice", Route::default()) + .requests_route("room/alice", Route::default()) .expect("a contained prefix is accepted"); assert!(matches!( - scoped.dynamic_route("other", Route::default()), + scoped.requests_route("other", Route::default()), Err(Error::Unauthorized) )); } #[moq_clock::test] #[cfg(feature = "async")] - async fn dynamic_route_keeps_its_producer_scope() { + async fn requests_route_keeps_its_producer_scope() { let producer = origin(1).produce(); let scope = Patterns::from("*/chat".parse::().unwrap()); let scoped = producer.scope("", &scope).unwrap(); - let dynamic = scoped.dynamic_route("", Route::default()).unwrap(); + let dynamic = scoped.requests_route("", Route::default()).unwrap(); let mut matching = producer .consume() @@ -9895,10 +9895,10 @@ mod tests { .unwrap() }; let _chat = scoped("*/chat") - .dynamic_route("", Route::default().with_cost(1)) + .requests_route("", Route::default().with_cost(1)) .unwrap(); let _video = scoped("*/video") - .dynamic_route("", Route::default().with_cost(5)) + .requests_route("", Route::default().with_cost(5)) .unwrap(); let mut video = producer @@ -9929,7 +9929,7 @@ mod tests { let chat = producer .scope("", &scopes(&["room/live/chat"])) .unwrap() - .dynamic_route("room/live", Route::default().with_hops(hops(&[7])).with_cost(1)) + .requests_route("room/live", Route::default().with_hops(hops(&[7])).with_cost(1)) .unwrap(); assert_eq!(all.expect_next_active("room/live").await.cost, Cost::new(1)); assert_eq!(rooted.expect_next_active("").await.cost, Cost::new(1)); @@ -9939,7 +9939,7 @@ mod tests { let video_route = producer .scope("", &scopes(&["room/live/video"])) .unwrap() - .dynamic_route("room/live", Route::default().with_hops(hops(&[8])).with_cost(5)) + .requests_route("room/live", Route::default().with_hops(hops(&[8])).with_cost(5)) .unwrap(); all.assert_next_wait(); rooted.assert_next_wait(); @@ -9964,9 +9964,9 @@ mod tests { #[cfg(feature = "async")] async fn root_cursor_keeps_the_more_specific_covering_route() { let producer = origin(1).produce(); - let broad = producer.dynamic_route("room", Route::default().with_cost(1)).unwrap(); + let broad = producer.requests_route("room", Route::default().with_cost(1)).unwrap(); let narrow = producer - .dynamic_route("room/live", Route::default().with_cost(9)) + .requests_route("room/live", Route::default().with_cost(9)) .unwrap(); let mut announced = producer .consume() @@ -9994,7 +9994,7 @@ mod tests { let mut announced = producer.consume().announced(); let dynamic = producer - .dynamic_route(&path, Route::default()) + .requests_route(&path, Route::default()) .expect("max depth is allowed"); announced.expect_next_active(&path).await; @@ -10007,7 +10007,7 @@ mod tests { async fn dynamic_exclusion_skips_routes_through_the_subscriber() { let producer = origin(1).produce(); let _server = producer - .dynamic_route("live", Route::default().with_hops(hops(&[7]))) + .requests_route("live", Route::default().with_hops(hops(&[7]))) .unwrap(); let mut excluded = producer.consume().excluding(origin(7)).announced(); @@ -10023,7 +10023,7 @@ mod tests { async fn announce_consumer_is_a_stream() { use futures::StreamExt; let producer = origin(1).produce(); - let server = producer.dynamic_route("live", Route::default()).unwrap(); + let server = producer.requests_route("live", Route::default()).unwrap(); let mut announced = producer.consume().announced(); let mut next = || StreamExt::next(&mut announced).now_or_never(); let Some(Some(AnnounceEvent::Start(update))) = next() else { @@ -10038,7 +10038,7 @@ mod tests { #[moq_clock::test] async fn dynamic_retracts() { let producer = origin(1).produce(); - let server = producer.dynamic_route("live", Route::default()).unwrap(); + let server = producer.requests_route("live", Route::default()).unwrap(); let mut announced = producer.consume().announced(); announced.expect_next_active("live").await; @@ -10070,7 +10070,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let pending = consumer.request_broadcast("room/alice", None); let request = queued(&server).await; @@ -10093,7 +10093,7 @@ mod tests { async fn served_requests_coalesce() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let first = consumer.request_broadcast("room/alice", None); let second = consumer.request_broadcast("room/alice", None); @@ -10115,7 +10115,7 @@ mod tests { async fn retract_rejects_pending_requests() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let pending = consumer.request_broadcast("room/alice", None); drop(server); @@ -10141,9 +10141,9 @@ mod tests { // Three identical routes, oldest first: the newest identical route wins // requests, and swapping between them emits no announce update. - let standby_server = producer.dynamic_route("room", Route::default()).unwrap(); - let second_server = producer.dynamic_route("room", Route::default()).unwrap(); - let incumbent_server = producer.dynamic_route("room", Route::default()).unwrap(); + let standby_server = producer.requests_route("room", Route::default()).unwrap(); + let second_server = producer.requests_route("room", Route::default()).unwrap(); + let incumbent_server = producer.requests_route("room", Route::default()).unwrap(); let mut resolving = Box::pin(consumer.routed_broadcast("room/alice")); assert!((&mut resolving).now_or_never().is_none()); @@ -10170,7 +10170,7 @@ mod tests { async fn split_horizon_skips_routes_through_the_requester() { let producer = origin(1).produce(); let _server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[7]))) + .requests_route("room", Route::default().with_hops(hops(&[7]))) .unwrap(); // The requester's own bytes must not be served back to it. @@ -10196,11 +10196,11 @@ mod tests { let mut announced = producer.consume().announced(); let _ingest = producer - .dynamic_route("client", Route::default().with_hops(hops(&[5])).with_via(origin(5))) + .requests_route("client", Route::default().with_hops(hops(&[5])).with_via(origin(5))) .unwrap(); let _gateway = producer.publish("gateway", Route::default()).unwrap(); let _forwarded = peer - .dynamic_route( + .requests_route( "forwarded", Route::default().with_hops(hops(&[5, 7])).with_via(origin(7)), ) @@ -10215,7 +10215,9 @@ mod tests { // The mark survives narrowing the handle. let scoped = peer.scope("room", &Patterns::from(Pattern::all())).unwrap(); - let _nested = scoped.dynamic_route("x", Route::default().with_via(origin(8))).unwrap(); + let _nested = scoped + .requests_route("x", Route::default().with_via(origin(8))) + .unwrap(); assert_eq!( announced.expect_next_active("room/x").await.source(), Source::Peer(origin(8)) @@ -10249,10 +10251,10 @@ mod tests { .with_hops(hops(chain)) .with_via(origin(via)) }; - let near = peer.dynamic_route("room", route(&[9, 2], 2)).unwrap(); + let near = peer.requests_route("room", route(&[9, 2], 2)).unwrap(); announced.assert_try_next_active("room"); - let _far = peer.dynamic_route("room", route(&[9, 3, 4], 4)).unwrap(); + let _far = peer.requests_route("room", route(&[9, 3, 4], 4)).unwrap(); drop(near); assert!(announced.try_next().is_none(), "the update is held"); step(Duration::from_millis(1)).await; @@ -10287,8 +10289,8 @@ mod tests { let mut near = Vec::new(); let mut far = Vec::new(); for i in 0..k { - near.push(peer.dynamic_route(format!("room/{i}"), route(&[9, 2], 2)).unwrap()); - far.push(peer.dynamic_route(format!("room/{i}"), route(&[9, 3, 4], 4)).unwrap()); + near.push(peer.requests_route(format!("room/{i}"), route(&[9, 2], 2)).unwrap()); + far.push(peer.requests_route(format!("room/{i}"), route(&[9, 3, 4], 4)).unwrap()); } let mut announced = producer.consume().announced(); for _ in 0..k { @@ -10333,12 +10335,12 @@ mod tests { .with_hops(hops(chain)) .with_via(origin(via)) }; - let near = peer.dynamic_route("room", route(&[9, 2], 2)).unwrap(); + let near = peer.requests_route("room", route(&[9, 2], 2)).unwrap(); announced.expect_next_active("room").await; // The best route changes twice; the consumer sees only the last, once. - let far = peer.dynamic_route("room", route(&[9, 3, 4], 4)).unwrap(); - let farther = peer.dynamic_route("room", route(&[9, 5, 6, 7], 7)).unwrap(); + let far = peer.requests_route("room", route(&[9, 3, 4], 4)).unwrap(); + let farther = peer.requests_route("room", route(&[9, 5, 6, 7], 7)).unwrap(); let start = moq_clock::now(); drop(near); drop(far); @@ -10366,30 +10368,30 @@ mod tests { let route = |chain: &[u64], via| Route::default().with_hops(hops(chain)).with_via(origin(via)); - let near = peer.dynamic_route("named", route(&[9, 2], 2)).unwrap(); + let near = peer.requests_route("named", route(&[9, 2], 2)).unwrap(); announced.expect_next_active("named").await; drop(near); announced.expect_next_ended("named").await; let start = moq_clock::now(); - let _stale = peer.dynamic_route("named", route(&[9, 3, 4], 4)).unwrap(); + let _stale = peer.requests_route("named", route(&[9, 3, 4], 4)).unwrap(); match announced.next().await.unwrap() { AnnounceEvent::Start(announce) => assert_eq!(announce.route.hops, hops(&[9, 3, 4])), other => panic!("should be a start: got {other:?}"), } assert!(moq_clock::now() - start >= RETRACT_QUARANTINE); - let near = peer.dynamic_route("anonymous", route(&[0, 2], 2)).unwrap(); + let near = peer.requests_route("anonymous", route(&[0, 2], 2)).unwrap(); announced.expect_next_active("anonymous").await; drop(near); announced.expect_next_ended("anonymous").await; - let _other = peer.dynamic_route("anonymous", route(&[0, 3, 4], 4)).unwrap(); + let _other = peer.requests_route("anonymous", route(&[0, 3, 4], 4)).unwrap(); announced.expect_next_active("anonymous").await; // Retract and announce cycles at one clock reading queue the prefix once, // whether or not the route names its publisher. let queued = announced.anchoring.len(); for chain in [[9, 2], [0, 2], [9, 2], [0, 2]] { - let churn = peer.dynamic_route("churn", route(&chain, 2)).unwrap(); + let churn = peer.requests_route("churn", route(&chain, 2)).unwrap(); announced.expect_next_active("churn").await; drop(churn); announced.expect_next_ended("churn").await; @@ -10398,7 +10400,7 @@ mod tests { // A quarantine is forgotten once it ends: the cursor wakes to anchor it, // then again to drop it. - let gone = peer.dynamic_route("gone", route(&[9, 2], 2)).unwrap(); + let gone = peer.requests_route("gone", route(&[9, 2], 2)).unwrap(); announced.expect_next_active("gone").await; drop(gone); announced.expect_next_ended("gone").await; @@ -10422,9 +10424,9 @@ mod tests { // Publisher 9 ingests at relay 2; relay 3 relays 2's route. let direct = || Route::default().with_hops(hops(&[9, 2])).with_via(origin(2)); - let first = peer.dynamic_route("room", direct()).unwrap(); + let first = peer.requests_route("room", direct()).unwrap(); let relayed = peer - .dynamic_route("room", Route::default().with_hops(hops(&[9, 2, 3])).with_via(origin(3))) + .requests_route("room", Route::default().with_hops(hops(&[9, 2, 3])).with_via(origin(3))) .unwrap(); announced.expect_next_active("room").await; announced.assert_next_wait(); @@ -10435,7 +10437,7 @@ mod tests { announced.assert_next_wait(); // Relay 2 announces again, and the relayed copy is live with it. - let second = peer.dynamic_route("room", direct()).unwrap(); + let second = peer.requests_route("room", direct()).unwrap(); announced.expect_next_active("room").await; assert!(producer.shared.lock().withdrawn.is_empty()); @@ -10455,8 +10457,8 @@ mod tests { let peer = producer.clone().with_link(Link::Peer); let mut announced = producer.consume().announced(); let route = Route::default().with_hops(hops(&[9, 2])); - let first = peer.dynamic_route("room", route.clone()).unwrap(); - let second = peer.dynamic_route("room", route.clone()).unwrap(); + let first = peer.requests_route("room", route.clone()).unwrap(); + let second = peer.requests_route("room", route.clone()).unwrap(); announced.expect_next_active("room").await; announced.assert_next_wait(); let remaining = if restart { @@ -10482,10 +10484,10 @@ mod tests { let producer = origin(1).produce(); let peer = producer.clone().with_link(Link::Peer); let direct = peer - .dynamic_route("room", Route::default().with_hops(hops(&[9, 2]))) + .requests_route("room", Route::default().with_hops(hops(&[9, 2]))) .unwrap(); let _relayed = peer - .dynamic_route("room", Route::default().with_hops(hops(&[9, 2, 3]))) + .requests_route("room", Route::default().with_hops(hops(&[9, 2, 3]))) .unwrap(); let path = Path::new("room/video"); let id = producer @@ -10515,14 +10517,14 @@ mod tests { .with_epoch(epoch()) .with_hops(hops(&[7])) .with_via(origin(7)); - let _forwarded = peer.dynamic_route("room", route.clone()).unwrap(); + let _forwarded = peer.requests_route("room", route.clone()).unwrap(); assert_eq!( announced.expect_next_active("room").await.source(), Source::Peer(origin(7)) ); // The newest identical route wins, so the local twin takes over. - let local = producer.dynamic_route("room", route).unwrap(); + let local = producer.requests_route("room", route).unwrap(); match announced.next().await.expect("no next") { AnnounceEvent::Update(announce) => assert_eq!(announce.route.source(), Source::Local), other => panic!("should be an update: got {other:?}"), @@ -10542,7 +10544,7 @@ mod tests { let mut local = producer.consume().local().announced(); let _forwarded = peer - .dynamic_route("remote", Route::default().with_hops(hops(&[7])).with_via(origin(7))) + .requests_route("remote", Route::default().with_hops(hops(&[7])).with_via(origin(7))) .unwrap(); local.assert_next_wait(); @@ -10550,10 +10552,10 @@ mod tests { // and retracts from the local view when the local route goes, even though // the peer's still covers it. let _shadow = peer - .dynamic_route("both", Route::default().with_hops(hops(&[7])).with_via(origin(7))) + .requests_route("both", Route::default().with_hops(hops(&[7])).with_via(origin(7))) .unwrap(); let ingest = producer - .dynamic_route( + .requests_route( "both", Route::default().with_hops(hops(&[5])).with_via(origin(5)).with_cost(9), ) @@ -10594,7 +10596,7 @@ mod tests { let mut everyone = producer.consume().announced(); let _core = core - .dynamic_route("core", Route::default().with_hops(hops(&[7])).with_via(origin(7))) + .requests_route("core", Route::default().with_hops(hops(&[7])).with_via(origin(7))) .unwrap(); assert_eq!( everyone.expect_next_active("core").await.source(), @@ -10603,7 +10605,7 @@ mod tests { toward_core.assert_next_wait(); let _mesh = peer - .dynamic_route("mesh", Route::default().with_hops(hops(&[8])).with_via(origin(8))) + .requests_route("mesh", Route::default().with_hops(hops(&[8])).with_via(origin(8))) .unwrap(); assert_eq!( toward_core.expect_next_active("mesh").await.source(), @@ -10613,10 +10615,10 @@ mod tests { // A path both an upstream and a mesh peer reach: the upstream route is // cheaper, yet the upstream view selects the mesh peer's. let _cheap = core - .dynamic_route("both", Route::default().with_hops(hops(&[7])).with_via(origin(7))) + .requests_route("both", Route::default().with_hops(hops(&[7])).with_via(origin(7))) .unwrap(); let mesh = peer - .dynamic_route( + .requests_route( "both", Route::default().with_hops(hops(&[8])).with_via(origin(8)).with_cost(9), ) @@ -10655,7 +10657,7 @@ mod tests { async fn handler_rejection_is_final() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let pending = consumer.request_broadcast("room/alice", None); let request = queued(&server).await; @@ -10681,7 +10683,7 @@ mod tests { async fn claim_answer_is_hidden_until_published_with_its_epoch() { let producer = origin(1).produce(); let consumer = producer.consume(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); let epoch = crate::Epoch::mint(); let mut pending = Box::pin(consumer.request_broadcast("room/alice", None)); assert!((&mut pending).now_or_never().is_none()); @@ -10705,7 +10707,7 @@ mod tests { async fn a_prepared_answer_cannot_announce_itself() { let producer = origin(1).produce(); let mut announced = producer.consume().announced(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); announced.assert_next_active("room"); let pending = producer.consume().request_broadcast("room/alice", None); let epoch = crate::Epoch::mint(); @@ -10775,7 +10777,7 @@ mod tests { #[cfg(feature = "async")] async fn a_refused_prepared_answer_cannot_announce_later() { let producer = origin(1).produce(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); let _pending = producer.consume().request_broadcast("room/alice", None); let prepared = queued(&claim).await.prepare(crate::Epoch::mint()).unwrap(); let answer = prepared.broadcast().clone(); @@ -10790,7 +10792,7 @@ mod tests { async fn dropping_a_prepared_claim_answer_refuses_the_request() { let producer = origin(1).produce(); let consumer = producer.consume(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); let pending = consumer.request_broadcast("room/alice", None); let prepared = queued(&claim).await.prepare(crate::Epoch::mint()).unwrap(); drop(prepared); @@ -10803,7 +10805,7 @@ mod tests { async fn a_prepared_answer_for_an_abandoned_claim_is_never_announced() { let producer = origin(1).produce(); let mut announced = producer.consume().announced(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); announced.assert_next_active("room"); let _pending = producer.consume().request_broadcast("room/alice", None); let prepared = queued(&claim).await.prepare(crate::Epoch::mint()).unwrap(); @@ -10820,7 +10822,7 @@ mod tests { async fn a_prepared_answer_for_a_released_request_is_never_announced() { let producer = origin(1).produce(); let mut announced = producer.consume().announced(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); announced.assert_next_active("room"); let _pending = producer.consume().request_broadcast("room/alice", None); let prepared = queued(&claim).await.prepare(crate::Epoch::mint()).unwrap(); @@ -10840,7 +10842,7 @@ mod tests { async fn a_pinned_request_resolves_only_through_the_published_epoch() { let producer = origin(1).produce(); let consumer = producer.consume(); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); let epoch = crate::Epoch::mint(); let unknown = consumer.request_broadcast("room/alice", crate::Epoch::mint()); assert!(matches!(unknown.await, Err(Error::Unroutable))); @@ -10862,9 +10864,9 @@ mod tests { async fn refusal_never_falls_through() { let producer = origin(1).produce(); let consumer = producer.consume(); - let catch_all = producer.dynamic_route("", Route::default()).unwrap(); - let winner = producer.dynamic_route("room", Route::default()).unwrap(); - let sibling = producer.dynamic_route("room", Route::default().with_cost(2)).unwrap(); + let catch_all = producer.requests_route("", Route::default()).unwrap(); + let winner = producer.requests_route("room", Route::default()).unwrap(); + let sibling = producer.requests_route("room", Route::default().with_cost(2)).unwrap(); let mut pending = Box::pin(consumer.request_broadcast("room/alice", None)); assert!((&mut pending).now_or_never().is_none()); @@ -10890,7 +10892,7 @@ mod tests { async fn superseded_refusal_does_not_end_the_request() { let producer = origin(1).produce(); let consumer = producer.consume(); - let stale = producer.dynamic_route("room", Route::default()).unwrap(); + let stale = producer.requests_route("room", Route::default()).unwrap(); let mut pending = Box::pin(consumer.request_broadcast("room/alice", None)); assert!((&mut pending).now_or_never().is_none()); @@ -10917,13 +10919,13 @@ mod tests { async fn refusal_from_a_beaten_route_asks_the_new_winner() { let producer = origin(1).produce(); let consumer = producer.consume(); - let stale = producer.dynamic_route("room", Route::default()).unwrap(); + let stale = producer.requests_route("room", Route::default()).unwrap(); let mut pending = Box::pin(consumer.request_broadcast("room/alice", None)); assert!((&mut pending).now_or_never().is_none()); let request = queued(&stale).await; - let winner = producer.dynamic_route("room/alice", Route::default()).unwrap(); + let winner = producer.requests_route("room/alice", Route::default()).unwrap(); request.reject(Error::NotFound); let source = broadcast::Info::new().produce(); queued(&winner).await.accept(&source); @@ -10944,7 +10946,7 @@ mod tests { async fn routed_broadcast_waits_out_a_rejection() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let mut resolving = Box::pin(consumer.routed_broadcast("room/alice")); assert!((&mut resolving).now_or_never().is_none()); @@ -10973,7 +10975,7 @@ mod tests { async fn routed_broadcast_reports_teardown_as_closed() { let (producer, driver) = Producer::new(Config::new(origin(1))); let consumer = producer.consume(); - let _server = producer.dynamic_route("room", Route::default()).unwrap(); + let _server = producer.requests_route("room", Route::default()).unwrap(); // Park on the covering route, past the loop's closed check. let mut resolving = Box::pin(consumer.routed_broadcast("room/alice")); @@ -10996,7 +10998,7 @@ mod tests { async fn routed_broadcast_wakes_for_a_local_broadcast() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let mut resolving = Box::pin(consumer.routed_broadcast("room/alice")); assert!((&mut resolving).now_or_never().is_none()); @@ -11020,7 +11022,7 @@ mod tests { async fn late_track_on_a_served_front_replays() { let producer = origin(1).produce(); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let source = broadcast::Info::new().produce(); for name in ["a", "b"] { @@ -11060,7 +11062,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); - let broad_server = producer.dynamic_route("", Route::default()).unwrap(); + let broad_server = producer.requests_route("", Route::default()).unwrap(); // A narrow advertise-only claim: requests under it must NOT route to the // broad server; they fall through to the (absent) fallback handler. let _narrow = producer.announce(".dash", Route::default()).unwrap(); @@ -11085,7 +11087,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let mut announced = consumer.announced(); - let dynamic = producer.dynamic_route("", Route::default()).unwrap(); + let dynamic = producer.requests_route("", Route::default()).unwrap(); // The root claim is advertised like any other prefix. announced.expect_next_active("").await; @@ -11119,7 +11121,7 @@ mod tests { #[cfg(feature = "async")] async fn out_of_scope_request_never_reaches_the_dynamic_handler() { let producer = origin(1).produce(); - let dynamic = producer.dynamic_route("", Route::default()).unwrap(); + let dynamic = producer.requests_route("", Route::default()).unwrap(); let scoped = producer.consume().scope("", &scopes(&["tenant-a"])).unwrap(); // `tenant-a-other` shares a character prefix but not a segment, so this @@ -11204,7 +11206,7 @@ mod tests { let mut announced = consumer.announced(); announced.expect_next_active("room").await; - let _server = producer.dynamic_route("served", Route::default()).unwrap(); + let _server = producer.requests_route("served", Route::default()).unwrap(); let pending = consumer.request_broadcast("served/path", None); drop(driver); @@ -11249,7 +11251,7 @@ mod tests { #[test] fn internal_route_requests_are_closed_on_teardown() { let (producer, mut driver) = Producer::new(Config::new(origin(1))); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); let _pending = producer.consume().request_broadcast("room/alice", None); driver.poll(Instant::now(), &kio::Waiter::noop()).unwrap(); let Poll::Ready(Ok(request)) = server.poll_requested_broadcast(&kio::Waiter::noop()) else { @@ -11276,12 +11278,12 @@ mod tests { /// Announce a served route with `first` as its first hop, materialize /// "room/alice" through it with a one-group "before" track, and subscribe. #[cfg(feature = "async")] - async fn new(first: &[u64]) -> (Self, Dynamic, broadcast::Producer) { + async fn new(first: &[u64]) -> (Self, Requests, broadcast::Producer) { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(first))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(first))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); @@ -11322,9 +11324,9 @@ mod tests { /// Stand up a second served route with `first` as its first hop and hand /// back its handle, ready to answer the front's re-request. - fn standby(&self, first: &[u64]) -> Dynamic { + fn standby(&self, first: &[u64]) -> Requests { self.producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(first))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(first))) .unwrap() } } @@ -11334,7 +11336,7 @@ mod tests { /// rig's subscription resumes onto it: the successor group is delivered on /// the same subscription, at the group boundary. #[cfg(feature = "async")] - async fn assert_resumes(rig: &mut ResumeRig, server: &Dynamic) { + async fn assert_resumes(rig: &mut ResumeRig, server: &Requests) { let request = queued(server).await; let replacement = broadcast::Info::new().produce(); let track = replacement.create_track("video", crate::track::Info::timed()).unwrap(); @@ -11378,7 +11380,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let first = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10])).with_cost(5)) + .requests_route("room", Route::default().with_hops(hops(&[10])).with_cost(5)) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let source = broadcast::Info::new().produce(); @@ -11389,7 +11391,7 @@ mod tests { deliver(&track, &mut subscription, b"first").await; let second = producer - .dynamic_route("room", Route::default().with_hops(hops(&[11])).with_cost(1)) + .requests_route("room", Route::default().with_hops(hops(&[11])).with_cost(1)) .unwrap(); deliver(&track, &mut subscription, b"pinned").await; @@ -11503,7 +11505,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let old = producer - .dynamic_route("room", Route::default().with_epoch(crate::Epoch::mint())) + .requests_route("room", Route::default().with_epoch(crate::Epoch::mint())) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let request = queued(&old).await; @@ -11533,7 +11535,7 @@ mod tests { let consumer = producer.consume(); let old = crate::Epoch::mint(); let dynamic = producer - .dynamic_route("room", Route::default().with_epoch(old.clone())) + .requests_route("room", Route::default().with_epoch(old.clone())) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let pinned = consumer.request_broadcast("room/alice", old); @@ -11589,7 +11591,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let dynamic = producer - .dynamic_route("room", Route::default().with_epoch(crate::Epoch::mint())) + .requests_route("room", Route::default().with_epoch(crate::Epoch::mint())) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); queued(&dynamic).await.reject(Error::NotFound); @@ -11614,7 +11616,7 @@ mod tests { let consumer = producer.consume(); let old = crate::Epoch::mint(); let dynamic = producer - .dynamic_route("room", Route::default().with_epoch(old.clone())) + .requests_route("room", Route::default().with_epoch(old.clone())) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let request = queued(&dynamic).await; @@ -11644,7 +11646,7 @@ mod tests { async fn losing_an_epoch_is_another_instance() { let producer = origin(1).produce(); let consumer = producer.consume(); - let dynamic = producer.dynamic_route("room", Route::default()).unwrap(); + let dynamic = producer.requests_route("room", Route::default()).unwrap(); let pending = consumer.request_broadcast("room/alice", None); let old = broadcast::Info::new().produce(); let _old_track = old.create_track("video", crate::track::Info::timed()).unwrap(); @@ -11832,7 +11834,7 @@ mod tests { drop(source); rig.incumbent_track.clone().abort(Error::Dropped).unwrap(); let replacement = broadcast::Info::new().produce(); - let mut handler = replacement.dynamic(); + let mut handler = replacement.requests(); queued(&standby).await.accept(&replacement); let request = handler.requested_track().await.unwrap(); assert_eq!(request.subscription().unwrap().start(), Some(5)); @@ -11891,11 +11893,11 @@ mod tests { None => producer.consume(), }; let incumbent = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) .unwrap(); // The same publisher, reached through the requesting peer. let echo = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10, 7]))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10, 7]))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); @@ -11958,7 +11960,7 @@ mod tests { // Session A: an assigned anonymous hop serving the path. let server_a = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); // Session C: a third anonymous session, excluding the hop the server @@ -12014,7 +12016,7 @@ mod tests { // Session B attaches at the same path. Its front is served immediately. let server_b = producer - .dynamic_route("room", Route::default().with_hops(hops(&[20]))) + .requests_route("room", Route::default().with_hops(hops(&[20]))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let request = queued(&server_b).await; @@ -12140,7 +12142,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); // The front selected the covering route and waits on its answer. @@ -12162,14 +12164,14 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let covering = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); let _beaten = queued(&covering).await; // The exact path wins, and the front asks it in turn. let exact = producer - .dynamic_route("room/alice", Route::default().with_hops(hops(&[10]))) + .requests_route("room/alice", Route::default().with_hops(hops(&[10]))) .unwrap(); let request = queued(&exact).await; let again = consumer.request_broadcast("room/alice", None); @@ -12240,7 +12242,7 @@ mod tests { let producer = origin(1).produce(); let consumer = producer.consume(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let pending = consumer.request_broadcast("room/alice", None); @@ -12288,7 +12290,7 @@ mod tests { async fn a_closed_source_is_not_requested_again_from_its_standing_route() { let producer = origin(1).produce(); let server = producer - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let pending = producer.consume().request_broadcast("room/alice", None); let source = broadcast::Info::new().produce(); @@ -12375,7 +12377,7 @@ mod tests { async fn a_held_group_continues_after_its_track_goes_unread() { let producer = origin(1).produce(); let server = producer - .dynamic_route("live", Route::default().with_hops(hops(&[10]))) + .requests_route("live", Route::default().with_hops(hops(&[10]))) .unwrap(); let pending = producer.consume().request_broadcast("live", None); let source = broadcast::Info::new().produce(); @@ -12464,7 +12466,7 @@ mod tests { let mid = origin(2).produce(); let mid_server = mid - .dynamic_route("room", Route::default().with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_hops(hops(&[10]))) .unwrap(); let mid_pending = mid.consume().request_broadcast("room/alice", None); queued(&mid_server).await.accept(&leaf_front); @@ -12472,7 +12474,7 @@ mod tests { let edge = origin(3).produce(); let edge_server = edge - .dynamic_route("room", Route::default().with_hops(hops(&[20]))) + .requests_route("room", Route::default().with_hops(hops(&[20]))) .unwrap(); let edge_pending = edge.consume().request_broadcast("room/alice", None); queued(&edge_server).await.accept(&mid_resolved); @@ -12595,14 +12597,14 @@ mod tests { #[cfg(feature = "async")] async fn remote_front() -> ( Producer, - Dynamic, + Requests, broadcast::Producer, track::Producer, track::Subscriber, ) { let producer = origin(1).produce(); let server = producer - .dynamic_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) + .requests_route("room", Route::default().with_epoch(epoch()).with_hops(hops(&[10]))) .unwrap(); let pending = producer.consume().request_broadcast("room/alice", None); let upstream = broadcast::Info::new().produce(); @@ -12627,7 +12629,7 @@ mod tests { let (producer, _server, _upstream, old, subscription) = remote_front().await; let newcomer = producer.create_broadcast("room/alice").unwrap(); - let mut handler = newcomer.dynamic(); + let mut handler = newcomer.requests(); newcomer.announce(Route::default().with_epoch(epoch())).unwrap(); let _unanswered = moq_clock::timeout(Duration::from_secs(1), handler.requested_track()) .await @@ -12877,7 +12879,7 @@ mod tests { drop(group); let second = producer.create_broadcast("room/alice").unwrap(); - let mut handler = second.dynamic(); + let mut handler = second.requests(); second.announce(Route::default().with_epoch(epoch())).unwrap(); let request = moq_clock::timeout(Duration::from_secs(1), handler.requested_track()) .await @@ -12990,7 +12992,7 @@ mod tests { assert!(matches!(driver.poll(Instant::now(), &waiter), Err(Error::Closed))); } - /// A handler holding only its `Dynamic` keeps serving once every producer + /// A handler holding only its `Requests` keeps serving once every producer /// handle drops, and the driver finishes once the handler is gone too. #[moq_clock::test] #[cfg(feature = "async")] @@ -12998,7 +13000,7 @@ mod tests { let (producer, driver) = Producer::new(Config::new(origin(1))); let run = moq_clock::sim::spawn(crate::time::run(driver)); let consumer = producer.consume(); - let server = producer.dynamic_route("room", Route::default()).unwrap(); + let server = producer.requests_route("room", Route::default()).unwrap(); drop(producer); let pending = consumer.request_broadcast("room/alice", None); @@ -13103,7 +13105,7 @@ mod tests { async fn source_selection_leases_survive_reprices_but_never_revive_pending_work() { let producer = origin(1).produce(); let broad = producer - .dynamic_route("room", Route::default().with_via(origin(2))) + .requests_route("room", Route::default().with_via(origin(2))) .unwrap(); let selected = broad.request_validity(&Path::new("room/a")).unwrap(); let pending = selected.current(); @@ -13112,11 +13114,11 @@ mod tests { assert!(!pending.is_closed()); // Another peer's winning route cannot change what a request on peer 2 names. let other = producer - .dynamic_route("room/a", Route::default().with_via(origin(3))) + .requests_route("room/a", Route::default().with_via(origin(3))) .unwrap(); assert!(!pending.is_closed()); let replacement = producer - .dynamic_route("room/a", Route::default().with_via(origin(2))) + .requests_route("room/a", Route::default().with_via(origin(2))) .unwrap(); assert!(pending.is_closed()); assert!(selected.current().is_closed()); @@ -13138,19 +13140,19 @@ mod tests { let producer = origin(1).produce(); let path = Path::new("room/a"); let first = producer - .dynamic_route("room", Route::default().with_via(origin(2))) + .requests_route("room", Route::default().with_via(origin(2))) .unwrap(); let selected = first.request_validity(&path).unwrap(); let answering = selected.answering(); // A route that loses to the selected one replaces nothing. let worse = producer - .dynamic_route("room", Route::default().with_via(origin(2)).with_cost(Cost::from(7))) + .requests_route("room", Route::default().with_via(origin(2)).with_cost(Cost::from(7))) .unwrap(); assert!(!answering.is_closed()); drop(worse); let replacement = producer - .dynamic_route("room/a", Route::default().with_via(origin(2))) + .requests_route("room/a", Route::default().with_via(origin(2))) .unwrap(); assert!(answering.is_closed()); // Winning again opens a new lease, which a withdrawal leaves open. @@ -13163,7 +13165,7 @@ mod tests { // Announced again, the path has a new instance: a replacement. let _again = producer - .dynamic_route("room", Route::default().with_via(origin(2))) + .requests_route("room", Route::default().with_via(origin(2))) .unwrap(); assert!(answering.is_closed()); } @@ -13172,7 +13174,7 @@ mod tests { async fn source_selection_unregisters_without_retaining_the_source() { let producer = origin(1).produce(); let route = producer - .dynamic_route("room", Route::default().with_via(origin(2))) + .requests_route("room", Route::default().with_via(origin(2))) .unwrap(); let path = Path::new("room/a"); let selected = route.request_validity(&path).unwrap(); @@ -13228,7 +13230,7 @@ mod tests { ..Default::default() }); let consumer = producer.consume(); - let _served = producer.dynamic_route("room", Route::default()).unwrap(); + let _served = producer.requests_route("room", Route::default()).unwrap(); // A consumer outlives its producer by design, so the task set can refuse // submissions while the origin is still open. The front's task is then // dropped on the spot, taking its `Watch` with it: the request must not diff --git a/rs/moq-net/src/model/requests.rs b/rs/moq-net/src/model/request_queue.rs similarity index 92% rename from rs/moq-net/src/model/requests.rs rename to rs/moq-net/src/model/request_queue.rs index 7561ce68529..ac27eefc763 100644 --- a/rs/moq-net/src/model/requests.rs +++ b/rs/moq-net/src/model/request_queue.rs @@ -1,4 +1,4 @@ -//! A coalescing request queue drained by dynamic handlers. +//! A coalescing request queue drained by request handlers. use std::{ borrow::Borrow, collections::{HashMap, VecDeque}, @@ -7,7 +7,7 @@ use std::{ /// Requests keyed by `K`, drained in FIFO order by a pool of handlers. /// -/// This is the state shared between requesters and the `Dynamic` handlers that +/// This is the state shared between requesters and the `Requests` handlers that /// serve them (origin broadcasts, broadcast tracks, track fetches), typically /// inside a [`kio::Shared`] so both sides work under one lock. It encodes two /// invariants in one place: @@ -20,7 +20,7 @@ use std::{ /// [`Self::pop`] hands out only the key: the entry stays pending (still /// joinable) until the caller explicitly removes it, on resolution or via /// [`Self::drain_queued`] when the last handler leaves. -pub(super) struct Requests { +pub(super) struct RequestQueue { // Every pending request: queued or already handed to a handler. pending: HashMap>, // The queued (not yet popped) subset, FIFO. Every key here is in `pending`. @@ -36,7 +36,7 @@ struct Entry { queued: bool, } -impl Default for Requests { +impl Default for RequestQueue { fn default() -> Self { Self { pending: HashMap::new(), @@ -46,7 +46,7 @@ impl Default for Requests { } } -impl Requests { +impl RequestQueue { /// Join the pending request for `key`, queued or already handed out. pub fn join(&mut self, key: &Q) -> Option<&mut V> where @@ -180,7 +180,7 @@ mod test { #[test] fn insert_gated_on_handlers() { - let mut requests = Requests::::default(); + let mut requests = RequestQueue::::default(); assert_eq!(requests.insert(1, "a"), Err("a")); requests.add_handler(); @@ -194,7 +194,7 @@ mod test { #[test] fn popped_stays_joinable_until_removed() { - let mut requests = Requests::::default(); + let mut requests = RequestQueue::::default(); requests.add_handler(); assert!(requests.insert(1, "a").is_ok()); @@ -210,7 +210,7 @@ mod test { #[test] fn remove_if_guards_identity() { - let mut requests = Requests::::default(); + let mut requests = RequestQueue::::default(); requests.add_handler(); assert!(requests.insert(1, "old").is_ok()); @@ -224,7 +224,7 @@ mod test { #[test] fn take_after_pop_keeps_the_queue_order() { - let mut requests = Requests::::default(); + let mut requests = RequestQueue::::default(); requests.add_handler(); for (key, value) in [(1, "a"), (2, "b"), (3, "c")] { assert!(requests.insert(key, value).is_ok()); @@ -238,7 +238,7 @@ mod test { #[test] fn drain_queued_spares_popped() { - let mut requests = Requests::::default(); + let mut requests = RequestQueue::::default(); requests.add_handler(); assert!(requests.insert(1, "handed out").is_ok()); assert!(requests.insert(2, "queued").is_ok()); diff --git a/rs/moq-net/src/model/resume.rs b/rs/moq-net/src/model/resume.rs index 94628830631..bd723779f58 100644 --- a/rs/moq-net/src/model/resume.rs +++ b/rs/moq-net/src/model/resume.rs @@ -2198,7 +2198,7 @@ mod test { assert_eq!(read(&mut held), Some(b"first".to_vec())); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); let mut newer = b.create_group(group::Info { sequence: 1 }).unwrap(); newer.write_frame(ts(1), b"newer".as_ref()).unwrap(); newer.finish().unwrap(); @@ -2672,7 +2672,7 @@ mod test { open.abort(Error::Dropped).unwrap(); let b = compressed(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(reading.read_frame().now_or_never().is_none()); let request = dynamic.requested_fill_group().now_or_never().unwrap().unwrap(); @@ -2751,7 +2751,7 @@ mod test { drop(a); let b = track::Producer::new(broadcast.clone(), "video", info.clone()); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(reading.read_frame().now_or_never().is_none()); let request = dynamic.requested_fill_group().now_or_never().unwrap().unwrap(); @@ -2833,7 +2833,7 @@ mod test { } let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(reading.read_frame().now_or_never().is_none(), "fails={fails}"); let _pending = dynamic.requested_fill().now_or_never().unwrap().unwrap(); @@ -2865,7 +2865,7 @@ mod test { ); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); b.drop_groups(0..1, StreamError::Old); assert!(fetched.read_frame().now_or_never().is_none()); @@ -2998,7 +2998,7 @@ mod test { ); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert_eq!(read(&mut reading), Some(b"b".to_vec())); assert!(reading.read_frame().now_or_never().is_none()); @@ -3035,7 +3035,7 @@ mod test { assert_eq!(read(&mut reading), Some(b"a".to_vec())); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(reading.read_frame().now_or_never().is_none()); let request = dynamic.requested_fill_group().now_or_never().unwrap().unwrap(); @@ -3068,7 +3068,7 @@ mod test { open.abort(Error::Evicted).unwrap(); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(fetched.read_frame().now_or_never().is_none()); let request = dynamic.requested_fill_group().now_or_never().unwrap().unwrap(); @@ -4985,7 +4985,7 @@ mod test { fn a_pending_fetch_wakes_and_moves_to_the_new_route() { let routes = Producer::new(); let a = copy(); - let dynamic = a.dynamic(); + let dynamic = a.requests(); routes.serve(a.consume()); let logical = logical(&routes); let mut fetching = logical.consume().fetch_group(0, None); @@ -5014,7 +5014,7 @@ mod test { let mut filling = Box::pin(consumer.fill_groups(0..4, 0)); assert!(filling.as_mut().now_or_never().is_none(), "no copy serves yet"); let a = copy(); - let dynamic = a.dynamic(); + let dynamic = a.requests(); routes.serve(a.consume()); assert!( filling.as_mut().now_or_never().is_none(), @@ -5037,7 +5037,7 @@ mod test { let mut reading = recv(&mut sub); assert_eq!(read(&mut reading), Some(b"a".to_vec())); let b = copy(); - let _dynamic = b.dynamic(); + let _dynamic = b.requests(); routes.serve(b.consume()); assert!(reading.read_frame().now_or_never().is_none()); for sequence in 1..=4 { @@ -5309,7 +5309,7 @@ mod test { fn a_fetched_group_outlives_its_delivery_giving_up() { let routes = Producer::new(); let a = copy(); - let dynamic = a.dynamic(); + let dynamic = a.requests(); routes.serve(a.consume()); let mut arriving = a.create_group(group::Info { sequence: 0 }).unwrap(); @@ -5363,7 +5363,7 @@ mod test { let routes = Producer::new(); let logical = logical(&routes); let a = copy(); - let dynamic = a.dynamic(); + let dynamic = a.requests(); routes.serve(a.consume()); let mut sub = subscribe(&logical, HOUR); let mut open = a.create_group(group::Info { sequence: 0 }).unwrap(); @@ -5399,7 +5399,7 @@ mod test { let routes = Producer::new(); let logical = logical(&routes); let a = copy(); - let a_requests = a.dynamic(); + let a_requests = a.requests(); routes.serve(a.consume()); let mut sub = subscribe(&logical, HOUR); let mut open = a.create_group(group::Info { sequence: 0 }).unwrap(); @@ -5411,7 +5411,7 @@ mod test { assert_eq!(read(&mut reading), Some(b"a".to_vec())); let b = copy(); - let b_requests = b.dynamic(); + let b_requests = b.requests(); routes.serve(b.consume()); let mut repeat = b.create_group(group::Info { sequence: 0 }).unwrap(); repeat.write_frame(ts(0), b"a".as_ref()).unwrap(); @@ -5450,7 +5450,7 @@ mod test { assert_eq!(read(&mut reading), Some(b"a".to_vec())); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); open.abort(Error::Stream(code.clone())).unwrap(); assert!(reading.read_frame().now_or_never().is_none(), "{code:?}"); @@ -5507,7 +5507,7 @@ mod test { assert_eq!(read(&mut fetched), Some(b"a".to_vec())); let b = copy(); - let dynamic = b.dynamic(); + let dynamic = b.requests(); routes.serve(b.consume()); assert!(fetched.read_frame().now_or_never().is_none()); let request = dynamic.requested_fill_group().now_or_never().unwrap().unwrap(); @@ -5814,7 +5814,7 @@ mod test { fn ending_the_front_releases_a_pending_fetch() { let routes = Producer::new(); let a = copy(); - let _dynamic = a.dynamic(); + let _dynamic = a.requests(); routes.serve(a.consume()); let logical = logical(&routes); let mut fetching = logical.consume().fetch_group(0, None); diff --git a/rs/moq-net/src/model/track.rs b/rs/moq-net/src/model/track.rs index a399e1923d9..36d145e51eb 100644 --- a/rs/moq-net/src/model/track.rs +++ b/rs/moq-net/src/model/track.rs @@ -476,7 +476,7 @@ pub(crate) struct TrackState { subscriptions: kio::Lock, // The fills readers queued for groups they miss (see [`Fill`]), same reasoning: a miss - // queues here and a `Dynamic` drains. + // queues here and a `Requests` drains. fills: kio::Shared, // A front's logical track: read straight from its routes' copies rather than this @@ -1475,7 +1475,7 @@ impl TrackState { /// Resolve a one-shot fetch from the track side: the cached group, or an [`Error`] /// once it can never be served. A missing group is a failure ([`Error::NotFound`]), not an - /// end-of-stream. The handler side (a refusal, or no [`Dynamic`] at all) lives + /// end-of-stream. The handler side (a refusal, or no [`Requests`] at all) lives /// in the track's fills; [`Fetching`] polls both. fn poll_fetch_cached(&self, sequence: u64, frame_start: u64) -> Poll> { // A group aborted between the lookup and the consume (an abandoned fetch cut @@ -2752,7 +2752,7 @@ pub struct Producer { broadcast: Arc, state: kio::Producer, prev_subscription: Option, - // Shared with every clone and every `Dynamic`: its `Drop` is the teardown. + // Shared with every clone and every `Requests`: its `Drop` is the teardown. alive: Arc, // Ingress stats scope, inherited from a tagged [`broadcast::Producer`]. Bumped as // one subscription on tag and closed when the last producer clone drops. Empty @@ -3517,11 +3517,11 @@ impl Producer { poll_combined_changed(&subs, bound, &mut self.prev_subscription, waiter).map(Ok) } - /// Create a [`Dynamic`] handle that serves on-demand fetches of uncached + /// Create a [`Requests`] handle that serves on-demand fetches of uncached /// (old) groups. Most producers never need this; a relay creates one to fetch /// past groups from upstream. - pub fn dynamic(&self) -> Dynamic { - Dynamic::new(self.name.clone(), self.state.clone(), self.alive.clone()) + pub fn requests(&self) -> Requests { + Requests::new(self.name.clone(), self.state.clone(), self.alive.clone()) } fn modify(&self) -> Result> { @@ -3530,15 +3530,15 @@ impl Producer { } /// Serves the groups a track's readers miss, the group-level analogue of -/// [`broadcast::Dynamic`]. +/// [`broadcast::Requests`]. /// /// Most tracks never serve old content, so this capability lives on a dedicated /// handle rather than [`Producer`]: a relay creates one (via -/// [`Producer::dynamic`] or [`Request::dynamic`]) to pull past groups +/// [`Producer::requests`] or [`Request::requests`]) to pull past groups /// from upstream. While at least one is alive a reader's miss queues a [`Fill`] for it /// to serve; with none, the miss is named dropped, and a cache-miss /// [`Consumer::fetch_group`] on an accepted track fails fast with [`Error::NotFound`]. -pub struct Dynamic { +pub struct Requests { name: Arc, // Kept to insert served groups into the cache and observe track abort. state: kio::Producer, @@ -3549,7 +3549,7 @@ pub struct Dynamic { alive: Arc, } -impl Dynamic { +impl Requests { fn new(name: Arc, state: kio::Producer, alive: Arc) -> Self { let fills = state.read().fills.clone(); fills.lock().add_handler(); @@ -3602,9 +3602,9 @@ impl Dynamic { } } -impl Clone for Dynamic { +impl Clone for Requests { fn clone(&self) -> Self { - // Count each live handle (mirrors `broadcast::Dynamic`). + // Count each live handle (mirrors `broadcast::Requests`). self.fills.lock().add_handler(); Self { name: self.name.clone(), @@ -3615,9 +3615,9 @@ impl Clone for Dynamic { } } -impl Drop for Dynamic { +impl Drop for Requests { fn drop(&mut self) { - // Unlike `broadcast::Dynamic`, dropping the last handle doesn't abort the track: + // Unlike `broadcast::Requests`, dropping the last handle doesn't abort the track: // a live `Producer` may still be serving the subscription. It just stops serving // fills: a queued one no handler will ever take closes, so its readers stop // waiting on it, while one already taken stays with its `Fill`. @@ -3625,7 +3625,7 @@ impl Drop for Dynamic { } } -/// Ends the track when the last [`Producer`] or [`Dynamic`] drops. +/// Ends the track when the last [`Producer`] or [`Requests`] drops. /// /// A refcount rather than a "am I the last one?" check inside `Drop`: that answer is a /// snapshot, and acting on it is exactly what invalidates it. The track state's own @@ -3638,7 +3638,7 @@ struct Alive { state: kio::Producer, // Set when a `Producer` is first minted, so a `Request` nobody accepted (its - // `Dynamic` holds this guard too) isn't reported as an abandoned publisher. + // `Requests` holds this guard too) isn't reported as an abandoned publisher. published: AtomicBool, // Ingress subscription for this track, opened by the tagged producer that claimed @@ -3898,7 +3898,7 @@ impl super::WeakEntry for TrackWeak { /// A cloneable, watch-only handle to a track's subscriber demand. /// -/// Obtained from [`Producer::demand`], [`Request::demand`], or [`Dynamic::demand`]. +/// Obtained from [`Producer::demand`], [`Request::demand`], or [`Requests::demand`]. /// A publisher uses it to learn which group anyone subscribed, querying, or fetching /// wants (on-demand capture / encoding) without being able to publish frames or close the /// track. A bare [`Consumer`] is not demand. It's a weak handle, so it neither keeps @@ -4607,12 +4607,12 @@ impl Consumer { /// Fetching a single past group, without holding a live subscription. /// /// Returns a [`kio::Pending`] that resolves to the [`group::Consumer`]: - /// immediately if the group is cached, otherwise once a [`Dynamic`] serves + /// immediately if the group is cached, otherwise once a [`Requests`] serves /// the request (a wire FETCH for a relay). `options` accepts `None`, a [`group::Fetch`], /// or `group::Fetch::default()`. /// /// The returned future resolves to [`Error::NotFound`] when the group can never be served - /// (past the final sequence, or no [`Dynamic`] on the track), [`Error::NotFetchable`] + /// (past the final sequence, or no [`Requests`] on the track), [`Error::NotFetchable`] /// instead when this track sent the sequence as a datagram still buffered, the handler's /// rejection (a relay's upstream miss is [`StreamError::NotFound`](StreamError::NotFound)), /// or the track's abort error if it's already closed. A miss queues a one-group [`Fill`], @@ -4700,7 +4700,7 @@ impl Consumer { } /// Fill the groups of `span` the cache misses and nothing recorded dropped, asking a - /// [`Dynamic`] once per run of misses so it fetches each run at once, and resolve once + /// [`Requests`] once per run of misses so it fetches each run at once, and resolve once /// every run is answered. The returned guard keeps the fills wanted, so the groups they /// accepted stay cached while the caller reads them. A track with no handler resolves at /// once, and a front's logical track fills through the copy the front assigns it. @@ -7714,7 +7714,7 @@ pub(crate) struct Staged { producer: Option, // The request's fetch claim, held until the track is published like an unanswered // request's: a cache miss meanwhile waits rather than racing its own handler. - _dynamic: Dynamic, + _dynamic: Requests, } impl Staged { @@ -7754,7 +7754,7 @@ impl Drop for Staged { /// A subscriber asked for a track this broadcast doesn't have yet. /// -/// Yielded by [`poll_requested_track`](crate::broadcast::Dynamic::poll_requested_track), +/// Yielded by [`poll_requested_track`](crate::broadcast::Requests::poll_requested_track), /// or created up front with [`broadcast::Producer::reserve_track`](crate::broadcast::Producer::reserve_track). /// Subscribers block until the request is /// resolved: call [`accept`](Self::accept) to serve it with a [`Producer`], or @@ -7772,7 +7772,7 @@ pub struct Request { // The previous subscription that was combined, used to detect changes. prev_subscription: Option, - // Shared with the accepted [`Producer`] and every [`Dynamic`]: its `Drop` is the + // Shared with the accepted [`Producer`] and every [`Requests`]: its `Drop` is the // teardown, and it stays inert until a producer is minted. alive: Arc, @@ -7780,7 +7780,7 @@ pub struct Request { // birth: a consumer's cache-miss `fetch_group` waits to be served instead of // racing the producer (e.g. a relay) into creating its own handler. Released // when the request is accepted or dropped; by then the relay holds its own. - _dynamic: Dynamic, + _dynamic: Requests, // Ingress stats scope, threaded into the accepted [`Producer`]. Empty (no-op) // unless this request was reserved on a tagged broadcast. @@ -7805,7 +7805,7 @@ impl Request { let name = name.into(); let state = TrackState::spawn(broadcast.clone()); let alive = Alive::new(name.clone(), state.clone()); - let dynamic = Dynamic::new(name.clone(), state.clone(), alive.clone()); + let dynamic = Requests::new(name.clone(), state.clone(), alive.clone()); Self { name, broadcast, @@ -7874,11 +7874,11 @@ impl Request { Consumer::new(self.name.clone(), self.state.weak().consume_weak()) } - /// Create a [`Dynamic`] handle that serves on-demand fetches of uncached + /// Create a [`Requests`] handle that serves on-demand fetches of uncached /// groups, before [`Self::accept`] is even called. A relay creates one to fetch /// past groups from upstream while (or instead of) serving a live subscription. - pub fn dynamic(&self) -> Dynamic { - Dynamic::new(self.name.clone(), self.state.clone(), self.alive.clone()) + pub fn requests(&self) -> Requests { + Requests::new(self.name.clone(), self.state.clone(), self.alive.clone()) } /// Watch subscriber demand without keeping the track alive. @@ -9313,7 +9313,7 @@ mod test { #[cfg(feature = "async")] fn the_last_sequence_misses_with_a_handler() { let producer = track_producer("test", None); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let fetch = consumer.fetch_group(u64::MAX, None).now_or_never(); assert!(matches!(fetch, Some(Err(Error::NotFound)))); @@ -12003,7 +12003,7 @@ mod test { #[test] fn cold_fetch_expires_without_waiting_for_the_upstream_group() { let mut producer = track_producer("test", Info::timed()); - let _dynamic = producer.dynamic(); + let _dynamic = producer.requests(); let mut successor = producer.create_group(group::Info { sequence: 1 }).unwrap(); successor .write_frame(Timestamp::from_millis(1000).unwrap(), bytes::Bytes::from_static(b"x")) @@ -12089,7 +12089,7 @@ mod test { fn a_fetch_only_cache_is_not_live() { let waiter = kio::Waiter::noop(); let request = Request::new(Arc::new(broadcast::Info::default()), "test"); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let consumer = request.consume(); let mut pending = consumer.fetch_group(2, None); let Poll::Ready(Ok(req)) = dynamic.poll_requested_fill_group(&waiter) else { @@ -12127,7 +12127,7 @@ mod test { #[cfg(feature = "async")] async fn fetched_group_is_not_a_live_drift_edge() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); append_at(&mut producer, 0); @@ -12777,7 +12777,7 @@ mod test { #[cfg(feature = "async")] async fn abort_ends_an_open_fetched_head() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut live = producer.create_group(group::Info { sequence: 0 }).unwrap(); live.start_at(1).unwrap(); @@ -13366,7 +13366,7 @@ mod test { async fn a_fetched_group_does_not_fill_a_pending_tail() { let mut producer = track_producer("test", None); producer.received(); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut arrival = producer.subscribe(None); producer.start_at(0).unwrap(); @@ -14841,7 +14841,7 @@ mod test { // A cached group resolves immediately and never queues a request. `peek_group` // also returns it synchronously. - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); assert!(consumer.peek_group(0).is_some()); let mut g = consumer.fetch_group(0, None).await.unwrap(); @@ -14856,7 +14856,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_miss_signals_dynamic() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // A cache miss isn't in `peek_group`, but a dynamic handler exists, so @@ -14890,7 +14890,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_miss_rejects() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let pending = consumer.fetch_group(5, None); @@ -14910,7 +14910,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_miss_drop_rejects() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let pending = consumer.fetch_group(5, None); @@ -14930,7 +14930,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_request_unused_once_every_fetch_leaves() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -14964,7 +14964,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_abandoned_while_queued_never_reaches_the_handler() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); drop(consumer.fetch_group(5, None)); @@ -14979,7 +14979,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_after_the_last_caller_left_is_not_dropped() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -15009,7 +15009,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_accept_after_withdrawal_caches_the_group() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -15054,7 +15054,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_hit_keeps_the_group_wanted() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -15085,7 +15085,7 @@ mod test { #[cfg(feature = "async")] async fn accepted_group_starts_at_the_request() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let _tail = consumer.fetch_group( @@ -15118,7 +15118,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_misses_an_abandoned_group() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -15145,7 +15145,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_reject_does_not_poison_retry() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let pending = consumer.fetch_group(5, None); @@ -15180,7 +15180,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_ignores_a_group_that_starts_too_late() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // The live subscription resumed mid-group, so only the tail is cached. @@ -15235,7 +15235,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_fills_the_head_of_a_live_group() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut live = producer.create_group(group::Info { sequence: 0 }).unwrap(); @@ -15280,7 +15280,7 @@ mod test { #[cfg(feature = "async")] async fn a_refused_end_leaves_every_copy_uncapped() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // The live copy holds frames 0 and 1, the fetched head frames 0 to 2. @@ -15310,7 +15310,7 @@ mod test { /// A live group with a fetched head: group 0, fed from frame 1, plus a two-frame head. #[cfg(feature = "async")] async fn live_group_with_head(producer: &Producer) -> (group::Producer, group::Producer) { - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut live = producer.create_group(group::Info { sequence: 0 }).unwrap(); @@ -15336,7 +15336,7 @@ mod test { #[cfg(feature = "async")] async fn a_fetched_head_holds_the_largest_open() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut reader = consumer.clone(); let noop = kio::Waiter::noop(); @@ -15434,7 +15434,7 @@ mod test { #[cfg(feature = "async")] async fn pressure_evicts_a_headed_slot(abort_live: bool) -> bool { let (producer, _pool) = pooled_producer(10_000); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut live = producer.create_group(group::Info { sequence: 0 }).unwrap(); @@ -15487,7 +15487,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_widens_or_asks_afresh() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let from = |frame_start| group::Fetch { frame_start, @@ -15546,7 +15546,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_coalesces_concurrent() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // Two fetches for the same uncached group produce ONE handler request, @@ -15599,7 +15599,7 @@ mod test { #[cfg(feature = "async")] async fn a_late_looser_fetch_asks_again_after_old() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let tight = consumer.fetch_group(5, group::Fetch::default().with_max_delay(Duration::from_secs(1))); @@ -15626,7 +15626,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_coalesced_reject_fails_all() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(5, None); @@ -15656,7 +15656,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_queued_fails_when_handlers_leave() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // Queued but never popped: the last handler leaving fails it fast. @@ -15673,7 +15673,7 @@ mod test { #[moq_clock::test] #[cfg(feature = "async")] async fn fetch_miss_no_dynamic_not_found() { - // A track with no `Dynamic` can't serve old content, so a cache miss + // A track with no `Requests` can't serve old content, so a cache miss // resolves to NotFound instead of blocking forever. let producer = track_producer("test", Info::timed()); let _open = producer.append_group().unwrap(); // seq 0, but we miss on seq 5 @@ -15690,7 +15690,7 @@ mod test { // A group at or past the final sequence can never exist, even with a handler, // so it resolves to NotFound. - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); assert!(matches!(consumer.fetch_group(5, None).await, Err(Error::NotFound))); @@ -15961,7 +15961,7 @@ mod test { ..Default::default() }; let request = Request::new(Arc::new(broadcast), "test"); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let consumer = request.consume(); // Serve a backfill before the track is accepted, then grow it. @@ -16068,12 +16068,12 @@ mod test { assert!(!Arc::ptr_eq(&a, &b), "each track owns its account"); } - /// A `Dynamic` still serving fetches keeps the track alive, so the publisher + /// A `Requests` still serving fetches keeps the track alive, so the publisher /// letting go isn't an abrupt teardown: the handler can still serve the cache. #[test] fn a_dynamic_defers_teardown() { let (mut producer, pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); finished_group(&mut producer, 100); drop(producer); @@ -16155,7 +16155,7 @@ mod test { ..Default::default() }; let request = Request::new(Arc::new(broadcast), "test"); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let consumer = request.consume(); // Serve backfill seq 0 before the track is accepted. @@ -16216,7 +16216,7 @@ mod test { #[cfg(feature = "async")] async fn refreshed_front_does_not_starve_expiry() { let (producer, _pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer.create_group(10u64.into()).unwrap().finish().unwrap(); @@ -16496,7 +16496,7 @@ mod test { #[cfg(feature = "async")] async fn refilled_sequence_stays_out_of_subscriptions() { let (producer, _pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer.create_group(0u64.into()).unwrap().finish().unwrap(); @@ -16533,7 +16533,7 @@ mod test { #[cfg(feature = "async")] async fn expired_backfill_behind_refreshed_reclaimed() { let (producer, _pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer.create_group(5u64.into()).unwrap().finish().unwrap(); @@ -16592,7 +16592,7 @@ mod test { #[cfg(feature = "async")] async fn refetched_latest_stays_protected() { let (producer, _pool) = pooled_producer(10_000); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let straggler = producer.append_group().unwrap(); // seq 0 @@ -16634,7 +16634,7 @@ mod test { #[cfg(feature = "async")] async fn eviction_allows_refetch() { let (mut producer, _pool) = pooled_producer(10_000); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); finished_group(&mut producer, 10_000); // seq 0 finished_group(&mut producer, 10_000); // seq 1: demotes seq 0 @@ -16703,7 +16703,7 @@ mod test { #[cfg(feature = "async")] async fn a_lowered_floor_reoffers_live_groups_but_not_fetched_ones() { let (producer, _pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer.create_group(5u64.into()).unwrap().finish().unwrap(); let mut subscriber = producer.subscribe(replay().with_range(5..)); @@ -16747,7 +16747,7 @@ mod test { #[cfg(feature = "async")] async fn fetched_backfill_not_subscribed() { let (producer, _pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); // The publisher starts at seq 5; earlier groups exist only upstream. @@ -16783,7 +16783,7 @@ mod test { #[cfg(feature = "async")] async fn expired_backfill_reclaimed() { let (producer, pool) = pooled_producer(1 << 40); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer.create_group(5u64.into()).unwrap().finish().unwrap(); @@ -16965,7 +16965,7 @@ mod test { #[cfg(feature = "async")] fn request_and_dynamic_share_weak_track_demand() { let request = Request::new(Arc::new(broadcast::Info::default()), "demand"); - let dynamic = request.dynamic(); + let dynamic = request.requests(); let demand = request.demand(); let consumer = request.consume(); assert!(!demand.is_used(), "a bare handle is not demand"); @@ -16989,7 +16989,7 @@ mod test { #[test] fn fill_demand_counts_every_joined_caller() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let first = consumer.fetch_group(3, None); let second = consumer.fetch_group(3, None); @@ -17015,7 +17015,7 @@ mod test { #[test] fn accepted_fill_resolves_its_fetch() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut fetch = consumer.fetch_group(3, None); let waiter = kio::Waiter::noop(); @@ -17034,9 +17034,9 @@ mod test { /// A feed declared to start at group 2, with groups 2 and 3 written, read from group 0. #[cfg(feature = "async")] - fn started_late() -> (Producer, Dynamic, Subscriber) { + fn started_late() -> (Producer, Requests, Subscriber) { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let subscriber = producer.subscribe(replay().with_range(0..)); producer.start_at(2).unwrap(); write_group(&producer, 2); @@ -17104,7 +17104,7 @@ mod test { fn filled_groups_are_read_in_the_readers_order() { for order in [Order::Descending, Order::Ascending] { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..).with_order(order)); producer.start_at(2).unwrap(); write_group(&producer, 2); @@ -17161,7 +17161,7 @@ mod test { #[cfg(feature = "async")] fn a_late_fresh_group_keeps_its_stretch_of_a_stalled_fill() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..)); producer.start_at(10).unwrap(); write_group(&producer, 10); @@ -17203,7 +17203,7 @@ mod test { #[cfg(feature = "async")] fn an_aborted_fetched_group_stays_wanted_by_its_replacement_fill() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); producer.start_at(10).unwrap(); write_group(&producer, 10); let waiter = kio::Waiter::noop(); @@ -17234,7 +17234,7 @@ mod test { #[cfg(feature = "async")] fn a_refused_group_is_asked_again_by_a_later_reader() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); for sequence in 0..5 { write_group(&producer, sequence); } @@ -17271,7 +17271,7 @@ mod test { #[cfg(feature = "async")] fn a_source_miss_is_asked_again_by_a_later_reader() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); for sequence in 0..5 { write_group(&producer, sequence); } @@ -17302,7 +17302,7 @@ mod test { #[cfg(feature = "async")] fn a_backfill_cached_before_its_answer_stays_owed() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let ascending = |groups| replay().with_range(groups).with_order(Order::Ascending); let mut subscriber = producer.subscribe(ascending(0..)); producer.start_at(10).unwrap(); @@ -17330,7 +17330,7 @@ mod test { #[cfg(feature = "async")] fn an_ordered_reader_leaves_a_filled_group_it_takes() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..1)); producer.start_at(10).unwrap(); write_group(&producer, 10); @@ -17358,7 +17358,7 @@ mod test { #[cfg(feature = "async")] fn a_narrowed_reader_leaves_the_rest_of_its_fill() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let ascending = |groups| replay().with_range(groups).with_order(Order::Ascending); let mut subscriber = producer.subscribe(ascending(0..)); producer.start_at(10).unwrap(); @@ -17401,7 +17401,7 @@ mod test { #[cfg(feature = "async")] fn a_filled_group_is_wanted_until_taken() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let ascending = |groups| replay().with_range(groups).with_order(Order::Ascending); let mut subscriber = producer.subscribe(ascending(0..)); producer.start_at(10).unwrap(); @@ -17434,7 +17434,7 @@ mod test { #[cfg(feature = "async")] fn an_accepted_groups_readers_leave_before_its_fill() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let ascending = |groups| replay().with_range(groups).with_order(Order::Ascending); let mut subscriber = producer.subscribe(ascending(0..)); producer.start_at(10).unwrap(); @@ -17462,7 +17462,7 @@ mod test { #[cfg(feature = "async")] fn a_time_start_before_the_cache_asks_nothing_below_it() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let at = |millis| Timestamp::from_millis(millis).unwrap(); let since = Range { start: Anchor::Time(at(5)), @@ -17500,7 +17500,7 @@ mod test { #[cfg(feature = "async")] fn a_wide_fill_forgets_refusals_its_readers_took() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..).with_order(Order::Ascending)); producer.start_at(100).unwrap(); write_group(&producer, 100); @@ -17524,7 +17524,7 @@ mod test { #[cfg(feature = "async")] fn a_later_reader_asks_afresh_for_what_a_fill_stopped_owing() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let ascending = |groups| replay().with_range(groups).with_order(Order::Ascending); let mut narrowed = producer.subscribe(ascending(0..)); producer.start_at(10).unwrap(); @@ -17553,7 +17553,7 @@ mod test { #[cfg(feature = "async")] fn a_descending_reader_asks_its_newest_miss_first() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_ranges([Range::groups(0..2), Range::groups(4..6), Range::groups(8..)])); producer.start_at(8).unwrap(); @@ -17574,7 +17574,7 @@ mod test { #[cfg(feature = "async")] fn a_reader_forgets_misses_behind_its_window() { let mut producer = track_producer("test", Info::timed()); - let _dynamic = producer.dynamic(); + let _dynamic = producer.requests(); let ascending = |groups| Subscription::default().with_range(groups).with_order(Order::Ascending); let mut subscriber = producer.subscribe(ascending(0..)); producer.start_at(0).unwrap(); @@ -17605,7 +17605,7 @@ mod test { #[cfg(feature = "async")] fn a_descending_reader_asks_its_newest_fragment_first() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut middle = producer.subscribe(replay().with_range(5..6)); producer.start_at(8).unwrap(); write_group(&producer, 8); @@ -17712,7 +17712,7 @@ mod test { fn a_wide_fill_its_handler_left_settles_by_run() { const WIDE: u64 = 1 << 40; let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..)); producer.start_at(WIDE).unwrap(); write_group(&producer, WIDE); @@ -17735,7 +17735,7 @@ mod test { const WIDE: u64 = 1 << 40; const REFUSED: u64 = 100_000; let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..)); producer.start_at(WIDE).unwrap(); write_group(&producer, WIDE); @@ -17757,7 +17757,7 @@ mod test { #[test] fn a_descending_reader_turns_a_queued_fill_newest_first() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut ascending = producer.subscribe(replay().with_range(0..).with_order(Order::Ascending)); let mut descending = producer.subscribe(replay().with_range(0..)); producer.start_at(4).unwrap(); @@ -17783,7 +17783,7 @@ mod test { #[cfg(feature = "async")] fn a_reader_update_reaches_its_fill() { let mut producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let mut subscriber = producer.subscribe(replay().with_range(0..).with_order(Order::Ascending)); producer.start_at(4).unwrap(); write_group(&producer, 4); @@ -17859,7 +17859,7 @@ mod test { } /// Fetch group 3 and drop it through the fill it queues, returning how the fetch ended. - fn drop_through_fill(producer: &Producer, dynamic: &Dynamic, drop_all: bool) -> Error { + fn drop_through_fill(producer: &Producer, dynamic: &Requests, drop_all: bool) -> Error { let consumer = producer.consume(); let mut fetch = consumer.fetch_group(3, None); let waiter = kio::Waiter::noop(); @@ -17892,7 +17892,7 @@ mod test { #[moq_clock::test] async fn dropped_fill_group_fails_its_fetch() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); write_group(&producer, 5); assert!(matches!(drop_through_fill(&producer, &dynamic, true), Error::NotFound)); assert!(drops(&producer).is_empty(), "the feed may still deliver 3"); @@ -17906,7 +17906,7 @@ mod test { #[moq_clock::test] async fn fill_dropped_unanswered_names_the_rest_dropped() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); write_group(&producer, 5); moq_clock::sim::advance(Duration::from_secs(60)).await; assert!(matches!(drop_through_fill(&producer, &dynamic, false), Error::Dropped)); @@ -17917,7 +17917,7 @@ mod test { #[cfg(feature = "async")] async fn fetch_aborts_with_track() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut pending = consumer.fetch_group(3, None); @@ -18262,7 +18262,7 @@ mod test { #[cfg(feature = "async")] async fn a_live_range_ignores_a_fetched_group_past_the_newest_group() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut early = producer.subscribe(replay().with_ranges([Range::live()])); let _fetching = consumer.fetch_group(5, None); @@ -18748,7 +18748,7 @@ mod test { #[cfg(feature = "async")] async fn a_filled_span_is_served_a_run_at_a_time() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); producer .create_group(group::Info { sequence: 2 }) @@ -18799,7 +18799,7 @@ mod test { #[cfg(feature = "async")] async fn a_span_fill_asks_again_after_another_budget_is_too_old() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let tight = consumer.fetch_group(5, group::Fetch::default().with_max_delay(Duration::from_secs(1))); @@ -18824,7 +18824,7 @@ mod test { #[cfg(feature = "async")] async fn a_drop_spares_a_fetched_head_still_arriving() { let producer = track_producer("test", Info::timed()); - let dynamic = producer.dynamic(); + let dynamic = producer.requests(); let consumer = producer.consume(); let mut live = producer.create_group(group::Info { sequence: 0 }).unwrap(); diff --git a/rs/moq-net/src/model/track/fill.rs b/rs/moq-net/src/model/track/fill.rs index 2b1bc7dea15..4998d7e8b09 100644 --- a/rs/moq-net/src/model/track/fill.rs +++ b/rs/moq-net/src/model/track/fill.rs @@ -1,4 +1,4 @@ -//! Fills: the groups readers miss, asked of a [`Dynamic`](super::Dynamic) handler by range. +//! Fills: the groups readers miss, asked of a [`Requests`](super::Requests) handler by range. //! //! A miss is a sequence a reader wants that the cache doesn't hold and the live feed will //! never deliver. A reader joins the fill already covering it, or queues a new one, and a @@ -26,7 +26,7 @@ use crate::{Error, Result, StreamError, group}; /// The fills a track's readers asked for, queued or taken by a handler, under one lock. #[derive(Default)] pub(in crate::model) struct FillState { - // Live `Dynamic` handles: a fill queues only while one can take it. + // Live `Requests` handles: a fill queues only while one can take it. handlers: usize, next: u64, // Every fill not yet ended, queued or taken, by id. @@ -653,7 +653,7 @@ pub(super) fn poll_requested( } } -/// A run of groups readers miss, for a [`Dynamic`](super::Dynamic) handler to serve. +/// A run of groups readers miss, for a [`Requests`](super::Requests) handler to serve. /// /// It names `start.group` up to the exclusive [`end`](Self::end), the first group from /// [`start`](Self::start)'s frame. Its [`priority`](Self::priority), diff --git a/rs/moq-net/src/util.rs b/rs/moq-net/src/util.rs index d7634a56d64..b453946afd8 100644 --- a/rs/moq-net/src/util.rs +++ b/rs/moq-net/src/util.rs @@ -79,7 +79,7 @@ pub(crate) struct Tasks { } /// A claim on a [`TaskSet`]'s lifetime with no submission queue: what a -/// broadcast published on an origin and an `origin::Dynamic` hold, so the +/// broadcast published on an origin and an `origin::Requests` hold, so the /// driver outlives the producer handles a session was given and dropped. pub(crate) struct Keepalive { _alive: kio::Producer<()>, diff --git a/rs/moq-net/tests/integration/catalog_acquisition.rs b/rs/moq-net/tests/integration/catalog_acquisition.rs index ca4bc66cf77..03b914e524e 100644 --- a/rs/moq-net/tests/integration/catalog_acquisition.rs +++ b/rs/moq-net/tests/integration/catalog_acquisition.rs @@ -28,7 +28,7 @@ async fn acquisition(version: &str, carries_epoch: bool) { let publisher = origin(1); let subscriber = origin(2); let broadcast = publisher.create_broadcast("live").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast .announce(origin::Route::default().with_epoch(moq_net::Epoch::mint())) .unwrap(); diff --git a/rs/moq-net/tests/integration/drained_claim.rs b/rs/moq-net/tests/integration/drained_claim.rs index ee13b3e47d1..3e4f7de7f6e 100644 --- a/rs/moq-net/tests/integration/drained_claim.rs +++ b/rs/moq-net/tests/integration/drained_claim.rs @@ -2,7 +2,7 @@ //! A relay's front for a path ends once unread, end to end over real sessions. //! -//! Two workers each claim the `pool` prefix with `origin::Producer::dynamic` and +//! Two workers each claim the `pool` prefix with `origin::Producer::requests` and //! announce it to relay `R` on their own sessions, the way a transcode pool does. A //! viewer on `R` reads `pool/p` from worker `A`, over the cheaper link, which then //! closes that output and drains its session. Nothing tells `R` the output closed, so @@ -46,7 +46,7 @@ async fn settle() { /// A worker claiming `pool`, answering each request with an output whose `video` /// track carries the worker's name. struct Worker { - _claim: Rc, + _claim: Rc, /// Each output with its track, which would end once its publication drops. outputs: Rc>>, origin: origin::Producer, @@ -55,7 +55,7 @@ struct Worker { impl Worker { fn new(hop: u64, name: &'static str) -> Self { let origin = produce_origin(hop); - let claim = Rc::new(origin.dynamic("pool").unwrap()); + let claim = Rc::new(origin.requests("pool").unwrap()); let outputs = Rc::new(RefCell::new(Vec::new())); let (handler, served) = (claim.clone(), outputs.clone()); drop(moq_clock::sim::spawn(async move { diff --git a/rs/moq-net/tests/integration/fetch_cancel.rs b/rs/moq-net/tests/integration/fetch_cancel.rs index e831383d2c7..3aaff468c8d 100644 --- a/rs/moq-net/tests/integration/fetch_cancel.rs +++ b/rs/moq-net/tests/integration/fetch_cancel.rs @@ -48,7 +48,7 @@ async fn abandoned_fetch_reaches_the_publisher(version: &str, relays: u64, stage } let broadcast = nodes[0].create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); moq_clock::sleep(Duration::from_secs(1)).await; @@ -65,7 +65,7 @@ async fn abandoned_fetch_reaches_the_publisher(version: &str, relays: u64, stage futures::future::Either::Left((request, _)) => request.expect("the track request reaches the publisher"), futures::future::Either::Right(_) => panic!("nothing answered the track"), }; - let groups = request.dynamic(); + let groups = request.requests(); let _track = request.accept(timed()); let request = match futures::future::select(std::pin::pin!(groups.requested_fill()), &mut waiting).await { futures::future::Either::Left((request, _)) => request.expect("the fetch reaches the publisher"), @@ -175,7 +175,7 @@ async fn a_refetch_within_the_linger_stays_on_the_relay(version: &str) { let _pair = peer(version, &publisher, &relay).await; let broadcast = publisher.create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); moq_clock::sleep(Duration::from_secs(1)).await; @@ -185,7 +185,7 @@ async fn a_refetch_within_the_linger_stays_on_the_relay(version: &str) { futures::future::Either::Left((request, _)) => request.expect("the track request reaches the publisher"), futures::future::Either::Right(_) => panic!("nothing answered the track"), }; - let groups = request.dynamic(); + let groups = request.requests(); let _track = request.accept(timed()); let request = match futures::future::select(std::pin::pin!(groups.requested_fill()), &mut waiting).await { futures::future::Either::Left((request, _)) => request.expect("the fetch reaches the publisher"), diff --git a/rs/moq-net/tests/integration/route_change.rs b/rs/moq-net/tests/integration/route_change.rs index f311e6942b0..9b53013a6a2 100644 --- a/rs/moq-net/tests/integration/route_change.rs +++ b/rs/moq-net/tests/integration/route_change.rs @@ -1111,7 +1111,7 @@ async fn producer_replaced(version: &str) { let subscriber = produce_origin(3); let broadcast = publisher.create_broadcast("live").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast .announce(origin::Route::default().with_epoch(moq_net::Epoch::mint())) .unwrap(); diff --git a/rs/moq-net/tests/integration/track_info_cancel.rs b/rs/moq-net/tests/integration/track_info_cancel.rs index dcc171298bf..bd0af6e56d3 100644 --- a/rs/moq-net/tests/integration/track_info_cancel.rs +++ b/rs/moq-net/tests/integration/track_info_cancel.rs @@ -31,7 +31,7 @@ async fn abandoned_request_reaches_the_publisher(version: &str, relays: u64) { } let broadcast = nodes[0].create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); moq_clock::sleep(Duration::from_secs(1)).await; @@ -75,7 +75,7 @@ async fn withdrawn_broadcast_releases_track_info(version: &str, answered: bool, let publisher = produce_origin(1); let reader = produce_origin(2); let broadcast = publisher.create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); let mut route = origin::Route::default(); if explicit { route.epoch = Some("019a1234-5678-7000-8000-000000000001".parse().unwrap()); diff --git a/rs/moq-net/tests/integration/track_stream_demand.rs b/rs/moq-net/tests/integration/track_stream_demand.rs index 8d905a3717e..c132853c31e 100644 --- a/rs/moq-net/tests/integration/track_stream_demand.rs +++ b/rs/moq-net/tests/integration/track_stream_demand.rs @@ -82,7 +82,7 @@ async fn one_used_edge(version: &str, relays: usize, reorder: bool) { let reader: &MockSession = &links.last().unwrap().client_transport; let broadcast = nodes[0].create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); // Serve every request for the track, keeping what it started. let requests = Rc::new(RefCell::new(Vec::new())); @@ -180,7 +180,7 @@ async fn bare_handle_is_lazy(version: &str, relays: usize) { } let broadcast = nodes[0].create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); let requests = Rc::new(RefCell::new(Vec::new())); let served = requests.clone(); diff --git a/rs/moq-net/tests/integration/untimed.rs b/rs/moq-net/tests/integration/untimed.rs index 501af56fa85..99a13b8fd7a 100644 --- a/rs/moq-net/tests/integration/untimed.rs +++ b/rs/moq-net/tests/integration/untimed.rs @@ -235,7 +235,7 @@ async fn a_fetched_untimed_frame_arrives_untimed() { for version in ["moq-lite-06", "moq-lite-07-wip", "moq-transport-18"] { let chain = Chain::new(&[version]).await; let broadcast = chain.nodes[0].create_broadcast("room").unwrap(); - let mut dynamic = broadcast.dynamic(); + let mut dynamic = broadcast.requests(); broadcast.announce(Default::default()).unwrap(); moq_clock::sleep(Duration::from_secs(1)).await; @@ -245,7 +245,7 @@ async fn a_fetched_untimed_frame_arrives_untimed() { futures::future::Either::Left((request, _)) => request.expect("the track request reaches the publisher"), futures::future::Either::Right(_) => panic!("nothing answered the track"), }; - let groups = request.dynamic(); + let groups = request.requests(); let _track = request.accept(untimed()); let request = match futures::future::select(std::pin::pin!(groups.requested_fill()), &mut waiting).await { futures::future::Either::Left((request, _)) => request.expect("the fetch reaches the publisher"), diff --git a/rs/moq-net/tests/integration/wide_hop.rs b/rs/moq-net/tests/integration/wide_hop.rs index ccb7e4ac848..82657f75e04 100644 --- a/rs/moq-net/tests/integration/wide_hop.rs +++ b/rs/moq-net/tests/integration/wide_hop.rs @@ -28,7 +28,7 @@ async fn widest_hop_crosses_each_varint_form() { let upstream: Version = "moq-transport-18".parse().unwrap(); let _upstream = peer(upstream, &source, &relay).await; let _downstream = peer(downstream.parse().unwrap(), &relay, &sink).await; - let _route = source.dynamic("room").unwrap(); + let _route = source.requests("room").unwrap(); moq_clock::sim::idle().await; let ids = |route: origin::Route| route.hops.iter().map(|hop| hop.id()).collect::>(); diff --git a/rs/moq-net/tests/loom.rs b/rs/moq-net/tests/loom.rs index 7cd685ef367..ad1121a64c4 100644 --- a/rs/moq-net/tests/loom.rs +++ b/rs/moq-net/tests/loom.rs @@ -418,7 +418,7 @@ fn a_fetch_never_joins_a_withdrawn_attempt() { model(|| { let broadcast = broadcast::Info::new().produce(); let track = broadcast.create_track("video", None).expect("create track"); - let dynamic = track.dynamic(); + let dynamic = track.requests(); let consumer = track.consume(); let first = consumer.fetch_group(5, None); @@ -479,7 +479,7 @@ fn a_request_never_joins_a_retiring_front() { fn a_refused_answer_is_never_announced() { model(|| { let (producer, mut driver) = origin::Producer::new(origin::Config::new(Hop::new(1).unwrap())); - let claim = producer.dynamic("room").unwrap(); + let claim = producer.requests("room").unwrap(); let pending = producer.consume().request_broadcast("room/alice", None); driver .poll(moq_net::time::Instant::now(), &kio::Waiter::noop()) diff --git a/rs/moq-rtc/src/egress.rs b/rs/moq-rtc/src/egress.rs index 30876d16aae..bcacd1cbdb6 100644 --- a/rs/moq-rtc/src/egress.rs +++ b/rs/moq-rtc/src/egress.rs @@ -1244,7 +1244,7 @@ mod tests { assert_eq!(written(&mut writes).await.as_ref(), b"low-0"); // The better rendition lives in a broadcast whose request is never answered. - let _handler = origin.dynamic("missing").unwrap(); + let _handler = origin.requests("missing").unwrap(); let mut config = VideoConfig::new(VideoCodec::VP8); config.container = hang::catalog::Container::Legacy; config.coded_width = Some(1920); diff --git a/rs/moq-stats/src/produce.rs b/rs/moq-stats/src/produce.rs index e587d4562d4..a35ca9d0479 100644 --- a/rs/moq-stats/src/produce.rs +++ b/rs/moq-stats/src/produce.rs @@ -611,7 +611,7 @@ struct NodePublisher { /// Holds the broadcast's request queue open, so a subscriber asking for a /// presence or prefix track parks until the next drain serves it instead /// of being rejected `NotFound` on the spot. - dynamic: broadcast::Dynamic, + dynamic: broadcast::Requests, local: HashMap>, totals: TotalsTrack, /// Held presence tracks, keyed by stats label. @@ -1028,7 +1028,7 @@ impl NodePublisher { } } - let dynamic = broadcast.dynamic(); + let dynamic = broadcast.requests(); Some(Self { broadcast, diff --git a/rs/moq-transcode/src/lib.rs b/rs/moq-transcode/src/lib.rs index 22b1254fbcc..f7570294850 100644 --- a/rs/moq-transcode/src/lib.rs +++ b/rs/moq-transcode/src/lib.rs @@ -75,7 +75,7 @@ pub struct Transcoder { config: Config, derived: moq_mux::catalog::Producer, // Consumers asking for a rung before (or after) it exists queue here. - dynamic: moq_net::broadcast::Dynamic, + dynamic: moq_net::broadcast::Requests, active: active::Producer, } @@ -92,7 +92,7 @@ impl Transcoder { // The catalog starts empty and fills in during `run`, exactly like a // media importer that hasn't seen parameter sets yet. let derived = moq_mux::catalog::Producer::new(&mut output, moq_mux::catalog::Config::default())?; - let dynamic = output.dynamic(); + let dynamic = output.requests(); Ok(Self { source, @@ -1348,7 +1348,7 @@ mod tests { /// The query held to resolve the track is demand that starts the live path, /// and the live path serves the same sequences from the same /// source, so the source publishes no group at all and serves this one - /// through a [`moq_net::track::Dynamic`] instead. That handle also parks the + /// through a [`moq_net::track::Requests`] instead. That handle also parks the /// fetch at exactly the point in question: past the rung's handler, before /// its `Fill::accept`. #[tokio::test] @@ -1356,7 +1356,7 @@ mod tests { let mut source = source_catalog(320, 240); // The source track carries no live groups; this serves them on demand, so // the test decides when the rung's fetch gets past its source read. - let source_fetches = source._track.dynamic(); + let source_fetches = source._track.requests(); let config = Config { ladder: Ladder::new([Rung::new(120, moq_net::bandwidth::Rate::from_bps(100_000))]).unwrap(), @@ -1441,7 +1441,7 @@ mod tests { async fn an_abandoned_fetch_encodes_nothing() { let source = source_catalog(320, 240); // Held, not served, until the abandoned fetch has let go of it. - let source_fetches = source._track.dynamic(); + let source_fetches = source._track.requests(); let config = Config { ladder: Ladder::new([Rung::new(120, moq_net::bandwidth::Rate::from_bps(100_000))]).unwrap(), @@ -1530,7 +1530,7 @@ mod tests { let mut source_demand = source._track.demand(); // Parks the rung's own fetch of the group below, so that fetch is demand // for as long as the caller holds it and nothing else serves it. - let _source_fetches = source._track.dynamic(); + let _source_fetches = source._track.requests(); // Two frames, so the output's largest moves once both are encoded. let mut group = source._track.create_group(0u64.into()).unwrap(); @@ -1623,7 +1623,7 @@ mod tests { let mut source_demand = source._track.demand(); // Parks the rung's own fetch of the group below, so that fetch is // demand for as long as the caller holds it and nothing else serves it. - let _source_fetches = source._track.dynamic(); + let _source_fetches = source._track.requests(); let mut encoder = moq_video::encode::Encoder::new(&{ let mut config = moq_video::encode::Config::new(320, 240, moq_video::FrameRate::new(30, 1).unwrap()); diff --git a/rs/moq-transcode/src/rung.rs b/rs/moq-transcode/src/rung.rs index 068c2e33eb6..1cd4485ed3e 100644 --- a/rs/moq-transcode/src/rung.rs +++ b/rs/moq-transcode/src/rung.rs @@ -182,7 +182,7 @@ enum Ended { pub(crate) fn serve(rung: Rung, request: moq_net::track::Request) -> impl Future> { // Grab the group-request handle before accepting: a Request is dynamic from // birth, so a fetch racing the acceptance queues instead of failing. - let dynamic = request.dynamic(); + let dynamic = request.requests(); let info = hang::container::track_info(hang::catalog::PRIORITY.video); let mut producer = request.accept(info); let serving = Serving(Some(producer.clone())); @@ -454,7 +454,7 @@ async fn live(rung: &Rung, producer: &mut moq_net::track::Producer) -> Result, ) -> Result<(), Error> { let limit = Arc::new(Semaphore::new(MAX_CONCURRENT_FETCHES)); @@ -961,12 +961,12 @@ mod tests { async fn a_group_nobody_reads_releases_its_fill() { use std::task::Poll; let (rung, source, _retire) = idle_rung(); - let source_fills = source.create_track("video", None).unwrap().dynamic(); + let source_fills = source.create_track("video", None).unwrap().requests(); let output = moq_net::broadcast::Info::default().produce(); let timed = moq_net::track::Info::default().with_timescale(moq_net::Timescale::MILLI); let mut track = output.create_track("video/120p", timed).unwrap(); - let fills = track.dynamic(); + let fills = track.requests(); let ascending = |groups| { moq_net::track::Subscription::default() .with_max_delay(None) @@ -1009,7 +1009,7 @@ mod tests { async fn cancelling_an_idle_rung_reports_cancel() { let (rung, _source, _retire) = idle_rung(); let output = moq_net::broadcast::Info::default().produce(); - let mut dynamic = output.dynamic(); + let mut dynamic = output.requests(); let view = output.consume(); let subscribing = tokio::spawn(async move { view.track("rung").unwrap().subscribe(None).await.unwrap() }); let request = dynamic.requested_track().await.unwrap(); @@ -1045,7 +1045,7 @@ mod tests { async fn an_unpolled_rung_reports_cancel() { let (rung, _source, _retire) = idle_rung(); let output = moq_net::broadcast::Info::default().produce(); - let mut dynamic = output.dynamic(); + let mut dynamic = output.requests(); let view = output.consume(); let subscribing = tokio::spawn(async move { view.track("rung").unwrap().subscribe(None).await.unwrap() }); let request = dynamic.requested_track().await.unwrap(); diff --git a/swift/MIGRATE.md b/swift/MIGRATE.md index 8b0c265707b..91806bc2417 100644 --- a/swift/MIGRATE.md +++ b/swift/MIGRATE.md @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first. ## Unreleased +### Request handlers are `requests()` ([#6752](https://github.com/moq-dev/moq/pull/6752)) + +Rename `dynamic()` on `OriginProducer`, `BroadcastProducer`, `TrackProducer`, and `TrackRequest` to `requests()`. +Their handles `OriginDynamic`, `BroadcastDynamic`, and `TrackDynamic` are `OriginRequests`, `BroadcastRequests`, and `TrackRequests`; their methods are unchanged. + ### `Allocator` ([#6751](https://github.com/moq-dev/moq/pull/6751)) `Bandwidth` is `Allocator`, `Session.bandwidth()` is `allocator()`, and `Reservation.grant()` is `rate()`. `Bandwidth.Consumer`, returned by `recvBandwidth()`, is the top-level `BandwidthConsumer`. The producers' `bandwidth:` parameter keeps its name. diff --git a/swift/Sources/Moq/Broadcast.swift b/swift/Sources/Moq/Broadcast.swift index c04dd1a3c8c..95b40b4aa8a 100644 --- a/swift/Sources/Moq/Broadcast.swift +++ b/swift/Sources/Moq/Broadcast.swift @@ -69,9 +69,9 @@ public final class BroadcastProducer: Sendable { } /// Accept subscriptions to tracks that are not published yet. Hold and iterate - /// the returned `BroadcastDynamic` while such requests should be served. - public func dynamic() throws -> BroadcastDynamic { - BroadcastDynamic(try ffi.dynamic()) + /// the returned `BroadcastRequests` while such requests should be served. + public func requests() throws -> BroadcastRequests { + BroadcastRequests(try ffi.requests()) } /// Advertise this broadcast's exact path as a route. diff --git a/swift/Sources/Moq/Origin.swift b/swift/Sources/Moq/Origin.swift index 4b5c0f0cda3..3eee7a651aa 100644 --- a/swift/Sources/Moq/Origin.swift +++ b/swift/Sources/Moq/Origin.swift @@ -24,10 +24,10 @@ public final class OriginProducer: Sendable { /// /// A route claims `prefix` and every path beneath it (`""` claims every path). /// A service that only serves some of them rejects the rest as they are - /// requested. Create, `dynamic` if tracks are served on demand, populate, + /// requested. Create, `requests` if tracks are served on demand, populate, /// then `BroadcastProducer.announce`. - public func dynamic(prefix: String) throws -> OriginDynamic { - OriginDynamic(try ffi.dynamic(prefix: prefix)) + public func requests(prefix: String) throws -> OriginRequests { + OriginRequests(try ffi.requests(prefix: prefix)) } /// Create a broadcast at `path`, returning the producer that feeds it. @@ -85,15 +85,15 @@ public final class BroadcastPrepared: Sendable { } /// A stream of broadcasts requested by consumers. Iterate directly: -/// `for try await request in dynamic { ... }`. Hold this while missing +/// `for try await request in requests { ... }`. Hold this while missing /// broadcasts should be served; cancelling the consuming task stops serving. -public final class OriginDynamic: AsyncSequence, Sendable { +public final class OriginRequests: AsyncSequence, Sendable { /// The broadcast request emitted by this sequence. public typealias Element = BroadcastRequest - let ffi: MoqOriginDynamic + let ffi: MoqOriginRequests - init(_ ffi: MoqOriginDynamic) { + init(_ ffi: MoqOriginRequests) { self.ffi = ffi } diff --git a/swift/Sources/Moq/Dynamic.swift b/swift/Sources/Moq/Requests.swift similarity index 91% rename from swift/Sources/Moq/Dynamic.swift rename to swift/Sources/Moq/Requests.swift index 12cbde9b2df..49ecc774fa0 100644 --- a/swift/Sources/Moq/Dynamic.swift +++ b/swift/Sources/Moq/Requests.swift @@ -27,8 +27,8 @@ public final class TrackRequest: Sendable { } /// Create a fetch handler before accepting this requested track. - public func dynamic() throws -> TrackDynamic { - TrackDynamic(try ffi.dynamic()) + public func requests() throws -> TrackRequests { + TrackRequests(try ffi.requests()) } /// Reject the request with an application error code, failing the subscriber. @@ -37,7 +37,7 @@ public final class TrackRequest: Sendable { } } -/// A run of groups readers miss, for a `TrackDynamic` to serve. +/// A run of groups readers miss, for a `TrackRequests` to serve. /// /// Accept each group you have and drop the rest; `next()` names what is still owed, in the /// fill's order. Releasing the fill names whatever is left as dropped while a reader still @@ -120,13 +120,13 @@ public final class Fill: Sendable { } /// A stream of the fills readers of one track need: runs of groups the cache lacks. -public final class TrackDynamic: AsyncSequence, Sendable { +public final class TrackRequests: AsyncSequence, Sendable { /// The fill emitted by this sequence. public typealias Element = Fill - let ffi: MoqTrackDynamic + let ffi: MoqTrackRequests - init(_ ffi: MoqTrackDynamic) { + init(_ ffi: MoqTrackRequests) { self.ffi = ffi } @@ -149,16 +149,16 @@ public final class TrackDynamic: AsyncSequence, Sendable { } /// A stream of track requests from subscribers for tracks that are not published -/// yet. Iterate directly: `for try await request in dynamic { ... }`. Hold this +/// yet. Iterate directly: `for try await request in requests { ... }`. Hold this /// while such requests should be served; the sequence ends (throwing `Closed`) /// when the broadcast closes, and cancelling the consuming task stops serving. -public final class BroadcastDynamic: AsyncSequence, Sendable { +public final class BroadcastRequests: AsyncSequence, Sendable { /// The track request emitted by this sequence. public typealias Element = TrackRequest - let ffi: MoqBroadcastDynamic + let ffi: MoqBroadcastRequests - init(_ ffi: MoqBroadcastDynamic) { + init(_ ffi: MoqBroadcastRequests) { self.ffi = ffi } diff --git a/swift/Sources/Moq/Track.swift b/swift/Sources/Moq/Track.swift index f7b2ee86f2a..7a3f1d23c1f 100644 --- a/swift/Sources/Moq/Track.swift +++ b/swift/Sources/Moq/Track.swift @@ -162,8 +162,8 @@ public final class TrackProducer: Sendable { } /// Serve fetches for groups that are not currently cached. - public func dynamic() throws -> TrackDynamic { - TrackDynamic(try ffi.dynamic()) + public func requests() throws -> TrackRequests { + TrackRequests(try ffi.requests()) } /// Append a new group, returning a producer for its frames. diff --git a/swift/Tests/MoqTests/SmokeTests.swift b/swift/Tests/MoqTests/SmokeTests.swift index 94d6969a52d..63c334be553 100644 --- a/swift/Tests/MoqTests/SmokeTests.swift +++ b/swift/Tests/MoqTests/SmokeTests.swift @@ -164,7 +164,7 @@ final class SmokeTests: XCTestCase { func testOriginProducerIsConstructible() throws { let origin = OriginProducer(cacheCapacityBytes: 4096) _ = origin.consume() - _ = try origin.dynamic(prefix: "") + _ = try origin.requests(prefix: "") } func testBroadcastIsReachableOnlyWhileAnnounced() async throws { @@ -238,7 +238,7 @@ final class SmokeTests: XCTestCase { func testDynamicServesARequestUnderAPrefix() async throws { let origin = OriginProducer() - let dynamic = try origin.dynamic(prefix: "live") + let dynamic = try origin.requests(prefix: "live") let pending = Task { try await origin.consume().requestBroadcast(path: "live/cam") } diff --git a/test/drill/mutations/relay-withdraws-lost-publisher.patch b/test/drill/mutations/relay-withdraws-lost-publisher.patch index 38c8bf4b571..36362fa0fd1 100644 --- a/test/drill/mutations/relay-withdraws-lost-publisher.patch +++ b/test/drill/mutations/relay-withdraws-lost-publisher.patch @@ -16,14 +16,14 @@ diff --git a/rs/moq-net/src/lite/subscriber.rs b/rs/moq-net/src/lite/subscriber. /// without recomputing the chain. route: crate::origin::Route, /// Dropping it retracts the route and rejects its queued requests. -- dynamic: crate::origin::Dynamic, +- dynamic: crate::origin::Requests, + // MUTATION: never dropped, so a route outlives the session that announced it. -+ dynamic: std::mem::ManuallyDrop, ++ dynamic: std::mem::ManuallyDrop, /// Closes as the route goes, which closes every source it minted. live: kio::Producer<()>, /// Whether the GOAWAY drain already re-priced this route. @@ -3584,7 +3585,7 @@ - fn new(route: crate::origin::Route, dynamic: crate::origin::Dynamic, wake: Arc) -> Self { + fn new(route: crate::origin::Route, dynamic: crate::origin::Requests, wake: Arc) -> Self { Self { route, - dynamic, diff --git a/test/drill/mutations/subscriber-leaks-broadcasts.patch b/test/drill/mutations/subscriber-leaks-broadcasts.patch index 75e14022e92..3bdc2a16b3a 100644 --- a/test/drill/mutations/subscriber-leaks-broadcasts.patch +++ b/test/drill/mutations/subscriber-leaks-broadcasts.patch @@ -37,7 +37,7 @@ diff --git a/rs/moq-net/src/lite/subscriber.rs b/rs/moq-net/src/lite/subscriber. - source: crate::model::broadcast::SourceGuard, + // MUTATION: never dropped, so a session that ends keeps every source it minted alive. + source: std::mem::ManuallyDrop, - dynamic: crate::broadcast::Dynamic, + dynamic: crate::broadcast::Requests, route: kio::Consumer<()>, // A dedicated close-watch handle, since each pending operation needs its own. @@ -1523,7 +1525,7 @@ impl SourceServe {