SSL related changes submitted by @almost in pull request tweepy/132
authorScott Barr <scott@signalvsnoise.com>
Thu, 28 Nov 2013 04:44:07 +0000 (12:44 +0800)
committerScott Barr <scott@signalvsnoise.com>
Thu, 28 Nov 2013 04:44:07 +0000 (12:44 +0800)
This commit contains the SSL related changes submitted by @almost in
tweepy/132

I didn't include the delimited changes because this change has not been
merged upstream yet, maybe because the changes are not separate.

tweepy/streaming.py

index 3a5651a49a5493f73b8ab555df0f7b97eba6c0b2..9d56e76eb42bfc18bdb0f8aaf1a85850ce6852a4 100644 (file)
@@ -7,6 +7,7 @@ import httplib
 from socket import timeout
 from threading import Thread
 from time import sleep
+import ssl
 
 from tweepy.models import Status
 from tweepy.api import API
@@ -61,6 +62,10 @@ class StreamListener(object):
         """Called when a new status arrives"""
         return
 
+    def on_exception(self, exception):
+        """Called when an unhandled exception occurs."""
+        return
+
     def on_delete(self, status_id, user_id):
         """Called when a delete notice arrives for a status"""
         return
@@ -96,8 +101,10 @@ class Stream(object):
         self.running = False
         self.timeout = options.get("timeout", 300.0)
         self.retry_count = options.get("retry_count")
-        self.retry_time = options.get("retry_time", 10.0)
-        self.snooze_time = options.get("snooze_time",  5.0)
+        self.retry_time_start = options.get("retry_time", 10.0)
+        self.retry_time_cap = options.get("retry_time_cap", 240.0)
+        self.snooze_time_start = options.get("snooze_time",  0.25)
+        self.snooze_time_cap = options.get("snooze_time_cap",  16)
         self.buffer_size = options.get("buffer_size",  1500)
         if options.get("secure", True):
             self.scheme = "https"
@@ -108,6 +115,8 @@ class Stream(object):
         self.headers = options.get("headers") or {}
         self.parameters = None
         self.body = None
+        self.retry_time = self.retry_time_start
+        self.snooze_time = self.snooze_time_start
 
     def _run(self):
         # Authenticate
@@ -135,17 +144,26 @@ class Stream(object):
                         break
                     error_counter += 1
                     sleep(self.retry_time)
+                    self.retry_time = min(self.retry_time * 2, self.retry_time_cap)
                 else:
                     error_counter = 0
+                    self.retry_time = self.retry_time_start
+                    self.snooze_time = self.snooze_time_start
                     self.listener.on_connect()
                     self._read_loop(resp)
-            except timeout:
+            except (timeout, ssl.SSLError), exc:
+                # If it's not time out treat it like any other exception
+                if isinstance(exc, ssl.SSLError) and not (exc.args and 'timed out' in str(exc.args[0])):
+                    exception = exc
+                    break
+
                 if self.listener.on_timeout() == False:
                     break
                 if self.running is False:
                     break
                 conn.close()
                 sleep(self.snooze_time)
+                self.snooze_time = min(self.snooze_time+0.25, self.snooze_time_cap)
             except Exception, exception:
                 # any other exception is fatal, so kill loop
                 break
@@ -156,6 +174,8 @@ class Stream(object):
             conn.close()
 
         if exception:
+            # call a handler first so that the exception can be logged.
+            self.listener.on_exception(exception)
             raise
 
     def _data(self, data):