Liking cljdoc? Tell your friends :D

taoensso.sente

Channel sockets for Clojure/Script.

Protocol  | client>server | client>server ?+ ack/reply | server>user push
  • WebSockets: ✓ [1] ✓
  • Ajax: [2] ✓ [3]

[1] Emulate with cb-uuid wrapping [2] Emulate with dummy-cb wrapping [3] Emulate with long-polling

Abbreviations:

  • chsk - Channel socket (Sente's own pseudo "socket")
  • server-ch - Underlying web server's async channel that implement Sente's server channel interface
  • sch - server-ch alias
  • uid - User-id. An application-level user identifier used for async push. May have semantic meaning (e.g. username, email address), may not (e.g. client/random id) - app's discretion.
  • cb - Callback
  • tout - Timeout
  • ws - WebSocket/s
  • pstr - Packed string. Arbitrary Clojure data serialized as a string (e.g. edn) for client<->server comms
  • udt - Unix timestamp (datetime long)

Special messages:

  • Callback wrapping: [<clj> <?cb-uuid>] for [1], [2]

  • Callback replies: :chsk/closed, :chsk/timeout, :chsk/error

  • Client-side events: [:chsk/handshake [<?uid> nil[4] <?handshake-data> <first-handshake?>]] [:chsk/state [<old-state-map> <new-state-map>]] [:chsk/recv <ev-as-pushed-from-server>] ; Server>user push [:chsk/ws-ping]

  • Server-side events: [:chsk/bad-package <packed-str>] [:chsk/bad-event <event>] [:chsk/uidport-open <uid>] [:chsk/uidport-close <uid>] [:chsk/ws-ping]

Channel socket state map: :type - e/o #{:auto :ws :ajax} :open? - Truthy iff chsk appears to be open (connected) now :ever-opened? - Truthy iff chsk handshake has ever completed successfully :first-open? - Truthy iff chsk just completed first successful handshake :uid - User id provided by server on handshake, or nil :csrf-token - CSRF token provided by server on handshake, or nil :handshake-data - Arb user data provided by server on handshake :last-ws-error - ?{:udt _ :ev <WebSocket-on-error-event>} :last-ws-close - ?{:udt _ :ev <WebSocket-on-close-event> :clean? _ :code _ :reason _} :last-close - ?{:udt _ :reason _}, with reason e/o #{nil :requested-disconnect :requested-reconnect :downgrading-ws-to-ajax :unexpected} :udt-next-reconnect - Approximate udt of next scheduled auto-reconnect attempt

Notable implementation details:

  • core.async is used liberally where brute-force core.async allows for significant implementation simplifications. We lean on core.async's efficiency here.
  • For WebSocket fallback we use long-polling rather than HTTP 1.1 streaming (chunked transfer encoding). Http-kit does support chunked transfer encoding but a small minority of browsers &/or proxies do not. Instead of implementing all 3 modes (WebSockets, streaming, long-polling) - it seemed reasonable to focus on the two extremes (performance + compatibility). In any case client support for WebSockets is growing rapidly so fallback modes will become increasingly irrelevant while the extra simplicity will continue to pay dividends.

General-use notes:

  • Single HTTP req+session persists over entire chsk session but cannot modify sessions! Use standard a/sync HTTP Ring req/resp for logins, etc.
  • Easy to wrap standard HTTP Ring resps for transport over chsks. Prefer this approach to modifying handlers (better portability).

[4] Used to be a csrf-token. Was removed in v1.14 for security reasons. A nil remains for semi-backwards-compatibility with pre-v1.14 clients.

Channel sockets for Clojure/Script.

    Protocol  | client>server | client>server ?+ ack/reply | server>user push
  * WebSockets:       ✓              [1]                           ✓
  * Ajax:            [2]              ✓                           [3]

  [1] Emulate with cb-uuid wrapping
  [2] Emulate with dummy-cb wrapping
  [3] Emulate with long-polling

Abbreviations:
  * chsk      - Channel socket (Sente's own pseudo "socket")
  * server-ch - Underlying web server's async channel that implement
                Sente's server channel interface
  * sch       - server-ch alias
  * uid       - User-id. An application-level user identifier used for async
                push. May have semantic meaning (e.g. username, email address),
                may not (e.g. client/random id) - app's discretion.
  * cb        - Callback
  * tout      - Timeout
  * ws        - WebSocket/s
  * pstr      - Packed string. Arbitrary Clojure data serialized as a
                string (e.g. edn) for client<->server comms
  * udt       - Unix timestamp (datetime long)

Special messages:
  * Callback wrapping: [<clj> <?cb-uuid>] for [1], [2]
  * Callback replies: :chsk/closed, :chsk/timeout, :chsk/error

  * Client-side events:
      [:chsk/handshake [<?uid> nil[4] <?handshake-data> <first-handshake?>]]
      [:chsk/state [<old-state-map> <new-state-map>]]
      [:chsk/recv <ev-as-pushed-from-server>] ; Server>user push
      [:chsk/ws-ping]

  * Server-side events:
      [:chsk/bad-package <packed-str>]
      [:chsk/bad-event   <event>]
      [:chsk/uidport-open  <uid>]
      [:chsk/uidport-close <uid>]
      [:chsk/ws-ping]

Channel socket state map:
  :type               - e/o #{:auto :ws :ajax}
  :open?              - Truthy iff chsk appears to be open (connected) now
  :ever-opened?       - Truthy iff chsk handshake has ever completed successfully
  :first-open?        - Truthy iff chsk just completed first successful handshake
  :uid                - User id provided by server on handshake,    or nil
  :csrf-token         - CSRF token provided by server on handshake, or nil
  :handshake-data     - Arb user data provided by server on handshake
  :last-ws-error      - ?{:udt _ :ev <WebSocket-on-error-event>}
  :last-ws-close      - ?{:udt _ :ev <WebSocket-on-close-event>
                          :clean? _ :code _ :reason _}
  :last-close         - ?{:udt _ :reason _}, with reason e/o
                          #{nil :requested-disconnect :requested-reconnect
                           :downgrading-ws-to-ajax :unexpected}
  :udt-next-reconnect - Approximate udt of next scheduled auto-reconnect attempt

Notable implementation details:
  * core.async is used liberally where brute-force core.async allows for
    significant implementation simplifications. We lean on core.async's
    efficiency here.
  * For WebSocket fallback we use long-polling rather than HTTP 1.1 streaming
    (chunked transfer encoding). Http-kit _does_ support chunked transfer
    encoding but a small minority of browsers &/or proxies do not. Instead of
    implementing all 3 modes (WebSockets, streaming, long-polling) - it seemed
    reasonable to focus on the two extremes (performance + compatibility).
    In any case client support for WebSockets is growing rapidly so fallback
    modes will become increasingly irrelevant while the extra simplicity will
    continue to pay dividends.

General-use notes:
  * Single HTTP req+session persists over entire chsk session but cannot
    modify sessions! Use standard a/sync HTTP Ring req/resp for logins, etc.
  * Easy to wrap standard HTTP Ring resps for transport over chsks. Prefer
    this approach to modifying handlers (better portability).

[4] Used to be a csrf-token. Was removed in v1.14 for security reasons.
A `nil` remains for semi-backwards-compatibility with pre-v1.14 clients.
raw docstring

ajax-litecljs

Alias of taoensso.encore/ajax-lite

Alias of `taoensso.encore/ajax-lite`
raw docstring

as-eventclj/s

(as-event x)

assert-eventclj/s

(assert-event x)

cb-error?clj/s

(cb-error? cb-reply-clj)

cb-success?clj/s

(cb-success? cb-reply-clj)

ChAjaxSocketcljs


ChAutoSocketcljs


chsk-connect!clj/s

(chsk-connect! chsk)

chsk-disconnect!clj/s

(chsk-disconnect! chsk)

chsk-reconnect!clj/s

(chsk-reconnect! chsk)

Useful for reauthenticating after login/logout, etc.

Useful for reauthenticating after login/logout, etc.
raw docstring

chsk-send!clj/s

(chsk-send! chsk ev)
(chsk-send! chsk ev opts)
(chsk-send! chsk ev ?timeout-ms ?cb)

Sends [ev-id ev-?data :as event], returns true on apparent success.

Sends `[ev-id ev-?data :as event]`, returns true on apparent success.
raw docstring

ChWebSocketcljs


client-event-msg?clj/s

(client-event-msg? x)

debug-mode?_clj/s


EdnPackercljs


event-msg?clj/s


event?clj/s

(event? x)

Valid [ev-id ?ev-data] form?

Valid [ev-id ?ev-data] form?
raw docstring

IChSocketclj/s≠protocol

-chsk-send!clj/s

(-chsk-send! chsk ev opts)

-chsk-reconnect!clj/s

(-chsk-reconnect! chsk)

-chsk-disconnect!clj/s

(-chsk-disconnect! chsk reason)

-chsk-connect!clj/s

(-chsk-connect! chsk)

js-websocket-creatorcljs

(js-websocket-creator url {:keys [on-msg on-error on-close]})

JSDefaultWebSocketcljs


jvm-websocket-creatorclj

(jvm-websocket-creator)

make-channel-socket-client!clj/s≠

clj
(make-channel-socket-client! path
                             ?csrf-token
                             &
                             [{:keys [type protocol host params packer ajax-opts
                                      ws-kalive-ms cws-creator recv-buf-or-n
                                      client-id backoff-ms-fn]
                               :as opts
                               :or {type :auto
                                    recv-buf-or-n (async/sliding-buffer 2048)
                                    packer :edn
                                    client-id (enc/uuid-str)
                                    backoff-ms-fn enc/exp-backoff
                                    ws-kalive-ms (enc/ms :secs 20)
                                    cws-creator jvm-websocket-creator}}])
cljs
(make-channel-socket-client! path
                             ?csrf-token
                             &
                             [{:keys [type protocol host params packer ajax-opts
                                      ws-kalive-ms cws-creator recv-buf-or-n
                                      client-id backoff-ms-fn]
                               :as opts
                               :or {type :auto
                                    recv-buf-or-n (async/sliding-buffer 2048)
                                    packer :edn
                                    client-id (enc/uuid-str)
                                    backoff-ms-fn enc/exp-backoff
                                    ws-kalive-ms (enc/ms :secs 20)
                                    cws-creator js-websocket-creator}}])

Returns nil on failure, or a map with keys: :ch-recv ; core.async channel to receive event-msgs (internal or from ; clients). May put! (inject) arbitrary events to this channel. :send-fn ; (fn [event & [?timeout-ms ?cb-fn]]) for client>server send. :state ; Watchable, read-only (atom {:type _ :open? _ :uid _ :csrf-token _}). :chsk ; IChSocket implementer. You can usu. ignore this. FIXME should be a parameter as well??

Common options: :type ; e/o #{:auto :ws :ajax}. You'll usually want the default (:auto). :protocol ; Server protocol, e/o #{:http :https}. :host ; Server host (defaults to current page's host). :params ; Map of any params to incl. in chsk Ring requests (handy ; for application-level auth, etc.). :packer ; :edn (default), or an IPacker implementation. :ajax-opts ; Base opts map provided to taoensso.encore/ajax-lite. :ws-kalive-ms ; Ping to keep a WebSocket conn alive if no activity ; w/in given msecs. Should be different to server's :ws-kalive-ms. :cws-creator ; function returning an implementation of IClientWebsocket

Returns nil on failure, or a map with keys:
  :ch-recv ; core.async channel to receive `event-msg`s (internal or from
           ; clients). May `put!` (inject) arbitrary `event`s to this channel.
  :send-fn ; (fn [event & [?timeout-ms ?cb-fn]]) for client>server send.
  :state   ; Watchable, read-only (atom {:type _ :open? _ :uid _ :csrf-token _}).
  :chsk    ; IChSocket implementer. You can usu. ignore this. FIXME should be a parameter as well??

Common options:
  :type           ; e/o #{:auto :ws :ajax}. You'll usually want the default (:auto).
  :protocol       ; Server protocol, e/o #{:http :https}.
  :host           ; Server host (defaults to current page's host).
  :params         ; Map of any params to incl. in chsk Ring requests (handy
                  ; for application-level auth, etc.).
  :packer         ; :edn (default), or an IPacker implementation.
  :ajax-opts      ; Base opts map provided to `taoensso.encore/ajax-lite`.
  :ws-kalive-ms   ; Ping to keep a WebSocket conn alive if no activity
                  ; w/in given msecs. Should be different to server's :ws-kalive-ms.
  :cws-creator    ; function returning an implementation of IClientWebsocket
raw docstring

make-channel-socket-server!clj/s

(make-channel-socket-server!
  web-server-ch-adapter
  &
  [{:keys [recv-buf-or-n ws-kalive-ms lp-timeout-ms send-buf-ms-ajax
           send-buf-ms-ws user-id-fn bad-csrf-fn csrf-token-fn handshake-data-fn
           packer]
    :or {ws-kalive-ms (enc/ms :secs 25)
         send-buf-ms-ws 30
         lp-timeout-ms (enc/ms :secs 20)
         csrf-token-fn
           (fn [ring-req]
               (or (get-in ring-req [:session :csrf-token])
                   (get-in ring-req
                           [:session
                            :ring.middleware.anti-forgery/anti-forgery-token])
                   (get-in ring-req [:session "__anti-forgery-token"])))
         packer :edn
         send-buf-ms-ajax 100
         handshake-data-fn (fn [ring-req] nil)
         user-id-fn (fn [ring-req] (get-in ring-req [:session :uid]))
         recv-buf-or-n (async/sliding-buffer 1000)
         bad-csrf-fn (fn [ring-req] {:status 403 :body "Bad CSRF token"})}}])

Takes a web server adapter[1] and returns a map with keys: :ch-recv ; core.async channel to receive event-msgs (internal or from clients). :send-fn ; (fn [user-id ev] for server>user push. :ajax-post-fn ; (fn [ring-req]) for Ring CSRF-POST + chsk URL. :ajax-get-or-ws-handshake-fn ; (fn [ring-req]) for Ring GET + chsk URL. :connected-uids ; Watchable, read-only (atom {:ws #{} :ajax #{} :any #{_}}).

Common options: :user-id-fn ; (fn [ring-req]) -> unique user-id for server>user push. :csrf-token-fn ; ?(fn [ring-req]) -> CSRF-token for Ajax POSTs and WS handshake. ; CSRF check will be skipped iff nil (NOT RECOMMENDED!).

:handshake-data-fn ; (fn [ring-req]) -> arb user data to append to handshake evs. :ws-kalive-ms ; Ping to keep a WebSocket conn alive if no activity ; w/in given msecs. Should be different to client's :ws-kalive-ms. :lp-timeout-ms ; Timeout (repoll) long-polling Ajax conns after given msecs. :send-buf-ms-ajax ; [2] :send-buf-ms-ws ; [2] :packer ; :edn (default), or an IPacker implementation.

[1] e.g. (taoensso.sente.server-adapters.http-kit/get-sch-adapter) or (taoensso.sente.server-adapters.immutant/get-sch-adapter). You must have the necessary web-server dependency in your project.clj and the necessary entry in your namespace's ns form.

[2] Optimization to allow transparent batching of rapidly-triggered server>user pushes. This is esp. important for Ajax clients which use a (slow) reconnecting poller. Actual event dispatch may occur <= given ms after send call (larger values => larger batch windows).

Takes a web server adapter[1] and returns a map with keys:
  :ch-recv ; core.async channel to receive `event-msg`s (internal or from clients).
  :send-fn ; (fn [user-id ev] for server>user push.
  :ajax-post-fn                ; (fn [ring-req]) for Ring CSRF-POST + chsk URL.
  :ajax-get-or-ws-handshake-fn ; (fn [ring-req]) for Ring GET + chsk URL.
  :connected-uids ; Watchable, read-only (atom {:ws #{_} :ajax #{_} :any #{_}}).

Common options:
  :user-id-fn        ; (fn [ring-req]) -> unique user-id for server>user push.
  :csrf-token-fn     ; ?(fn [ring-req]) -> CSRF-token for Ajax POSTs and WS handshake.
                     ;                    CSRF check will be skipped iff nil (NOT RECOMMENDED!).

  :handshake-data-fn ; (fn [ring-req]) -> arb user data to append to handshake evs.
  :ws-kalive-ms      ; Ping to keep a WebSocket conn alive if no activity
                     ; w/in given msecs. Should be different to client's :ws-kalive-ms.
  :lp-timeout-ms     ; Timeout (repoll) long-polling Ajax conns after given msecs.
  :send-buf-ms-ajax  ; [2]
  :send-buf-ms-ws    ; [2]
  :packer            ; :edn (default), or an IPacker implementation.

[1] e.g. `(taoensso.sente.server-adapters.http-kit/get-sch-adapter)` or
         `(taoensso.sente.server-adapters.immutant/get-sch-adapter)`.
    You must have the necessary web-server dependency in your project.clj and
    the necessary entry in your namespace's `ns` form.

[2] Optimization to allow transparent batching of rapidly-triggered
    server>user pushes. This is esp. important for Ajax clients which use a
    (slow) reconnecting poller. Actual event dispatch may occur <= given ms
    after send call (larger values => larger batch windows).
raw docstring

server-event-msg?clj/s

(server-event-msg? x)

start-chsk-router!clj/s

Platform-specific alias for start-server-chsk-router! or start-client-chsk-router!. Please see the appropriate aliased fn docstring for details.

Platform-specific alias for `start-server-chsk-router!` or
`start-client-chsk-router!`. Please see the appropriate aliased fn
docstring for details.
raw docstring

start-client-chsk-router!clj/s

(start-client-chsk-router! ch-recv
                           event-msg-handler
                           &
                           [{:as opts :keys [trace-evs? error-handler]}])

Creates a simple go-loop to call (event-msg-handler <server-event-msg>) and log any errors. Returns a (fn stop! []). Note that advanced users may prefer to just write their own loop against ch-recv.

Nb performance note: since your event-msg-handler fn will be executed within a simple go block, you'll want this fn to be ~non-blocking (you'll especially want to avoid blocking IO) to avoid starving the core.async thread pool under load. To avoid blocking, you can use futures, agents, core.async, etc. as appropriate.

Creates a simple go-loop to call `(event-msg-handler <server-event-msg>)`
and log any errors. Returns a `(fn stop! [])`. Note that advanced users may
prefer to just write their own loop against `ch-recv`.

Nb performance note: since your `event-msg-handler` fn will be executed
within a simple go block, you'll want this fn to be ~non-blocking
(you'll especially want to avoid blocking IO) to avoid starving the
core.async thread pool under load. To avoid blocking, you can use futures,
agents, core.async, etc. as appropriate.
raw docstring

start-server-chsk-router!clj/s

(start-server-chsk-router!
  ch-recv
  event-msg-handler
  {:keys [trace-evs? error-handler simple-auto-threading?] :as opts})

Creates a simple go-loop to call (event-msg-handler <server-event-msg>) and log any errors. Returns a (fn stop! []). Note that advanced users may prefer to just write their own loop against ch-recv.

Nb performance note: since your event-msg-handler fn will be executed within a simple go block, you'll want this fn to be ~non-blocking (you'll especially want to avoid blocking IO) to avoid starving the core.async thread pool under load. To avoid blocking, you can use futures, agents, core.async, etc. as appropriate.

Or for simple automatic future-based threading of every request, enable the :simple-auto-threading? opt (disabled by default).

Creates a simple go-loop to call `(event-msg-handler <server-event-msg>)`
and log any errors. Returns a `(fn stop! [])`. Note that advanced users may
prefer to just write their own loop against `ch-recv`.

Nb performance note: since your `event-msg-handler` fn will be executed
within a simple go block, you'll want this fn to be ~non-blocking
(you'll especially want to avoid blocking IO) to avoid starving the
core.async thread pool under load. To avoid blocking, you can use futures,
agents, core.async, etc. as appropriate.

Or for simple automatic future-based threading of every request, enable
the `:simple-auto-threading?` opt (disabled by default).
raw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close