Added more documentation
This commit is contained in:
parent
2361706c4e
commit
455890a700
2 changed files with 62 additions and 12 deletions
|
|
@ -16,7 +16,6 @@ except ImportError:
|
||||||
from .exceptions import ConnectionError, TimeoutError, PacketError
|
from .exceptions import ConnectionError, TimeoutError, PacketError
|
||||||
from .transports import _get_response
|
from .transports import _get_response
|
||||||
|
|
||||||
|
|
||||||
_SocketIOSession = namedtuple('_SocketIOSession', [
|
_SocketIOSession = namedtuple('_SocketIOSession', [
|
||||||
'id',
|
'id',
|
||||||
'heartbeat_interval',
|
'heartbeat_interval',
|
||||||
|
|
@ -24,7 +23,6 @@ _SocketIOSession = namedtuple('_SocketIOSession', [
|
||||||
'server_supported_transports',
|
'server_supported_transports',
|
||||||
])
|
])
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
PROTOCOL_VERSION = 1
|
|
||||||
RETRY_INTERVAL_IN_SECONDS = 1
|
RETRY_INTERVAL_IN_SECONDS = 1
|
||||||
|
|
||||||
class BaseNamespace(object):
|
class BaseNamespace(object):
|
||||||
|
|
@ -171,6 +169,9 @@ class SocketIO(object):
|
||||||
self._terminate_heartbeat();
|
self._terminate_heartbeat();
|
||||||
|
|
||||||
def _terminate_heartbeat(self):
|
def _terminate_heartbeat(self):
|
||||||
|
"""Terminates the heartbeat thread.
|
||||||
|
|
||||||
|
"""
|
||||||
if self.heartbeat_terminator is not None:
|
if self.heartbeat_terminator is not None:
|
||||||
self.heartbeat_terminator.set();
|
self.heartbeat_terminator.set();
|
||||||
self.heartbeat_thread.join();
|
self.heartbeat_thread.join();
|
||||||
|
|
@ -365,6 +366,21 @@ class SocketIO(object):
|
||||||
return self.__transport
|
return self.__transport
|
||||||
|
|
||||||
def _upgrade(self):
|
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 = transports.WebsocketTransport(self.session, self.is_secure, self.base_url, **self.kw);
|
||||||
websocket.send_packet(PacketType.PING, "", "probe");
|
websocket.send_packet(PacketType.PING, "", "probe");
|
||||||
for packet in websocket.recv_packet():
|
for packet in websocket.recv_packet():
|
||||||
|
|
@ -384,6 +400,19 @@ class SocketIO(object):
|
||||||
return websocket;
|
return websocket;
|
||||||
|
|
||||||
def _start_heartbeat(self, transport):
|
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]");
|
_log.debug("[start heartbeat pacemaker]");
|
||||||
self.heartbeat_terminator = multiprocessing.Event();
|
self.heartbeat_terminator = multiprocessing.Event();
|
||||||
self.heartbeat_thread = multiprocessing.Process(
|
self.heartbeat_thread = multiprocessing.Process(
|
||||||
|
|
@ -458,10 +487,14 @@ class SocketIO(object):
|
||||||
find_event_callback('disconnect')()
|
find_event_callback('disconnect')()
|
||||||
|
|
||||||
def _on_event(self, packet, find_event_callback):
|
def _on_event(self, packet, find_event_callback):
|
||||||
# Accoding to the documentation
|
"""This delegate is called when there is an EVENT packet.
|
||||||
# (https://github.com/automattic/socket.io-protocol#event),
|
|
||||||
# the event name is the first entry in the message array, and
|
Accoding to the documentation
|
||||||
# the arguments are the rest of the entries.
|
(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];
|
event = packet.payload.message[0];
|
||||||
args = packet.payload.message[1:] if len(packet.payload.message) > 1 else [];
|
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):
|
def _get_socketIO_session(is_secure, base_url, **kw):
|
||||||
server_url = '%s://%s/?EIO=%d&transport=polling' \
|
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)
|
_log.debug('[session] %s', server_url)
|
||||||
try:
|
try:
|
||||||
response = _get_response(requests.get, server_url, **kw)
|
response = _get_response(requests.get, server_url, **kw)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import json
|
||||||
|
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
ENGINE_PROTOCOL = 3;
|
ENGINEIO_PROTOCOL = 3;
|
||||||
|
|
||||||
class PacketType(Enum):
|
class PacketType(Enum):
|
||||||
OPEN = 0;
|
OPEN = 0;
|
||||||
|
|
@ -25,6 +25,8 @@ class MessageType(Enum):
|
||||||
BINARY_ACK = 6;
|
BINARY_ACK = 6;
|
||||||
|
|
||||||
class Packet():
|
class Packet():
|
||||||
|
""" Represents a 'packet' from the engine.io protocol.
|
||||||
|
"""
|
||||||
def __init__(self, packet_type, payload):
|
def __init__(self, packet_type, payload):
|
||||||
self.type = packet_type;
|
self.type = packet_type;
|
||||||
self.payload = payload;
|
self.payload = payload;
|
||||||
|
|
@ -33,6 +35,16 @@ class Packet():
|
||||||
return "PACKET{type: " + str(self.type) + ", payload: " + str(self.payload) + "}";
|
return "PACKET{type: " + str(self.type) + ", payload: " + str(self.payload) + "}";
|
||||||
|
|
||||||
def encode_as_string(self, for_websocket = False):
|
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 = "";
|
data = "";
|
||||||
path = "";
|
path = "";
|
||||||
if self.type == PacketType.MESSAGE and not isinstance(self.payload, basestring):
|
if self.type == PacketType.MESSAGE and not isinstance(self.payload, basestring):
|
||||||
|
|
@ -54,6 +66,8 @@ class Packet():
|
||||||
return encoded;
|
return encoded;
|
||||||
|
|
||||||
class Message():
|
class Message():
|
||||||
|
"""Represents a 'message' from the socket.io protocol.
|
||||||
|
"""
|
||||||
def __init__(self, message_type, message, path = "", attachments = "", message_id = None):
|
def __init__(self, message_type, message, path = "", attachments = "", message_id = None):
|
||||||
self.type = message_type;
|
self.type = message_type;
|
||||||
if isinstance(message, basestring):
|
if isinstance(message, basestring):
|
||||||
|
|
@ -84,9 +98,8 @@ class Message():
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
def encode_as_json(self):
|
def encode_as_json(self):
|
||||||
"""Encodes a Message to be sent to socket.io server.
|
"""Encodes a JSON Message to be sent to socket.io server.
|
||||||
|
|
||||||
Assumes the message payload will be dumped as a json string.
|
|
||||||
"""
|
"""
|
||||||
data = json.dumps(self.message);
|
data = json.dumps(self.message);
|
||||||
if self.id is not None:
|
if self.id is not None:
|
||||||
|
|
@ -97,7 +110,11 @@ class Message():
|
||||||
return str(self.type) + self.path + "," + data;
|
return str(self.type) + self.path + "," + data;
|
||||||
|
|
||||||
def encode_as_string(self):
|
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):
|
if not isinstance(self.message, basestring):
|
||||||
return self.encode_as_json();
|
return self.encode_as_json();
|
||||||
data = self.message;
|
data = self.message;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue