diff --git a/socketIO_client/__init__.py b/socketIO_client/__init__.py index 8196327..a2b6c8c 100644 --- a/socketIO_client/__init__.py +++ b/socketIO_client/__init__.py @@ -16,7 +16,6 @@ except ImportError: from .exceptions import ConnectionError, TimeoutError, PacketError from .transports import _get_response - _SocketIOSession = namedtuple('_SocketIOSession', [ 'id', 'heartbeat_interval', @@ -24,7 +23,6 @@ _SocketIOSession = namedtuple('_SocketIOSession', [ 'server_supported_transports', ]) _log = logging.getLogger(__name__) -PROTOCOL_VERSION = 1 RETRY_INTERVAL_IN_SECONDS = 1 class BaseNamespace(object): @@ -171,6 +169,9 @@ class SocketIO(object): self._terminate_heartbeat(); def _terminate_heartbeat(self): + """Terminates the heartbeat thread. + + """ if self.heartbeat_terminator is not None: self.heartbeat_terminator.set(); self.heartbeat_thread.join(); @@ -365,6 +366,21 @@ class SocketIO(object): return self.__transport def _upgrade(self): + """Attempts to upgrade the connection to a websocket. + + This method will execute the update process outline here: + https://github.com/Automattic/engine.io-protocol#transport-upgrading + + To summarize, we first send a PING packet with the string + 'probe' appended as data. This signals to the server that we + want to probe the ability to upgrade. If the server has this + functionality, it responds with a PONG packet and the 'probe' + string. + + We then send an UPGRADE packet, restart the heartbeat thread, + and return. + + """ websocket = transports.WebsocketTransport(self.session, self.is_secure, self.base_url, **self.kw); websocket.send_packet(PacketType.PING, "", "probe"); for packet in websocket.recv_packet(): @@ -384,6 +400,19 @@ class SocketIO(object): return websocket; def _start_heartbeat(self, transport): + """Starts the heartbeat thread. + + The heartbeat thread ensures that our connection is never + severed. This effectively spawns a thread that sits in an + infinite loop. The thread waits + self.session.heartbeat_interval / 2 (gleaned from the server) + seconds, then sends a heartbeat packet (PING). + + The thread is implemented using a multiprocessing.Event to + perform the wait, so it doesn't waste any cpu cycles while + it's waiting. + + """ _log.debug("[start heartbeat pacemaker]"); self.heartbeat_terminator = multiprocessing.Event(); self.heartbeat_thread = multiprocessing.Process( @@ -458,10 +487,14 @@ class SocketIO(object): find_event_callback('disconnect')() def _on_event(self, packet, find_event_callback): - # Accoding to the documentation - # (https://github.com/automattic/socket.io-protocol#event), - # the event name is the first entry in the message array, and - # the arguments are the rest of the entries. + """This delegate is called when there is an EVENT packet. + + Accoding to the documentation + (https://github.com/automattic/socket.io-protocol#event), the + event name is the first entry in the message array, and the + arguments are the rest of the entries. + + """ event = packet.payload.message[0]; args = packet.payload.message[1:] if len(packet.payload.message) > 1 else []; @@ -556,7 +589,7 @@ def _yield_elapsed_time(seconds=None): def _get_socketIO_session(is_secure, base_url, **kw): server_url = '%s://%s/?EIO=%d&transport=polling' \ - % ('https' if is_secure else 'http', base_url, parser.ENGINE_PROTOCOL) + % ('https' if is_secure else 'http', base_url, parser.ENGINEIO_PROTOCOL) _log.debug('[session] %s', server_url) try: response = _get_response(requests.get, server_url, **kw) diff --git a/socketIO_client/parser.py b/socketIO_client/parser.py index 27a2d7f..070cf14 100644 --- a/socketIO_client/parser.py +++ b/socketIO_client/parser.py @@ -4,7 +4,7 @@ import json _log = logging.getLogger(__name__) -ENGINE_PROTOCOL = 3; +ENGINEIO_PROTOCOL = 3; class PacketType(Enum): OPEN = 0; @@ -25,6 +25,8 @@ class MessageType(Enum): BINARY_ACK = 6; class Packet(): + """ Represents a 'packet' from the engine.io protocol. + """ def __init__(self, packet_type, payload): self.type = packet_type; self.payload = payload; @@ -33,6 +35,16 @@ class Packet(): return "PACKET{type: " + str(self.type) + ", payload: " + str(self.payload) + "}"; def encode_as_string(self, for_websocket = False): + """Returns the packet encoded according to the engine.io-protocol. + + Reference: (https://github.com/Automattic/engine.io-protocol). + + It's worth noting that websockets have their own framing and + encoding mechanism so if the packet is going to be transmitted + via websockets, we encode it slightly differently per the + documentation. + + """ data = ""; path = ""; if self.type == PacketType.MESSAGE and not isinstance(self.payload, basestring): @@ -54,6 +66,8 @@ class Packet(): return encoded; class Message(): + """Represents a 'message' from the socket.io protocol. + """ def __init__(self, message_type, message, path = "", attachments = "", message_id = None): self.type = message_type; if isinstance(message, basestring): @@ -84,9 +98,8 @@ class Message(): "}"; def encode_as_json(self): - """Encodes a Message to be sent to socket.io server. - - Assumes the message payload will be dumped as a json string. + """Encodes a JSON Message to be sent to socket.io server. + """ data = json.dumps(self.message); if self.id is not None: @@ -97,7 +110,11 @@ class Message(): return str(self.type) + self.path + "," + data; def encode_as_string(self): - """Same as the encode_as_string method except it doesn't encode things as a JSON string""" + """Encodes a Message to be to a socket.io server. + + This will call encode_as_json if the message is not a string. + + """ if not isinstance(self.message, basestring): return self.encode_as_json(); data = self.message;