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")
(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)
event (assoc parsed-event :ws-channel ws-channel-id)]
(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]
(a/go-loop []
@ -41,25 +50,13 @@
(httpkit/send! ws-channel (str event))
(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]
(let [[ws-channel-id client-chan] (add-connected-client! ws-channel)]
(println "Client connected:" (.toString ws-channel) (str "(" ws-channel-id ")"))
(println (count @connected-clients) "client(s) connected")
(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))
(forward-other-events-to-client client-chan ws-channel)
(send-current-grubs-and-recipes-to-client client-chan)))
(httpkit/on-receive ws-channel #(on-receive % ws-channel-id client-chan))
(forward-other-events-to-client client-chan ws-channel)))
(defn websocket-handler [request]
(httpkit/with-channel request ws-channel (setup-new-connection ws-channel)))

View file

@ -1,31 +1,45 @@
(ns grub.websocket
(: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]]
[grub.macros :refer [log logs]]))
(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]
(go-loop []
(let [event (<! ch)]
(.send @websocket* event)
(recur))))
(let [event (<! ch)]
(if (.isOpen @websocket*)
(.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]
(let [server-url (str "ws://" (.-host (.-location js/document)) "/ws")]
(reset! websocket* (js/WebSocket. server-url))
(aset @websocket* "onopen" (fn [event] (log "Connected:" event)))
(aset @websocket* "onclose" (fn [event] (log "Connection closed:" event)))
(aset @websocket* "onerror" (fn [event] (log "Connection error:" event)))
(let [server-url (str "ws://" (.-host (.-location js/document)) "/ws")
handler (goog.events.EventHandler.)
remote-events (chan)]
(reset! websocket* (goog.net.WebSocket.))
(.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)
(receive-remote-events)))
(go (>! to-remote {:event :send-all-items}))
(.open @websocket* server-url)
remote-events))