views.reagent/views.reagent.sente/src/views/reagent/sente/client.cljs

78 lines
3 KiB
Clojure

(ns views.reagent.sente.client
(:require
[views.reagent.client.core :as client]
[taoensso.sente :as sente]))
(defonce ^:private send-buffer (atom []))
(defn- sente-connected?
[sente-chsk-map]
(:open? @(:state sente-chsk-map)))
(defn send-fn
[sente-chsk-map data]
(if-not (sente-connected? sente-chsk-map)
(swap! send-buffer conj data)
((:send-fn sente-chsk-map) data)))
(defn- flush-send-buffer!
[sente-chsk-map]
(doseq [data @send-buffer]
(send-fn sente-chsk-map data))
(reset! send-buffer []))
(defn chsk-open-event?
"returns true if the sente event is for a channel-socket state change to 'open' or 'connected'."
[{:keys [event] :as ev}]
; for :chsk/state events, sente sends the event data in the form [old-state new-state].
; we only care about the new state for the purposes of performing this check ...
(let [[ev-id ev-data] event]
(and (= :chsk/state ev-id)
(:open? (second ev-data)))))
(defn on-open!
"should be called when a new Sente connection is established. ev is the event
map provided by Sente where id = :chsk/state, and :open? = true. make sure
to call this function on all connection open events, not just the first one."
[sente-chsk-map {:keys [event id client-id] :as ev}]
(flush-send-buffer! sente-chsk-map)
(client/on-open!))
(defn on-receive!
"should be called whenever a new message is received by Sente from the server.
ev is the event map provided by Sente where id = :chsk/recv. if this function
returns true it means the received message was for views.reagent and your
application code does not need to handle the event itself."
[sente-chsk-map {:keys [event id client-id] :as ev}]
(let [[event-id event-data] event]
(client/on-receive! event-data)))
(defn default-event-msg-handler
"very basic Sente event handler that can be used with Sente's start-chsk-router!
which makes sure on-open! and on-receive! are called when appropriate. if your
application does not need to do any custom Sente event handling, then you can
opt to use this event handler."
[sente-chsk-map {:keys [event id client-id] :as ev}]
(cond
(chsk-open-event? event)
(on-open! sente-chsk-map ev)
(= :chsk/recv id)
(on-receive! sente-chsk-map ev)))
(defn init!
"performs initial configuration necessary to hook Sente into views.reagent as the
client/server messaging backend. should be called once on page-load after the
Sente channel socket has been created (via make-channel-socket!).
extra available options specific to views.reagent/sente:
:use-default-sente-router?
- if set, enables the use of a default Sente event handler (set via Sente's
start-chsk-router!). if your application does not need to respond to any
Sente events itself, then you may wish to use this option."
[sente-chsk-map & [options]]
(reset! client/send-fn #(send-fn sente-chsk-map %))
(if (:use-default-sente-router? options)
(sente/start-chsk-router! (:ch-recv sente-chsk-map) #(default-event-msg-handler sente-chsk-map %))))