| 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 analysis.server; | 5 library analysis.server; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/analysis_logger.dart'; | 9 import 'package:analysis_server/src/analysis_logger.dart'; |
| 10 import 'package:analysis_server/src/channel.dart'; | 10 import 'package:analysis_server/src/channel.dart'; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 */ | 36 */ |
| 37 static const String CONNECTED_NOTIFICATION = 'server.connected'; | 37 static const String CONNECTED_NOTIFICATION = 'server.connected'; |
| 38 | 38 |
| 39 /** | 39 /** |
| 40 * The channel from which requests are received and to which responses should | 40 * The channel from which requests are received and to which responses should |
| 41 * be sent. | 41 * be sent. |
| 42 */ | 42 */ |
| 43 final ServerCommunicationChannel channel; | 43 final ServerCommunicationChannel channel; |
| 44 | 44 |
| 45 /** | 45 /** |
| 46 * A flag indicating whether the server is running. | 46 * A flag indicating whether the server is running. When false, contexts |
| 47 * will no longer be added to [contextWorkQueue], and [performTask] will |
| 48 * discard any tasks it finds on [contextWorkQueue]. |
| 47 */ | 49 */ |
| 48 bool running; | 50 bool running; |
| 49 | 51 |
| 50 /** | 52 /** |
| 51 * A list of the request handlers used to handle the requests sent to this | 53 * A list of the request handlers used to handle the requests sent to this |
| 52 * server. | 54 * server. |
| 53 */ | 55 */ |
| 54 List<RequestHandler> handlers; | 56 List<RequestHandler> handlers; |
| 55 | 57 |
| 56 /** | 58 /** |
| 57 * A table mapping context id's to the analysis contexts associated with them. | 59 * A table mapping context id's to the analysis contexts associated with them. |
| 58 */ | 60 */ |
| 59 final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContex
t>(); | 61 final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisContex
t>(); |
| 60 | 62 |
| 61 /** | 63 /** |
| 62 * A list of the analysis contexts for which analysis work needs to be | 64 * A list of the analysis contexts for which analysis work needs to be |
| 63 * performed. | 65 * performed. |
| 66 * |
| 67 * Invariant: when this list is non-empty, there is exactly one pending call |
| 68 * to [performTask] on the event queue. When this list is empty, there are |
| 69 * no calls to [performTask] on the event queue. |
| 64 */ | 70 */ |
| 65 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>(); | 71 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>(); |
| 66 | 72 |
| 67 /** | 73 /** |
| 68 * Initialize a newly created server to receive requests from and send | 74 * Initialize a newly created server to receive requests from and send |
| 69 * responses to the given [channel]. | 75 * responses to the given [channel]. |
| 70 */ | 76 */ |
| 71 AnalysisServer(this.channel) { | 77 AnalysisServer(this.channel) { |
| 72 AnalysisEngine.instance.logger = new AnalysisLogger(); | 78 AnalysisEngine.instance.logger = new AnalysisLogger(); |
| 73 running = true; | 79 running = true; |
| 74 Notification notification = new Notification(CONNECTED_NOTIFICATION); | 80 Notification notification = new Notification(CONNECTED_NOTIFICATION); |
| 75 channel.sendNotification(notification); | 81 channel.sendNotification(notification); |
| 76 channel.listen(handleRequest, onDone: done, onError: error); | 82 channel.listen(handleRequest, onDone: done, onError: error); |
| 77 } | 83 } |
| 78 | 84 |
| 79 /** | 85 /** |
| 80 * Add the given [context] to the list of analysis contexts for which analysis | 86 * If [running] is true, add the given [context] to the list of analysis |
| 81 * work needs to be performed. Ensure that the work will be performed. | 87 * contexts for which analysis work needs to be performed, and ensure that |
| 88 * the work will be performed. |
| 82 */ | 89 */ |
| 83 void addContextToWorkQueue(AnalysisContext context) { | 90 void addContextToWorkQueue(AnalysisContext context) { |
| 91 if (!running) { |
| 92 return; |
| 93 } |
| 84 if (!contextWorkQueue.contains(context)) { | 94 if (!contextWorkQueue.contains(context)) { |
| 85 contextWorkQueue.add(context); | 95 contextWorkQueue.add(context); |
| 86 run(); | 96 if (contextWorkQueue.length == 1) { |
| 97 // Work queue was previously empty, so schedule analysis. |
| 98 _scheduleTask(); |
| 99 } |
| 87 } | 100 } |
| 88 } | 101 } |
| 89 | 102 |
| 90 /** | 103 /** |
| 91 * The socket from which requests are being read has been closed. | 104 * The socket from which requests are being read has been closed. |
| 92 */ | 105 */ |
| 93 void done() { | 106 void done() { |
| 94 running = false; | 107 running = false; |
| 95 } | 108 } |
| 96 | 109 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 121 } | 134 } |
| 122 channel.sendResponse(new Response.unknownRequest(request)); | 135 channel.sendResponse(new Response.unknownRequest(request)); |
| 123 } | 136 } |
| 124 | 137 |
| 125 /** | 138 /** |
| 126 * Perform the next available task. If a request was received that has not yet | 139 * Perform the next available task. If a request was received that has not yet |
| 127 * been performed, perform it next. Otherwise, look for some analysis that | 140 * been performed, perform it next. Otherwise, look for some analysis that |
| 128 * needs to be done and do that. Otherwise, do nothing. | 141 * needs to be done and do that. Otherwise, do nothing. |
| 129 */ | 142 */ |
| 130 void performTask() { | 143 void performTask() { |
| 144 if (!running) { |
| 145 // An error has occurred, or the connection to the client has been |
| 146 // closed, since performTask() was scheduled on the event queue. So |
| 147 // don't do any analysis. Instead clear the work queue. |
| 148 contextWorkQueue.clear(); |
| 149 } |
| 150 if (contextWorkQueue.isEmpty) { |
| 151 // Nothing to do. |
| 152 return; |
| 153 } |
| 131 // | 154 // |
| 132 // Look for a context that has work to be done and then perform one task. | 155 // Look for a context that has work to be done and then perform one task. |
| 133 // | 156 // |
| 134 if (!contextWorkQueue.isEmpty) { | 157 List<ChangeNotice> notices = null; |
| 158 try { |
| 135 AnalysisContext context = contextWorkQueue[0]; | 159 AnalysisContext context = contextWorkQueue[0]; |
| 136 AnalysisResult result = context.performAnalysisTask(); | 160 AnalysisResult result = context.performAnalysisTask(); |
| 137 List<ChangeNotice> notices = result.changeNotices; | 161 notices = result.changeNotices; |
| 162 } finally { |
| 138 if (notices == null) { | 163 if (notices == null) { |
| 164 // Either we have no more work to do for this context, or there was an |
| 165 // unhandled exception trying to perform the analysis. In either case, |
| 166 // remove the context form the work queue so we won't try to do more |
| 167 // analysis on it. |
| 139 contextWorkQueue.removeAt(0); | 168 contextWorkQueue.removeAt(0); |
| 140 } else { //if (context.analysisOptions.provideErrors) { | 169 } |
| 141 sendNotices(notices); | 170 // |
| 171 // Schedule this method to be run again if there is any more work to be |
| 172 // done. |
| 173 // |
| 174 if (!contextWorkQueue.isEmpty) { |
| 175 _scheduleTask(); |
| 142 } | 176 } |
| 143 } | 177 } |
| 144 // | 178 if (notices != null) { |
| 145 // Schedule this method to be run again if there is any more work to be done
. | 179 sendNotices(notices); |
| 146 // | |
| 147 if (contextWorkQueue.isEmpty) { | |
| 148 running = false; | |
| 149 } else { | |
| 150 new Future(performTask).catchError((ex, st) { | |
| 151 AnalysisEngine.instance.logger.logError("${ex}\n${st}"); | |
| 152 }); | |
| 153 } | 180 } |
| 154 } | 181 } |
| 155 | 182 |
| 156 /** | 183 /** |
| 157 * Send the information in the given list of notices back to the client. | 184 * Send the information in the given list of notices back to the client. |
| 158 */ | 185 */ |
| 159 void sendNotices(List<ChangeNotice> notices) { | 186 void sendNotices(List<ChangeNotice> notices) { |
| 160 for (int i = 0; i < notices.length; i++) { | 187 for (int i = 0; i < notices.length; i++) { |
| 161 ChangeNotice notice = notices[i]; | 188 ChangeNotice notice = notices[i]; |
| 162 Notification notification = new Notification(ERROR_NOTIFICATION_NAME); | 189 Notification notification = new Notification(ERROR_NOTIFICATION_NAME); |
| 163 notification.setParameter(SOURCE_PARAM, notice.source.encoding); | 190 notification.setParameter(SOURCE_PARAM, notice.source.encoding); |
| 164 notification.setParameter(ERRORS_PARAM, notice.errors); | 191 notification.setParameter(ERRORS_PARAM, notice.errors); |
| 165 sendNotification(notification); | 192 sendNotification(notification); |
| 166 } | 193 } |
| 167 } | 194 } |
| 168 | 195 |
| 169 /** | 196 /** |
| 170 * Perform the tasks that are waiting for execution until the server is shut | |
| 171 * down. | |
| 172 */ | |
| 173 void run() { | |
| 174 if (!running) { | |
| 175 running = true; | |
| 176 new Future(performTask).catchError((exception, stackTrace) { | |
| 177 AnalysisEngine.instance.logger.logError(exception); | |
| 178 }); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 /** | |
| 183 * Send the given [notification] to the client. | 197 * Send the given [notification] to the client. |
| 184 */ | 198 */ |
| 185 void sendNotification(Notification notification) { | 199 void sendNotification(Notification notification) { |
| 186 channel.sendNotification(notification); | 200 channel.sendNotification(notification); |
| 187 } | 201 } |
| 202 |
| 203 void _scheduleTask() { |
| 204 new Future(performTask).catchError((ex, st) { |
| 205 AnalysisEngine.instance.logger.logError("${ex}\n${st}"); |
| 206 }); |
| 207 } |
| 188 } | 208 } |
| OLD | NEW |