Open vstreame opened 2 years ago
@lpil Thanks for the feedback! So disclaimer, I'm still pretty unfamiliar with gleam/otp
still, but it seems like this API may still work by hooking into the websocket_init/1
handler as described here: https://ninenines.eu/docs/en/cowboy/2.9/guide/ws_handlers/#_post_upgrade_initialization
I would expect that would be the place that one one hook in to register their new self()
pid with some sort of event bus / connection tracker.
Then that connection tracker can send normal messages to the pid which will trigger the on_message
handler which will will allow us to then trigger a Frame to be sent to the client?
Does that all make sense? Or am I'm misunderstanding how gleam/otp
currently works?
You've got the general idea, and that is largely how cowboy websockets work today as I understand. It becomes more complex when you consider the types of messages send to the websocket service process. If there's a handle_message
callback in the websocket service abstraction the type of the message must be Dynamic
as it would be called for any possible message, and in that case we have no type information. To have typed messages the abstraction would need to be based around gleam_otp
's (soon to be substantially modified) channels, as they are how we link type information to Erlang messages.
The API would likely need to look less like a gen_server
and more like gleam_otp
's actor
. How easy it would be to do this within the constraints of cowboy's APIs I'm unsure.
@lpil Ah, yes totally get it now when it comes to types. I think what I'll do is publish this as a separate experimental package for now then just so I can start playing around with real time apps with Gleam myself. Then once those new OTP APIs exist we can create a better more official API for this package!
FYI, got tests all working over in the new repository here: https://github.com/vstreame/gleam_cowboy_websockets
Thinking about this more, perhaps it's OK that the typing is not amazing here. If that's a limitation of cowboy it's good motivation to make a Gleam websocket server that is well typed and hopefully even faster than cowboy!
@lpil I've also spent the last week learning more about gleam/otp
and how the actor
and process
modules work better now. I may be able to take a second crack at this to better use the actor
APIs
(Note: This PR is rebased on #12 just to have some test infra in place. We'll need to merge that before this one can land)(Note 2: Cannot get tests to pass until we get a new version ofnerf
out that works with HTTP 3.0 APIs. PR: https://github.com/lpil/nerf/pull/3)What
This is an experimental PR to add Websocket support to the Gleam API. The main change is that when dealing with websockets we more than one "handler". Not only do we need the initial HTTP handler, but we also needs handlers for
As well as we need a piece of state to share between all of these handlers.
Please view the tests for the proposed API.
Why
This would unlock Gleam as a language to build "real-time" applications with. Which would be a very neat use-case!
How
This PR is mostly to discuss the proposed API, but here is also how it currently implements that API (which I'm less sure of). Instead of passing a single handler function to
init/1
we instead pass down a map with known keys.handler
- The function that is passed ahttp/request.{Request}
and returns aWSResponse
. AWSResponse
is either a wrapper over a normalhttp/response.{Response}
or it's anUpgrade(init_state)
. WhenUpgrade
is returned this is signal to us that the developer wants to upgrade the request to a persistant websocket connection.on_ws_init
- This handler is used to grab any relevantpid
s and/or return a frame immediately to the clienton_ws_frame
- Handler called whenever a new WS frame is sent from the clienton_message
- Handler called whenever pid receives as message from ErlangEach handler is expected to tell us if we want to send any Frames in response as well as what the new state should be updated to.
Links