This commit is contained in:
Roy Hyunjin Han 2015-02-15 10:20:11 -05:00
commit 18cf130d9e
3 changed files with 88 additions and 32 deletions

View file

@ -1,4 +1,3 @@
Use HTTP headers for Websocket connection #44
Do not connect to blank namespace if overriding default namespace exists #40
Pass wait timeout to underlying transports #34
Check that we have the correct version of websocket #62

View file

@ -34,9 +34,6 @@ class BaseNamespace(object):
self._callback_by_event = {}
self.initialize()
def _log(self, level, msg, *attrs):
_log.log(level, '%s: %s' % (self._transport._url, msg), *attrs)
def initialize(self):
'Initialize custom variables here; you can override this method'
pass
@ -57,19 +54,19 @@ class BaseNamespace(object):
def on_connect(self):
'Called after server connects; you can override this method'
self._log(logging.DEBUG, '%s [connect]', self.path)
pass
def on_disconnect(self):
'Called after server disconnects; you can override this method'
self._log(logging.DEBUG, '%s [disconnect]', self.path)
pass
def on_heartbeat(self):
'Called after server sends a heartbeat; you can override this method'
self._log(logging.DEBUG, '%s [heartbeat]', self.path)
pass
def on_message(self, data):
'Called after server sends a message; you can override this method'
self._log(logging.INFO, '%s [message] %s', self.path, data)
pass
def on_event(self, event, *args):
"""
@ -78,32 +75,28 @@ class BaseNamespace(object):
such as one defined by namespace.on('my_event', my_function).
"""
callback, args = find_callback(args)
arguments = [repr(_) for _ in args]
if callback:
arguments.append('callback(*args)')
callback(*args)
self._log(logging.INFO, '%s [event] %s(%s)', self.path, event,
', '.join(arguments))
def on_error(self, reason, advice):
'Called after server sends an error; you can override this method'
self._log(logging.INFO, '%s [error] %s', self.path, advice)
pass
def on_noop(self):
'Called after server sends a noop; you can override this method'
self._log(logging.INFO, '%s [noop]', self.path)
pass
def on_open(self, *args):
self._log(logging.INFO, '%s [open] %s', self.path, args)
pass
def on_close(self, *args):
self._log(logging.INFO, '%s [close] %s', self.path, args)
pass
def on_retry(self, *args):
self._log(logging.INFO, '%s [retry] %s', self.path, args)
pass
def on_reconnect(self, *args):
self._log(logging.INFO, '%s [reconnect] %s', self.path, args)
pass
def _find_event_callback(self, event):
# Check callbacks defined by on()
@ -111,15 +104,12 @@ class BaseNamespace(object):
return self._callback_by_event[event]
except KeyError:
pass
# Convert connect to reconnect if we have seen connect
# already.
# Convert connect to reconnect if we have seen connect already
if event == 'connect':
if self.was_connected == False:
if not self.was_connected:
self.was_connected = True
else:
event = 'reconnect'
# Check callbacks defined explicitly or use on_event()
return getattr(
self,
@ -127,6 +117,61 @@ class BaseNamespace(object):
lambda *args: self.on_event(event, *args))
class LoggingNamespace(BaseNamespace):
def _log(self, level, msg, *attrs):
_log.log(level, '%s: %s' % (self._transport._url, msg), *attrs)
def on_connect(self):
self._log(logging.DEBUG, '%s [connect]', self.path)
super(LoggingNamespace, self).on_connect()
def on_disconnect(self):
self._log(logging.DEBUG, '%s [disconnect]', self.path)
super(LoggingNamespace, self).on_disconnect()
def on_heartbeat(self):
self._log(logging.DEBUG, '%s [heartbeat]', self.path)
super(LoggingNamespace, self).on_heartbeat()
def on_message(self, data):
self._log(logging.INFO, '%s [message] %s', self.path, data)
super(LoggingNamespace, self).on_message(data)
def on_event(self, event, *args):
callback, args = find_callback(args)
arguments = [repr(_) for _ in args]
if callback:
arguments.append('callback(*args)')
self._log(logging.INFO, '%s [event] %s(%s)', self.path, event,
', '.join(arguments))
super(LoggingNamespace, self).on_event(event, *args)
def on_error(self, reason, advice):
self._log(logging.INFO, '%s [error] %s', self.path, advice)
super(LoggingNamespace, self).on_error(reason, advice)
def on_noop(self):
self._log(logging.INFO, '%s [noop]', self.path)
super(LoggingNamespace, self).on_noop()
def on_open(self, *args):
self._log(logging.INFO, '%s [open] %s', self.path, args)
super(LoggingNamespace, self).on_open(*args)
def on_close(self, *args):
self._log(logging.INFO, '%s [close] %s', self.path, args)
super(LoggingNamespace, self).on_close(*args)
def on_retry(self, *args):
self._log(logging.INFO, '%s [retry] %s', self.path, args)
super(LoggingNamespace, self).on_retry(*args)
def on_reconnect(self, *args):
self._log(logging.INFO, '%s [reconnect] %s', self.path, args)
super(LoggingNamespace, self).on_reconnect(*args)
class SocketIO(object):
"""Create a socket.io client that connects to a socket.io server
@ -147,14 +192,16 @@ class SocketIO(object):
"""
def __init__(
self, host, port=None, Namespace=BaseNamespace,
wait_for_connection=True, transports=TRANSPORTS, resource='socket.io', **kw):
self, host, port=None, Namespace=None,
wait_for_connection=True, transports=TRANSPORTS,
resource='socket.io', **kw):
self.is_secure, self.base_url = _parse_host(host, port, resource)
self.wait_for_connection = wait_for_connection
self._namespace_by_path = {}
self.client_supported_transports = transports
self.kw = kw
self.define(Namespace)
if Namespace:
self.define(Namespace)
def log(self, level, msg, *attrs):
_log.log(level, '%s: %s' % (self.base_url, msg),
@ -177,6 +224,8 @@ class SocketIO(object):
return namespace
def on(self, event, callback, path=''):
if path not in self._namespace_by_path:
self.define(BaseNamespace, path)
return self.get_namespace(path).on(event, callback)
def message(self, data='', callback=None, path=''):
@ -237,10 +286,12 @@ class SocketIO(object):
def disconnect(self, path=''):
if self.connected:
self._transport.disconnect(path)
namespace = self._namespace_by_path[path]
namespace.on_disconnect()
if path:
del self._namespace_by_path[path]
try:
namespace = self._namespace_by_path[path]
namespace.on_disconnect()
except KeyError:
pass
del self._namespace_by_path[path]
@property
def connected(self):

View file

@ -2,7 +2,7 @@ import logging
import time
from unittest import TestCase
from . import SocketIO, BaseNamespace, find_callback
from . import SocketIO, LoggingNamespace, find_callback
from .transports import TIMEOUT_IN_SECONDS
@ -31,6 +31,7 @@ class BaseMixin(object):
def test_disconnect(self):
'Disconnect'
self.socketIO.define(LoggingNamespace)
self.assertTrue(self.socketIO.connected)
self.socketIO.disconnect()
self.assertFalse(self.socketIO.connected)
@ -65,12 +66,14 @@ class BaseMixin(object):
def test_message_with_callback(self):
'Message with callback'
self.socketIO.define(LoggingNamespace)
self.socketIO.message(callback=self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
self.assertTrue(self.called_on_response)
def test_message_with_callback_with_data(self):
'Message with callback with data'
self.socketIO.define(LoggingNamespace)
self.socketIO.message(DATA, self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
self.assertTrue(self.called_on_response)
@ -104,12 +107,14 @@ class BaseMixin(object):
def test_emit_with_callback(self):
'Emit with callback'
self.socketIO.define(LoggingNamespace)
self.socketIO.emit('emit_with_callback', self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
self.assertTrue(self.called_on_response)
def test_emit_with_callback_with_payload(self):
'Emit with callback with payload'
self.socketIO.define(LoggingNamespace)
self.socketIO.emit(
'emit_with_callback_with_payload', self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
@ -117,6 +122,7 @@ class BaseMixin(object):
def test_emit_with_callback_with_multiple_payloads(self):
'Emit with callback with multiple payloads'
self.socketIO.define(LoggingNamespace)
self.socketIO.emit(
'emit_with_callback_with_multiple_payloads', self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
@ -205,7 +211,7 @@ class Test_JSONP_PollingTransport(TestCase, BaseMixin):
self.wait_time_in_seconds = TIMEOUT_IN_SECONDS + 1
class Namespace(BaseNamespace):
class Namespace(LoggingNamespace):
def initialize(self):
self.response = None