[Python-modules-commits] [pychromecast] 04/15: Updated socket client.

Ruben Undheim rubund-guest at moszumanska.debian.org
Sat Sep 12 12:30:56 UTC 2015


This is an automated email from the git hooks/post-receive script.

rubund-guest pushed a commit to branch master
in repository pychromecast.

commit beaa6c79899a7986d8599ed95f93a6d339d94a95
Author: Ryan Kraus <rmkraus at gmail.com>
Date:   Sun Aug 23 03:19:54 2015 -0400

    Updated socket client.
    
    The socket client was updated to eliminate nuisance errors. Before,
    errors were regularly thrown that the socket connection was dropped and
    the pychromecast would be reconnecting. This no longer happens.
    
    An error also existed where Chromecast connections were dropped after a
    few hours. It is my guess that this commit will fix this issue, but
    that has not yet been confirmed.
    
    The PING command is also now sent to the Chromecast and the PONG
    response is now handled. Pychromecast now uses this mechanism to
    determine if a socket connection is dropped. PINGs are set every 10
    seconds and a PONG is expected back within 10 seconds. The Chromecast
    will usually automatically PING the client, but not always. Because of
    this, the PINGs sent to the client were not relied upon.
    
    All hardcoded times were brought to the top and put in constants. The
    timeout time was reduced to 30 seconds from 60.
---
 pychromecast/socket_client.py | 57 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 8 deletions(-)

diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py
index 858aa33..1f24521 100644
--- a/pychromecast/socket_client.py
+++ b/pychromecast/socket_client.py
@@ -9,6 +9,7 @@ Without him this would not have been possible.
 # pylint: disable=no-member
 
 import logging
+import select
 import socket
 import ssl
 import json
@@ -48,6 +49,11 @@ APP_ID = 'appId'
 REQUEST_ID = "requestId"
 SESSION_ID = "sessionId"
 
+HB_PING_TIME = 10
+HB_PONG_TIME = 10
+POLL_TIME = 5
+TIMEOUT_TIME = 30
+
 
 def _json_from_message(message):
     """ Parses a PB2 message into JSON format. """
@@ -113,8 +119,9 @@ class SocketClient(threading.Thread):
 
         self.receiver_controller = ReceiverController()
         self.media_controller = MediaController()
+        self.heartbeat_controller = HeartbeatController()
 
-        self.register_handler(HeartbeatController())
+        self.register_handler(self.heartbeat_controller)
         self.register_handler(ConnectionController())
         self.register_handler(self.receiver_controller)
         self.register_handler(self.media_controller)
@@ -147,10 +154,12 @@ class SocketClient(threading.Thread):
         while tries is None or tries > 0:
             try:
                 self.socket = ssl.wrap_socket(socket.socket())
-                self.socket.settimeout(60)
+                self.socket.settimeout(TIMEOUT_TIME)
                 self.socket.connect((self.host, 8009))
                 self.connecting = False
                 self.receiver_controller.update_status()
+                self.heartbeat_controller.ping()
+                self.heartbeat_controller.reset()
 
                 self.logger.debug("Connected!")
                 break
@@ -204,23 +213,36 @@ class SocketClient(threading.Thread):
     def run(self):
         """ Start polling the socket. """
         # pylint: disable=too-many-branches
+        self.heartbeat_controller.reset()
         while not self.stop.is_set():
-            try:
-                message = self._read_message()
-            except socket.error:
-                self.logger.exception(
+
+            # check if connection is expired
+            if self.heartbeat_controller.expired:
+                self.logger.error(
                     "Error communicating with socket, resetting connection")
-                self.initialize_connection()
+                try:
+                    self.initialize_connection()
+                except ChromecastConnectionError:
+                    self.stop.set()
                 continue
 
-            data = _json_from_message(message)
+            # read messages from chromecast
+            can_read, _, _ = select.select([self.socket], [], [], POLL_TIME)
+            if self.socket in can_read:
+                message = self._read_message()
+                data = _json_from_message(message)
+            else:
+                continue
 
+            # route message to handlers
             if message.namespace in self._handlers:
 
+                # debug messages
                 if message.namespace != NS_HEARTBEAT:
                     self.logger.debug(
                         "Received: %s", _message_to_string(message, data))
 
+                # message handlers
                 try:
                     handled = \
                         self._handlers[message.namespace].receive_message(
@@ -424,6 +446,8 @@ class HeartbeatController(BaseController):
     def __init__(self):
         super(HeartbeatController, self).__init__(
             NS_HEARTBEAT, target_platform=True)
+        self.last_ping = 0
+        self.last_pong = time.time()
 
     def receive_message(self, message, data):
         """ Called when a heartbeat message is received. """
@@ -442,13 +466,30 @@ class HeartbeatController(BaseController):
 
             return True
 
+        elif data[MESSAGE_TYPE] == TYPE_PONG:
+            self.reset()
+            return True
+
         else:
             return False
 
     def ping(self):
         """ Send a ping message. """
+        self.last_ping = time.time()
         self.send_message({MESSAGE_TYPE: TYPE_PING})
 
+    def reset(self):
+        """ Reset expired counter. """
+        self.last_pong = time.time()
+
+    @property
+    def expired(self):
+        """ Indicates if connection has expired. """
+        if time.time() - self.last_ping > HB_PING_TIME:
+            self.ping()
+
+        return (time.time() - self.last_pong) > HB_PING_TIME + HB_PONG_TIME
+
 
 class ReceiverController(BaseController):
     """ Controller to interact with the Chromecast platform. """

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pychromecast.git



More information about the Python-modules-commits mailing list