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

Side by Side Diff: pkg/analysis_server/lib/src/analysis_server.dart

Issue 298823007: add server.status notification (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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';
11 import 'package:analysis_server/src/protocol.dart'; 11 import 'package:analysis_server/src/protocol.dart';
12 import 'package:analyzer/src/generated/engine.dart'; 12 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/error.dart'; 13 import 'package:analyzer/src/generated/error.dart';
14 import 'package:analyzer/src/generated/java_core.dart'; 14 import 'package:analyzer/src/generated/java_core.dart';
15 import 'package:analyzer/src/generated/source.dart';
15 16
16 /** 17 /**
17 * Instances of the class [AnalysisServer] implement a server that listens on a 18 * Instances of the class [AnalysisServer] implement a server that listens on a
18 * [CommunicationChannel] for analysis requests and process them. 19 * [CommunicationChannel] for analysis requests and process them.
19 */ 20 */
20 class AnalysisServer { 21 class AnalysisServer {
21 /** 22 /**
22 * The name of the notification of new errors associated with a source. 23 * The name of the notification of new errors associated with a source.
23 */ 24 */
24 static const String ERROR_NOTIFICATION_NAME = 'context.errors'; 25 static const String ERROR_NOTIFICATION_NAME = 'context.errors';
(...skipping 12 matching lines...) Expand all
37 * The name of the parameter whose value is a source. 38 * The name of the parameter whose value is a source.
38 */ 39 */
39 static const String SOURCE_PARAM = 'source'; 40 static const String SOURCE_PARAM = 'source';
40 41
41 /** 42 /**
42 * The event name of the connected notification. 43 * The event name of the connected notification.
43 */ 44 */
44 static const String CONNECTED_NOTIFICATION = 'server.connected'; 45 static const String CONNECTED_NOTIFICATION = 'server.connected';
45 46
46 /** 47 /**
48 * The event name of the status notification.
49 */
50 static const String STATUS_NOTIFICATION = 'server.status';
51
52 /**
47 * The channel from which requests are received and to which responses should 53 * The channel from which requests are received and to which responses should
48 * be sent. 54 * be sent.
49 */ 55 */
50 final ServerCommunicationChannel channel; 56 final ServerCommunicationChannel channel;
51 57
52 /** 58 /**
53 * A flag indicating whether the server is running. When false, contexts 59 * A flag indicating whether the server is running. When false, contexts
54 * will no longer be added to [contextWorkQueue], and [performTask] will 60 * will no longer be added to [contextWorkQueue], and [performTask] will
55 * discard any tasks it finds on [contextWorkQueue]. 61 * discard any tasks it finds on [contextWorkQueue].
56 */ 62 */
(...skipping 19 matching lines...) Expand all
76 * A list of the analysis contexts for which analysis work needs to be 82 * A list of the analysis contexts for which analysis work needs to be
77 * performed. 83 * performed.
78 * 84 *
79 * Invariant: when this list is non-empty, there is exactly one pending call 85 * Invariant: when this list is non-empty, there is exactly one pending call
80 * to [performTask] on the event queue. When this list is empty, there are 86 * to [performTask] on the event queue. When this list is empty, there are
81 * no calls to [performTask] on the event queue. 87 * no calls to [performTask] on the event queue.
82 */ 88 */
83 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>(); 89 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>();
84 90
85 /** 91 /**
92 * The time at which a status message was sent to the client.
93 */
94 final Stopwatch statusStopwatch = new Stopwatch();
95
96 /**
86 * Initialize a newly created server to receive requests from and send 97 * Initialize a newly created server to receive requests from and send
87 * responses to the given [channel]. 98 * responses to the given [channel].
88 */ 99 */
89 AnalysisServer(this.channel) { 100 AnalysisServer(this.channel) {
90 AnalysisEngine.instance.logger = new AnalysisLogger(); 101 AnalysisEngine.instance.logger = new AnalysisLogger();
91 running = true; 102 running = true;
92 Notification notification = new Notification(CONNECTED_NOTIFICATION); 103 Notification notification = new Notification(CONNECTED_NOTIFICATION);
93 channel.sendNotification(notification); 104 channel.sendNotification(notification);
94 channel.listen(handleRequest, onDone: done, onError: error); 105 channel.listen(handleRequest, onDone: done, onError: error);
95 } 106 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 } 172 }
162 if (contextWorkQueue.isEmpty) { 173 if (contextWorkQueue.isEmpty) {
163 // Nothing to do. 174 // Nothing to do.
164 return; 175 return;
165 } 176 }
166 // 177 //
167 // Look for a context that has work to be done and then perform one task. 178 // Look for a context that has work to be done and then perform one task.
168 // 179 //
169 List<ChangeNotice> notices = null; 180 List<ChangeNotice> notices = null;
170 String contextId; 181 String contextId;
182 AnalysisResult result;
171 try { 183 try {
172 AnalysisContext context = contextWorkQueue[0]; 184 AnalysisContext context = contextWorkQueue[0];
173 contextId = contextIdMap[context]; 185 contextId = contextIdMap[context];
174 AnalysisResult result = context.performAnalysisTask(); 186 result = context.performAnalysisTask();
175 notices = result.changeNotices; 187 notices = result.changeNotices;
176 } finally { 188 } finally {
177 if (notices == null) { 189 if (notices == null) {
178 // Either we have no more work to do for this context, or there was an 190 // Either we have no more work to do for this context, or there was an
179 // unhandled exception trying to perform the analysis. In either case, 191 // unhandled exception trying to perform the analysis. In either case,
180 // remove the context form the work queue so we won't try to do more 192 // remove the context form the work queue so we won't try to do more
181 // analysis on it. 193 // analysis on it.
182 contextWorkQueue.removeAt(0); 194 contextWorkQueue.removeAt(0);
183 } 195 }
184 // 196 //
185 // Schedule this method to be run again if there is any more work to be 197 // Schedule this method to be run again if there is any more work to be
186 // done. 198 // done.
187 // 199 //
188 if (!contextWorkQueue.isEmpty) { 200 if (!contextWorkQueue.isEmpty) {
189 _scheduleTask(); 201 _scheduleTask();
190 } 202 }
191 } 203 }
204 sendStatusNotification(result);
192 if (notices != null) { 205 if (notices != null) {
193 sendNotices(contextId, notices); 206 sendNotices(contextId, notices);
194 } 207 }
195 } 208 }
196 209
197 /** 210 /**
198 * Send the information in the given list of notices back to the client. 211 * Send the information in the given list of notices back to the client.
199 */ 212 */
200 void sendNotices(String contextId, List<ChangeNotice> notices) { 213 void sendNotices(String contextId, List<ChangeNotice> notices) {
201 for (int i = 0; i < notices.length; i++) { 214 for (int i = 0; i < notices.length; i++) {
202 ChangeNotice notice = notices[i]; 215 ChangeNotice notice = notices[i];
203 Notification notification = new Notification(ERROR_NOTIFICATION_NAME); 216 Notification notification = new Notification(ERROR_NOTIFICATION_NAME);
204 notification.setParameter(CONTEXT_ID_PARAM, contextId); 217 notification.setParameter(CONTEXT_ID_PARAM, contextId);
205 notification.setParameter(SOURCE_PARAM, notice.source.encoding); 218 notification.setParameter(SOURCE_PARAM, notice.source.encoding);
206 notification.setParameter(ERRORS_PARAM, notice.errors.map( 219 notification.setParameter(ERRORS_PARAM, notice.errors.map(
207 errorToJson).toList()); 220 errorToJson).toList());
208 sendNotification(notification); 221 sendNotification(notification);
209 } 222 }
210 } 223 }
211 224
225 /**
226 * Send status notification to the client.
227 */
228 void sendStatusNotification(AnalysisResult result) {
229 Notification notification = new Notification(STATUS_NOTIFICATION);
230 if (result.changeNotices != null) {
231 // Throttle status messages to at most 1 every half second
232 if (!statusStopwatch.isRunning) {
233 statusStopwatch.start();
234 } else if (statusStopwatch.elapsedMilliseconds > 500) {
235 statusStopwatch.reset();
236 } else {
237 return;
Paul Berry 2014/05/23 15:56:45 This technique for throttling status notifications
238 }
239 String shortMessage = 'Analyzing';
240 String longMessage = 'Analyzing';
241 if (result.changeNotices.length > 0) {
242 ChangeNotice notice = result.changeNotices[0];
243 if (notice != null) {
244 shortMessage = 'Analyzing ${notice.source.shortName}';
Paul Berry 2014/05/23 15:56:45 Similar concern here. As you've arranged things,
245 longMessage = 'Analyzing ${notice.source.fullName}';
246 }
247 }
248 // TODO(danrubel): improve message once AnalysisResult can provide
249 // something more human readable
250 notification.params['shortMessage'] = shortMessage;
251 notification.params['longMessage'] = longMessage;
252 notification.params['isAnalyzing'] = true;
253 } else {
254 // Reset to ensure notification when analysis starts again
255 statusStopwatch..stop()..reset();
256 notification.params['shortMessage'] = 'Analysis complete';
257 notification.params['longMessage'] = 'Analysis complete';
258 notification.params['isAnalyzing'] = false;
259 }
260 channel.sendNotification(notification);
261 }
262
212 static Map<String, Object> errorToJson(AnalysisError analysisError) { 263 static Map<String, Object> errorToJson(AnalysisError analysisError) {
213 // TODO(paulberry): move this function into the AnalysisError class. 264 // TODO(paulberry): move this function into the AnalysisError class.
214 265
215 // TODO(paulberry): we really shouldn't be exposing errorCode.ordinal 266 // TODO(paulberry): we really shouldn't be exposing errorCode.ordinal
216 // outside the analyzer, since the ordinal numbers change whenever we 267 // outside the analyzer, since the ordinal numbers change whenever we
217 // regenerate the analysis engine. 268 // regenerate the analysis engine.
218 Map<String, Object> result = { 269 Map<String, Object> result = {
219 'source': analysisError.source.encoding, 270 'source': analysisError.source.encoding,
220 'errorCode': (analysisError.errorCode as Enum).ordinal, 271 'errorCode': (analysisError.errorCode as Enum).ordinal,
221 'offset': analysisError.offset, 272 'offset': analysisError.offset,
(...skipping 12 matching lines...) Expand all
234 void sendNotification(Notification notification) { 285 void sendNotification(Notification notification) {
235 channel.sendNotification(notification); 286 channel.sendNotification(notification);
236 } 287 }
237 288
238 void _scheduleTask() { 289 void _scheduleTask() {
239 new Future(performTask).catchError((ex, st) { 290 new Future(performTask).catchError((ex, st) {
240 AnalysisEngine.instance.logger.logError("${ex}\n${st}"); 291 AnalysisEngine.instance.logger.logError("${ex}\n${st}");
241 }); 292 });
242 } 293 }
243 } 294 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/analysis_server_test.dart » ('j') | pkg/analysis_server/test/analysis_server_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698