44
55import 'dart:async' ;
66
7+ import 'package:async/async.dart' ;
8+
79import '../stream_channel.dart' ;
810
911/// Allows the caller to force a channel to disconnect.
@@ -17,8 +19,7 @@ import '../stream_channel.dart';
1719/// be disconnected immediately.
1820class Disconnector <T > implements StreamChannelTransformer <T , T > {
1921 /// Whether [disconnect] has been called.
20- bool get isDisconnected => _isDisconnected;
21- var _isDisconnected = false ;
22+ bool get isDisconnected => _disconnectMemo.hasRun;
2223
2324 /// The sinks for transformed channels.
2425 ///
@@ -28,20 +29,25 @@ class Disconnector<T> implements StreamChannelTransformer<T, T> {
2829 final _sinks = < _DisconnectorSink <T >> [];
2930
3031 /// Disconnects all channels that have been transformed.
31- void disconnect () {
32- _isDisconnected = true ;
33- for (var sink in _sinks) {
34- sink._disconnect ();
35- }
32+ ///
33+ /// Returns a future that completes when all inner sinks' [StreamSink.close]
34+ /// futures have completed. Note that a [StreamController] 's sink won't close
35+ /// until the corresponding stream has a listener.
36+ Future disconnect () => _disconnectMemo.runOnce (() {
37+ var futures = _sinks.map ((sink) => sink._disconnect ()).toList ();
3638 _sinks.clear ();
37- }
39+ return Future .wait (futures, eagerError: true );
40+ });
41+ final _disconnectMemo = new AsyncMemoizer ();
3842
3943 StreamChannel <T > bind (StreamChannel <T > channel) {
4044 return channel.changeSink ((innerSink) {
4145 var sink = new _DisconnectorSink <T >(innerSink);
4246
43- if (_isDisconnected) {
44- sink._disconnect ();
47+ if (isDisconnected) {
48+ // Ignore errors here, because otherwise there would be no way for the
49+ // user to handle them gracefully.
50+ sink._disconnect ().catchError ((_) {});
4551 } else {
4652 _sinks.add (sink);
4753 }
@@ -126,14 +132,18 @@ class _DisconnectorSink<T> implements StreamSink<T> {
126132
127133 /// Disconnects this sink.
128134 ///
129- /// This closes the underlying sink and stops forwarding events.
130- void _disconnect () {
135+ /// This closes the underlying sink and stops forwarding events. It returns
136+ /// the [StreamSink.close] future for the underlying sink.
137+ Future _disconnect () {
131138 _isDisconnected = true ;
132- _inner.close ();
139+ var future = _inner.close ();
140+
141+ if (_inAddStream) {
142+ _addStreamCompleter.complete (_addStreamSubscription.cancel ());
143+ _addStreamCompleter = null ;
144+ _addStreamSubscription = null ;
145+ }
133146
134- if (! _inAddStream) return ;
135- _addStreamCompleter.complete (_addStreamSubscription.cancel ());
136- _addStreamCompleter = null ;
137- _addStreamSubscription = null ;
147+ return future;
138148 }
139149}
0 commit comments