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

Unified Diff: pkg/analysis_server/lib/src/analysis_manager.dart

Issue 180253005: Error handling and code cleanup (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge Created 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analysis_server/bin/dartdeps.dart ('k') | pkg/analysis_server/lib/src/channel.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/lib/src/analysis_manager.dart
diff --git a/pkg/analysis_server/lib/src/analysis_manager.dart b/pkg/analysis_server/lib/src/analysis_manager.dart
index f46d1c90f06371b3ec76d16063384ed370d02437..cb001e4c41740c31903371b39ad697f97b979946 100644
--- a/pkg/analysis_server/lib/src/analysis_manager.dart
+++ b/pkg/analysis_server/lib/src/analysis_manager.dart
@@ -5,10 +5,13 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'package:analysis_server/src/channel.dart';
+import 'package:analysis_server/src/domain_server.dart';
+import 'package:analysis_server/src/protocol.dart';
/**
* [AnalysisManager] is used to launch and manage an analysis server
- * running in a separate process using the static [start] method.
+ * running in a separate process using either the [start] or [connect] methods.
*/
class AnalysisManager {
// TODO dynamically allocate port and/or allow client to specify port
@@ -18,75 +21,120 @@ class AnalysisManager {
* The analysis server process being managed
* or `null` if managing an analysis server that was already running.
*/
- final Process process;
+ Process process;
/**
- * The websocket used to communicate with the analysis server.
+ * The socket used to communicate with the analysis server.
*/
- final WebSocket socket;
+ WebSocket socket;
/**
- * Launch analysis server in a separate process and return a
- * [Future<AnalysisManager>] for managing that analysis server.
+ * Launch analysis server in a separate process
+ * and return a future with a manager for that analysis server.
*/
- static Future<AnalysisManager> start(String pathToServer) {
- // TODO dynamically allocate port and/or allow client to specify port
- return Process.start(Platform.executable, [pathToServer, "--port",
- PORT.toString()]).then(_attach).catchError((error) {
- print("Failed to launch analysis server: $error");
- exitCode = 1;
- throw error;
- });
+ static Future<AnalysisManager> start(String serverPath) {
+ return new AnalysisManager()._launchServer(serverPath);
}
/**
* Open a connection to a running analysis server
+ * and return a future with a manager for that analysis server.
*/
- static Future<AnalysisManager> connect(String url) {
- return WebSocket.connect(url)
- .then((WebSocket socket) => new AnalysisManager(null, socket));
+ static Future<AnalysisManager> connect(String serverUrl) {
+ return new AnalysisManager()._openConnection(serverUrl);
}
/**
- * Attach this process to the newly launched analysis server process,
- * and open a connection to the analysis server.
+ * Launch an analysis server and open a connection to that server.
*/
- static Future<AnalysisManager> _attach(Process process) {
- var url = 'ws://${InternetAddress.LOOPBACK_IP_V4.address}:$PORT/';
- process.stderr.pipe(stderr);
- Stream out = process.stdout.transform(UTF8.decoder).asBroadcastStream();
- out.listen((line) {
- print(line);
- });
- return out
- .any((String line) => line.startsWith("Listening on port"))
- .then((bool listening) {
- if (!listening) {
- throw "Expected analysis server to listen on a port";
- }
+ Future<AnalysisManager> _launchServer(String pathToServer) {
+ // TODO dynamically allocate port and/or allow client to specify port
+ var serverArgs = [pathToServer, '--port', PORT.toString()];
+ return Process.start(Platform.executable, serverArgs)
+ .catchError((error) {
+ exitCode = 1;
+ throw 'Failed to launch analysis server: $error';
})
- .then((_) => WebSocket.connect(url))
- .then((WebSocket socket) => new AnalysisManager(process, socket))
+ .then(_listenForPort);
+ }
+
+ /**
+ * Listen for a port from the given analysis server process.
+ */
+ Future<AnalysisManager> _listenForPort(Process process) {
+ this.process = process;
+
+ // Echo stdout and stderr
+ Stream out = process.stdout.transform(UTF8.decoder).asBroadcastStream();
+ out.listen((line) => print(line));
+ process.stderr.pipe(stderr);
+
+ // Listen for port from server
+ const String pattern = 'Listening on port ';
+ return out.firstWhere((String line) => line.startsWith(pattern))
+ .timeout(new Duration(seconds: 10))
.catchError((error) {
- process.kill();
- print("Failed to connect to analysis server: $error");
exitCode = 1;
- throw error;
+ process.kill();
+ throw 'Expected port from analysis server';
+ })
+ .then((String line) {
+ String port = line.substring(pattern.length).trim();
+ var url = 'ws://${InternetAddress.LOOPBACK_IP_V4.address}:$port/';
+ return _openConnection(url);
});
}
/**
- * Create a new instance that manages the specified analysis server process.
+ * Open a connection to the analysis server using the given URL.
*/
- AnalysisManager(this.process, this.socket);
+ Future<AnalysisManager> _openConnection(String serverUrl) {
+ var onError = (error) {
+ exitCode = 1;
+ if (process != null) {
+ process.kill();
+ }
+ throw 'Failed to connect to analysis server at $serverUrl\n $error';
+ };
+ try {
+ return WebSocket.connect(serverUrl)
+ .catchError(onError)
+ .then((WebSocket socket) {
+ this.socket = socket;
+ return this;
+ });
+ } catch (error) {
+ onError(error);
+ }
+ }
/**
* Stop the analysis server.
*
- * Returns `true` if the signal is successfully sent and process is killed.
+ * Returns `true` if the signal is successfully sent and process terminates.
* Otherwise there was no attached process or the signal could not be sent,
* usually meaning that the process is already dead.
*/
- // TODO request analysis server stop
- bool stop() => process != null ? process.kill() : false;
+ Future<bool> stop() {
+ if (process == null) {
+ return new Future.value(false);
+ }
+ var shutdownRequest = {
+ Request.ID : '0',
+ Request.METHOD : ServerDomainHandler.SHUTDOWN_METHOD };
+ socket.add(JSON.encoder.convert(shutdownRequest));
+ return process.exitCode
+ .timeout(new Duration(seconds: 10))
+ .catchError((error) {
+ process.kill();
+ throw 'Expected server to shutdown';
+ })
+ .then((result) {
+ if (result != 0) {
+ exitCode = result;
+ }
+ return true;
+ });
+ }
+
}
« no previous file with comments | « pkg/analysis_server/bin/dartdeps.dart ('k') | pkg/analysis_server/lib/src/channel.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698