Better - uses tx-listen
This commit is contained in:
parent
f087309c0f
commit
4320401a4e
5 changed files with 52 additions and 71 deletions
|
@ -14,17 +14,9 @@
|
||||||
|
|
||||||
(defn save-history-state [history new-state]
|
(defn save-history-state [history new-state]
|
||||||
(when-not (= (hasch/uuid (last history)) (hasch/uuid new-state))
|
(when-not (= (hasch/uuid (last history)) (hasch/uuid new-state))
|
||||||
(println "Adding state to history: " (hasch/uuid new-state))
|
|
||||||
(println "History:")
|
|
||||||
(doseq [s (conj history new-state)]
|
|
||||||
(println (hasch/uuid s)))
|
|
||||||
(conj history new-state)))
|
(conj history new-state)))
|
||||||
|
|
||||||
(defn get-history-state [hash]
|
(defn get-history-state [hash]
|
||||||
(println "Look for history state:" hash)
|
|
||||||
(println "History:")
|
|
||||||
(doseq [s @state-history]
|
|
||||||
(println (hasch/uuid s)))
|
|
||||||
(first (filter #(= (hasch/uuid %) hash) @state-history)))
|
(first (filter #(= (hasch/uuid %) hash) @state-history)))
|
||||||
|
|
||||||
(add-watch state :history (fn [_ _ _ new-state]
|
(add-watch state :history (fn [_ _ _ new-state]
|
||||||
|
@ -40,18 +32,16 @@
|
||||||
log (fn [& args]
|
log (fn [& args]
|
||||||
(apply println client-id args))]
|
(apply println client-id args))]
|
||||||
(add-watch state client-id (fn [_ _ _ current-state]
|
(add-watch state client-id (fn [_ _ _ current-state]
|
||||||
(when-let [msg (cs/diff-states @client-state current-state)]
|
(let [msg (cs/diff-states @client-state current-state)]
|
||||||
(a/put! to msg)
|
(a/put! to msg)
|
||||||
;; send ACK even if nothing changes
|
|
||||||
;; TODO: reset only if send succeeds?
|
|
||||||
(reset! client-state current-state))))
|
(reset! client-state current-state))))
|
||||||
(a/go-loop []
|
(a/go-loop []
|
||||||
(if-let [{:keys [type diff hash shadow-hash] :as msg} (<! from)]
|
(if-let [{:keys [type diff hash shadow-hash] :as msg} (<! from)]
|
||||||
(do (condp = type
|
(do (condp = type
|
||||||
:diff
|
:diff
|
||||||
(if (= (hasch/uuid @client-state) shadow-hash)
|
(if (= (hasch/uuid @client-state) shadow-hash)
|
||||||
;; we have what they thought we had
|
;; We have what they thought we had
|
||||||
;; apply changes normally
|
;; Apply changes normally
|
||||||
(let [new-shadow (swap! client-state sync/patch-state diff)]
|
(let [new-shadow (swap! client-state sync/patch-state diff)]
|
||||||
(log "Hash matched state, apply changes")
|
(log "Hash matched state, apply changes")
|
||||||
(if (= (hasch/uuid new-shadow) hash)
|
(if (= (hasch/uuid new-shadow) hash)
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
[cljs.core.async :as a :refer [<! >! chan]])
|
[cljs.core.async :as a :refer [<! >! chan]])
|
||||||
(:require-macros [grub.macros :refer [log logs]]))
|
(:require-macros [grub.macros :refer [log logs]]))
|
||||||
|
|
||||||
(defn connect-to-server [reset?]
|
(defn connect-to-server [reset? state-changes]
|
||||||
(let [to-remote (chan)
|
(let [to-remote (chan)
|
||||||
from-remote (chan)]
|
from-remote (chan)]
|
||||||
(ws/connect-client! to-remote from-remote)
|
(ws/connect-client! to-remote from-remote)
|
||||||
(state/sync-state! from-remote to-remote reset?)))
|
(state/sync-state! from-remote to-remote reset? state-changes)))
|
||||||
|
|
||||||
(defn init-app []
|
(defn init-app []
|
||||||
(view/render-app state/state)
|
(let [state-changes (chan)]d
|
||||||
(connect-to-server true))
|
(view/render-app state/state state-changes)
|
||||||
|
(connect-to-server true state-changes)))
|
||||||
|
|
||||||
(init-app)
|
(init-app)
|
||||||
|
|
|
@ -7,47 +7,45 @@
|
||||||
[cljs.core.async.macros :refer [go go-loop]]))
|
[cljs.core.async.macros :refer [go go-loop]]))
|
||||||
|
|
||||||
(def state (atom cs/empty-state))
|
(def state (atom cs/empty-state))
|
||||||
|
(def server-state (atom cs/empty-state))
|
||||||
|
|
||||||
(def unacked-history (atom {}))
|
(def unacked-states (atom {}))
|
||||||
|
|
||||||
(defn get-unacked-state [hash]
|
(defn get-server-state [hash]
|
||||||
(logs "Look for history state:" hash)
|
(if (= (hasch/uuid @server-state) hash)
|
||||||
(get @unacked-history hash))
|
@server-state
|
||||||
|
(get @unacked-states hash)))
|
||||||
|
|
||||||
(defn sync-state! [to from reset?]
|
(defn sync-state! [to from reset? state-changes]
|
||||||
(let [server-state (atom cs/empty-state)]
|
(go-loop []
|
||||||
(add-watch state :state (fn [_ _ _ current-state]
|
(when-let [current-state (<! state-changes)]
|
||||||
(when-not (= @server-state current-state)
|
(when-not (= @server-state current-state)
|
||||||
(let [msg (cs/diff-states @server-state current-state)]
|
(let [msg (cs/diff-states @server-state current-state)]
|
||||||
(when-not (get @unacked-history (hasch/uuid current-state))
|
(swap! unacked-states assoc (:hash msg) current-state)
|
||||||
(logs "state change! msg: " msg)
|
(a/put! from msg)))
|
||||||
(swap! unacked-history assoc (hasch/uuid current-state) current-state)
|
(recur)))
|
||||||
(logs "History:" (keys @unacked-history))
|
|
||||||
(a/put! from msg))
|
|
||||||
))))
|
|
||||||
(go-loop []
|
(go-loop []
|
||||||
(if-let [{:keys [type diff hash shadow-hash] :as msg} (<! to)]
|
(if-let [{:keys [type diff hash shadow-hash] :as msg} (<! to)]
|
||||||
(do (condp = type
|
(do (condp = type
|
||||||
:diff (do
|
:diff
|
||||||
(logs "Received diff:" msg)
|
(if-let [acked-server-state (get-server-state shadow-hash)]
|
||||||
(when (not (= (hasch/uuid @server-state) shadow-hash))
|
(do (reset! server-state acked-server-state)
|
||||||
(reset! server-state (get-unacked-state shadow-hash)))
|
(reset! unacked-states {})
|
||||||
(reset! unacked-history {})
|
(let [new-server (swap! server-state #(sync/patch-state % diff))]
|
||||||
(let [ ;; what they now think we have (after updating)
|
(if (= (hasch/uuid new-server) hash)
|
||||||
new-shadow (swap! server-state #(sync/patch-state % diff))]
|
|
||||||
;; should match hash
|
|
||||||
(if (= (hasch/uuid new-shadow) hash)
|
|
||||||
;; apply same changes locally
|
|
||||||
;; if there are differences, they will be sent back
|
|
||||||
(swap! state sync/patch-state diff)
|
(swap! state sync/patch-state diff)
|
||||||
(do (log "Hash check failed --> complete sync")
|
(do (log "State update failure --> complete sync")
|
||||||
(a/put! from cs/complete-sync-request)))))
|
(a/put! from cs/complete-sync-request)))))
|
||||||
|
(do (log "Could not find server state locally --> complete sync")
|
||||||
|
(a/put! from cs/complete-sync-request)))
|
||||||
:complete (do
|
:complete (do
|
||||||
(logs "Complete sync:" (hasch/uuid (:state msg)))
|
(logs "Complete sync")
|
||||||
(reset! unacked-history {})
|
(reset! unacked-states {})
|
||||||
(reset! server-state (:state msg))
|
(reset! server-state (:state msg))
|
||||||
(reset! state (:state msg)))
|
(reset! state (:state msg)))
|
||||||
(logs "Invalid msg:" msg))
|
(logs "Invalid msg:" msg))
|
||||||
(recur))
|
(recur))
|
||||||
(remove-watch state :state)))
|
(remove-watch state :state)))
|
||||||
(when reset? (a/put! from cs/complete-sync-request))))
|
(if reset?
|
||||||
|
(a/put! from cs/complete-sync-request)
|
||||||
|
(a/put! from (cs/diff-states @server-state @state))))
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
(dom/on-document-mousedown #(put! >events {:type :body-mousedown :event %}))
|
(dom/on-document-mousedown #(put! >events {:type :body-mousedown :event %}))
|
||||||
(dom/on-window-scroll #(put! >events {:type :body-scroll :event %}))))))
|
(dom/on-window-scroll #(put! >events {:type :body-scroll :event %}))))))
|
||||||
|
|
||||||
(defn render-app [state]
|
(defn render-app [state state-changes]
|
||||||
(let [>events (chan)
|
(let [>events (chan)
|
||||||
<events (a/pub >events :type)
|
<events (a/pub >events :type)
|
||||||
add-grubs-ch (chan)]
|
add-grubs-ch (chan)]
|
||||||
|
@ -34,4 +34,6 @@
|
||||||
{:target (.getElementById js/document "container")
|
{:target (.getElementById js/document "container")
|
||||||
:shared {:>events >events
|
:shared {:>events >events
|
||||||
:<events <events
|
:<events <events
|
||||||
:add-grubs-ch add-grubs-ch}})))
|
:add-grubs-ch add-grubs-ch}
|
||||||
|
:tx-listen (fn [{:keys [new-state]} _]
|
||||||
|
(put! state-changes new-state))})))
|
||||||
|
|
|
@ -17,17 +17,7 @@
|
||||||
|
|
||||||
(defn diff-states [shadow state]
|
(defn diff-states [shadow state]
|
||||||
(let [diff (sync/diff-states shadow state)
|
(let [diff (sync/diff-states shadow state)
|
||||||
;; what we now have
|
|
||||||
hash (hasch/uuid state)
|
hash (hasch/uuid state)
|
||||||
|
|
||||||
;; what we had/what you used to have
|
|
||||||
;; should match what they think we have
|
|
||||||
shadow-hash (hasch/uuid shadow)
|
shadow-hash (hasch/uuid shadow)
|
||||||
msg (diff-msg diff hash shadow-hash)]
|
msg (diff-msg diff hash shadow-hash)]
|
||||||
msg
|
msg))
|
||||||
;(logs "Sync because:")
|
|
||||||
;(logs "Local = " state)
|
|
||||||
;(logs "Remote = " shadow)
|
|
||||||
;(logs "Diff:" diff)
|
|
||||||
;(logs "Send" shadow-hash "->" hash)
|
|
||||||
))
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue