Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

WebSocket handler #11

Open
miyagawa opened this Issue · 8 comments

2 participants

@melo

Yep, and it seems easy. See http://github.com/typester/anyevent-websocket-demo for some working code.

@miyagawa
Owner

Well the only difficulty is that PSGI doesn't specify how to read input non-blockingly, so we should add a support for raw socket access in $env somewhere.

@miyagawa
Owner

See http://groups.google.com/group/rack-devel/browse_thread/thread/8a474cb03564cdb1 for rack.io extension, which discusses the same thing for Rack.

@melo

Ahs, you want to include it on PSGI... Given that this is under the Tatsumaki repo I was expecting a standalone AnyEvent::WebSocket module.

But as for read input non-blockingly, why would that be a problem? The Plack AnyEvent server also reads input non-blocking and works. From PSGI POV, you would get a request per websocket message, with a common connection ID.

I'll read the other comments, I'm probably missing something obvious.

@miyagawa
Owner

Yes AnyEvent::WebSocket would be possible but I don't think Tatsumaki can make use of it since it does use Tatsumaki::Server or Plack::Server::AnyEvent.

Reading input non-blockingly is a problem since your PSGI application (= Tatsumaki app), not a server, needs to read input, which actually causes problems when you do $sock->read since it's set to non-blocking mode.

Well, current Plack::Server::AnyEvent (on CPAN) sets the raw socket to $env->{'psgi.input'} so it's possible but fails with most frameworks (including Tatsumaki on linux) since they want to read it blockingly. There should be some extension or protocol to allow blocking apps read blockingly (but without blocking the server! so maybe using buffered read and then PerlIO) and allow non-blocking apps like WebSocket apps to read client input with the callbacks, etc.

@miyagawa
Owner

From PSGI POV, you would get a request per websocket message, with a common connection ID.

Yeah, that's one abstraction but i don't think that's a good way to do it in PSGI since WebSocket is a protocol on top of HTTP (and HTTP is merely used as a handshake) and subsequent messages shouldn't be handled as HTTP requests.

@melo

I need to re-read Tatsumaki code. There is some disconnect between my idea of Tatsumaki does and how it actually works.

I don't know why Tatsumaki would need to read anything in blocking mode.

I assumed that a Tatsumaki::Service::WebSockets could be written that would get each message from a Websocket connection and would deliver it to a Tatsumaki handler, one call per message.

@miyagawa
Owner

There is some disconnect between my idea of Tatsumaki does and how it actually works.

I don't think there is. Tatsumaki is fully non-blocking but that begins only when the application gets the control from the server. In case of AnyEvent when header parsing is done, and in case of Tatsumaki::Server, which is a fork of old AnyEvent implementation, the server reads the whole input non-blockingly and pass the PerlIO to it.

It's just becuase Tatsumaki is a normal PSGI application by default and it works on all server backends including Standalone and mod_perl.

I don't know why Tatsumaki would need to read anything in blocking mode.

Tatsumaki doesn't need to read in blocking mode, but because there's no server independent way (yet) to read input non-blockingly, it reads just like normal CGI scripts do with $sock->read (and that's why it fails on linux over internet, because it might fail with EAGAIN error).

Remember, psgi.input is a "filehandle-like" object that has read() and close(), so you can't safely use AnyEvent::Handle on it. To do that a) Tatsumaki should assume that it always runs on AnyEvent backend, or b) we define PSGI extension interface to access raw socket, possibly other than psgi.input.

So, the difficulty here is to let Tatsumaki run on non-AnyEvent backends and AnyEvent server being able to run POST requests for blocking apps (say, Catalyst) without blocking the server process.

Anyway, I don't have any intent to make this thing more complicated. Just adding an env entry like psgi.socket which has a raw socket would be good enough, but we should make sure the timing when socket is available since most servers buffers the request body and pass PerlIO, in which case reading from socket can't get the body.

So maybe, we should have an entry for sockets and then a flag if the body is already read, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.