| 1 |  |  | import 'dart:async'; | 
                
                
                    | 2 |  |  |  | 
                
                
                    | 3 |  |  | import '../../exceptions/squadron_error.dart'; | 
                
                
                    | 4 |  |  | import '../../exceptions/squadron_exception.dart'; | 
                
                
                    | 5 |  |  |  | 
                
                
                    | 6 |  |  | class ForwardStreamController<T> { | 
                
                
                    | 7 |  | 10 |   ForwardStreamController( | 
                
                
                    | 8 |  |  |       {void Function()? onListen, FutureOr<void> Function()? onCancel}) { | 
                
                
                    | 9 |  | 20 |     _controller = StreamController( | 
                
                
                    | 10 |  |  |       onListen: onListen, | 
                
                
                    | 11 |  | 10 |       onPause: _pause, | 
                
                
                    | 12 |  | 10 |       onResume: _resume, | 
                
                
                    | 13 |  |  |       onCancel: onCancel, | 
                
                
                    | 14 |  |  |     ); | 
                
                
                    | 15 |  |  |   } | 
                
                
                    | 16 |  |  |  | 
                
                
                    | 17 |  |  |   late final StreamController<T> _controller; | 
                
                
                    | 18 |  |  |  | 
                
                
                    | 19 |  | 30 |   Stream<T> get stream => _controller.stream; | 
                
                
                    | 20 |  |  |  | 
                
                
                    | 21 |  | 30 |   Future<void> get done => _controller.done; | 
                
                
                    | 22 |  |  |  | 
                
                
                    | 23 |  |  |   var _closed = false; | 
                
                
                    | 24 |  | 40 |   bool get isClosed => _closed || _controller.isClosed; | 
                
                
                    | 25 |  |  |  | 
                
                
                    | 26 |  |  |   StreamSubscription<T>? _sub; | 
                
                
                    | 27 |  |  |  | 
                
                
                    | 28 |  | 20 |   StreamSubscription<T>? get subscription => _sub; | 
                
                
                    | 29 |  |  |  | 
                
                
                    | 30 |  | 10 |   void add(T data) { | 
                
                
                    | 31 |  | 30 |     if (!isClosed) _controller.add(data); | 
                
                
                    | 32 |  |  |   } | 
                
                
                    | 33 |  |  |  | 
                
                
                    | 34 |  | 7 |   void addError(SquadronException ex) { | 
                
                
                    | 35 |  | 21 |     if (!isClosed) _controller.addError(ex); | 
                
                
                    | 36 |  |  |   } | 
                
                
                    | 37 |  |  |  | 
                
                
                    | 38 |  | 10 |   Future<void> close() async { | 
                
                
                    | 39 |  | 10 |     _closed = true; | 
                
                
                    | 40 |  | 20 |     await _sub?.cancel(); | 
                
                
                    | 41 |  | 10 |     _sub = null; | 
                
                
                    | 42 |  | 20 |     _controller.close(); | 
                
                
                    | 43 |  |  |   } | 
                
                
                    | 44 |  |  |  | 
                
                
                    | 45 |  |  |   int _pauses = 0; | 
                
                
                    | 46 |  |  |  | 
                
                
                    | 47 |  | 1 |   void _pause() { | 
                
                
                    | 48 |  |  |     // per Dart documentation https://api.dart.dev/dart-async/StreamSubscription/pause.html | 
                
                
                    | 49 |  |  |     // If the subscription is paused more than once, an equal number of resumes | 
                
                
                    | 50 |  |  |     // must be performed to resume the stream | 
                
                
                    | 51 |  | 2 |     _pauses++; | 
                
                
                    | 52 |  |  |   } | 
                
                
                    | 53 |  |  |  | 
                
                
                    | 54 |  | 1 |   void _resume() { | 
                
                
                    | 55 |  | 2 |     if (_pauses > 0) { | 
                
                
                    | 56 |  |  |       // per Dart documentation https://api.dart.dev/dart-async/StreamSubscription/pause.html | 
                
                
                    | 57 |  |  |       // If the subscription is paused more than once, an equal number of resumes | 
                
                
                    | 58 |  |  |       // must be performed to resume the stream | 
                
                
                    | 59 |  | 2 |       _pauses--; | 
                
                
                    | 60 |  |  |     } else { | 
                
                
                    | 61 |  |  |       // per Dart documentation https://api.dart.dev/dart-async/StreamSubscription/resume.html | 
                
                
                    | 62 |  |  |       // It is safe to resume even when the subscription is not paused, and the | 
                
                
                    | 63 |  |  |       // resume will have no effect. | 
                
                
                    | 64 |  |  |     } | 
                
                
                    | 65 |  |  |   } | 
                
                
                    | 66 |  |  |  | 
                
                
                    | 67 |  | 10 |   void attachSubscription(StreamSubscription<T> sub) { | 
                
                
                    | 68 |  | 10 |     if (_sub != null) { | 
                
                
                    | 69 |  | 0 |       throw SquadronErrorImpl.create( | 
                
                
                    | 70 |  |  |           'Invalid state: a subscription is already attached'); | 
                
                
                    | 71 |  |  |     } | 
                
                
                    | 72 |  | 10 |     _sub = sub; | 
                
                
                    | 73 |  |  |     // pass pending pause events on to the subscription | 
                
                
                    | 74 |  | 20 |     while (_pauses > 0) { | 
                
                
                    | 75 |  | 2 |       _pauses--; | 
                
                
                    | 76 |  | 1 |       sub.pause(); | 
                
                
                    | 77 |  |  |     } | 
                
                
                    | 78 |  |  |     // have the subscription handle pause/resume events from now on | 
                
                
                    | 79 |  | 30 |     _controller.onPause = sub.pause; | 
                
                
                    | 80 |  | 30 |     _controller.onResume = sub.resume; | 
                
                
                    | 81 |  |  |     // have the subscription handle the cancel event if the controller doesn't | 
                
                
                    | 82 |  |  |     // handle it already | 
                
                
                    | 83 |  | 25 |     _controller.onCancel ??= sub.cancel; | 
                
                
                    | 84 |  |  |   } | 
                
                
                    | 85 |  |  | } |