89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
import collections
|
|
import errno
|
|
from eventlet import wsgi
|
|
from eventlet import pools
|
|
import eventlet
|
|
from eventlet.common import get_errno
|
|
from eventlet.green import socket
|
|
#from pprint import pformat
|
|
|
|
class WebSocket(object):
|
|
"""Handles access to the actual socket"""
|
|
|
|
def __init__(self, sock, environ):
|
|
"""
|
|
:param socket: The eventlet socket
|
|
:type socket: :class:`eventlet.greenio.GreenSocket`
|
|
:param environ: The wsgi environment
|
|
"""
|
|
self.socket = sock
|
|
self.origin = environ.get('HTTP_ORIGIN')
|
|
self.protocol = environ.get('HTTP_WEBSOCKET_PROTOCOL')
|
|
self.path = environ.get('PATH_INFO')
|
|
self.environ = environ
|
|
self._buf = ""
|
|
self._msgs = collections.deque()
|
|
self._sendlock = pools.TokenPool(1)
|
|
|
|
@staticmethod
|
|
def pack_message(message):
|
|
"""Pack the message inside ``00`` and ``FF``
|
|
|
|
As per the dataframing section (5.3) for the websocket spec
|
|
"""
|
|
if isinstance(message, unicode):
|
|
message = message.encode('utf-8')
|
|
elif not isinstance(message, str):
|
|
message = str(message)
|
|
packed = "\x00%s\xFF" % message
|
|
return packed
|
|
|
|
def parse_messages(self):
|
|
""" Parses for messages in the buffer *buf*. It is assumed that
|
|
the buffer contains the start character for a message, but that it
|
|
may contain only part of the rest of the message. NOTE: only understands
|
|
lengthless messages for now.
|
|
|
|
Returns an array of messages, and the buffer remainder that didn't contain
|
|
any full messages."""
|
|
msgs = []
|
|
end_idx = 0
|
|
buf = self._buf
|
|
while buf:
|
|
assert ord(buf[0]) == 0, "Don't understand how to parse this type of message: %r" % buf
|
|
end_idx = buf.find("\xFF")
|
|
if end_idx == -1: #pragma NO COVER
|
|
break
|
|
msgs.append(buf[1:end_idx].decode('utf-8', 'replace'))
|
|
buf = buf[end_idx+1:]
|
|
self._buf = buf
|
|
return msgs
|
|
|
|
def send(self, message):
|
|
"""Send a message to the client"""
|
|
packed = self.pack_message(message)
|
|
# if two greenthreads are trying to send at the same time
|
|
# on the same socket, sendlock prevents interleaving and corruption
|
|
t = self._sendlock.get()
|
|
try:
|
|
self.socket.sendall(packed)
|
|
finally:
|
|
self._sendlock.put(t)
|
|
|
|
def wait(self):
|
|
"""Waits for an deserializes messages"""
|
|
|
|
while not self._msgs:
|
|
# no parsed messages, must mean buf needs more data
|
|
delta = self.socket.recv(1024)
|
|
if delta == '':
|
|
return None
|
|
self._buf += delta
|
|
msgs = self.parse_messages()
|
|
self._msgs.extend(msgs)
|
|
return self._msgs.popleft()
|
|
|
|
def close(self):
|
|
self.socket.shutdown(True)
|
|
|