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

Unified Diff: lib/src/util/multi_channel.dart

Issue 1664433002: Support shelf 0.7.0. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 4 years, 11 months 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 | « lib/src/runner/browser/suite.dart ('k') | lib/src/util/stream_channel.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/util/multi_channel.dart
diff --git a/lib/src/util/multi_channel.dart b/lib/src/util/multi_channel.dart
deleted file mode 100644
index acf4e219639395bb06f3ded3221839bbd476d499..0000000000000000000000000000000000000000
--- a/lib/src/util/multi_channel.dart
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'stream_channel.dart';
-
-/// A class that multiplexes multiple virtual channels across a single
-/// underlying transport layer.
-///
-/// This should be connected to another [MultiChannel] on the other end of the
-/// underlying channel. It starts with a single default virtual channel,
-/// accessible via [stream] and [sink]. Additional virtual channels can be
-/// created with [virtualChannel].
-///
-/// When a virtual channel is created by one endpoint, the other must connect to
-/// it before messages may be sent through it. The first endpoint passes its
-/// [VirtualChannel.id] to the second, which then creates a channel from that id
-/// also using [virtualChannel]. For example:
-///
-/// ```dart
-/// // First endpoint
-/// var virtual = multiChannel.virtualChannel();
-/// multiChannel.sink.add({
-/// "channel": virtual.id
-/// });
-///
-/// // Second endpoint
-/// multiChannel.stream.listen((message) {
-/// var virtual = multiChannel.virtualChannel(message["channel"]);
-/// // ...
-/// });
-/// ```
-///
-/// Sending errors across a [MultiChannel] is not supported. Any errors from the
-/// underlying stream will be reported only via the default
-/// [MultiChannel.stream].
-///
-/// Each virtual channel may be closed individually. When all of them are
-/// closed, the underlying [StreamSink] is closed automatically.
-abstract class MultiChannel implements StreamChannel {
- /// The default input stream.
- ///
- /// This connects to the remote [sink].
- Stream get stream;
-
- /// The default output stream.
- ///
- /// This connects to the remote [stream]. If this is closed, the remote
- /// [stream] will close, but other virtual channels will remain open and new
- /// virtual channels may be opened.
- StreamSink get sink;
-
- /// Creates a new [MultiChannel] that sends messages over [innerStream] and
- /// [innerSink].
- ///
- /// The inner streams must take JSON-like objects.
- factory MultiChannel(Stream innerStream, StreamSink innerSink) =>
- new _MultiChannel(innerStream, innerSink);
-
- /// Creates a new virtual channel.
- ///
- /// If [id] is not passed, this creates a virtual channel from scratch. Before
- /// it's used, its [VirtualChannel.id] must be sent to the remote endpoint
- /// where [virtualChannel] should be called with that id.
- ///
- /// If [id] is passed, this creates a virtual channel corresponding to the
- /// channel with that id on the remote channel.
- ///
- /// Throws an [ArgumentError] if a virtual channel already exists for [id].
- /// Throws a [StateError] if the underlying channel is closed.
- VirtualChannel virtualChannel([id]);
-}
-
-/// The implementation of [MultiChannel].
-///
-/// This is private so that [VirtualChannel] can inherit from [MultiChannel]
-/// without having to implement all the private members.
-class _MultiChannel extends StreamChannelMixin implements MultiChannel {
- /// The inner stream over which all communication is received.
- ///
- /// This will be `null` if the underlying communication channel is closed.
- Stream _innerStream;
-
- /// The inner sink over which all communication is sent.
- ///
- /// This will be `null` if the underlying communication channel is closed.
- StreamSink _innerSink;
-
- /// The subscription to [_innerStream].
- StreamSubscription _innerStreamSubscription;
-
- Stream get stream => _streamController.stream;
- final _streamController = new StreamController(sync: true);
-
- StreamSink get sink => _sinkController.sink;
- final _sinkController = new StreamController(sync: true);
-
- /// A map from virtual channel ids to [StreamController]s that should be used
- /// to write messages received from those channels.
- final _streamControllers = new Map<int, StreamController>();
-
- /// A map from virtual channel ids to [StreamControllers]s that are used
- /// to receive messages to write to those channels.
- ///
- /// Note that this uses the same keys as [_streamControllers].
- final _sinkControllers = new Map<int, StreamController>();
-
- /// The next id to use for a local virtual channel.
- ///
- /// Ids are used to identify virtual channels. Each message is tagged with an
- /// id; the receiving [MultiChannel] uses this id to look up which
- /// [VirtualChannel] the message should be dispatched to.
- ///
- /// The id scheme for virtual channels is somewhat complicated. This is
- /// necessary to ensure that there are no conflicts even when both endpoints
- /// have virtual channels with the same id; since both endpoints can send and
- /// receive messages across each virtual channel, a naïve scheme would make it
- /// impossible to tell whether a message was from a channel that originated in
- /// the remote endpoint or a reply on a channel that originated in the local
- /// endpoint.
- ///
- /// The trick is that each endpoint only uses odd ids for its own channels.
- /// When sending a message over a channel that was created by the remote
- /// endpoint, the channel's id plus one is used. This way each [MultiChannel]
- /// knows that if an incoming message has an odd id, it's using the local id
- /// scheme, but if it has an even id, it's using the remote id scheme.
- var _nextId = 1;
-
- _MultiChannel(this._innerStream, this._innerSink) {
- // The default connection is a special case which has id 0 on both ends.
- // This allows it to begin connected without having to send over an id.
- _streamControllers[0] = _streamController;
- _sinkControllers[0] = _sinkController;
- _sinkController.stream.listen(
- (message) => _innerSink.add([0, message]),
- onDone: () => _closeChannel(0, 0));
-
- _innerStreamSubscription = _innerStream.listen((message) {
- var id = message[0];
- var sink = _streamControllers[id];
-
- // A sink might not exist if the channel was closed before an incoming
- // message was processed.
- if (sink == null) return;
- if (message.length > 1) {
- sink.add(message[1]);
- return;
- }
-
- // A message without data indicates that the channel has been closed.
- _sinkControllers[id].close();
- }, onDone: _closeInnerChannel,
- onError: _streamController.addError);
- }
-
- VirtualChannel virtualChannel([id]) {
- if (_innerStream == null) {
- throw new StateError("The underlying channel is closed.");
- }
-
- var inputId;
- var outputId;
- if (id != null) {
- // Since the user is passing in an id, we're connected to a remote
- // VirtualChannel. This means messages they send over this channel will
- // have the original odd id, but our replies will have an even id.
- inputId = id;
- outputId = (id as int) + 1;
- } else {
- // Since we're generating an id, we originated this VirtualChannel. This
- // means messages we send over this channel will have the original odd id,
- // but the remote channel's replies will have an even id.
- inputId = _nextId + 1;
- outputId = _nextId;
- _nextId += 2;
- }
-
- if (_streamControllers.containsKey(inputId)) {
- throw new ArgumentError("A virtual channel with id $id already exists.");
- }
-
- var streamController = new StreamController(sync: true);
- var sinkController = new StreamController(sync: true);
- _streamControllers[inputId] = streamController;
- _sinkControllers[inputId] = sinkController;
- sinkController.stream.listen(
- (message) => _innerSink.add([outputId, message]),
- onDone: () => _closeChannel(inputId, outputId));
-
- return new VirtualChannel._(
- this, outputId, streamController.stream, sinkController.sink);
- }
-
- /// Closes the virtual channel for which incoming messages have [inputId] and
- /// outgoing messages have [outputId].
- void _closeChannel(int inputId, int outputId) {
- // A message without data indicates that the virtual channel has been
- // closed.
- _streamControllers.remove(inputId).close();
- _sinkControllers.remove(inputId).close();
-
- if (_innerSink == null) return;
- _innerSink.add([outputId]);
- if (_streamControllers.isEmpty) _closeInnerChannel();
- }
-
- /// Closes the underlying communication channel.
- void _closeInnerChannel() {
- _innerSink.close();
- _innerStreamSubscription.cancel();
- _innerStream = null;
- _innerSink = null;
- for (var controller in _sinkControllers.values.toList()) {
- controller.close();
- }
- }
-}
-
-/// A virtual channel created by [MultiChannel].
-///
-/// This implements [MultiChannel] for convenience.
-/// [VirtualChannel.virtualChannel] is semantically identical to the parent's
-/// [MultiChannel.virtualChannel].
-class VirtualChannel extends StreamChannelMixin implements MultiChannel {
- /// The [MultiChannel] that created this.
- final MultiChannel _parent;
-
- /// The identifier for this channel.
- ///
- /// This can be sent across the [MultiChannel] to provide the remote endpoint
- /// a means to connect to this channel. Nothing about this is guaranteed
- /// except that it will be JSON-serializable.
- final id;
-
- final Stream stream;
- final StreamSink sink;
-
- VirtualChannel._(this._parent, this.id, this.stream, this.sink);
-
- VirtualChannel virtualChannel([id]) => _parent.virtualChannel(id);
-}
« no previous file with comments | « lib/src/runner/browser/suite.dart ('k') | lib/src/util/stream_channel.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698