17.12
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# channel.py
|
||||
# ~~~~~~~~~
|
||||
# This module implements the Channel class.
|
||||
# :authors: Justin Karneges, Konstantin Bokarius.
|
||||
# :copyright: (c) 2015 by Fanout, Inc.
|
||||
# :license: MIT, see LICENSE for more details.
|
||||
|
||||
# The Channel class is used to represent a channel in a GRIP proxy and
|
||||
# tracks the previous ID of the last message.
|
||||
class Channel(object):
|
||||
|
||||
# Initialize with the channel name and an optional previous ID.
|
||||
def __init__(self, name, prev_id=None):
|
||||
self.name = name
|
||||
self.prev_id = prev_id
|
||||
self.filters = []
|
||||
@@ -0,0 +1,46 @@
|
||||
# httpstreamformat.py
|
||||
# ~~~~~~~~~
|
||||
# This module implements the HttpStreamFormat class.
|
||||
# :authors: Justin Karneges, Konstantin Bokarius.
|
||||
# :copyright: (c) 2015 by Fanout, Inc.
|
||||
# :license: MIT, see LICENSE for more details.
|
||||
|
||||
from base64 import b64encode
|
||||
from pubcontrol import Format
|
||||
from .gripcontrol import _bin_or_text
|
||||
|
||||
# The HttpStreamFormat class is the format used to publish messages to
|
||||
# HTTP stream clients connected to a GRIP proxy.
|
||||
class HttpStreamFormat(Format):
|
||||
|
||||
# Initialize with either the message content or a boolean indicating that
|
||||
# the streaming connection should be closed. If neither the content nor
|
||||
# the boolean flag is set then an error will be raised.
|
||||
def __init__(self, content=None, close=False, content_filters=None):
|
||||
self.content = content
|
||||
self.close = close
|
||||
self.content_filters = content_filters
|
||||
if not self.close and self.content is None:
|
||||
raise ValueError('content not set')
|
||||
|
||||
# The name used when publishing this format.
|
||||
def name(self):
|
||||
return 'http-stream'
|
||||
|
||||
# Exports the message in the required format depending on whether the
|
||||
# message content is binary or not, or whether the connection should
|
||||
# be closed.
|
||||
def export(self):
|
||||
out = dict()
|
||||
if self.close:
|
||||
out['action'] = 'close'
|
||||
else:
|
||||
if self.content_filters is not None:
|
||||
out['content-filters'] = self.content_filters
|
||||
|
||||
is_text, val = _bin_or_text(self.content)
|
||||
if is_text:
|
||||
out['content'] = val
|
||||
else:
|
||||
out['content-bin'] = b64encode(val)
|
||||
return out
|
||||
@@ -0,0 +1,115 @@
|
||||
from copy import deepcopy
|
||||
from struct import unpack
|
||||
from .gripcontrol import is_python3, websocket_control_message
|
||||
from .websocketevent import WebSocketEvent
|
||||
|
||||
class WebSocketContext(object):
|
||||
def __init__(self, id, meta, in_events, grip_prefix=''):
|
||||
self.id = id
|
||||
self.in_events = in_events
|
||||
self.read_index = 0
|
||||
self.accepted = False
|
||||
self.close_code = None
|
||||
self.closed = False
|
||||
self.out_close_code = None
|
||||
self.out_events = []
|
||||
self.orig_meta = meta
|
||||
self.meta = deepcopy(meta)
|
||||
self.grip_prefix = grip_prefix
|
||||
|
||||
def is_opening(self):
|
||||
return (self.in_events and self.in_events[0].type == 'OPEN')
|
||||
|
||||
def accept(self):
|
||||
self.accepted = True
|
||||
|
||||
def close(self, code=None):
|
||||
self.closed = True
|
||||
if code is not None:
|
||||
self.out_close_code = code
|
||||
else:
|
||||
self.out_close_code = 0
|
||||
|
||||
def can_recv(self):
|
||||
for n in range(self.read_index, len(self.in_events)):
|
||||
if self.in_events[n].type in ('TEXT', 'BINARY', 'CLOSE', 'DISCONNECT'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def recv(self):
|
||||
e = None
|
||||
while e is None and self.read_index < len(self.in_events):
|
||||
if self.in_events[self.read_index].type in ('TEXT', 'BINARY', 'CLOSE', 'DISCONNECT'):
|
||||
e = self.in_events[self.read_index]
|
||||
elif self.in_events[self.read_index].type == 'PING':
|
||||
self.out_events.append(WebSocketEvent('PONG'))
|
||||
self.read_index += 1
|
||||
if e is None:
|
||||
raise IndexError('read from empty buffer')
|
||||
|
||||
if e.type == 'TEXT':
|
||||
if e.content:
|
||||
return e.content.decode('utf-8')
|
||||
else:
|
||||
if is_python3:
|
||||
return ''
|
||||
else:
|
||||
return u''
|
||||
elif e.type == 'BINARY':
|
||||
if e.content:
|
||||
return e.content
|
||||
else:
|
||||
if is_python3:
|
||||
return b''
|
||||
else:
|
||||
return ''
|
||||
elif e.type == 'CLOSE':
|
||||
if e.content and len(e.content) == 2:
|
||||
self.close_code = unpack('>H', e.content)[0]
|
||||
return None
|
||||
else: # DISCONNECT
|
||||
raise IOError('client disconnected unexpectedly')
|
||||
|
||||
def send(self, message):
|
||||
if is_python3:
|
||||
if isinstance(message, str):
|
||||
message = message.encode('utf-8')
|
||||
content = b'm:' + message
|
||||
else:
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode('utf-8')
|
||||
content = 'm:' + message
|
||||
self.out_events.append(WebSocketEvent('TEXT', content))
|
||||
|
||||
def send_binary(self, message):
|
||||
if is_python3:
|
||||
if isinstance(message, str):
|
||||
message = message.encode('utf-8')
|
||||
content = b'm:' + message
|
||||
else:
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode('utf-8')
|
||||
content = 'm:' + message
|
||||
self.out_events.append(WebSocketEvent('BINARY', content))
|
||||
|
||||
def send_control(self, message):
|
||||
if is_python3:
|
||||
if isinstance(message, str):
|
||||
message = message.encode('utf-8')
|
||||
content = b'c:' + message
|
||||
else:
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode('utf-8')
|
||||
content = 'c:' + message
|
||||
self.out_events.append(WebSocketEvent('TEXT', content))
|
||||
|
||||
def subscribe(self, channel):
|
||||
self.send_control(websocket_control_message(
|
||||
'subscribe', {'channel': self.grip_prefix + channel}))
|
||||
|
||||
def unsubscribe(self, channel):
|
||||
self.send_control(websocket_control_message(
|
||||
'unsubscribe', {'channel': self.grip_prefix + channel}))
|
||||
|
||||
def detach(self):
|
||||
self.send_control(websocket_control_message('detach'))
|
||||
Reference in New Issue
Block a user