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

Side by Side Diff: sdk/lib/io/websocket_impl.dart

Issue 19970004: Add ability to send a ping interval on a WebSocket. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add pingInterval test for server-side and add close-check when sending Created 7 years, 5 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
« no previous file with comments | « sdk/lib/io/websocket.dart ('k') | tests/standalone/io/web_socket_ping_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 part of dart.io; 5 part of dart.io;
6 6
7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8 8
9 class _WebSocketMessageType { 9 class _WebSocketMessageType {
10 static const int NONE = 0; 10 static const int NONE = 0;
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 final _WebSocketImpl webSocket; 448 final _WebSocketImpl webSocket;
449 449
450 _WebSocketOutgoingTransformer(_WebSocketImpl this.webSocket); 450 _WebSocketOutgoingTransformer(_WebSocketImpl this.webSocket);
451 451
452 void handleData(message, EventSink<List<int>> sink) { 452 void handleData(message, EventSink<List<int>> sink) {
453 if (message is _WebSocketPong) { 453 if (message is _WebSocketPong) {
454 addFrame(_WebSocketOpcode.PONG, message.payload, sink); 454 addFrame(_WebSocketOpcode.PONG, message.payload, sink);
455 return; 455 return;
456 } 456 }
457 if (message is _WebSocketPing) { 457 if (message is _WebSocketPing) {
458 addFrame(_WebSocketOpcode.PONG, message.payload, sink); 458 addFrame(_WebSocketOpcode.PING, message.payload, sink);
459 return; 459 return;
460 } 460 }
461 List<int> data; 461 List<int> data;
462 int opcode; 462 int opcode;
463 if (message != null) { 463 if (message != null) {
464 if (message is String) { 464 if (message is String) {
465 opcode = _WebSocketOpcode.TEXT; 465 opcode = _WebSocketOpcode.TEXT;
466 data = _encodeString(message); 466 data = _encodeString(message);
467 } else { 467 } else {
468 if (message is !List<int>) { 468 if (message is !List<int>) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 } 564 }
565 } 565 }
566 } 566 }
567 567
568 568
569 class _WebSocketConsumer implements StreamConsumer { 569 class _WebSocketConsumer implements StreamConsumer {
570 final _WebSocketImpl webSocket; 570 final _WebSocketImpl webSocket;
571 final Socket socket; 571 final Socket socket;
572 StreamController _controller; 572 StreamController _controller;
573 StreamSubscription _subscription; 573 StreamSubscription _subscription;
574 bool _issuedPause = false;
574 Completer _closeCompleter = new Completer(); 575 Completer _closeCompleter = new Completer();
575 Completer _completer; 576 Completer _completer;
576 577
577 _WebSocketConsumer(_WebSocketImpl this.webSocket, Socket this.socket); 578 _WebSocketConsumer(_WebSocketImpl this.webSocket, Socket this.socket);
578 579
579 void _onListen() { 580 void _onListen() {
580 if (_subscription != null) { 581 if (_subscription != null) {
581 _subscription.cancel(); 582 _subscription.cancel();
582 } 583 }
583 } 584 }
584 585
586 void _onPause() {
587 if (_subscription != null) {
588 _subscription.pause();
589 } else {
590 _issuedPause = true;
591 }
592 }
593
594 void _onResume() {
595 if (_subscription != null) {
596 _subscription.resume();
597 } else {
598 _issuedPause = false;
599 }
600 }
601
585 _ensureController() { 602 _ensureController() {
586 if (_controller != null) return; 603 if (_controller != null) return;
587 _controller = new StreamController(sync: true, 604 _controller = new StreamController(sync: true,
588 onPause: () => _subscription.pause(), 605 onPause: _onPause,
589 onResume: () => _subscription.resume(), 606 onResume: _onResume,
590 onCancel: _onListen); 607 onCancel: _onListen);
591 var stream = _controller.stream.transform( 608 var stream = _controller.stream.transform(
592 new _WebSocketOutgoingTransformer(webSocket)); 609 new _WebSocketOutgoingTransformer(webSocket));
593 socket.addStream(stream) 610 socket.addStream(stream)
594 .then((_) { 611 .then((_) {
595 _done(); 612 _done();
596 _closeCompleter.complete(webSocket); 613 _closeCompleter.complete(webSocket);
597 }, 614 },
598 onError: (error) { 615 onError: (error) {
599 if (!_done(error)) { 616 if (!_done(error)) {
(...skipping 20 matching lines...) Expand all
620 (data) { 637 (data) {
621 _controller.add(data); 638 _controller.add(data);
622 }, 639 },
623 onDone: () { 640 onDone: () {
624 _done(); 641 _done();
625 }, 642 },
626 onError: (error) { 643 onError: (error) {
627 _done(error); 644 _done(error);
628 }, 645 },
629 cancelOnError: true); 646 cancelOnError: true);
647 if (_issuedPause) {
648 _subscription.pause();
649 _issuedPause = false;
650 }
630 return _completer.future; 651 return _completer.future;
631 } 652 }
632 653
633 Future close() { 654 Future close() {
634 _ensureController(); 655 _ensureController();
635 Future closeSocket() { 656 Future closeSocket() {
636 return socket.close().then((_) => webSocket); 657 return socket.close().then((_) => webSocket);
637 } 658 }
638 _controller.close(); 659 _controller.close();
639 return _closeCompleter.future.then((_) => closeSocket()); 660 return _closeCompleter.future.then((_) => closeSocket());
640 } 661 }
641 662
642 void add(data) { 663 void add(data) {
643 _ensureController(); 664 _ensureController();
644 _controller.add(data); 665 _controller.add(data);
645 } 666 }
646 } 667 }
647 668
648 669
649 class _WebSocketImpl extends Stream implements WebSocket { 670 class _WebSocketImpl extends Stream implements WebSocket {
650 final StreamController _controller = new StreamController(sync: true); 671 final StreamController _controller = new StreamController(sync: true);
651 StreamSink _sink; 672 StreamSink _sink;
652 673
653 final Socket _socket; 674 final Socket _socket;
654 final bool _serverSide; 675 final bool _serverSide;
655 int _readyState = WebSocket.CONNECTING; 676 int _readyState = WebSocket.CONNECTING;
656 bool _writeClosed = false; 677 bool _writeClosed = false;
657 int _closeCode; 678 int _closeCode;
658 String _closeReason; 679 String _closeReason;
680 Duration _pingInterval;
681 Timer _pingTimer;
682 _WebSocketConsumer _consumer;
659 683
660 int _outCloseCode; 684 int _outCloseCode;
661 String _outCloseReason; 685 String _outCloseReason;
662 686
663 static final HttpClient _httpClient = new HttpClient(); 687 static final HttpClient _httpClient = new HttpClient();
664 688
665 static Future<WebSocket> connect(String url, [protocols]) { 689 static Future<WebSocket> connect(String url, [protocols]) {
666 Uri uri = Uri.parse(url); 690 Uri uri = Uri.parse(url);
667 if (uri.scheme != "ws" && uri.scheme != "wss") { 691 if (uri.scheme != "ws" && uri.scheme != "wss") {
668 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'"); 692 throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'");
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 error("Bad response 'Sec-WebSocket-Accept' header"); 751 error("Bad response 'Sec-WebSocket-Accept' header");
728 } 752 }
729 } 753 }
730 return response.detachSocket() 754 return response.detachSocket()
731 .then((socket) => new _WebSocketImpl._fromSocket(socket)); 755 .then((socket) => new _WebSocketImpl._fromSocket(socket));
732 }); 756 });
733 } 757 }
734 758
735 _WebSocketImpl._fromSocket(Socket this._socket, 759 _WebSocketImpl._fromSocket(Socket this._socket,
736 [bool this._serverSide = false]) { 760 [bool this._serverSide = false]) {
737 var consumer = new _WebSocketConsumer(this, _socket); 761 _consumer = new _WebSocketConsumer(this, _socket);
738 _sink = new _StreamSinkImpl(consumer); 762 _sink = new _StreamSinkImpl(_consumer);
739 _readyState = WebSocket.OPEN; 763 _readyState = WebSocket.OPEN;
740 764
741 var transformer = new _WebSocketProtocolTransformer(_serverSide); 765 var transformer = new _WebSocketProtocolTransformer(_serverSide);
742 _socket.transform(transformer).listen( 766 _socket.transform(transformer).listen(
743 (data) { 767 (data) {
744 if (data is _WebSocketPing) { 768 if (data is _WebSocketPing) {
745 consumer.add(new _WebSocketPong(data.payload)); 769 if (!_writeClosed) _consumer.add(new _WebSocketPong(data.payload));
746 } else if (data is _WebSocketPong) { 770 } else if (data is _WebSocketPong) {
747 // TODO(ajohnsen): Notify pong? 771 // Simply set pingInterval, as it'll cancel any timers.
772 pingInterval = _pingInterval;
748 } else { 773 } else {
749 _controller.add(data); 774 _controller.add(data);
750 } 775 }
751 }, 776 },
752 onError: (error) { 777 onError: (error) {
753 if (error is ArgumentError) { 778 if (error is ArgumentError) {
754 close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA); 779 close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
755 } else { 780 } else {
756 close(WebSocketStatus.PROTOCOL_ERROR); 781 close(WebSocketStatus.PROTOCOL_ERROR);
757 } 782 }
(...skipping 20 matching lines...) Expand all
778 StreamSubscription listen(void onData(message), 803 StreamSubscription listen(void onData(message),
779 {void onError(error), 804 {void onError(error),
780 void onDone(), 805 void onDone(),
781 bool cancelOnError}) { 806 bool cancelOnError}) {
782 return _controller.stream.listen(onData, 807 return _controller.stream.listen(onData,
783 onError: onError, 808 onError: onError,
784 onDone: onDone, 809 onDone: onDone,
785 cancelOnError: cancelOnError); 810 cancelOnError: cancelOnError);
786 } 811 }
787 812
813 Duration get pingnterval => _pingInterval;
814
815 void set pingInterval(Duration interval) {
816 if (_writeClosed) return;
817 if (_pingTimer != null) _pingTimer.cancel();
818 _pingInterval = interval;
819
820 if (_pingInterval == null) return;
821
822 _pingTimer = new Timer(_pingInterval, () {
823 if (_writeClosed) return;
824 _consumer.add(new _WebSocketPing());
825 _pingTimer = new Timer(_pingInterval, () {
826 // No pong received.
827 close(WebSocketStatus.GOING_AWAY);
828 });
829 });
830 }
831
788 int get readyState => _readyState; 832 int get readyState => _readyState;
789 833
790 String get extensions => null; 834 String get extensions => null;
791 String get protocol => null; 835 String get protocol => null;
792 int get closeCode => _closeCode; 836 int get closeCode => _closeCode;
793 String get closeReason => _closeReason; 837 String get closeReason => _closeReason;
794 838
795 void add(data) => _sink.add(data); 839 void add(data) => _sink.add(data);
796 void addError(error) => _sink.addError(error); 840 void addError(error) => _sink.addError(error);
797 Future addStream(Stream stream) => _sink.addStream(stream); 841 Future addStream(Stream stream) => _sink.addStream(stream);
(...skipping 16 matching lines...) Expand all
814 (code < WebSocketStatus.NORMAL_CLOSURE || 858 (code < WebSocketStatus.NORMAL_CLOSURE ||
815 code == WebSocketStatus.RESERVED_1004 || 859 code == WebSocketStatus.RESERVED_1004 ||
816 code == WebSocketStatus.NO_STATUS_RECEIVED || 860 code == WebSocketStatus.NO_STATUS_RECEIVED ||
817 code == WebSocketStatus.ABNORMAL_CLOSURE || 861 code == WebSocketStatus.ABNORMAL_CLOSURE ||
818 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && 862 (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
819 code < WebSocketStatus.RESERVED_1015) || 863 code < WebSocketStatus.RESERVED_1015) ||
820 (code >= WebSocketStatus.RESERVED_1015 && 864 (code >= WebSocketStatus.RESERVED_1015 &&
821 code < 3000)); 865 code < 3000));
822 } 866 }
823 } 867 }
OLDNEW
« no previous file with comments | « sdk/lib/io/websocket.dart ('k') | tests/standalone/io/web_socket_ping_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698