feat: add SSE live sync between clients
When any client pushes changes, the server broadcasts an SSE event to all connected clients watching that group. Clients immediately pull the latest data — no polling delay, no page reload. Server (~30 lines): - GET /events?group=G — SSE endpoint, holds connection open - On successful POST /sync, notify all SSE listeners for affected groups - Auth-aware: respects token and group permissions - Auto-cleanup on disconnect via http-kit on-close Client (~25 lines): - EventSource connects to /events?group=G on sync loop start - On SSE message, triggers do-pull! to fetch latest data - Auto-reconnects (browser EventSource built-in behavior) - Cleanup on destroy! Periodic polling remains as fallback (30s default). SSE provides sub-second sync for the common case.
This commit is contained in:
@@ -275,26 +275,31 @@
|
||||
(defn- start-sync-loop!
|
||||
"Start the background sync loop. Returns a stop function."
|
||||
[sa]
|
||||
(let [stop-ch (.-stop_ch sa)
|
||||
interval (.-sync_interval sa)]
|
||||
;; Periodic sync
|
||||
(let [stop-ch (.-stop_ch sa)
|
||||
interval (.-sync_interval sa)
|
||||
cleanups (atom [])]
|
||||
;; Periodic sync (fallback)
|
||||
(go-loop []
|
||||
(let [[_ ch] (alts! [stop-ch (timeout interval)])]
|
||||
(when-not (= ch stop-ch)
|
||||
(<! (do-sync! sa))
|
||||
(recur))))
|
||||
;; Online/offline handler
|
||||
(let [cleanup (sync/on-connectivity-change
|
||||
(fn [] ; online
|
||||
(go (<! (do-sync! sa))))
|
||||
(fn [] ; offline
|
||||
nil))]
|
||||
(reset! (.-cleanup_fn sa) cleanup))
|
||||
(swap! cleanups conj
|
||||
(sync/on-connectivity-change
|
||||
(fn [] (go (<! (do-sync! sa))))
|
||||
(fn [] nil)))
|
||||
;; SSE — live pull on server push
|
||||
(when-let [opts (.-server_opts sa)]
|
||||
(swap! cleanups conj
|
||||
(sync/listen-events opts (.-group sa)
|
||||
(fn [_group]
|
||||
(go (<! (do-pull! sa)))))))
|
||||
(reset! (.-cleanup_fn sa) cleanups)
|
||||
;; Return stop function
|
||||
(fn []
|
||||
(put! stop-ch :stop)
|
||||
(when-let [cleanup @(.-cleanup_fn sa)]
|
||||
(cleanup)))))
|
||||
(doseq [f @(.-cleanup_fn sa)] (f)))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Public API
|
||||
@@ -352,5 +357,4 @@
|
||||
"Stop the sync loop and clean up. Does not close the IDB connection."
|
||||
[sa]
|
||||
(put! (.-stop_ch sa) :stop)
|
||||
(when-let [cleanup @(.-cleanup_fn sa)]
|
||||
(cleanup)))
|
||||
(doseq [f @(.-cleanup_fn sa)] (f)))
|
||||
|
||||
Reference in New Issue
Block a user