| 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:convert'; |
| 6 import 'dart:isolate'; | 7 import 'dart:isolate'; |
| 7 | 8 |
| 9 import 'package:analyzer/instrumentation/instrumentation.dart'; |
| 8 import 'package:analyzer_plugin/channel/channel.dart'; | 10 import 'package:analyzer_plugin/channel/channel.dart'; |
| 9 import 'package:analyzer_plugin/protocol/protocol.dart'; | 11 import 'package:analyzer_plugin/protocol/protocol.dart'; |
| 10 | 12 |
| 11 /** | 13 /** |
| 12 * The object that allows a [ServerPlugin] to receive [Request]s and to return | 14 * 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 | 15 * both [Response]s and [Notification]s. It communicates with the analysis |
| 14 * server by passing data to the server's main isolate. | 16 * server by passing data to the server's main isolate. |
| 15 */ | 17 */ |
| 16 class PluginIsolateChannel implements PluginCommunicationChannel { | 18 class PluginIsolateChannel implements PluginCommunicationChannel { |
| 17 /** | 19 /** |
| (...skipping 25 matching lines...) Expand all Loading... |
| 43 _subscription.cancel(); | 45 _subscription.cancel(); |
| 44 _subscription = null; | 46 _subscription = null; |
| 45 } | 47 } |
| 46 } | 48 } |
| 47 | 49 |
| 48 @override | 50 @override |
| 49 void listen(void onRequest(Request request), | 51 void listen(void onRequest(Request request), |
| 50 {Function onError, void onDone()}) { | 52 {Function onError, void onDone()}) { |
| 51 void onData(data) { | 53 void onData(data) { |
| 52 Map<String, Object> requestMap = data; | 54 Map<String, Object> requestMap = data; |
| 55 // print('[plugin] Received request: ${JSON.encode(requestMap)}'); |
| 53 Request request = new Request.fromJson(requestMap); | 56 Request request = new Request.fromJson(requestMap); |
| 54 if (request != null) { | 57 if (request != null) { |
| 55 onRequest(request); | 58 onRequest(request); |
| 56 } | 59 } |
| 57 } | 60 } |
| 58 | 61 |
| 59 if (_subscription != null) { | 62 if (_subscription != null) { |
| 60 throw new StateError('Only one listener is allowed per channel'); | 63 throw new StateError('Only one listener is allowed per channel'); |
| 61 } | 64 } |
| 62 _subscription = _receivePort.listen(onData, | 65 _subscription = _receivePort.listen(onData, |
| 63 onError: onError, onDone: onDone, cancelOnError: false); | 66 onError: onError, onDone: onDone, cancelOnError: false); |
| 64 } | 67 } |
| 65 | 68 |
| 66 @override | 69 @override |
| 67 void sendNotification(Notification notification) { | 70 void sendNotification(Notification notification) { |
| 68 _sendPort.send(notification.toJson()); | 71 Map<String, Object> json = notification.toJson(); |
| 72 // print('[plugin] Send notification: ${JSON.encode(json)}'); |
| 73 _sendPort.send(json); |
| 69 } | 74 } |
| 70 | 75 |
| 71 @override | 76 @override |
| 72 void sendResponse(Response response) { | 77 void sendResponse(Response response) { |
| 73 _sendPort.send(response.toJson()); | 78 Map<String, Object> json = response.toJson(); |
| 79 // print('[plugin] Send response: ${JSON.encode(json)}'); |
| 80 _sendPort.send(json); |
| 74 } | 81 } |
| 75 } | 82 } |
| 76 | 83 |
| 77 /** | 84 /** |
| 78 * The communication channel that allows an analysis server to send [Request]s | 85 * 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. | 86 * to, and to receive both [Response]s and [Notification]s from, a plugin. |
| 80 */ | 87 */ |
| 81 class ServerIsolateChannel implements ServerCommunicationChannel { | 88 class ServerIsolateChannel implements ServerCommunicationChannel { |
| 82 /** | 89 /** |
| 83 * The URI for the plugin that will be run in the isolate that this channel | 90 * The URI for the Dart file that will be run in the isolate that this channel |
| 84 * communicates with. | 91 * communicates with. |
| 85 */ | 92 */ |
| 86 final Uri uri; | 93 final Uri pluginUri; |
| 94 |
| 95 /** |
| 96 * The URI for the '.packages' file that will control how 'package:' URIs are |
| 97 * resolved. |
| 98 */ |
| 99 final Uri packagesUri; |
| 100 |
| 101 /** |
| 102 * The instrumentation service that is being used by the analysis server. |
| 103 */ |
| 104 final InstrumentationService instrumentationService; |
| 87 | 105 |
| 88 /** | 106 /** |
| 89 * The isolate in which the plugin is running, or `null` if the plugin has | 107 * The isolate in which the plugin is running, or `null` if the plugin has |
| 90 * not yet been started by invoking [listen]. | 108 * not yet been started by invoking [listen]. |
| 91 */ | 109 */ |
| 92 Isolate _isolate; | 110 Isolate _isolate; |
| 93 | 111 |
| 94 /** | 112 /** |
| 95 * The port used to send requests to the plugin, or `null` if the plugin has | 113 * The port used to send requests to the plugin, or `null` if the plugin has |
| 96 * not yet been started by invoking [listen]. | 114 * not yet been started by invoking [listen]. |
| 97 */ | 115 */ |
| 98 SendPort _sendPort; | 116 SendPort _sendPort; |
| 99 | 117 |
| 118 ReceivePort receivePort; |
| 119 |
| 120 ReceivePort errorPort; |
| 121 |
| 122 ReceivePort exitPort; |
| 123 |
| 100 /** | 124 /** |
| 101 * Initialize a newly created channel to communicate with an isolate running | 125 * Initialize a newly created channel to communicate with an isolate running |
| 102 * the code at the given [uri]. | 126 * the code at the given [uri]. |
| 103 */ | 127 */ |
| 104 ServerIsolateChannel(this.uri); | 128 ServerIsolateChannel( |
| 105 | 129 this.pluginUri, this.packagesUri, this.instrumentationService); |
| 106 @override | 130 @override |
| 107 void close() { | 131 void close() { |
| 108 // TODO(brianwilkerson) Is there anything useful to do here? | 132 receivePort?.close(); |
| 133 errorPort?.close(); |
| 134 exitPort?.close(); |
| 109 _isolate = null; | 135 _isolate = null; |
| 110 _sendPort = null; | 136 // _sendPort = null; |
| 137 // receivePort = null; |
| 138 // errorPort = null; |
| 139 // exitPort = null; |
| 111 } | 140 } |
| 112 | 141 |
| 113 @override | 142 @override |
| 114 Future<Null> listen(void onResponse(Response response), | 143 Future<Null> listen(void onResponse(Response response), |
| 115 void onNotification(Notification notification), | 144 void onNotification(Notification notification), |
| 116 {Function onError, void onDone()}) async { | 145 {Function onError, void onDone()}) async { |
| 117 if (_isolate != null) { | 146 if (_isolate != null) { |
| 118 throw new StateError('Cannot listen to the same channel more than once.'); | 147 throw new StateError('Cannot listen to the same channel more than once.'); |
| 119 } | 148 } |
| 120 ReceivePort receivePort = new ReceivePort(); | 149 receivePort = new ReceivePort(); |
| 121 ReceivePort errorPort; | |
| 122 if (onError != null) { | 150 if (onError != null) { |
| 123 errorPort = new ReceivePort(); | 151 errorPort = new ReceivePort(); |
| 124 errorPort.listen((error) { | 152 errorPort.listen((error) { |
| 125 onError(error); | 153 onError(error); |
| 126 }); | 154 }); |
| 127 } | 155 } |
| 128 ReceivePort exitPort; | |
| 129 if (onDone != null) { | 156 if (onDone != null) { |
| 130 exitPort = new ReceivePort(); | 157 exitPort = new ReceivePort(); |
| 131 exitPort.listen((_) { | 158 exitPort.listen((_) { |
| 132 onDone(); | 159 onDone(); |
| 133 }); | 160 }); |
| 134 } | 161 } |
| 135 _isolate = await Isolate.spawnUri(uri, <String>[], receivePort.sendPort, | 162 _isolate = await Isolate.spawnUri( |
| 136 automaticPackageResolution: true, | 163 pluginUri, <String>[], receivePort.sendPort, |
| 137 onError: errorPort?.sendPort, | 164 onError: errorPort?.sendPort, |
| 138 onExit: exitPort?.sendPort); | 165 onExit: exitPort?.sendPort, |
| 139 _sendPort = await receivePort.first as SendPort; | 166 packageConfig: packagesUri); |
| 167 Completer<Null> channelReady = new Completer<Null>(); |
| 140 receivePort.listen((dynamic input) { | 168 receivePort.listen((dynamic input) { |
| 141 if (input is Map) { | 169 if (input is SendPort) { |
| 170 // print('[server] Received send port'); |
| 171 _sendPort = input; |
| 172 channelReady.complete(null); |
| 173 } else if (input is Map) { |
| 142 if (input.containsKey('id') != null) { | 174 if (input.containsKey('id') != null) { |
| 175 String encodedInput = JSON.encode(input); |
| 176 // print('[server] Received response: $encodedInput'); |
| 177 instrumentationService.logPluginResponse(pluginUri, encodedInput); |
| 143 onResponse(new Response.fromJson(input)); | 178 onResponse(new Response.fromJson(input)); |
| 144 } else if (input.containsKey('event')) { | 179 } else if (input.containsKey('event')) { |
| 180 String encodedInput = JSON.encode(input); |
| 181 // print('[server] Received notification: $encodedInput'); |
| 182 instrumentationService.logPluginNotification(pluginUri, encodedInput); |
| 145 onNotification(new Notification.fromJson(input)); | 183 onNotification(new Notification.fromJson(input)); |
| 146 } | 184 } |
| 147 } | 185 } |
| 148 }); | 186 }); |
| 187 return channelReady.future; |
| 149 } | 188 } |
| 150 | 189 |
| 151 @override | 190 @override |
| 152 void sendRequest(Request request) { | 191 void sendRequest(Request request) { |
| 153 _sendPort.send(request.toJson()); | 192 Map<String, Object> json = request.toJson(); |
| 193 String encodedRequest = JSON.encode(json); |
| 194 // print('[server] Send request: $encodedRequest'); |
| 195 instrumentationService.logPluginRequest(pluginUri, encodedRequest); |
| 196 _sendPort.send(json); |
| 154 } | 197 } |
| 155 } | 198 } |
| OLD | NEW |