Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Merge websocket_connect into the WebSocketClientConnection class #934

Merged
merged 2 commits into from

2 participants

@Caligatio

It is currently extremely difficult to subclass WebSocketClientConnection without reimplementing websocket_connect due to the fact that WebSocketClientConnection is never really exposed outside the websocket module. In my program, my websocket client is also operating as a HTTP server so needing to loop on the websocket client's read_message is awkward. I ended up subclassing WebSocketClientConnection and overriding its on_message to act more like an expected callback-type function but it seems like a hack since I also had to reimplement websocket_connect to use my own class.

My idea is to move the call the parent's init to a connect function (which admittedly is also hacky) and change the connect_future's eventual return value to True/False value instead of returning a handle to the websocket client object.

EDIT: I'm happy to submit a merge request if people aren't opposed to the init hackery.

@bdarnell
Owner

WebSocketClientConnection isn't supposed to be subclassed; it's more or less an implementation detail. As much as possible I'd like to add functionality without inviting user-created subclasses. For example, we could add a set_message_callback function as an alternative to the (admittedly somewhat experimental) Future-based interface it has now.

@Caligatio

The ability to have a specified callback would satisfy my requirements just fine.

Would you want this to be specified at initialization or changeable during runtime? My concern about the latter is there may be some weird race condition with trying to empty the possible non-empty queue (presumably if you go from no callback to something, queued messages should call the callback) and attaching the new callback. I imagine one would want messages to be delivered in order so changing over the callback before emptying the queue would cause out of order delivery.

@bdarnell
Owner

I think initialization-time is probably best given the complexity of dealing with the queue. It's kind of analogous to the httpclient streaming_callback - I wonder if it should be on the HTTPRequest object (perhaps even just using streaming_callback?) or a parameter to websocket_connect.

@Caligatio

Admittedly I'm not really familiar with streaming_callback but wouldn't that interrupt the "normal" websocket processing if we hook into something that low in stack?

I'll come up with something that takes a on_message_callback on init and do a pull request. If I can figure out Hub I'll try to link it to this Issue.

@bdarnell bdarnell added the websocket label
@bdarnell bdarnell merged commit 1e8582f into from
@Caligatio Caligatio deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 10 additions and 4 deletions.
  1. +10 −4 tornado/websocket.py
View
14 tornado/websocket.py
@@ -773,11 +773,12 @@ class WebSocketClientConnection(simple_httpclient._HTTPConnection):
This class should not be instantiated directly; use the
`websocket_connect` function instead.
"""
- def __init__(self, io_loop, request):
+ def __init__(self, io_loop, request, on_message_callback=None):
self.connect_future = TracebackFuture()
self.read_future = None
self.read_queue = collections.deque()
self.key = base64.b64encode(os.urandom(16))
+ self._on_message_callback = on_message_callback
scheme, sep, rest = request.url.partition(':')
scheme = {'ws': 'http', 'wss': 'https'}[scheme]
@@ -838,6 +839,9 @@ def write_message(self, message, binary=False):
def read_message(self, callback=None):
"""Reads a message from the WebSocket server.
+
+ If on_message_callback was specified at WebSocket
+ initialization, this function will never return messages
Returns a future whose result is the message, or None
if the connection is closed. If a callback argument
@@ -855,7 +859,9 @@ def read_message(self, callback=None):
return future
def on_message(self, message):
- if self.read_future is not None:
+ if self._on_message_callback:
+ self._on_message_callback(message)
+ elif self.read_future is not None:
self.read_future.set_result(message)
self.read_future = None
else:
@@ -865,7 +871,7 @@ def on_pong(self, data):
pass
-def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):
+def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None, on_message_callback=None):
"""Client-side websocket support.
Takes a url and returns a Future whose result is a
@@ -886,7 +892,7 @@ def websocket_connect(url, io_loop=None, callback=None, connect_timeout=None):
request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)
request = httpclient._RequestProxy(
request, httpclient.HTTPRequest._DEFAULTS)
- conn = WebSocketClientConnection(io_loop, request)
+ conn = WebSocketClientConnection(io_loop, request, on_message_callback=on_message_callback)
if callback is not None:
io_loop.add_future(conn.connect_future, callback)
return conn.connect_future
Something went wrong with that request. Please try again.