| OLD | NEW |
| 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 library json_rpc_2.client; | 5 library json_rpc_2.client; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:stack_trace/stack_trace.dart'; | 9 import 'package:stack_trace/stack_trace.dart'; |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 final TwoWayStream _streams; | 21 final TwoWayStream _streams; |
| 22 | 22 |
| 23 /// The next request id. | 23 /// The next request id. |
| 24 var _id = 0; | 24 var _id = 0; |
| 25 | 25 |
| 26 /// The current batch of requests to be sent together. | 26 /// The current batch of requests to be sent together. |
| 27 /// | 27 /// |
| 28 /// Each element is a JSON-serializable object. | 28 /// Each element is a JSON-serializable object. |
| 29 List _batch; | 29 List _batch; |
| 30 | 30 |
| 31 /// The map of request ids for pending requests to [Completer]s that will be | 31 /// The map of request ids to pending requests. |
| 32 /// completed with those requests' responses. | 32 final _pendingRequests = new Map<int, _Request>(); |
| 33 final _pendingRequests = new Map<int, Completer>(); | |
| 34 | 33 |
| 35 /// Returns a [Future] that completes when the connection is closed. | 34 /// Returns a [Future] that completes when the connection is closed. |
| 36 /// | 35 /// |
| 37 /// This is the same future that's returned by [listen]. | 36 /// This is the same future that's returned by [listen]. |
| 38 Future get done => _streams.done; | 37 Future get done => _streams.done; |
| 39 | 38 |
| 40 /// Creates a [Client] that writes requests to [requests] and reads responses | 39 /// Creates a [Client] that writes requests to [requests] and reads responses |
| 41 /// from [responses]. | 40 /// from [responses]. |
| 42 /// | 41 /// |
| 43 /// If [responses] is a [StreamSink] as well as a [Stream] (for example, a | 42 /// If [responses] is a [StreamSink] as well as a [Stream] (for example, a |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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] |
| 91 /// describing the failure. | 90 /// describing the failure. |
| 92 Future sendRequest(String method, [parameters]) { | 91 Future sendRequest(String method, [parameters]) { |
| 93 var id = _id++; | 92 var id = _id++; |
| 94 _send(method, parameters, id); | 93 _send(method, parameters, id); |
| 95 | 94 |
| 96 var completer = new Completer.sync(); | 95 var completer = new Completer.sync(); |
| 97 _pendingRequests[id] = completer; | 96 _pendingRequests[id] = new _Request(completer, new Chain.current()); |
| 98 return completer.future; | 97 return completer.future; |
| 99 } | 98 } |
| 100 | 99 |
| 101 /// Sends a JSON-RPC 2 request to invoke the given [method] without expecting | 100 /// Sends a JSON-RPC 2 request to invoke the given [method] without expecting |
| 102 /// a response. | 101 /// a response. |
| 103 /// | 102 /// |
| 104 /// If passed, [parameters] is the parameters for the method. This must be | 103 /// If passed, [parameters] is the parameters for the method. This must be |
| 105 /// either an [Iterable] (to pass parameters by position) or a [Map] with | 104 /// either an [Iterable] (to pass parameters by position) or a [Map] with |
| 106 /// [String] keys (to pass parameters by name). Either way, it must be | 105 /// [String] keys (to pass parameters by name). Either way, it must be |
| 107 /// JSON-serializable. | 106 /// JSON-serializable. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 response.forEach(_handleSingleResponse); | 163 response.forEach(_handleSingleResponse); |
| 165 } else { | 164 } else { |
| 166 _handleSingleResponse(response); | 165 _handleSingleResponse(response); |
| 167 } | 166 } |
| 168 } | 167 } |
| 169 | 168 |
| 170 /// Handles a decoded response from the server after batches have been | 169 /// Handles a decoded response from the server after batches have been |
| 171 /// resolved. | 170 /// resolved. |
| 172 void _handleSingleResponse(response) { | 171 void _handleSingleResponse(response) { |
| 173 if (!_isResponseValid(response)) return; | 172 if (!_isResponseValid(response)) return; |
| 174 var completer = _pendingRequests.remove(response["id"]); | 173 var request = _pendingRequests.remove(response["id"]); |
| 175 if (response.containsKey("result")) { | 174 if (response.containsKey("result")) { |
| 176 completer.complete(response["result"]); | 175 request.completer.complete(response["result"]); |
| 177 } else { | 176 } else { |
| 178 completer.completeError(new RpcException( | 177 request.completer.completeError(new RpcException( |
| 179 response["error"]["code"], | 178 response["error"]["code"], |
| 180 response["error"]["message"], | 179 response["error"]["message"], |
| 181 data: response["error"]["data"]), | 180 data: response["error"]["data"]), |
| 182 new Chain.current()); | 181 request.chain); |
| 183 } | 182 } |
| 184 } | 183 } |
| 185 | 184 |
| 186 /// Determines whether the server's response is valid per the spec. | 185 /// Determines whether the server's response is valid per the spec. |
| 187 bool _isResponseValid(response) { | 186 bool _isResponseValid(response) { |
| 188 if (response is! Map) return false; | 187 if (response is! Map) return false; |
| 189 if (response["jsonrpc"] != "2.0") return false; | 188 if (response["jsonrpc"] != "2.0") return false; |
| 190 if (!_pendingRequests.containsKey(response["id"])) return false; | 189 if (!_pendingRequests.containsKey(response["id"])) return false; |
| 191 if (response.containsKey("result")) return true; | 190 if (response.containsKey("result")) return true; |
| 192 | 191 |
| 193 if (!response.containsKey("error")) return false; | 192 if (!response.containsKey("error")) return false; |
| 194 var error = response["error"]; | 193 var error = response["error"]; |
| 195 if (error is! Map) return false; | 194 if (error is! Map) return false; |
| 196 if (error["code"] is! int) return false; | 195 if (error["code"] is! int) return false; |
| 197 if (error["message"] is! String) return false; | 196 if (error["message"] is! String) return false; |
| 198 return true; | 197 return true; |
| 199 } | 198 } |
| 200 } | 199 } |
| 200 |
| 201 /// A pending request to the server. |
| 202 class _Request { |
| 203 /// The completer to use to complete the response future. |
| 204 final Completer completer; |
| 205 |
| 206 /// The stack chain from where the request was made. |
| 207 final Chain chain; |
| 208 |
| 209 _Request(this.completer, this.chain); |
| 210 } |
| OLD | NEW |