Interceptor has fixed some issues and been made more performant. Connection closing and resolution is much more reliable with a single :before-dispatch interceptor.
The previous interceptors ran more frequently and had lifecycle issues that made manually closing connections cumbersome.
Previously:
(defn create-interceptor
[store {:keys [id-fn on-purge]
:or {id-fn (constantly :datastar.wow.deacon/id)
on-purge (constantly nil)}}]
(assert (impl/store? store) "Interceptor store must satisfy ConnectionStore protocol")
{:id :datastar.wow.deacon/connections
:before-dispatch
(fn [{:keys [actions] :as ctx}]
(if (= :datastar.wow/connection (ffirst actions))
(let [k (scoped-key ctx id-fn)]
(if-some [connection
(when k
(impl/connection store k))]
(assoc-in ctx [:dispatch-data :datastar.wow/connection] connection)
ctx))
ctx))
:after-effect
(fn [{:keys [effect system dispatch-data] :as ctx}]
(let [{:keys [request]} system]
(when (and effect (= :datastar.wow/sse-closed (first effect)))
(when-some [cname (get-in dispatch-data [:datastar.wow/response :datastar.wow.deacon/key])]
(on-purge ctx)
(impl/purge! store [(id-fn request) cname]))))
ctx)
:after-dispatch
(fn [{{:keys [sse]} :system
{:datastar.wow/keys [connection]
{:datastar.wow/keys [with-open-sse?]} :datastar.wow/response} :dispatch-data
:as ctx}]
(let [k (scoped-key ctx id-fn)
store? (and (some? k)
(nil? connection)
(not with-open-sse?))]
(when store?
(impl/store! store k sse))
ctx))})
Now:
(defn create-interceptor
"An interceptor that allows opt-in/managed connection persistence and reuse by adding
a :datastar.wow.deacon/key value to a datastar.wow response."
[store {:keys [id-fn on-purge]
:or {id-fn (constantly :datastar.wow.deacon/id)
on-purge (constantly nil)}}]
(assert (impl/store? store) "Interceptor store must satisfy ConnectionStore protocol")
{:id :datastar.wow.deacon/connections
:before-dispatch
(fn [{:keys [actions]
{:keys [sse]} :system
{:datastar.wow/keys [connection]
{:datastar.wow/keys [with-open-sse?]} :datastar.wow/response} :dispatch-data
:as ctx}]
(if-some [k (scoped-key ctx id-fn)]
(let [action-ids (->> actions (map first) set)
conn? (action-ids :datastar.wow/connection)
purge? (action-ids :datastar.wow/sse-closed)
store? (and (some? sse)
(nil? connection)
(not with-open-sse?))]
(cond
conn? (with-connection ctx store k)
purge? (purge! ctx store k on-purge)
store? (store! ctx store k sse)
:else ctx))
ctx))})
This allows the following pattern:
(defn index
"Renders the initial page and handles app state management (reset and starting the timer). Loading
the index with a running timer will subscribe to those changes"
[{:keys [request-method]}]
(case request-method
:get {:body (app)}
:delete {::d*conn/key [::counter 1]
:🚀 [[::reset
[::d*/patch-signals [:timer/state]]
[::d*/close-sse]]]}
:put {::d*conn/key [::counter 1]
:🚀 [[::start-timer
[::d*/patch-signals [:timer/state]]]]}))
Where one handler can initiate a connection (:put
in this example) and another may close it (:delete
). So in this case we keep the [::counter 1]
connection open until it is explicitly closed in the :delete
handler.
The demo has been simplified (hopefully) in order to better highlight provided functionality. Check it out!
1.3.0 will only work with datastar.wow version 1.0.0-RC1-wow-2 and higher.
The :datastar.wow/connection
key is no longer used. :datastar.wow.deacon/key
is used for writing AND reading connections.
Previously:
(defn handler-1 [_]
{::d*conn/key ::counter
::d*/with-open-sse? false
::d*/fx [[::subscribe ::index]
[::start-timer]]})
(defn handler-2 [_]
{::d*/connection ::counter})
Now:
(defn handler-1 [_]
{::d*conn/key ::counter
::d*/with-open-sse? false
::d*/fx [[::subscribe ::index]
[::start-timer]]})
(defn handler-2 [_]
{::d*conn/key ::counter})
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
Ctrl+k | Jump to recent docs |
← | Move to previous article |
→ | Move to next article |
Ctrl+/ | Jump to the search field |