Skip to content

Commit db33c8e

Browse files
committed
1.oops
1 parent 70042b1 commit db33c8e

File tree

5 files changed

+486
-42
lines changed

5 files changed

+486
-42
lines changed

pyenv_wsio/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
from ._wsio import *
1919
from ._events import *
20+
from ._client import *
21+
from ._packet import *
2022

2123
# if __name__ == "__main__":
2224
# raise Exception(

pyenv_wsio/_client.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# # -*- coding: utf-8 -*-
2+
3+
import signal
4+
from ._events import EventEmitter
5+
from ._wsio import *
6+
7+
reconnecting_clients = []
8+
9+
10+
def _signal_handler(sig, frame):
11+
pass
12+
13+
14+
_original_signal_handler = signal.signal(signal.SIGINT, _signal_handler)
15+
16+
17+
class Client(EventEmitter):
18+
def __init__(self, reconnection=True, reconnection_attempts=0,
19+
reconnection_delay=1, reconnection_delay_max=5,
20+
randomization_factor=0.5, binary=False):
21+
EventEmitter.__init__(self)
22+
23+
self.reconnection = reconnection
24+
self.reconnection_attempts = reconnection_attempts
25+
self.reconnection_delay = reconnection_delay
26+
self.reconnection_delay_max = reconnection_delay_max
27+
self.randomization_factor = randomization_factor
28+
self.binary = binary
29+
30+
self.eio=Wsio()
31+
self.eio.on('connect',self.on_eio_connect)
32+
self.eio.on('message',self.on_eio_message)
33+
self.eio.on('disconnect',self.on_eio_disconnect)
34+
self.eio.on('error',self.on_eio_error)
35+
36+
self.connection_url = None
37+
self.connection_headers = None
38+
self.connection_namespaces = None
39+
self.sid = None
40+
41+
self.connected = False
42+
self.namespaces = []
43+
self.handlers = {}
44+
self.namespace_handlers = {}
45+
self.callbacks = {}
46+
self._binary_packet = None
47+
self._reconnect_task = None
48+
self._reconnect_abort = self.eio.create_event()
49+
50+
51+
def connect(self,url, headers={},namespaces=None):
52+
self.connection_url=url
53+
self.connection_headers=headers
54+
self.connection_namespaces=namespaces
55+
self.eio.connect(url,headers=headers)
56+
self.connected=True
57+
58+
# def emit()
59+
60+
def on_eio_connect(self):
61+
self.sid=self.eio.sid
62+
63+
def on_eio_message(self,pkg):
64+
print 'on_eio_message'
65+
66+
def on_eio_disconnect(self):
67+
print 'on_eio_disconnect'
68+
69+
def on_eio_error(self,e):
70+
print 'on_eio_error'
71+

