-
-
Notifications
You must be signed in to change notification settings - Fork 50
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
Ring websocket API compatibility #115
Comments
Sounds great! Do you have a link for the spec? |
#116 is a working implementation for current ring.websocket spec |
Oh excellent, you beat me to the implementation! Thank you for your work on that. |
I have some feedback while implementing this:
|
Thanks for the feedback! It's genuinely very helpful.
The I wanted to create an implementation that could be used on a broad array of back ends without the user needing to worry about whether a particular feature was implemented, so I've gone for a "lowest common denominator" approach.
Yes. The reason why they're not separated is because a (defn wrap-websocket-edn [listener]
(reify Listener
(on-message [_ sock mesg]
(on-message listener
(wrap-socket-edn sock)
(edn/read-string mesg)))
...)) So rather than sending strings or bytes directly, you add a wrapper for translating edn, transit, json or whatever data format you want. You could even add middleware that checks the accepted protocol list on the request map, chooses a protocol, and automatically wraps the listener in the response in the appropriate translation layer. So hypothetically, something like: (defn handler [request]
{::ws/listener
{:on-message
(fn [sock mesg] (ws/send! sock (update mesg :count inc)))}})
(def wrapped-handler
(wrap-websocket-procotols handler {:edn edn-wrapper, :transit transit-wrapper}))
Yes, I wasn't entirely sure how to go about testing this. My plan was to omit it for now, and if anyone complains add in a
There's a function request-protocols for accessing the protocol list on the request map. Is that the sort of thing you mean?
I don't I've run across any implementation where this wouldn't be accessible, so it's entirely possible to add it. But wouldn't this be the same information as |
This might be a deal-breaker for some use-cases. My previous websocket application relies on client's ping for connection openness check. I would suggest to provide it as optional like
Makes sense!
I am the first one :)
Yes! I was thinking about adding
Yes but in this way we can only access it during handshaking. We will have to store it somewhere to be able it access it in listeners. |
That's interesting. It looks like Jakarta's design deliberately hides access to the ping event, considering it to be an implementation detail. I guess their view would be that if the server wants to check openness, it can send a ping itself and listen for the pong. That said, we don't have to follow what Jakarta does. We could have a protocol as you describe: (defprotocol PingListener
(on-ping [listener data])) Since you're the second person to comment on it, I'm inclined to add this. I can't see any compelling reason why not.
Are extensions something you've used, or know of someone who have used them? And if so, do you know of a Java websocket client library that supports checking for them? 🙂
Yep, I'll add a
Very true, but the same thing applies to the URI and session information, right? My inclination is to lean toward having one place to find information, as it's a potentially slippery slope of duplicated data otherwise. Even if it is perhaps a little less convenient. That said, it doesn't seem hard to pass the information via a closure: (defn handler [{:keys [remote-addr]}]
{::ws/listener {:on-open (fn [sock] (ws/send sock remote-addr))}}) |
I've released Ring 1.11.0-alpha4 with a |
I don't really use Jetty's websocket client in any of my projects but it seems to have support for extensions:
I've changed my mind and agree with you. Let's keep the API set compact and small.
|
You may want to check that the Ring websocket protocol implementations in rj9a written for the beta still work in the released version. There were a couple of changes made based on feedback. |
I have been following your development and it should work. |
I just looked over the code as a double-check, and it mostly looks great. But there's two errors that I think won't show until runtime. The first is that (defprotocol Foo (foo [x] x)
(extend-protocol Foo String (foo [x] x) (bar [x] x))
;; no errors are thrown despite `bar` not being in `Foo`! The second is more subtle: I changed the spec from using With these two changes, I think the socket definition should be: (extend-type Session
ring-ws/Socket
(-send [this msg]
(if (instance? CharSequence msg)
(.sendText this msg (write-callback noop noop))
(.sendBinary this msg (write-callback noop noop))))
(-ping [this msg]
(.sendPing this msg (write-callback noop noop)))
(-pong [this msg]
(.sendPong this msg (write-callback noop noop)))
(-close [this status-code reason]
(.close this status-code reason (write-callback {})))
(-open? [this]
(.isOpen this))
ring-ws/AsyncSocket
(-send-async [this msg succeed fail]
(if (instance? CharSequence msg)
(.sendText this msg (write-callback succeed fail))
(.sendBinary this msg (write-callback succeed fail))))) |
Great! I just created #121 for the fix |
I've been working on a Ring websocket API that's currently in experimental alpha. Would you be interested in a PR to support this API in rj9a, to be merged when the API is stable? This Ring API would be supported in conjunction with rj9a's existing implementation.
The reason I'm asking this while the Ring API is still experimental is that I'd like to try implementing the API for different third-party adapters, so I can get forewarning of any design issues.
The text was updated successfully, but these errors were encountered: