Reconnect automatically when disconnected

- only send all server items when connecting initially
- on reconnect, send pending events (that couldn't be sent)
- rudimentary solution
This commit is contained in:
Nicholas Kariniemi 2013-10-22 00:16:46 +03:00
parent 307c6cfad5
commit d4753418ca
2 changed files with 45 additions and 34 deletions

View file

@ -27,12 +27,21 @@
(println (count @connected-clients) "client(s) still connected") (println (count @connected-clients) "client(s) still connected")
(a/close! client-chan)) (a/close! client-chan))
(defn send-current-grubs-and-recipes-to-client [client-chan]
(let [add-grubs-event {:event :add-grub-list
:grubs (db/get-current-grubs)}
add-recipes-event {:event :add-recipe-list
:recipes (db/get-current-recipes)}]
(go (>! client-chan add-grubs-event)
(>! client-chan add-recipes-event))))
(defn add-event-to-incoming-channel [raw-event ws-channel-id] (defn on-receive [raw-event ws-channel-id client-chan]
(let [parsed-event (read-string raw-event) (let [parsed-event (read-string raw-event)
event (assoc parsed-event :ws-channel ws-channel-id)] event (assoc parsed-event :ws-channel ws-channel-id)]
(println "Received event" event) (println "Received event" event)
(go (>! incoming-events event)))) (if (= (:event event) :send-all-items)
(send-current-grubs-and-recipes-to-client client-chan)
(go (>! incoming-events event)))))
(defn forward-other-events-to-client [c ws-channel] (defn forward-other-events-to-client [c ws-channel]
(a/go-loop [] (a/go-loop []
@ -41,25 +50,13 @@
(httpkit/send! ws-channel (str event)) (httpkit/send! ws-channel (str event))
(recur)))) (recur))))
(defn send-current-grubs-and-recipes-to-client [client-chan]
(let [add-grubs-event {:event :add-grub-list
:grubs (db/get-current-grubs)}
add-recipes-event {:event :add-recipe-list
:recipes (db/get-current-recipes)}]
(go (>! client-chan add-grubs-event)
(>! client-chan add-recipes-event))))
;(a/pipe (db/get-current-grubs-as-events) client-chan false)
;(a/pipe (db/get-current-recipes-as-events) client-chan false))
(defn setup-new-connection [ws-channel] (defn setup-new-connection [ws-channel]
(let [[ws-channel-id client-chan] (add-connected-client! ws-channel)] (let [[ws-channel-id client-chan] (add-connected-client! ws-channel)]
(println "Client connected:" (.toString ws-channel) (str "(" ws-channel-id ")")) (println "Client connected:" (.toString ws-channel) (str "(" ws-channel-id ")"))
(println (count @connected-clients) "client(s) connected") (println (count @connected-clients) "client(s) connected")
(httpkit/on-close ws-channel #(remove-connected-client! % ws-channel ws-channel-id client-chan)) (httpkit/on-close ws-channel #(remove-connected-client! % ws-channel ws-channel-id client-chan))
(httpkit/on-receive ws-channel #(add-event-to-incoming-channel % ws-channel-id)) (httpkit/on-receive ws-channel #(on-receive % ws-channel-id client-chan))
(forward-other-events-to-client client-chan ws-channel) (forward-other-events-to-client client-chan ws-channel)))
(send-current-grubs-and-recipes-to-client client-chan)))
(defn websocket-handler [request] (defn websocket-handler [request]
(httpkit/with-channel request ws-channel (setup-new-connection ws-channel))) (httpkit/with-channel request ws-channel (setup-new-connection ws-channel)))

View file

@ -1,31 +1,45 @@
(ns grub.websocket (ns grub.websocket
(:require [cljs.core.async :as a :refer [<! >! chan]] (:require [cljs.core.async :as a :refer [<! >! chan]]
[cljs.reader]) [cljs.reader]
goog.net.WebSocket
goog.events.EventHandler
goog.events.EventTarget)
(:require-macros [cljs.core.async.macros :refer [go go-loop]] (:require-macros [cljs.core.async.macros :refer [go go-loop]]
[grub.macros :refer [log logs]])) [grub.macros :refer [log logs]]))
(def websocket* (atom nil)) (def websocket* (atom nil))
(def pending-events (atom []))
(defn on-connected [event]
(log "Connected:" event)
(when (> (count @pending-events))
(doseq [event @pending-events] (.send @websocket* event))
(reset! pending-events [])))
(defn send-outgoing-events [ch] (defn send-outgoing-events [ch]
(go-loop [] (go-loop []
(let [event (<! ch)] (let [event (<! ch)]
(.send @websocket* event) (if (.isOpen @websocket*)
(recur)))) (.send @websocket* event)
(swap! pending-events conj event))
(recur))))
(defn on-message-fn [out]
(fn [event]
(let [grub-event (cljs.reader/read-string (.-message event))]
(go (>! out grub-event)))))
(defn receive-remote-events []
(let [out (chan)]
(aset @websocket*
"onmessage"
(fn [event]
(let [grub-event (cljs.reader/read-string (.-data event))]
(go (>! out grub-event)))))
out))
(defn get-remote-chan [to-remote] (defn get-remote-chan [to-remote]
(let [server-url (str "ws://" (.-host (.-location js/document)) "/ws")] (let [server-url (str "ws://" (.-host (.-location js/document)) "/ws")
(reset! websocket* (js/WebSocket. server-url)) handler (goog.events.EventHandler.)
(aset @websocket* "onopen" (fn [event] (log "Connected:" event))) remote-events (chan)]
(aset @websocket* "onclose" (fn [event] (log "Connection closed:" event))) (reset! websocket* (goog.net.WebSocket.))
(aset @websocket* "onerror" (fn [event] (log "Connection error:" event))) (.listen handler @websocket* goog.net.WebSocket.EventType.OPENED on-connected false)
(.listen handler @websocket* goog.net.WebSocket.EventType.MESSAGE (on-message-fn remote-events) false)
(.listen handler @websocket* goog.net.WebSocket.EventType.CLOSED #(log "Closed:" %) false)
(.listen handler @websocket* goog.net.WebSocket.EventType.ERROR #(log "Error:" %) false)
(send-outgoing-events to-remote) (send-outgoing-events to-remote)
(receive-remote-events))) (go (>! to-remote {:event :send-all-items}))
(.open @websocket* server-url)
remote-events))