Closed AlexHill closed 9 years ago
Hi Alex - not at all!
Chord exposes the closure of the web-socket by closing the core.async channel - we can tell when this has happened because a take from the channel will return nil. (In fact, the only time a take on a core.async channel returns nil is when it's been closed - you cannot put nil onto a channel.)
I usually wrap this up in a go-loop
, which repeatedly takes from the channel - if we get a message back, then we process it in some way; otherwise, if we get nil, we know we need to clean up:
(:require [chord.http-kit :refer [with-channel]]
[clojure.core.async :refer [go-loop <! >!]])
(def clients (atom #{}))
(defn handle-req [req]
(with-channel req ch
(swap! clients conj ch)
(go-loop []
(if-let [{:keys [message error]} (<! ch)]
(do
(if (nil? error)
(process-msg! message)
(process-error! error))
(recur))
;; The channel take has returned nil
;; -> the channel has closed
;; -> the WS has been closed
;; -> we need to clean up
(swap! clients disj ch)))))
HTH :)
James
Perfect! Thanks James.
I started with your solution which worked great. Then, since I was dealing with real core.async channels thanks to chord, my use-case allowed me to replace my clients
atom with a channel and a mult and further reduce my handler to:
(defn handle-req [message-mult req]
(with-channel req ch {:format :transit-json}
(tap message-mult ch)))
(defroutes all-routes
(GET "/ws" [] (partial handle-req message-mult))
...)
chord closes each channel when its websocket disconnects, and the mult automatically untaps closed channels. All I have to do when I want to send a message is chuck a map on message-ch
, and chord makes sure that map ends up in my browser. Beautiful:
(defn handle-event [message-ch event]
(go
(>! message-ch (make-message event))))
This is downright amazing. I never want to go back.
Many thanks, Alex
Great, glad to hear it! :D
James
Hi James,
I currently have a small web service, using http-kit's websocket support, which broadcasts messages to a number of clients.
My connection handler looks like this:
I want to convert my program to use chord so I don't have to do my own transit handling, but I'm not sure how to handle client disconnections to remove dead channels from
clients
. As far as I can seeon-close
isn't exposed. Am I just thinking about this wrong? Is there some better way of doing what I want?Sorry if this is dumb, I'm very new.
Cheers, Alex