OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library watcher.resubscribable; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import '../watcher.dart'; | |
10 import 'watch_event.dart'; | |
11 | |
12 typedef ManuallyClosedWatcher WatcherFactory(); | |
13 | |
14 /// A wrapper for [ManuallyClosedWatcher] that encapsulates support for closing | |
15 /// the watcher when it has no subscribers and re-opening it when it's | |
16 /// re-subscribed. | |
17 /// | |
18 /// It's simpler to implement watchers without worrying about this behavior. | |
19 /// This class wraps a watcher class which can be written with the simplifying | |
20 /// assumption that it can continue emitting events until an explicit `close` | |
21 /// method is called, at which point it will cease emitting events entirely. The | |
22 /// [ManuallyClosedWatcher] interface is used for these watchers. | |
23 /// | |
24 /// This would be more cleanly implemented as a function that takes a class and | |
25 /// emits a new class, but Dart doesn't support that sort of thing. Instead it | |
26 /// takes a factory function that produces instances of the inner class. | |
27 abstract class ResubscribableWatcher implements Watcher { | |
28 /// The factory function that produces instances of the inner class. | |
29 final WatcherFactory _factory; | |
30 | |
31 final String path; | |
32 | |
33 Stream<WatchEvent> get events => _eventsController.stream; | |
34 StreamController<WatchEvent> _eventsController; | |
35 | |
36 bool get isReady => _readyCompleter.isCompleted; | |
37 | |
38 Future get ready => _readyCompleter.future; | |
39 var _readyCompleter = new Completer(); | |
40 | |
41 /// Creates a new [ResubscribableWatcher] wrapping the watchers | |
42 /// emitted by [_factory]. | |
43 ResubscribableWatcher(this.path, this._factory) { | |
44 var watcher; | |
45 var subscription; | |
46 | |
47 _eventsController = new StreamController<WatchEvent>.broadcast( | |
48 onListen: () { | |
49 watcher = _factory(); | |
50 subscription = watcher.events.listen(_eventsController.add, | |
51 onError: _eventsController.addError, | |
52 onDone: _eventsController.close); | |
53 | |
54 // It's important that we complete the value of [_readyCompleter] at the | |
55 // time [onListen] is called, as opposed to the value when [watcher.ready] | |
56 // fires. A new completer may be created by that time. | |
57 watcher.ready.then(_readyCompleter.complete); | |
58 }, onCancel: () { | |
59 // Cancel the subscription before closing the watcher so that the | |
60 // watcher's `onDone` event doesn't close [events]. | |
61 subscription.cancel(); | |
62 watcher.close(); | |
63 _readyCompleter = new Completer(); | |
64 }, sync: true); | |
65 } | |
66 } | |
67 | |
68 /// An interface for watchers with an explicit, manual [close] method. | |
69 /// | |
70 /// See [ResubscribableWatcher]. | |
71 abstract class ManuallyClosedWatcher implements Watcher { | |
72 /// Closes the watcher. | |
73 /// | |
74 /// Subclasses should close their [events] stream and release any internal | |
75 /// resources. | |
76 void close(); | |
77 } | |
OLD | NEW |