Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Unified Diff: sdk/lib/async/stream.dart

Issue 96473003: Add Stream.timeout method. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Changed zone behavior. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/lib/async/stream_timeout_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/async/stream.dart
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 58bb090cba99e14547def60c9a5e0d31e43dede9..2734021a0ea0f203db481642ec5dc869e165379c 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -649,7 +649,7 @@ abstract class Stream<T> {
* as [test] returns [:true:] for the event data. The stream is done
* when either this stream is done, or when this stream first provides
* a value that [test] doesn't accept.
- *
+ *
* Stops listening to the stream after the accepted elements.
*
* Internally the method cancels its subscription after these elements. This
@@ -960,6 +960,84 @@ abstract class Stream<T> {
cancelOnError: true);
return future;
}
+
+ /**
+ * Creates a new stream with the same events as this stream.
+ *
+ * Whenever more than [timeLimit] passes between two events from this stream,
+ * the [onTimeout] function is called.
+ *
+ * The countdown doesn't start until the returned stream is listened to.
+ * The countdown is reset every time an event is forwarded from this stream,
+ * or when the stream is paused and resumed.
+ *
+ * The [onTimeout] function is called with one argument: an
+ * [EventSink] that allows putting events into the returned stream.
+ * This `EventSink` is only valid during the call to `onTimeout`.
+ *
+ * If `onTimeout` is omitted, a timeout will just put a [TimeoutException]
+ * into the error channel of the returned stream.
+ */
+ Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) {
+ StreamSubscription<T> subscription;
+ _StreamController controller;
+ // The following variables are set on listen.
+ Timer timer;
+ Zone zone;
+ Function timeout;
+
+ void onData(T event) {
+ timer.cancel();
+ controller.add(event);
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+ void onError(error, StackTrace stackTrace) {
+ timer.cancel();
+ controller.addError(error, stackTrace);
+ timer = zone.createTimer(timeLimit, timeout);
+ }
+ void onDone() {
+ timer.cancel();
+ controller.close();
+ }
+ controller = new _SyncStreamController(
+ () {
+ zone = Zone.current;
floitsch 2013/12/05 12:37:38 As discussed: we should just use the subscription'
Lasse Reichstein Nielsen 2013/12/05 13:28:44 That is what we are doing now. The zone is being s
floitsch 2013/12/05 14:20:49 yes. didn't see that the code was already changed.
+ if (onTimeout == null) {
+ timeout = () {
+ controller.addError(new TimeoutException("No stream event",
+ timeLimit));
+ };
+ } else {
+ onTimeout = zone.registerUnaryCallback(onTimeout);
+ _ControllerEventSinkWrapper wrapper =
+ new _ControllerEventSinkWrapper(null);
+ timeout = () {
+ wrapper._sink = controller; // Only valid during call.
+ zone.runUnaryGuarded(onTimeout, wrapper);
floitsch 2013/12/05 14:20:49 It's actually not runUnaryGuarded. If the onTimeou
Lasse Reichstein Nielsen 2013/12/05 14:57:54 I can see the point. I actually preferred to have
+ wrapper._sink = null;
+ };
+ }
+
+ subscription = this.listen(onData, onError: onError, onDone: onDone);
+ timer = zone.createTimer(timeLimit, timeout);
+ },
+ () {
+ timer.cancel();
+ subscription.pause();
+ },
+ () {
+ subscription.resume();
+ timer = zone.createTimer(timeLimit, timeout);
+ },
+ () {
+ timer.cancel();
+ Future result = subscription.cancel();
+ subscription = null;
+ return result;
+ });
+ return controller.stream;
+ }
}
/**
@@ -1282,3 +1360,18 @@ abstract class StreamIterator<T> {
*/
Future cancel();
}
+
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _ControllerEventSinkWrapper<T> implements EventSink<T> {
+ EventSink _sink;
+ _ControllerEventSinkWrapper(this._sink);
+
+ void add(T data) { _sink.add(data); }
+ void addError(error, [StackTrace stackTrace]) {
+ _sink.addError(error, stackTrace);
+ }
+ void close() { _sink.close(); }
+}
« no previous file with comments | « no previous file | tests/lib/async/stream_timeout_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698