EsStreamController
Description
A controller with the stream it controls.
This controller allows sending data, error and done events on its #stream. This class can be used to create a simple stream that others can listen on, and to push events to that stream.
It's possible to check whether the stream is paused or not, and whether it has subscribers or not, as well as getting a callback when either of these change.
Class Methods
broadcast
A default async controller where #stream can be listened to more than once.
For async, the event will always be fired at a later time,
after the code adding the event has completed.
In that case, no guarantees are given with regard to when
multiple listeners get the events, except that each listener will get
all events in the correct order. Each subscription handles the events
individually.
If two events are sent on an async controller with two listeners,
one of the listeners may get both events before the other listener gets any.
A listener must be subscribed both when the event is initiated
(that is, when #add: is called) and when the event is later delivered,
in order to receive the event.
Answers:
<EsStreamController>
broadcast:onCancel:sync:
A controller where [stream] can be listened to more than once.
The <EsStream> answered by #stream is a broadcast stream.
It can be listened to more than once.
A Stream should be inert until a subscriber starts listening on it (using
the @onListen handler to start producing events). Streams should not
leak resources (like websockets) when no user ever listens on the stream.
Broadcast streams do not buffer events when there is no listener.
The controller distributes any events to all currently subscribed
listeners at the time when #add:, #addError: or #close is called.
It is not allowed to call #add:, #addError:, or #close before a previous
call has answered. The controller does not have any internal queue of
events, and if there are no listeners at the time the event is added,
it will just be dropped, or, if it is an error, be reported as uncaught.
Each listener subscription is handled independently,
and if one pauses, only the pausing listener is affected.
A paused listener will buffer events internally until unpaused or canceled.
If @sync is true, events may be fired directly by the stream's
subscriptions during an #add:, #addError: or #close call.
The answered stream controller is a <EsSyncStreamController>,
and must be used with the care and attention necessary to not break
the <EsStream> contract.
See [EsPromise sync] for some explanations on when a synchronous
dispatching can be used.
If in doubt, keep the controller non-sync.
If @sync is false, the event will always be fired at a later time,
after the code adding the event has completed.
In that case, no guarantees are given with regard to when
multiple listeners get the events, except that each listener will get
all events in the correct order. Each subscription handles the events
individually.
If two events are sent on an async controller with two listeners,
one of the listeners may get both events before the other listener gets any.
A listener must be subscribed both when the event is initiated
(that is, when #add: is called) and when the event is later delivered,
in order to receive the event.
The @onListen block is evaluated when the first listener is subscribed,
and the @onCancel block is evaluated when there are no longer any active listeners.
If a listener is added again later, after an @onCancel was evaluated,
the @onListen will be evalutated again.
Arguments:
onListen - <Block> 0-arg block or nil.
onCancel - <Block> 0-arg block or nil.
sync - <Boolean> or nil. defaults to `false`
Answers:
<EsStreamController>
broadcastAsync
An async controller where #stream can be listened to more than once.
For async, the event will always be fired at a later time,
after the code adding the event has completed.
In that case, no guarantees are given with regard to when
multiple listeners get the events, except that each listener will get
all events in the correct order. Each subscription handles the events
individually.
If two events are sent on an async controller with two listeners,
one of the listeners may get both events before the other listener gets any.
A listener must be subscribed both when the event is initiated
(that is, when #add: is called) and when the event is later delivered,
in order to receive the event.
Answers:
<EsStreamController>
broadcastSync
An async controller where #stream can be listened to more than once.
For sync, events may be fired directly by the stream's
subscriptions during an #add:, #addError: or #close call.
The answered stream controller is a <EsSyncStreamController>,
and must be used with the care and attention necessary to not break
the <EsStream> contract.
See [EsPromise sync] for some explanations on when a synchronous
dispatching can be used.
If in doubt, keep the controller non-sync.
Answers:
<EsStreamController>
new
A default asynchronous controller with a #stream that supports only one single subscriber.
Using an asynchronous controller will never give the wrong
behavior, but using a synchronous controller incorrectly can cause
otherwise correct programs to break.
Answers:
<EsStreamController>
onListen:onPause:onResume:onCancel:sync:
A controller with a #stream that supports only one single subscriber.
If @sync is true, the answered stream controller is a
<EsSyncStreamController>, and must be used with the care
and attention necessary to not break the <EsStream> contract. If in doubt,
use the non-sync version.
Using an asynchronous controller will never give the wrong
behavior, but using a synchronous controller incorrectly can cause
otherwise correct programs to break.
A synchronous controller is only intended for optimizing event
propagation when one asynchronous event immediately triggers another.
It should not be used unless the calls to #add: or #addError:
are guaranteed to occur in places where it won't break `EsStream` invariants.
Use synchronous controllers only to forward (potentially transformed)
events from another stream or a future.
A Stream should be inert until a subscriber starts listening on it (using
the @onListen handler to start producing events). Streams should not
leak resources (like websockets) when no user ever listens on the stream.
The controller buffers all incoming events until a subscriber is
registered, but this feature should only be used in rare circumstances.
The @onPause block is called when the stream becomes
paused. @onResume is called when the stream resumed.
The @onListen handler is called when the stream
receives its listener and [onCancel] when the listener ends
its subscription. If @onCancel needs to perform an asynchronous operation,
@onCancel should return a future that completes when the cancel operation
is done.
If the stream is canceled before the controller needs data the
@onResume call might not be executed.
Arguments:
onListen - <Block> 0-arg block or nil.
onPause - <Block> 0-arg block or nil.
onResume - <Block> 0-arg block or nil.
onCancel - <Block> 0-arg block or nil. Answers an <EsFuture> or nil.
sync - <Boolean> or nil. defaults to `false`
Answers:
<EsStreamController>
single
A default asynchronous controller with a #stream that supports only one single subscriber.
Using an asynchronous controller will never give the wrong
behavior, but using a synchronous controller incorrectly can cause
otherwise correct programs to break.
Answers:
<EsStreamController>
singleAsync
A asynchronous controller with a #stream that supports only one single subscriber.
Using an asynchronous controller will never give the wrong
behavior, but using a synchronous controller incorrectly can cause
otherwise correct programs to break.
Answers:
<EsStreamController>
singleSync
A synchronous controller with a #stream that supports only one single subscriber.
The answered stream controller is a
<EsSyncStreamController>, and must be used with the care
and attention necessary to not break the <EsStream> contract. If in doubt,
use the non-sync version.
A synchronous controller is only intended for optimizing event
propagation when one asynchronous event immediately triggers another.
It should not be used unless the calls to #add: or #addError:
are guaranteed to occur in places where it won't break `EsStream` invariants.
Use synchronous controllers only to forward (potentially transformed)
events from another stream or a future.
Answers:
<EsStreamController>
Instance Methods
add:
Sends a data @event.
Listeners receive this event in a later scheduled task process.
Note that a synchronous controller (created by passing true to the `sync`
argument of the `EsStreamController` creational method) delivers events
immediately. Since this behavior violates the contract mentioned here,
synchronous controllers should only be used as described in the
documentation to ensure that the delivered events always *appear* as if
they were delivered in a separate scheduled task process
Arguments:
event - <Object>
Answers:
<EsStreamController> self
addError:stackTrace:
Sends or enqueues an error event.
Listeners receive this event at a later scheduled task process. This behavior can be
overridden by using `sync` controllers. Note, however, that sync
controllers have to satisfy the preconditions mentioned in the
documentation of the creational apis
Arguments:
error - <Object>
stackTrace - <EsAsyncStackTrace>
Answers:
<EsStreamController> self
addStream:
Receives events from @source and puts them into this controller's stream.
Answers a future which completes when the source stream is done.
See #addStream:cancelOnError: for more details
addStream:cancelOnError:
Receives events from @source and puts them into this controller's stream.
Returns a future which completes when the source stream is done.
Events must not be added directly to this controller using #add:,
#addError:, #close or #addStream:, until the answered future
is complete.
Data and error events are forwarded to this controller's stream. A done
event on the source will end the `addStream:` operation and complete the
answered future.
If @cancelOnError is `true`, only the first error on @source is
forwarded to the controller's stream, and the `addStream:` ends
after this. If @cancelOnError is false, all errors are forwarded
and only a done event will end the `addStream:`.
If @cancelOnError is omitted or `nil`, it defaults to `false`.
Arguments:
source - <EsStream>
cancelOnError - <Boolean>
Answers:
<EsFuture>
close
Closes the stream.
No further events can be added to a closed stream.
The answered future is the same future provided by #done.
It is completed when the stream listeners is done sending events,
This happens either when the done event has been sent,
or when the subscriber on a single-subscription stream is canceled.
A broadcast stream controller will send the done event
even if listeners are paused, so some broadcast events may not have been
received yet when the answered future completes.
If none listens to a non-broadcast stream, or the listener pauses and never resumes,
the done event will not be sent and this future will never complete.
Answers:
<EsFuture>
done
A future which is completed when the stream controller is done
sending events.
This happens either when the done event has been sent, or if the
subscriber on a single-subscription stream is canceled.
A broadcast stream controller will send the done event
even if listeners are paused, so some broadcast events may not have been
received yet when the answered future completes.
If there is no listener on a non-broadcast stream,
or the listener pauses and never resumes,
the done event will not be sent and this future will never complete.
Answers:
<EsFuture>
hasListener
Whether there is a subscriber on the <EsStream>
Answers:
<Boolean>
isClosed
Whether the stream controller is closed for adding more events.
The controller becomes closed by calling the #close method.
New events cannot be added, by calling #add: or #addError:*,
to a closed controller.
If the controller is closed,
the `done` event might not have been delivered yet,
but it has been scheduled, and it is too late to add more events.
Answers:
<Boolean>
isPaused
Whether the stream controller would need to buffer events.
This is the case if the controller's stream has a listener and it is
paused, or if it has not received a listener yet. In that case, the
controller is considered paused as well.
A broadcast stream controller is never considered paused. It always
forwards its events to all uncanceled subscriptions, if any,
and let the subscriptions handle their own pausing and buffering.
Answers:
<Boolean>
onCancel
The 0-arg block which is evaluated when the stream is canceled..
May be set to `nil`, in which case no block eval will happen.
Answers:
<Block> 0-arg block or nil. Answers <EsFuture>
onListen
The 0-arg block which is evaluated when the stream is listened to.
May be set to `nil`, in which case no handler will happen.
Answers:
<Block> 0-arg block or nil
onPause
The 0-arg block which is evaluated when the stream is paused..
May be set to `nil`, in which case no block eval will happen.
Pause related blocks are not supported on broadcast stream controllers.
Answers:
<Block> 0-arg block or nil
onResume
The 0-arg block which is evaluated when the stream is resumed..
May be set to `nil`, in which case no block eval will happen.
Pause/resume related blocks are not supported on broadcast stream controllers.
Answers:
<Block> 0-arg block or nil
sink
Answers a view of this object that only exposes the <EsStreamSink> interface.
Answers:
<EsStreamSink>
stream
The stream that this controller is controlling.
Answers:
<EsStream>
Last modified date: 04/21/2022