Open bluetech opened 6 years ago
That's a very good point.
The current design doesn't make it easy to implement this because it separates strongly the opening handshake (where you could return a 404) from the data transfer phase (the actual websockets protocol).
I think there's room for a higher level API than calling serve
, possibly with a custom WebSocketServerProtocol
. In addition to websockets.serve(handler, host, port)
we could provide websockets.route(routes, host, port)
.
We could also add that to serve
itself and dispatch on the type of the first argument... My gut feeling is that it would muddy the fact that route
brings in an URL router and thus has a much larger scope.
There's also the question of designing the URL router. We could simply copy https://github.com/django/deps/blob/master/final/0201-simplified-routing-syntax.rst or the Flask URL router (which inspired DEP 201).
The URL router should be swappable anyway, similar to create_protocol=WebSocketServerProtocol
for swapping the protocol class.
Just a quick note in response to the original post:
This is a little messy. Is there a better way to do this?
I'm actually somewhat okay with how routing can be handled currently, though I agree it's not easy to "discover" how to best handle it.
Regarding the routing and 404 handling being split between WebSocketServerProtocol.process_request()
and ws_handler()
, here is a way to have all of the handling be done in process_request()
to avoid this split:
The process_request()
function can parse the URL, and if the URL should be handled as a websocket, process_request()
can save the function to do the handling as an attribute of the WebSocketServerProtocol
instance self
. Then, ws_handler(websocket)
can access this function as an attribute of websocket
so that ws_handler()
doesn't need to parse the URL again, etc.
If we get a solid integration with sanic (cf. https://github.com/channelcat/sanic/issues/1214) we could point to sanic rather than write our own router.
Or we could write our own router because that's fun :-) and because I prefer centralizing the declaration of routes (like Django, unlike Flask).
Hey all, I've made a small package for URL routing with this library. You can check it out here yrouter-websockets.
I'm hoping that it will be useful to some folks here and I'll be happy to receive any feedback.
Another third-party solution courtesy of @uranusjr: https://github.com/uranusjr/websockets-routes .
Consider a websocket server with the following example URL structure:
/echo
- First WS endpoint./chat/<room: string>
- Second WS endpoint./health
- Dumb HTTP endpointIf we only had the first two, it may be handled easily enough in the handler, with something like this:
To handle the
/health
endpoint, we can overridewebsockets.WebSocketServerProtocol.process_request
.To handle the 404 requirement, it seems like it should also be handled in
process_request
, by checkingROUTES
and failing if there's no match.This is a little messy. Is there a better way to do this?
Some unsolicited thoughts:
In general I like that the library is focused and does not try to handle routing or be a full HTTP server.
There are 2 approaches I can see a library like this take:
The library has control and calls into user code. This is how Torando does it for example -- you define an
Application
object with routes, and Tornado parses the URL and calls the user's HTTP or WS handler.The user has control and calls into the library. In the extreme this is how a library like wsproto works, but mostly what I mean is something like this:
The current API does a little bit of both, so it works great for the intended use case, but becomes harder when straying a little.