To be honest, I agree on that. A "pull style" API for WebSocket feels
unnatural to me. But it's a matter of taste, sure.

Does a pull-style HTTP server also feel unnatural to you?

In short, yes.

The way I most often do "classic" Web stuff on Python is via Flask:

@app.route('/')
def page_home():
   return render_template('home.html')

The decorators route URLs to callbacks which render Jinja templates.

This feels natural.

Doing something like

while True:
   request = yield from http.block_until_request()
   if request.url == "/":
      request.write(render_template('home.html'))

would seem strange to me.

In fact, Autobahn provides a protocol layer above WebSocket for RPC and PubSub, and the RPC lets you expose Python functions that can be called via WebSocket (eg from browser JavaScript):

@exportRpc("com.myapp.myfun")
def myfun(a, b):
   return a + b

and in JS:

session.call("com.myapp.myfun", 2, 3).then(
   function (res) {
      console.log(res); // prints 5
   }
);

session.call returns a Promise.

Btw: Promises are coming natively to browsers .. they are specified in ECMAScript6.


I only vaguely recall what Websockets is used for, but isn't is a
cumbersome implementation (constrained by HTTP architecture) for an
elegant abstraction (long-living bidirectional streams) which are
typically used to send requests "upstream" (i.e. from the server to
the client) and send responses back?

WebSocket is essentially a HTTP compatible opening handshake, that when finished, establishes a bidirectional, full-duplex, reliable, message based channel.


I would find it totally natural to have loop in the client that pulls
one request from the stream (blocking until it is ready), processes
it, and sends a response back -- and similar, in the server, to
occasionally send a request to the stream and block until you have the
response. (The latter could all be done by a coroutine designed to
send one request and receive one response.)

If I understand right, that API to WebSocket is more like what Aymeric has:

while True:
   msg = yield from websocket.recv()
   // do something with msg, which is a WebSocket message

I don't have plans to implement a pull-style API, since .. yeah,
unnatural;)

Please reconsider.

One problem is that this would be totally intrusive into my existing codebase _and_ API. Another one: Autobahn has multiple implementations in other languages (JS and Android currently) - and those APIs are event-driven style also, and having APIs similar across enviroments is a plus. Another (personal) issue: the synchronous style feels weird to me;) Maybe I am spoiled already.

It's a holy war that asyncio stays out of at the low level by
supporting either. But at the high level asyncio's opinion is that in
terms of coding convenience, pull-style is better, because it's more
familiar to Python programmers. Asyncio (and e.g. StreamReader) put in
the work to bridge the interface gap for you.


Thanks alot for pointing this out! I now understand better. Asyncio at high-level is opinionated towards "pull-style". This is fine - and important to recognize.

Regarding Autobahn: I think it's already quite cool that we can now support Twisted and asyncio at the same time - even if "push style" only ..

Thanks for your hints and comments!

/Tobias


Reply via email to