add general connect/disconnect functions, redo init! connect callbacks

This commit is contained in:
Gered 2014-12-29 02:08:35 -05:00
parent 95df1e80dc
commit 973104277f

View file

@ -5,12 +5,14 @@
[cljs.reader :as reader] [cljs.reader :as reader]
[cljs.core.async :refer [pub sub chan <! put!]] [cljs.core.async :refer [pub sub chan <! put!]]
goog.net.BrowserChannel goog.net.BrowserChannel
goog.net.BrowserChannel.State
[goog.events :as events] [goog.events :as events]
[dommy.core :refer-macros [sel1]] [dommy.core :refer-macros [sel1]]
[clj-browserchannel-messaging.utils :refer [run-middleware get-handlers encode-message decode-message]])) [clj-browserchannel-messaging.utils :refer [run-middleware get-handlers encode-message decode-message]]))
(defonce ^:private handler-middleware (atom nil)) (defonce ^:private handler-middleware (atom nil))
(defonce ^:private connect-opts (atom {}))
(defonce browser-channel (goog.net.BrowserChannel.)) (defonce browser-channel (goog.net.BrowserChannel.))
(defonce incoming-messages (chan)) (defonce incoming-messages (chan))
@ -72,12 +74,16 @@
(let [h (goog.net.BrowserChannel.Handler.)] (let [h (goog.net.BrowserChannel.Handler.)]
(set! (.-channelOpened h) (set! (.-channelOpened h)
(fn [channel] (fn [channel]
(if-let [on-connect (:on-connect @connect-opts)]
(on-connect))
(run-middleware (:on-open @handler-middleware) (fn [])))) (run-middleware (:on-open @handler-middleware) (fn []))))
(set! (.-channelHandleArray h) (set! (.-channelHandleArray h)
(fn [channel msg] (fn [channel msg]
(handle-incoming channel msg))) (handle-incoming channel msg)))
(set! (.-channelClosed h) (set! (.-channelClosed h)
(fn [channel pending undelivered] (fn [channel pending undelivered]
(if-let [on-disconnect (:on-disconnect @connect-opts)]
(on-disconnect))
(run-middleware (run-middleware
(:on-close @handler-middleware) (:on-close @handler-middleware)
(fn [pending undelivered] (fn [pending undelivered]
@ -111,6 +117,39 @@
(if-let [tag (sel1 "meta[name='anti-forgery-token']")] (if-let [tag (sel1 "meta[name='anti-forgery-token']")]
(.-content tag))) (.-content tag)))
(defn connected?
"Returns true if a browserchannel session is currently established with
the server."
[]
(= (.getState browser-channel) goog.net.BrowserChannel.State/OPENED))
(defn connect!
"Initiates a browserchannel connection with the server. Note that
init! calls this function, so you only need to use this if the
connection closes for any reason and needs to be reopened.
When a connection is established, the on-connect callback provided to
init! will be invoked (if it was provided). This will occur before
any middleware(s) are processed."
[]
(let [state (.getState browser-channel)]
(if (or (= state goog.net.BrowserChannel.State/CLOSED)
(= state goog.net.BrowserChannel.State/INIT))
(.connect
browser-channel
(:test-path @connect-opts)
(:channel-path @connect-opts)))))
(defn disconnect!
"Closes the browserchannel connection with the server.
When the disconnection finishes, the on-disconnect callback provided
to init! will be invoked (if it was provided). This will occur before
any middleware(s) are processed."
[]
(if (not= (.getState browser-channel) goog.net.BrowserChannel.State/CLOSED)
(.disconnect browser-channel)))
(defn init! (defn init!
"Sets up browserchannel for use, creating a handler with the specified "Sets up browserchannel for use, creating a handler with the specified
properties. this function should be called once on page load. properties. this function should be called once on page load.
@ -118,10 +157,15 @@
:base - the base URL on which the server's browserchannel routes are :base - the base URL on which the server's browserchannel routes are
located at. default if not specified is '/browserchannel' located at. default if not specified is '/browserchannel'
:callback - optional function that receives no arguments which will :on-connect - optional function that will be called once a
get called once the browserchannel session is established browserchannel session is established with the server.
(useful if your cljs app init should not be run until an this function receives no arguments. it will be invoked
active browserchannel session is available) before any middleware(s) are processed.
:on-disconnect - optional function that will be called once the
browserchannel session is closed for any reason. this
function receives no arguments. it will be invoked
before any middleware(s) are processed.
:middleware - a vector of middleware maps. :middleware - a vector of middleware maps.
@ -180,21 +224,14 @@
X-CSRF-Token HTTP header on all BrowserChannel POST requests to work with X-CSRF-Token HTTP header on all BrowserChannel POST requests to work with
any CSRF protection your web app uses (e.g. Ring's wrap-anti-forgery any CSRF protection your web app uses (e.g. Ring's wrap-anti-forgery
middleware)." middleware)."
[& {:keys [base middleware callback]}] [& {:keys [base middleware on-connect on-disconnect]}]
(let [base (or base "/browserchannel") (let [base (or base "/browserchannel")
anti-forgery-token (get-anti-forgery-token) anti-forgery-token (get-anti-forgery-token)]
middleware (if callback
(cons
{:on-open (fn [handler]
(fn []
(callback)
(handler)))}
middleware))]
(register-middleware! middleware) (register-middleware! middleware)
(events/listen (events/listen
js/window "unload" js/window "unload"
(fn [] (fn []
(.disconnect browser-channel) (disconnect!)
(events/removeAll))) (events/removeAll)))
(set-debug-logger! goog.debug.Logger.Level.OFF) (set-debug-logger! goog.debug.Logger.Level.OFF)
; this seems to help prevent premature session timeouts from occuring (vs the default of 3) ; this seems to help prevent premature session timeouts from occuring (vs the default of 3)
@ -202,6 +239,8 @@
(.setHandler browser-channel (->handler)) (.setHandler browser-channel (->handler))
(if anti-forgery-token (if anti-forgery-token
(.setExtraHeaders browser-channel (js-obj "X-CSRF-Token" anti-forgery-token))) (.setExtraHeaders browser-channel (js-obj "X-CSRF-Token" anti-forgery-token)))
(.connect browser-channel (reset! connect-opts {:test-path (str base "/test")
(str base "/test") :channel-path (str base "/bind")
(str base "/bind")))) :on-connect on-connect
:on-disconnect on-disconnect})
(connect!)))