pyenv_wsio/_packet.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import functools
4+
import json as _json
5+
6+
import six
7+
8+
(CONNECT, DISCONNECT, EVENT, ACK, ERROR, BINARY_EVENT, BINARY_ACK, HANDSHAKE) = \
9+
(0, 1, 2, 3, 4, 5, 6, 7)
10+
packet_names = ['CONNECT', 'DISCONNECT', 'EVENT', 'ACK', 'ERROR',
11+
'BINARY_EVENT', 'BINARY_ACK', 'HANDSHAKE']
12+
13+
14+
class Packet(object):
15+
"""Socket.IO packet."""
16+
17+
# the format of the Socket.IO packet is as follows:
18+
#
19+
# packet type: 1 byte, values 0-6
20+
# num_attachments: ASCII encoded, only if num_attachments != 0
21+
# '-': only if num_attachments != 0
22+
# namespace: only if namespace != '/'
23+
# ',': only if namespace and one of id and data are defined in this packet
24+
# id: ASCII encoded, only if id is not None
25+
# data: JSON dump of data payload
26+
27+
json = _json
28+
29+
def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None,
30+
binary=None, encoded_packet=None):
31+
self.packet_type = packet_type
32+
self.data = data
33+
self.namespace = namespace
34+
self.id = id
35+
if binary or (binary is None and self._data_is_binary(self.data)):
36+
if self.packet_type == EVENT:
37+
self.packet_type = BINARY_EVENT
38+
elif self.packet_type == ACK:
39+
self.packet_type = BINARY_ACK
40+
else:
41+
raise ValueError('Packet does not support binary payload.')
42+
self.attachment_count = 0
43+
self.attachments = []
44+
if encoded_packet:
45+
self.attachment_count = self.decode(encoded_packet)
46+
47+
def encode(self):
48+
"""Encode the packet for transmission.
49+
50+
If the packet contains binary elements, this function returns a list
51+
of packets where the first is the original packet with placeholders for
52+
the binary components and the remaining ones the binary attachments.
53+
"""
54+
encoded_packet = six.text_type(self.packet_type)
55+
if self.packet_type == BINARY_EVENT or self.packet_type == BINARY_ACK:
56+
data, attachments = self._deconstruct_binary(self.data)
57+
encoded_packet += six.text_type(len(attachments)) + '-'
58+
else:
59+
data = self.data
60+
attachments = None
61+
needs_comma = False
62+
if self.namespace is not None and self.namespace != '/':
63+
encoded_packet += self.namespace
64+
needs_comma = True
65+
if self.id is not None:
66+
if needs_comma:
67+
encoded_packet += ','
68+
needs_comma = False
69+
encoded_packet += six.text_type(self.id)
70+
if data is not None:
71+
if needs_comma:
72+
encoded_packet += ','
73+
encoded_packet += self.json.dumps(data, separators=(',', ':'))
74+
if attachments is not None:
75+
encoded_packet = [encoded_packet] + attachments
76+
return encoded_packet
77+
78+
def decode(self, encoded_packet):
79+
"""Decode a transmitted package.
80+
81+
The return value indicates how many binary attachment packets are
82+
necessary to fully decode the packet.
83+
"""
84+
ep = encoded_packet
85+
try:
86+
self.packet_type = int(ep[0:1])
87+
except TypeError:
88+
self.packet_type = ep
89+
ep = ''
90+
self.namespace = None
91+
self.data = None
92+
ep = ep[1:]
93+
dash = ep.find('-')
94+
attachment_count = 0
95+
if dash > 0 and ep[0:dash].isdigit():
96+
attachment_count = int(ep[0:dash])
97+
ep = ep[dash + 1:]
98+
if ep and ep[0:1] == '/':
99+
sep = ep.find(',')
100+
if sep == -1:
101+
self.namespace = ep
102+
ep = ''
103+
else:
104+
self.namespace = ep[0:sep]
105+
ep = ep[sep + 1:]
106+
q = self.namespace.find('?')
107+
if q != -1:
108+
self.namespace = self.namespace[0:q]
109+
if ep and ep[0].isdigit():
110+
self.id = 0
111+
while ep and ep[0].isdigit():
112+
self.id = self.id * 10 + int(ep[0])
113+
ep = ep[1:]
114+
if ep:
115+
self.data = self.json.loads(ep)
116+
return attachment_count
117+
118+
def add_attachment(self, attachment):
119+
if self.attachment_count <= len(self.attachments):
120+
raise ValueError('Unexpected binary attachment')
121+
self.attachments.append(attachment)
122+
if self.attachment_count == len(self.attachments):
123+
self.reconstruct_binary(self.attachments)
124+
return True
125+
return False
126+
127+
def reconstruct_binary(self, attachments):
128+
"""Reconstruct a decoded packet using the given list of binary
129+
attachments.
130+
"""
131+
self.data = self._reconstruct_binary_internal(self.data,
132+
self.attachments)
133+
134+
def _reconstruct_binary_internal(self, data, attachments):
135+
if isinstance(data, list):
136+
return [self._reconstruct_binary_internal(item, attachments)
137+
for item in data]
138+
elif isinstance(data, dict):
139+
if data.get('_placeholder') and 'num' in data:
140+
return attachments[data['num']]
141+
else:
142+
return {key: self._reconstruct_binary_internal(value,
143+
attachments)
144+
for key, value in six.iteritems(data)}
145+
else:
146+
return data
147+
148+
def _deconstruct_binary(self, data):
149+
"""Extract binary components in the packet."""
150+
attachments = []
151+
data = self._deconstruct_binary_internal(data, attachments)
152+
return data, attachments
153+
154+
def _deconstruct_binary_internal(self, data, attachments):
155+
if isinstance(data, six.binary_type):
156+
attachments.append(data)
157+
return {'_placeholder': True, 'num': len(attachments) - 1}
158+
elif isinstance(data, list):
159+
return [self._deconstruct_binary_internal(item, attachments)
160+
for item in data]
161+
elif isinstance(data, dict):
162+
return {key: self._deconstruct_binary_internal(value, attachments)
163+
for key, value in six.iteritems(data)}
164+
else:
165+
return data
166+
167+
def _data_is_binary(self, data):
168+
"""Check if the data contains binary components."""
169+
if isinstance(data, six.binary_type):
170+
return True
171+
elif isinstance(data, list):
172+
return functools.reduce(
173+
lambda a, b: a or b, [self._data_is_binary(item)
174+
for item in data], False)
175+
elif isinstance(data, dict):
176+
return functools.reduce(
177+
lambda a, b: a or b, [self._data_is_binary(item)
178+
for item in six.itervalues(data)],
179+
False)
180+
else:
181+
return False
182+

0 commit comments

Comments
 (0)