| Index: pkg/analysis_server/lib/src/analysis_server.dart
|
| diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7fd84f4f019d64a765b37e10b6b646ccf7f0b38f
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/analysis_server.dart
|
| @@ -0,0 +1,178 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library analysis.server;
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +
|
| +import 'analysis_logger.dart';
|
| +import 'channel.dart';
|
| +import 'protocol.dart';
|
| +
|
| +/**
|
| + * Instances of the class [AnalysisServer] implement a server that listens on a
|
| + * [CommunicationChannel] for analysis requests and process them.
|
| + */
|
| +class AnalysisServer {
|
| + /**
|
| + * The name of the notification of new errors associated with a source.
|
| + */
|
| + static const String ERROR_NOTIFICATION_NAME = 'context.errors';
|
| +
|
| + /**
|
| + * The name of the parameter whose value is a list of errors.
|
| + */
|
| + static const String ERRORS_PARAM = 'errors';
|
| +
|
| + /**
|
| + * The name of the parameter whose value is a source.
|
| + */
|
| + static const String SOURCE_PARAM = 'source';
|
| +
|
| + /**
|
| + * The channel from which requests are received and to which responses should
|
| + * be sent.
|
| + */
|
| + CommunicationChannel channel;
|
| +
|
| + /**
|
| + * A flag indicating whether the server is running.
|
| + */
|
| + bool running;
|
| +
|
| + /**
|
| + * A list of the request handlers used to handle the requests sent to this
|
| + * server.
|
| + */
|
| + List<RequestHandler> handlers;
|
| +
|
| + /**
|
| + * A table mapping context id's to the analysis contexts associated with them.
|
| + */
|
| + final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContext>();
|
| +
|
| + /**
|
| + * A list of the analysis contexts for which analysis work needs to be
|
| + * performed.
|
| + */
|
| + final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>();
|
| +
|
| + /**
|
| + * Initialize a newly created server to receive requests from and send
|
| + * responses to the given [channel].
|
| + */
|
| + AnalysisServer(CommunicationChannel channel) {
|
| + AnalysisEngine.instance.logger = new AnalysisLogger();
|
| + running = true;
|
| + this.channel = channel;
|
| + this.channel.listen(handleRequest, onError: error, onDone: done);
|
| + }
|
| +
|
| + /**
|
| + * Add the given [context] to the list of analysis contexts for which analysis
|
| + * work needs to be performed. Ensure that the work will be performed.
|
| + */
|
| + void addContextToWorkQueue(AnalysisContext context) {
|
| + if (!contextWorkQueue.contains(context)) {
|
| + contextWorkQueue.add(context);
|
| + run();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * The socket from which requests are being read has been closed.
|
| + */
|
| + void done() {
|
| + running = false;
|
| + }
|
| +
|
| + /**
|
| + * There was an error related to the socket from which requests are being
|
| + * read.
|
| + */
|
| + void error() {
|
| + running = false;
|
| + }
|
| +
|
| + /**
|
| + * Handle a [request] that was read from the communication channel.
|
| + */
|
| + void handleRequest(Request request) {
|
| + int count = handlers.length;
|
| + for (int i = 0; i < count; i++) {
|
| + Response response = handlers[i].handleRequest(request);
|
| + if (response != null) {
|
| + channel.sendResponse(response);
|
| + return;
|
| + }
|
| + }
|
| + channel.sendResponse(new Response.unknownRequest(request));
|
| + }
|
| +
|
| + /**
|
| + * Perform the next available task. If a request was received that has not yet
|
| + * been performed, perform it next. Otherwise, look for some analysis that
|
| + * needs to be done and do that. Otherwise, do nothing.
|
| + */
|
| + void performTask() {
|
| + //
|
| + // Look for a context that has work to be done and then perform one task.
|
| + //
|
| + if (!contextWorkQueue.isEmpty) {
|
| + AnalysisContext context = contextWorkQueue[0];
|
| + AnalysisResult result = context.performAnalysisTask();
|
| + List<ChangeNotice> notices = result.changeNotices;
|
| + if (notices == null) {
|
| + contextWorkQueue.removeAt(0);
|
| + } else { //if (context.analysisOptions.provideErrors) {
|
| + sendNotices(notices);
|
| + }
|
| + }
|
| + //
|
| + // Schedule this method to be run again if there is any more work to be done.
|
| + //
|
| + if (contextWorkQueue.isEmpty) {
|
| + running = false;
|
| + } else {
|
| + Timer.run(() {
|
| + performTask();
|
| + });
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Send the information in the given list of notices back to the client.
|
| + */
|
| + void sendNotices(List<ChangeNotice> notices) {
|
| + for (int i = 0; i < notices.length; i++) {
|
| + ChangeNotice notice = notices[i];
|
| + Notification notification = new Notification(ERROR_NOTIFICATION_NAME);
|
| + notification.setParameter(SOURCE_PARAM, notice.source.encoding);
|
| + notification.setParameter(ERRORS_PARAM, notice.errors);
|
| + sendNotification(notification);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Perform the tasks that are waiting for execution until the server is shut
|
| + * down.
|
| + */
|
| + void run() {
|
| + if (!running) {
|
| + running = true;
|
| + Timer.run(() {
|
| + performTask();
|
| + });
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Send the given [notification] to the client.
|
| + */
|
| + void sendNotification(Notification notification) {
|
| + channel.sendNotification(notification);
|
| + }
|
| +}
|
|
|