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

Side by Side Diff: lib/src/client.dart

Issue 1652413002: Use StreamChannel. (Closed) Base URL: git@github.com:dart-lang/json_rpc_2.git@master
Patch Set: Created 4 years, 10 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 6
7 import 'package:stack_trace/stack_trace.dart'; 7 import 'package:stack_trace/stack_trace.dart';
8 import 'package:stream_channel/stream_channel.dart';
8 9
10 import 'channel_manager.dart';
9 import 'exception.dart'; 11 import 'exception.dart';
10 import 'two_way_stream.dart';
11 import 'utils.dart'; 12 import 'utils.dart';
12 13
13 /// A JSON-RPC 2.0 client. 14 /// A JSON-RPC 2.0 client.
14 /// 15 ///
15 /// A client calls methods on a server and handles the server's responses to 16 /// A client calls methods on a server and handles the server's responses to
16 /// those method calls. Methods can be called with [sendRequest], or with 17 /// those method calls. Methods can be called with [sendRequest], or with
17 /// [sendNotification] if no response is expected. 18 /// [sendNotification] if no response is expected.
18 class Client { 19 class Client {
19 final TwoWayStream _streams; 20 final ChannelManager _manager;
20 21
21 /// The next request id. 22 /// The next request id.
22 var _id = 0; 23 var _id = 0;
23 24
24 /// The current batch of requests to be sent together. 25 /// The current batch of requests to be sent together.
25 /// 26 ///
26 /// Each element is a JSON-serializable object. 27 /// Each element is a JSON-serializable object.
27 List _batch; 28 List _batch;
28 29
29 /// The map of request ids to pending requests. 30 /// The map of request ids to pending requests.
30 final _pendingRequests = new Map<int, _Request>(); 31 final _pendingRequests = new Map<int, _Request>();
31 32
32 /// Returns a [Future] that completes when the connection is closed. 33 /// Returns a [Future] that completes when the underlying connection is
34 /// closed.
33 /// 35 ///
34 /// This is the same future that's returned by [listen]. 36 /// This is the same future that's returned by [listen] and [close]. It may
35 Future get done => _streams.done; 37 /// fire before [close] is called if the remote endpoint closes the
Bob Nystrom 2016/02/02 17:54:15 fire -> complete
38 /// connection.
39 Future get done => _manager.done;
36 40
37 /// Whether the connection is closed. 41 /// Whether the underlying connection is closed.
38 bool get isClosed => _streams.isClosed; 42 ///
43 /// Note that this will be `true` before [close] is called if the remote
44 /// endpoint closes the connection.
45 bool get isClosed => _manager.isClosed;
39 46
40 /// Creates a [Client] that writes requests to [requests] and reads responses 47 /// Creates a [Client] that communicates over [channel].
41 /// from [responses].
42 ///
43 /// If [responses] is a [StreamSink] as well as a [Stream] (for example, a
44 /// `WebSocket`), [requests] may be omitted.
45 /// 48 ///
46 /// Note that the client won't begin listening to [responses] until 49 /// Note that the client won't begin listening to [responses] until
47 /// [Client.listen] is called. 50 /// [Client.listen] is called.
48 Client(Stream<String> responses, [StreamSink<String> requests]) 51 Client(StreamChannel<String> channel)
49 : _streams = new TwoWayStream( 52 : this.withoutJson(channel
50 "Client", responses, "responses", requests, "requests"); 53 .transform(jsonDocument)
54 .transformStream(ignoreFormatExceptions));
51 55
52 /// Creates a [Client] that writes decoded responses to [responses] and reads 56 /// Creates a [Client] that communicates using decoded messages over
53 /// decoded requests from [requests]. 57 /// [channel].
54 /// 58 ///
55 /// Unlike [new Client], this doesn't read or write JSON strings. Instead, it 59 /// Unlike [new Client], this doesn't read or write JSON strings. Instead, it
56 /// reads and writes decoded maps or lists. 60 /// reads and writes decoded maps or lists.
57 /// 61 ///
58 /// If [responses] is a [StreamSink] as well as a [Stream], [requests] may be
59 /// omitted.
60 ///
61 /// Note that the client won't begin listening to [responses] until 62 /// Note that the client won't begin listening to [responses] until
62 /// [Client.listen] is called. 63 /// [Client.listen] is called.
63 Client.withoutJson(Stream responses, [StreamSink requests]) 64 Client.withoutJson(StreamChannel channel)
64 : _streams = new TwoWayStream.withoutJson( 65 : _manager = new ChannelManager("Client", channel);
65 "Client", responses, "responses", requests, "requests");
66 66
67 /// Starts listening to the underlying stream. 67 /// Starts listening to the underlying stream.
68 /// 68 ///
69 /// Returns a [Future] that will complete when the stream is closed or when it 69 /// Returns a [Future] that will complete when the connection is closed or
70 /// has an error. 70 /// when it has an error. This is the same as [done].
71 /// 71 ///
72 /// [listen] may only be called once. 72 /// [listen] may only be called once.
73 Future listen() => _streams.listen(_handleResponse); 73 Future listen() => _manager.listen(_handleResponse);
74 74
75 /// Closes the server's request sink and response subscription. 75 /// Closes the underlying connection.
76 /// 76 ///
77 /// Returns a [Future] that completes when all resources have been released. 77 /// Returns a [Future] that completes when all resources have been released.
78 /// 78 /// This is the same as [done].
79 /// A client can't be closed before [listen] has been called. 79 Future close() => _manager.close();
80 Future close() => _streams.close();
81 80
82 /// Sends a JSON-RPC 2 request to invoke the given [method]. 81 /// Sends a JSON-RPC 2 request to invoke the given [method].
83 /// 82 ///
84 /// If passed, [parameters] is the parameters for the method. This must be 83 /// If passed, [parameters] is the parameters for the method. This must be
85 /// either an [Iterable] (to pass parameters by position) or a [Map] with 84 /// either an [Iterable] (to pass parameters by position) or a [Map] with
86 /// [String] keys (to pass parameters by name). Either way, it must be 85 /// [String] keys (to pass parameters by name). Either way, it must be
87 /// JSON-serializable. 86 /// JSON-serializable.
88 /// 87 ///
89 /// If the request succeeds, this returns the response result as a decoded 88 /// If the request succeeds, this returns the response result as a decoded
90 /// JSON-serializable object. If it fails, it throws an [RpcException] 89 /// JSON-serializable object. If it fails, it throws an [RpcException]
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 var message = { 124 var message = {
126 "jsonrpc": "2.0", 125 "jsonrpc": "2.0",
127 "method": method 126 "method": method
128 }; 127 };
129 if (id != null) message["id"] = id; 128 if (id != null) message["id"] = id;
130 if (parameters != null) message["params"] = parameters; 129 if (parameters != null) message["params"] = parameters;
131 130
132 if (_batch != null) { 131 if (_batch != null) {
133 _batch.add(message); 132 _batch.add(message);
134 } else { 133 } else {
135 _streams.add(message); 134 _manager.add(message);
136 } 135 }
137 } 136 }
138 137
139 /// Runs [callback] and batches any requests sent until it returns. 138 /// Runs [callback] and batches any requests sent until it returns.
140 /// 139 ///
141 /// A batch of requests is sent in a single message on the underlying stream, 140 /// A batch of requests is sent in a single message on the underlying stream,
142 /// and the responses are likewise sent back in a single message. 141 /// and the responses are likewise sent back in a single message.
143 /// 142 ///
144 /// [callback] may be synchronous or asynchronous. If it returns a [Future], 143 /// [callback] may be synchronous or asynchronous. If it returns a [Future],
145 /// requests will be batched until that Future returns; otherwise, requests 144 /// requests will be batched until that Future returns; otherwise, requests
146 /// will only be batched while synchronously executing [callback]. 145 /// will only be batched while synchronously executing [callback].
147 /// 146 ///
148 /// If this is called in the context of another [withBatch] call, it just 147 /// If this is called in the context of another [withBatch] call, it just
149 /// invokes [callback] without creating another batch. This means that 148 /// invokes [callback] without creating another batch. This means that
150 /// responses are batched until the first batch ends. 149 /// responses are batched until the first batch ends.
151 withBatch(callback()) { 150 withBatch(callback()) {
152 if (_batch != null) return callback(); 151 if (_batch != null) return callback();
153 152
154 _batch = []; 153 _batch = [];
155 return tryFinally(callback, () { 154 return tryFinally(callback, () {
156 _streams.add(_batch); 155 _manager.add(_batch);
157 _batch = null; 156 _batch = null;
158 }); 157 });
159 } 158 }
160 159
161 /// Handles a decoded response from the server. 160 /// Handles a decoded response from the server.
162 void _handleResponse(response) { 161 void _handleResponse(response) {
163 if (response is List) { 162 if (response is List) {
164 response.forEach(_handleSingleResponse); 163 response.forEach(_handleSingleResponse);
165 } else { 164 } else {
166 _handleSingleResponse(response); 165 _handleSingleResponse(response);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 /// A pending request to the server. 201 /// A pending request to the server.
203 class _Request { 202 class _Request {
204 /// The completer to use to complete the response future. 203 /// The completer to use to complete the response future.
205 final Completer completer; 204 final Completer completer;
206 205
207 /// The stack chain from where the request was made. 206 /// The stack chain from where the request was made.
208 final Chain chain; 207 final Chain chain;
209 208
210 _Request(this.completer, this.chain); 209 _Request(this.completer, this.chain);
211 } 210 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698