RpcBufferedBroadcastController<T> class

A broadcast stream controller that retains events while it has no listener and replays them, in arrival order, to the first subscriber.

A plain StreamController.broadcast() silently drops events delivered while it has no listener. Transports start consuming the connection as soon as it is up, but the RPC pipeline subscribes to stream slightly later — so the first inbound frames (e.g. a client-stream's leading chunk on a cold connection) would be lost. This controller queues them and flushes on the first listen, then forwards live events straight through.

Buffering applies ONLY while there is no listener: broadcast streams have no per-listener backpressure, so once listened, events pass straight through. Detach and re-attach are handled the same way — events delivered between listeners are queued and flushed when the next one arrives.

Leak-safety:

  • the pending queue is cleared on close;
  • it never grows past maxPendingEvents events, NOR past maxPendingBytes when a sizeOf is supplied. Hitting either bound while still unlistened — a producer feeding a controller nobody consumes, i.e. an abandoned transport — drops further events and fires onOverflow once.

BOTH dimensions are required. A bound on events says nothing about bytes, and the neighbouring RpcSecurityPolicy.maxMessageLengthBytes bounds ONE message at 16 MiB by default — so a count-only bound of 4096 admits up to 64 GiB of payload while appearing to keep memory bounded.

Implements StreamSink, the writable half of a StreamController, so it can stand in for one as a sink while exposing stream as a controller does. It deliberately does NOT implement the whole of StreamController, whose settable onListen this type uses internally to flush the buffer: exposing it would let a caller override the flush and break the invariant.

Implemented types

Constructors

RpcBufferedBroadcastController({int maxPendingEvents = 4096, int maxPendingBytes = 16 * 1024 * 1024, int sizeOf(T event)?, void onOverflow()?, bool sync = false})
Creates a buffered broadcast controller.

Properties

done → Future<void>
Completes when this sink is closed.
no setteroverride
hashCode → int
The hash code for this object.
no setterinherited
hasListener → bool
Whether at least one subscriber is currently attached.
no setter
isClosed → bool
Whether this controller has been closed.
no setter
maxPendingBytes → int
Upper bound on the total size of those events, when sizeOf is given.
final
maxPendingEvents → int
Upper bound on events buffered while no listener is attached.
final
onOverflow → void Function()?
Called once when either bound is first exceeded (diagnostics).
final
pendingCount → int
Number of events currently buffered awaiting a listener (diagnostics).
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
sizeOf → int Function(T event)?
Weighs a pending event, in bytes. Null disables the byte bound.
final
stream → Stream<T>
The broadcast stream consumers listen to.
no setter

Methods

add(T event) → void
Adds a data event: delivered immediately when listened, else queued.
override
addError(Object error, [StackTrace? stackTrace]) → void
Adds an error event, preserving order relative to add.
override
addStream(Stream<T> source, {bool? cancelOnError}) → Future<void>
Pipes source into this sink (events and errors), completing when the source is done. Same buffering semantics as add/addError.
override
close() → Future<void>
Clears the buffer and closes the underlying controller.
override
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited