New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WebSockets #1305
base: main
Are you sure you want to change the base?
WebSockets #1305
Conversation
macro setup_ws_call_method(&block) | ||
|
||
abstract def on_message(message) | ||
abstract def on_close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought was by having these abstract, the websocket can proxy to them, and forces you to set these up. Websockets have a few other methods though.... are any of them as necessary? Is there ever a time you'd use a websocket and not use these?
src/lucky/web_socket_action.cr
Outdated
def initialize(@context : HTTP::Server::Context, @route_params : Hash(String, String)) | ||
@websocket = Lucky::WebSocket.new(self.class) do |ws| | ||
ws.on_message { |message| on_message(message) } | ||
ws.on_close { on_close } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't make on_message
and on_close
abstract, then we can't guarantee they will exist which means we can't do this proxy. You'd just have to use them on your own. Not bad, but is this the better path?
why does |
@fernandes With websockets, would you ever need to send an Accept header to say the messages being passed back and forth are of any specific type? Or does that not matter? I'm wondering if there should be a default Also, I inherited the action from a base class just because that's what you'd normally do in any other action. My hope here is that this can feel like the rest of the actions (i.e. BrowserAction, ApiAction). Then you could have all of your websocket actions inherit from the same parent class in case they all need to do something like ensure you're logged in before connecting or whatever. |
This comes in nice timing. I was actually planning to use @fernandes cable repo for this. What I want in WebSocket support is:
|
@confact ohhh that's nice to hear! I'm working with @jwoertink in some stability/scalability issues, so I'd advice to not use in production atm, hope to fix this soon 🤞 anything you can ping me on lucky discord server 😉 |
I built a mini chat app using this setup over the weekend. Worked pretty well, but now I have a better idea of how I want to do this. It's going to require a TON more work than I originally wanted, but will be much better in the long run. I'll try to get a PoC out to flesh out the details, but in the end, I think this may have to be a post 1.0 feature. For now, anyone coming to this looking for WebSocket support, use https://github.com/cable-cr/cable |
As part of this PR, I think you'll also need to add |
I wish I would have done this 😭 I was going to come back to this, and I don't have any of that code I worked on now.... I guess I'll have to just re-imagine the whole thing 😮💨 |
@@ -58,6 +58,17 @@ module Lucky::Routable | |||
end | |||
{% end %} | |||
|
|||
# Define a route that responds to a WebSocket request | |||
macro ws(path, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would need wss
too
@handler = HTTP::WebSocketHandler.new do |ws| | ||
@socket = ws | ||
ws.on_ping { ws.pong("PONG") } | ||
call | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would create a new handler for every websocket action you added. I'm not sure how many a person would add, but it seems like you should only have 1, and the handler would just route to each action based on where it connected. This looks like what Kemal seems to be doing too. A single instance that just adds each route and the handler.
Purpose
Fixes #554
Description
I wanted to get the discussion moving on how WebSockets might look in Lucky. The idea here would be that Lucky provides a very basic interface to using WebSockets from the backend, but it would be up to the developer to implement the client side portion on their own with whatever tools they know.
This implementation tries to stick as close to current actions as we can while maintaining all of the type-safety features that Lucky gives us. It shouldn't feel like a ton of setup to get using.
Imagine you just generated a fresh Lucky app with this in it (maybe the wizard asks if you need websockets?), here is code that would be in your generated app:
Then you add your action:
And your JS:
Note
This setup "works", but it's still early planning stages. It'll probably change drastically before being ready for a real review.
Checklist
crystal tool format spec src
./script/setup
./script/test