OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:isolate'; | 6 import 'dart:isolate'; |
7 | 7 |
8 import 'package:analyzer_plugin/channel/channel.dart'; | 8 import 'package:analyzer_plugin/channel/channel.dart'; |
9 import 'package:analyzer_plugin/protocol/protocol.dart'; | 9 import 'package:analyzer_plugin/protocol/protocol.dart'; |
10 | 10 |
11 /** | 11 /** |
12 * The object that allows a [ServerPlugin] to receive [Request]s and to return | 12 * The object that allows a [ServerPlugin] to receive [Request]s and to return |
13 * both [Response]s and [Notification]s. It communicates with the analysis | 13 * both [Response]s and [Notification]s. It communicates with the analysis |
14 * server by passing data to the server's main isolate. | 14 * server by passing data to the server's main isolate. |
15 */ | 15 */ |
16 class IsolateChannel implements PluginCommunicationChannel { | 16 class PluginIsolateChannel implements PluginCommunicationChannel { |
17 /** | 17 /** |
18 * The port used to send notifications and responses to the server. | 18 * The port used to send notifications and responses to the server. |
19 */ | 19 */ |
20 SendPort _sendPort; | 20 SendPort _sendPort; |
21 | 21 |
22 /** | 22 /** |
23 * The port used to receive requests from the server. | 23 * The port used to receive requests from the server. |
24 */ | 24 */ |
25 ReceivePort _receivePort; | 25 ReceivePort _receivePort; |
26 | 26 |
27 /** | 27 /** |
28 * The subscription that needs to be cancelled when the channel is closed. | 28 * The subscription that needs to be cancelled when the channel is closed. |
29 */ | 29 */ |
30 StreamSubscription _subscription; | 30 StreamSubscription _subscription; |
31 | 31 |
32 /** | 32 /** |
33 * Initialize a newly created channel to communicate with the server. | 33 * Initialize a newly created channel to communicate with the server. |
34 */ | 34 */ |
35 IsolateChannel(this._sendPort) { | 35 PluginIsolateChannel(this._sendPort) { |
36 _receivePort = new ReceivePort(); | 36 _receivePort = new ReceivePort(); |
37 _sendPort.send(_receivePort.sendPort); | 37 _sendPort.send(_receivePort.sendPort); |
38 } | 38 } |
39 | 39 |
40 @override | 40 @override |
41 void close() { | 41 void close() { |
42 if (_subscription != null) { | 42 if (_subscription != null) { |
43 _subscription.cancel(); | 43 _subscription.cancel(); |
44 _subscription = null; | 44 _subscription = null; |
45 } | 45 } |
(...skipping 20 matching lines...) Expand all Loading... |
66 @override | 66 @override |
67 void sendNotification(Notification notification) { | 67 void sendNotification(Notification notification) { |
68 _sendPort.send(notification.toJson()); | 68 _sendPort.send(notification.toJson()); |
69 } | 69 } |
70 | 70 |
71 @override | 71 @override |
72 void sendResponse(Response response) { | 72 void sendResponse(Response response) { |
73 _sendPort.send(response.toJson()); | 73 _sendPort.send(response.toJson()); |
74 } | 74 } |
75 } | 75 } |
| 76 |
| 77 /** |
| 78 * The communication channel that allows an analysis server to send [Request]s |
| 79 * to, and to receive both [Response]s and [Notification]s from, a plugin. |
| 80 */ |
| 81 class ServerIsolateChannel implements ServerCommunicationChannel { |
| 82 /** |
| 83 * The URI for the plugin that will be run in the isolate that this channel |
| 84 * communicates with. |
| 85 */ |
| 86 final Uri uri; |
| 87 |
| 88 /** |
| 89 * The isolate in which the plugin is running, or `null` if the plugin has |
| 90 * not yet been started by invoking [listen]. |
| 91 */ |
| 92 Isolate _isolate; |
| 93 |
| 94 /** |
| 95 * The port used to send requests to the plugin, or `null` if the plugin has |
| 96 * not yet been started by invoking [listen]. |
| 97 */ |
| 98 SendPort _sendPort; |
| 99 |
| 100 /** |
| 101 * Initialize a newly created channel to communicate with an isolate running |
| 102 * the code at the given [uri]. |
| 103 */ |
| 104 ServerIsolateChannel(this.uri); |
| 105 |
| 106 @override |
| 107 void close() { |
| 108 // TODO(brianwilkerson) Is there anything useful to do here? |
| 109 _isolate = null; |
| 110 _sendPort = null; |
| 111 } |
| 112 |
| 113 @override |
| 114 Future<Null> listen(void onResponse(Response response), |
| 115 void onNotification(Notification notification), |
| 116 {Function onError, void onDone()}) async { |
| 117 if (_isolate != null) { |
| 118 throw new StateError('Cannot listen to the same channel more than once.'); |
| 119 } |
| 120 ReceivePort receivePort = new ReceivePort(); |
| 121 ReceivePort errorPort; |
| 122 if (onError != null) { |
| 123 errorPort = new ReceivePort(); |
| 124 errorPort.listen((error) { |
| 125 onError(error); |
| 126 }); |
| 127 } |
| 128 ReceivePort exitPort; |
| 129 if (onDone != null) { |
| 130 exitPort = new ReceivePort(); |
| 131 exitPort.listen((_) { |
| 132 onDone(); |
| 133 }); |
| 134 } |
| 135 _isolate = await Isolate.spawnUri(uri, <String>[], receivePort.sendPort, |
| 136 automaticPackageResolution: true, |
| 137 onError: errorPort?.sendPort, |
| 138 onExit: exitPort?.sendPort); |
| 139 _sendPort = await receivePort.first as SendPort; |
| 140 receivePort.listen((dynamic input) { |
| 141 if (input is Map) { |
| 142 if (input.containsKey('id') != null) { |
| 143 onResponse(new Response.fromJson(input)); |
| 144 } else if (input.containsKey('event')) { |
| 145 onNotification(new Notification.fromJson(input)); |
| 146 } |
| 147 } |
| 148 }); |
| 149 } |
| 150 |
| 151 @override |
| 152 void sendRequest(Request request) { |
| 153 _sendPort.send(request.toJson()); |
| 154 } |
| 155 } |
OLD | NEW |