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

Side by Side Diff: samples/chat/chat_server_lib.dart

Issue 9495007: Prepare the HTTP library for inclusion in the standalone VM (step 2) (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 9 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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("chat_server"); 5 #library("chat_server");
6 #import("dart:io"); 6 #import("dart:io");
7 #import("dart:json"); 7 #import("dart:json");
8 #import("dart:isolate"); 8 #import("dart:isolate");
9 #import("http.dart"); 9 #import("http.dart");
10 10
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 _serverPort = port; 50 _serverPort = port;
51 _start(hostAddress, tcpPort, listenBacklog); 51 _start(hostAddress, tcpPort, listenBacklog);
52 }); 52 });
53 // We can only guess this is the right URL. At least it gives a 53 // We can only guess this is the right URL. At least it gives a
54 // hint to the user. 54 // hint to the user.
55 print('Server starting http://${hostAddress}:${tcpPort}/'); 55 print('Server starting http://${hostAddress}:${tcpPort}/');
56 } 56 }
57 57
58 void _start(String hostAddress, int tcpPort, int listenBacklog) { 58 void _start(String hostAddress, int tcpPort, int listenBacklog) {
59 // Handle status messages from the server. 59 // Handle status messages from the server.
60 _statusPort.receive( 60 _statusPort.receive((var message, SendPort replyTo) {
61 void _(var message, SendPort replyTo) { 61 String status = message.message;
62 String status = message.message; 62 print("Received status: $status");
63 print("Received status: $status"); 63 });
64 });
65 64
66 // Send server start message to the server. 65 // Send server start message to the server.
67 var command = new ChatServerCommand.start(hostAddress, 66 var command = new ChatServerCommand.start(hostAddress,
68 tcpPort, 67 tcpPort,
69 backlog: listenBacklog); 68 backlog: listenBacklog);
70 _serverPort.send(command, _statusPort.toSendPort()); 69 _serverPort.send(command, _statusPort.toSendPort());
71 } 70 }
72 71
73 void shutdown() { 72 void shutdown() {
74 // Send server stop message to the server. 73 // Send server stop message to the server.
(...skipping 22 matching lines...) Expand all
97 String _handle; 96 String _handle;
98 String _sessionId; 97 String _sessionId;
99 Date _lastActive; 98 Date _lastActive;
100 } 99 }
101 100
102 101
103 class Message { 102 class Message {
104 static final int JOIN = 0; 103 static final int JOIN = 0;
105 static final int MESSAGE = 1; 104 static final int MESSAGE = 1;
106 static final int LEAVE = 2; 105 static final int LEAVE = 2;
107 static final int TIMEOUT = 2; 106 static final int TIMEOUT = 3;
108 static final List<String> _typeName = 107 static final List<String> _typeName =
109 const [ "join", "message", "leave", "timeout"]; 108 const [ "join", "message", "leave", "timeout"];
110 109
111 Message.join(this._from) 110 Message.join(this._from)
112 : _received = new Date.now(), _type = JOIN; 111 : _received = new Date.now(), _type = JOIN;
113 Message(this._from, this._message) 112 Message(this._from, this._message)
114 : _received = new Date.now(), _type = MESSAGE; 113 : _received = new Date.now(), _type = MESSAGE;
115 Message.leave(this._from) 114 Message.leave(this._from)
116 : _received = new Date.now(), _type = LEAVE; 115 : _received = new Date.now(), _type = LEAVE;
117 Message.timeout(this._from) 116 Message.timeout(this._from)
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 _activeUsers.remove(sessionId); 166 _activeUsers.remove(sessionId);
168 } 167 }
169 168
170 bool _addMessage(Message message) { 169 bool _addMessage(Message message) {
171 message.messageNumber = _nextMessageNumber++; 170 message.messageNumber = _nextMessageNumber++;
172 _messages.add(message); 171 _messages.add(message);
173 172
174 // Send the new message to all polling clients. 173 // Send the new message to all polling clients.
175 List messages = new List(); 174 List messages = new List();
176 messages.add(message.toMap()); 175 messages.add(message.toMap());
177 _callbacks.forEach( 176 _callbacks.forEach((String sessionId, Function callback) {
178 void _(String sessionId, Function callback) { 177 callback(messages);
179 callback(messages); 178 });
180 });
181 _callbacks = new Map(); 179 _callbacks = new Map();
182 } 180 }
183 181
184 bool _userMessage(Map requestData) { 182 bool _userMessage(Map requestData) {
185 String sessionId = requestData["sessionId"]; 183 String sessionId = requestData["sessionId"];
186 User user = _userLookup(sessionId); 184 User user = _userLookup(sessionId);
187 if (user == null) return false; 185 if (user == null) return false;
188 String handle = user.handle; 186 String handle = user.handle;
189 String messageText = requestData["message"]; 187 String messageText = requestData["message"];
190 if (messageText == null) return false; 188 if (messageText == null) return false;
(...skipping 24 matching lines...) Expand all
215 } 213 }
216 214
217 void registerChangeCallback(String sessionId, var callback) { 215 void registerChangeCallback(String sessionId, var callback) {
218 _callbacks[sessionId] = callback; 216 _callbacks[sessionId] = callback;
219 } 217 }
220 218
221 void _handleTimer(Timer timer) { 219 void _handleTimer(Timer timer) {
222 Set inactiveSessions = new Set(); 220 Set inactiveSessions = new Set();
223 // Collect all sessions which have not been active for some time. 221 // Collect all sessions which have not been active for some time.
224 Date now = new Date.now(); 222 Date now = new Date.now();
225 _activeUsers.forEach( 223 _activeUsers.forEach((String sessionId, User user) {
226 void _(String sessionId, User user) { 224 if (user.idleTime(now).inMilliseconds > DEFAULT_IDLE_TIMEOUT) {
227 if (user.idleTime(now).inMilliseconds > DEFAULT_IDLE_TIMEOUT) { 225 inactiveSessions.add(sessionId);
228 inactiveSessions.add(sessionId); 226 }
229 } 227 });
230 });
231 // Terminate the inactive sessions. 228 // Terminate the inactive sessions.
232 inactiveSessions.forEach( 229 inactiveSessions.forEach((String sessionId) {
233 void _(String sessionId) { 230 Function callback = _callbacks.remove(sessionId);
234 Function callback = _callbacks.remove(sessionId); 231 if (callback != null) callback(null);
235 if (callback != null) callback(null); 232 User user = _activeUsers.remove(sessionId);
236 User user = _activeUsers.remove(sessionId); 233 Message message = new Message.timeout(user);
237 Message message = new Message.timeout(user); 234 _addMessage(message);
238 _addMessage(message); 235 });
239 });
240
241 } 236 }
242 237
243 Map<String, User> _activeUsers; 238 Map<String, User> _activeUsers;
244 List<Message> _messages; 239 List<Message> _messages;
245 int _nextMessageNumber; 240 int _nextMessageNumber;
246 Map<String, Function> _callbacks; 241 Map<String, Function> _callbacks;
247 } 242 }
248 243
249 244
250 class ChatServerCommand { 245 class ChatServerCommand {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 if (extension == ".js") { mimeType = "application/javascript"; } 371 if (extension == ".js") { mimeType = "application/javascript"; }
377 if (extension == ".ico") { mimeType = "image/vnd.microsoft.icon"; } 372 if (extension == ".ico") { mimeType = "image/vnd.microsoft.icon"; }
378 if (extension == ".png") { mimeType = "image/png"; } 373 if (extension == ".png") { mimeType = "image/png"; }
379 } 374 }
380 response.setHeader("Content-Type", mimeType); 375 response.setHeader("Content-Type", mimeType);
381 // Get the length of the file for setting the Content-Length header. 376 // Get the length of the file for setting the Content-Length header.
382 RandomAccessFile openedFile = file.openSync(); 377 RandomAccessFile openedFile = file.openSync();
383 response.contentLength = openedFile.lengthSync(); 378 response.contentLength = openedFile.lengthSync();
384 openedFile.close(); 379 openedFile.close();
385 // Pipe the file content into the response. 380 // Pipe the file content into the response.
386 file.openInputStream().pipe(response.outputStream); 381 file.openInputStreamSync().pipe(response.outputStream);
387 } else { 382 } else {
388 print("File not found: $fileName"); 383 print("File not found: $fileName");
389 _notFoundHandler(request, response); 384 _notFoundHandler(request, response);
390 } 385 }
391 } 386 }
392 387
393 // Serve the not found page. 388 // Serve the not found page.
394 void _notFoundHandler(HTTPRequest request, HTTPResponse response) { 389 void _notFoundHandler(HTTPRequest request, HTTPResponse response) {
395 if (_notFoundPage == null) { 390 if (_notFoundPage == null) {
396 _notFoundPage = notFoundPageHtml.charCodes(); 391 _notFoundPage = notFoundPageHtml.charCodes();
397 } 392 }
398 response.statusCode = HTTPStatus.NOT_FOUND; 393 response.statusCode = HTTPStatus.NOT_FOUND;
399 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 394 response.setHeader("Content-Type", "text/html; charset=UTF-8");
400 response.contentLength = _notFoundPage.length; 395 response.contentLength = _notFoundPage.length;
401 response.outputStream.write(_notFoundPage); 396 response.outputStream.write(_notFoundPage);
402 response.outputStream.close(); 397 response.outputStream.close();
403 } 398 }
404 399
405 // Unexpected protocol data. 400 // Unexpected protocol data.
406 void _protocolError(HTTPRequest request, HTTPResponse response) { 401 void _protocolError(HTTPRequest request, HTTPResponse response) {
407 response.statusCode = HTTPStatus.INTERNAL_SERVER_ERROR; 402 response.statusCode = HTTPStatus.INTERNAL_SERVER_ERROR;
408 response.contentLength = 0; 403 response.contentLength = 0;
409 response.outputStream.close(); 404 response.outputStream.close();
410 } 405 }
411 406
412 // Join request: 407 // Join request:
413 // { "request": "join", 408 // { "request": "join",
414 // "handle": <handle> } 409 // "handle": <handle> }
415 void _joinHandler(HTTPRequest request, HTTPResponse response) { 410 void _joinHandler(HTTPRequest request, HTTPResponse response) {
416 void dataEndHandler(String data) { 411 StringBuffer body = new StringBuffer();
Anders Johnsen 2012/02/28 12:23:40 It could be nice to have a StringBuffer.fromStream
Mads Ager (google) 2012/02/28 12:27:40 I agree that we should get back to a situation whe
Søren Gjesse 2012/02/28 13:03:42 As discussed offline I will add a simple way to ge
412 StringInputStream input = new StringInputStream(request.inputStream);
413 input.dataHandler = () => body.add(input.read());
414 input.closeHandler = () {
415 String data = body.toString();
417 if (data != null) { 416 if (data != null) {
418 var requestData = JSON.parse(data); 417 var requestData = JSON.parse(data);
419 if (requestData["request"] == "join") { 418 if (requestData["request"] == "join") {
420 String handle = requestData["handle"]; 419 String handle = requestData["handle"];
421 if (handle != null) { 420 if (handle != null) {
422 // New user joining. 421 // New user joining.
423 User user = _topic._userJoined(handle); 422 User user = _topic._userJoined(handle);
424 423
425 // Send response. 424 // Send response.
426 Map responseData = new Map(); 425 Map responseData = new Map();
427 responseData["response"] = "join"; 426 responseData["response"] = "join";
428 responseData["sessionId"] = user.sessionId; 427 responseData["sessionId"] = user.sessionId;
429 _sendJSONResponse(response, responseData); 428 _sendJSONResponse(response, responseData);
430 } else { 429 } else {
431 _protocolError(request, response); 430 _protocolError(request, response);
432 } 431 }
433 } else { 432 } else {
434 _protocolError(request, response); 433 _protocolError(request, response);
435 } 434 }
436 } else { 435 } else {
437 _protocolError(request, response); 436 _protocolError(request, response);
438 } 437 }
439 } 438 };
440
441 // Register callback for full request data.
442 request.dataEnd = dataEndHandler;
443 } 439 }
444 440
445 // Leave request: 441 // Leave request:
446 // { "request": "leave", 442 // { "request": "leave",
447 // "sessionId": <sessionId> } 443 // "sessionId": <sessionId> }
448 void _leaveHandler(HTTPRequest request, HTTPResponse response) { 444 void _leaveHandler(HTTPRequest request, HTTPResponse response) {
449 void dataEndHandler(String data) { 445 StringBuffer body = new StringBuffer();
446 StringInputStream input = new StringInputStream(request.inputStream);
447 input.dataHandler = () => body.add(input.read());
448 input.closeHandler = () {
449 String data = body.toString();
450 var requestData = JSON.parse(data); 450 var requestData = JSON.parse(data);
451 if (requestData["request"] == "leave") { 451 if (requestData["request"] == "leave") {
452 String sessionId = requestData["sessionId"]; 452 String sessionId = requestData["sessionId"];
453 if (sessionId != null) { 453 if (sessionId != null) {
454 // User leaving. 454 // User leaving.
455 _topic._userLeft(sessionId); 455 _topic._userLeft(sessionId);
456 456
457 // Send response. 457 // Send response.
458 Map responseData = new Map(); 458 Map responseData = new Map();
459 responseData["response"] = "leave"; 459 responseData["response"] = "leave";
460 _sendJSONResponse(response, responseData); 460 _sendJSONResponse(response, responseData);
461 } else { 461 } else {
462 _protocolError(request, response); 462 _protocolError(request, response);
463 } 463 }
464 } else { 464 } else {
465 _protocolError(request, response); 465 _protocolError(request, response);
466 } 466 }
467 } 467 };
468
469 request.dataEnd = dataEndHandler;
470 } 468 }
471 469
472 // Message request: 470 // Message request:
473 // { "request": "message", 471 // { "request": "message",
474 // "sessionId": <sessionId>, 472 // "sessionId": <sessionId>,
475 // "message": <message> } 473 // "message": <message> }
476 void _messageHandler(HTTPRequest request, HTTPResponse response) { 474 void _messageHandler(HTTPRequest request, HTTPResponse response) {
477 void dataEndHandler(String data) { 475 StringBuffer body = new StringBuffer();
476 StringInputStream input = new StringInputStream(request.inputStream);
477 input.dataHandler = () => body.add(input.read());
478 input.closeHandler = () {
479 String data = body.toString();
478 _messageCount++; 480 _messageCount++;
479 _messageRate.record(1); 481 _messageRate.record(1);
480 var requestData = JSON.parse(data); 482 var requestData = JSON.parse(data);
481 if (requestData["request"] == "message") { 483 if (requestData["request"] == "message") {
482 String sessionId = requestData["sessionId"]; 484 String sessionId = requestData["sessionId"];
483 if (sessionId != null) { 485 if (sessionId != null) {
484 // New message from user. 486 // New message from user.
485 bool success = _topic._userMessage(requestData); 487 bool success = _topic._userMessage(requestData);
486 488
487 // Send response. 489 // Send response.
488 if (success) { 490 if (success) {
489 Map responseData = new Map(); 491 Map responseData = new Map();
490 responseData["response"] = "message"; 492 responseData["response"] = "message";
491 _sendJSONResponse(response, responseData); 493 _sendJSONResponse(response, responseData);
492 } else { 494 } else {
493 _protocolError(request, response); 495 _protocolError(request, response);
494 } 496 }
495 } else { 497 } else {
496 _protocolError(request, response); 498 _protocolError(request, response);
497 } 499 }
498 } else { 500 } else {
499 _protocolError(request, response); 501 _protocolError(request, response);
500 } 502 }
501 } 503 };
502
503 request.dataEnd = dataEndHandler;
504 } 504 }
505 505
506 // Receive request: 506 // Receive request:
507 // { "request": "receive", 507 // { "request": "receive",
508 // "sessionId": <sessionId>, 508 // "sessionId": <sessionId>,
509 // "nextMessage": <nextMessage>, 509 // "nextMessage": <nextMessage>,
510 // "maxMessages": <maxMesssages> } 510 // "maxMessages": <maxMesssages> }
511 void _receiveHandler(HTTPRequest request, HTTPResponse response) { 511 void _receiveHandler(HTTPRequest request, HTTPResponse response) {
512 void dataEndHandler(String data) { 512 StringBuffer body = new StringBuffer();
513 StringInputStream input = new StringInputStream(request.inputStream);
514 input.dataHandler = () => body.add(input.read());
515 input.closeHandler = () {
516 String data = body.toString();
513 var requestData = JSON.parse(data); 517 var requestData = JSON.parse(data);
514 if (requestData["request"] == "receive") { 518 if (requestData["request"] == "receive") {
515 String sessionId = requestData["sessionId"]; 519 String sessionId = requestData["sessionId"];
516 int nextMessage = requestData["nextMessage"]; 520 int nextMessage = requestData["nextMessage"];
517 int maxMessages = requestData["maxMessages"]; 521 int maxMessages = requestData["maxMessages"];
518 if (sessionId != null && nextMessage != null) { 522 if (sessionId != null && nextMessage != null) {
519 523
520 void sendResponse(messages) { 524 void sendResponse(messages) {
521 // Send response. 525 // Send response.
522 Map responseData = new Map(); 526 Map responseData = new Map();
(...skipping 16 matching lines...) Expand all
539 } else { 543 } else {
540 sendResponse(messages); 544 sendResponse(messages);
541 } 545 }
542 546
543 } else { 547 } else {
544 _protocolError(request, response); 548 _protocolError(request, response);
545 } 549 }
546 } else { 550 } else {
547 _protocolError(request, response); 551 _protocolError(request, response);
548 } 552 }
549 } 553 };
550
551 request.dataEnd = dataEndHandler;
552 } 554 }
553 555
554 void addHandler(String path, 556 void addHandler(String path,
555 void handler(HTTPRequest request, HTTPResponse response)) { 557 void handler(HTTPRequest request, HTTPResponse response)) {
556 _requestHandlers[path] = handler; 558 _requestHandlers[path] = handler;
557 } 559 }
558 560
559 void main() { 561 void main() {
560 _logRequests = false; 562 _logRequests = false;
561 _topic = new Topic(); 563 _topic = new Topic();
562 _serverStart = new Date.now(); 564 _serverStart = new Date.now();
563 _messageCount = 0; 565 _messageCount = 0;
564 _messageRate = new Rate(); 566 _messageRate = new Rate();
565 567
566 // Start a timer for cleanup events. 568 // Start a timer for cleanup events.
567 _cleanupTimer = 569 _cleanupTimer =
568 new Timer.repeating((timer) => _topic._handleTimer(timer), 10000); 570 new Timer.repeating((timer) => _topic._handleTimer(timer), 10000);
569 571
570 // Start timer for periodic logging. 572 // Start timer for periodic logging.
571 void _handleLogging(Timer timer) { 573 void _handleLogging(Timer timer) {
572 if (_logging) { 574 if (_logging) {
573 print((_messageRate.rate).toString() + 575 print((_messageRate.rate).toString() +
574 " messages/s (total " + 576 " messages/s (total " +
575 _messageCount + 577 _messageCount +
576 " messages)"); 578 " messages)");
577 } 579 }
578 } 580 }
579 581
580 this.port.receive( 582 this.port.receive((var message, SendPort replyTo) {
581 void _(var message, SendPort replyTo) { 583 if (message.isStart) {
582 if (message.isStart) { 584 _host = message.host;
583 _host = message.host; 585 _port = message.port;
584 _port = message.port; 586 _logging = message.logging;
585 _logging = message.logging; 587 replyTo.send(new ChatServerStatus.starting(), null);
586 replyTo.send(new ChatServerStatus.starting(), null); 588 _server = new HTTPServer();
587 _server = new HTTPServer(); 589 try {
588 try { 590 _server.listen(_host, _port, backlog: message.backlog);
589 _server.listen(_host, _port, backlog: message.backlog); 591 _server.requestHandler = (HTTPRequest req, HTTPResponse rsp) =>
590 _server.requestHandler = (HTTPRequest req, HTTPResponse rsp) => 592 _requestReceivedHandler(req, rsp);
591 _requestReceivedHandler(req, rsp); 593 replyTo.send(new ChatServerStatus.started(_server.port), null);
592 replyTo.send(new ChatServerStatus.started(_server.port), null); 594 _loggingTimer = new Timer.repeating(_handleLogging, 1000);
593 _loggingTimer = new Timer.repeating(_handleLogging, 1000); 595 } catch (var e) {
594 } catch (var e) { 596 replyTo.send(new ChatServerStatus.error(e.toString()), null);
595 replyTo.send(new ChatServerStatus.error(e.toString()), null); 597 }
596 } 598 } else if (message.isStop) {
597 } else if (message.isStop) { 599 replyTo.send(new ChatServerStatus.stopping(), null);
598 replyTo.send(new ChatServerStatus.stopping(), null); 600 stop();
599 stop(); 601 replyTo.send(new ChatServerStatus.stopped(), null);
600 replyTo.send(new ChatServerStatus.stopped(), null); 602 }
601 } 603 });
602 });
603 } 604 }
604 605
605 stop() { 606 stop() {
606 _server.close(); 607 _server.close();
607 _cleanupTimer.cancel(); 608 _cleanupTimer.cancel();
608 this.port.close(); 609 this.port.close();
609 } 610 }
610 611
611 void _requestReceivedHandler(HTTPRequest request, HTTPResponse response) { 612 void _requestReceivedHandler(HTTPRequest request, HTTPResponse response) {
612 if (_logRequests) { 613 if (_logRequests) {
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 } 710 }
710 } 711 }
711 712
712 int _timeRange; 713 int _timeRange;
713 List<int> _buckets; 714 List<int> _buckets;
714 int _currentBucket; 715 int _currentBucket;
715 int _currentBucketTime; 716 int _currentBucketTime;
716 num _bucketTimeRange; 717 num _bucketTimeRange;
717 int _sum; 718 int _sum;
718 } 719 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698