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