From ebd18b70175b5c0da4db687dbd5abfa1361c2b47 Mon Sep 17 00:00:00 2001 From: Roy Hyunjin Han Date: Sun, 22 Feb 2015 14:17:24 -0500 Subject: [PATCH] Prepare to check against master branch --- socketIO_client/__init__.py | 72 +++++++++++++++++------------------ socketIO_client/namespaces.py | 16 ++++++++ socketIO_client/parsers.py | 25 +++++++++++- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/socketIO_client/__init__.py b/socketIO_client/__init__.py index 2d1cc66..8ece708 100644 --- a/socketIO_client/__init__.py +++ b/socketIO_client/__init__.py @@ -1,11 +1,11 @@ -import json - from .exceptions import ConnectionError, TimeoutError, PacketError from .heartbeats import HeartbeatThread from .logs import LoggingMixin from .namespaces import EngineIONamespace, SocketIONamespace, find_callback -from .parsers import parse_host, parse_socketIO_data -from .symmetries import encode_string, get_character +from .parsers import ( + parse_host, parse_engineIO_session, + parse_socketIO_data, format_socketIO_data) +from .symmetries import get_character from .transports import XHR_PollingTransport, prepare_http_session, TRANSPORTS @@ -46,7 +46,7 @@ class EngineIO(LoggingMixin): return self.__transport except AttributeError: pass - self._get_engineIO_session() + self._engineIO_session = self._get_engineIO_session() self._negotiate_transport() self._reset_heartbeat() self._connect_namespaces() @@ -60,18 +60,13 @@ class EngineIO(LoggingMixin): try: engineIO_packet_type, engineIO_packet_data = next( transport.recv_packet()) - except (TimeoutError, ConnectionError) as e: if not self._wait_for_connection: raise warning = Exception('[waiting for connection] %s' % e) warning_screen.throw(warning) assert engineIO_packet_type == 0 - value_by_name = json.loads(encode_string(engineIO_packet_data)) - self._session_id = value_by_name['sid'] - self._ping_interval = value_by_name['pingInterval'] / float(1000) - self._ping_timeout = value_by_name['pingTimeout'] / float(1000) - self._transport_upgrades = value_by_name['upgrades'] + return parse_engineIO_session(engineIO_packet_data) def _negotiate_transport(self): self.__transport = self._get_transport('xhr-polling') @@ -83,7 +78,7 @@ class EngineIO(LoggingMixin): pass self._heartbeat_thread = HeartbeatThread( send_heartbeat=self.__transport._ping, - relax_interval_in_seconds=self._ping_interval, + relax_interval_in_seconds=self._engineIO_session.ping_interval, hurry_interval_in_seconds=1) self._heartbeat_thread.start() @@ -129,6 +124,9 @@ class EngineIO(LoggingMixin): # Act + def send(self, engineIO_packet_data): + self._message(engineIO_packet_data) + def _open(self): engineIO_packet_type = 0 self._transport.send_packet(engineIO_packet_type, '') @@ -188,7 +186,6 @@ class EngineIO(LoggingMixin): self._heartbeat_thread.relax() def _should_stop_waiting(self): - # Use __transport to make sure that we do not reconnect inadvertently return self._wants_to_close def _process_packets(self): @@ -278,7 +275,7 @@ class SocketIO(EngineIO): for path, namespace in self._namespace_by_path.items(): namespace._transport = self.__transport if path: - self.__transport.connect(path) + self.connect(path) def __exit__(self, *exception_pack): self.disconnect() @@ -311,34 +308,29 @@ class SocketIO(EngineIO): # Act - def connect(): - pass + def connect(self, path): + socketIO_packet_type = 0 + socketIO_packet_data = format_socketIO_data(path) + self._message(str(socketIO_packet_type) + socketIO_packet_data) - def disconnect(): - pass + def disconnect(self, path=''): + socketIO_packet_type = 1 + socketIO_packet_data = format_socketIO_data(path) + self._message(str(socketIO_packet_type) + socketIO_packet_data) + try: + namespace = self._namespace_by_path.pop(path) + namespace.on_disconnect() + except KeyError: + pass def emit(self, event, *args, **kw): path = kw.get('path', '') callback, args = find_callback(args, kw) - self._emit(path, event, args, callback) - - def _emit(self, path, event, args, callback): + ack_id = self._set_ack_callback(callback) if callback else None socketIO_packet_type = 2 - - socketIO_packet_data = json.dumps([event] + list(args)) - if callback: - ack_id = self._set_ack_callback(callback) if callback else '' - socketIO_packet_data = str(ack_id) + socketIO_packet_data - if path: - socketIO_packet_data = path + ',' + socketIO_packet_data - + socketIO_packet_data = format_socketIO_data(path, ack_id, args) self._message(str(socketIO_packet_type) + socketIO_packet_data) - def _set_ack_callback(self, callback): - self._ack_id += 1 - self._callback_by_ack_id[self._ack_id] = callback - return self._ack_id - def send(self, data='', callback=None): args = [data] if callback: @@ -354,8 +346,7 @@ class SocketIO(EngineIO): self.wait(seconds, for_callbacks=True) def _should_stop_waiting(self, for_callbacks): - # Use __transport to make sure that we do not reconnect inadvertently - if for_callbacks and not self.__transport.has_ack_callback: + if for_callbacks and not self._has_ack_callback: return True return super(SocketIO, self)._should_stop_waiting() @@ -423,5 +414,14 @@ class SocketIO(EngineIO): 'Return function that acknowledges the server' return lambda *args: self._ack(path, ack_id, *args) + def _set_ack_callback(self, callback): + self._ack_id += 1 + self._callback_by_ack_id[self._ack_id] = callback + return self._ack_id + def _get_ack_callback(self, ack_id): return self._callback_by_ack_id.pop(ack_id) + + @property + def _has_ack_callback(self): + return True if self._callback_by_ack_id else False diff --git a/socketIO_client/namespaces.py b/socketIO_client/namespaces.py index db96007..c622e65 100644 --- a/socketIO_client/namespaces.py +++ b/socketIO_client/namespaces.py @@ -18,6 +18,10 @@ class EngineIONamespace(LoggingMixin): 'Define a callback to handle an event emitted by the server' self._callback_by_event[event] = callback + def send(self, data): + 'Send a message' + self._io.send(data) + def on_open(self): """Called after engine.io connects. You can override this method.""" @@ -63,6 +67,18 @@ class SocketIONamespace(EngineIONamespace): self.path = path super(SocketIONamespace, self).__init__(io) + def connect(self): + self._io.connect(self.path) + + def disconnect(self): + self._io.disconnect(self.path) + + def emit(self, event, *args, **kw): + self._io.emit(event, *args, **kw) + + def send(self, data='', callback=None): + self._io.send(data, callback) + def on_connect(self): """Called after socket.io connects. You can override this method.""" diff --git a/socketIO_client/parsers.py b/socketIO_client/parsers.py index 7a5a9d7..e748164 100644 --- a/socketIO_client/parsers.py +++ b/socketIO_client/parsers.py @@ -1,9 +1,12 @@ import json from collections import namedtuple -from .symmetries import encode_string, get_byte, get_character, parse_url +from .symmetries import ( + decode_string, encode_string, get_byte, get_character, parse_url) +EngineIOSession = namedtuple('EngineIOSession', [ + 'id', 'ping_interval', 'ping_timeout', 'transport_upgrades']) SocketIOData = namedtuple('SocketIOData', ['path', 'ack_id', 'args']) @@ -17,6 +20,15 @@ def parse_host(host, port, resource): return is_secure, url +def parse_engineIO_session(engineIO_packet_data): + d = json.loads(decode_string(engineIO_packet_data)) + return EngineIOSession( + id=d['sid'], + ping_interval=d['pingInterval'] / float(1000), + ping_timeout=d['pingTimeout'] / float(1000), + transport_upgrades=d['upgrades']) + + def encode_engineIO_content(engineIO_packets): parts = [] for packet_type, packet_data in engineIO_packets: @@ -42,7 +54,7 @@ def decode_engineIO_content(content): def parse_socketIO_data(data): - data = encode_string(data) + data = decode_string(data) if data.startswith('/'): try: path, data = data.split(',', 1) @@ -64,6 +76,15 @@ def parse_socketIO_data(data): return SocketIOData(path=path, ack_id=ack_id, args=args) +def format_socketIO_data(path=None, ack_id=None, args=None): + socketIO_packet_data = json.dumps(args) if args else '' + if ack_id is not None: + socketIO_packet_data = str(ack_id) + socketIO_packet_data + if path: + socketIO_packet_data = path + ',' + socketIO_packet_data + return socketIO_packet_data + + def _make_packet_header(packet_string): length_string = str(len(packet_string)) header_digits = [0]