diff --git a/src/cljx/grub/shared_state.cljx b/src/cljx/grub/shared_state.cljx index 157e125..37a5f5c 100644 --- a/src/cljx/grub/shared_state.cljx +++ b/src/cljx/grub/shared_state.cljx @@ -7,12 +7,12 @@ #+cljs (:require-macros [cljs.core.async.macros :refer [go]])) ;; Server state -(def states (atom [])) +;; (def states (atom [])) (defn make-server-agent ([in out states] (make-server-agent in out states sync/empty-state)) - ([in out states initial-client-state] - (go (loop [client-state initial-client-state] + ([in out states initial-client-shadow] + (go (loop [client-shadow initial-client-shadow] (when-let [msg (! out (message/diff-msg diff hash)) - (recur client-state)) - (recur client-state))))))) + (recur client-shadow)) + (recur client-shadow))))))) -;; (defn make-client-agent -;; ([in out states] (make-client-agent in out states sync/empty-state)) -;; ([in out states initial-server-state] -;; (a/go-loop [server-state initial-server-state] -;; (when-let [msg (! out (message/full-sync state)) -;; (recur state)))) +(defn make-client-agent + ([in out states] (make-client-agent in out states sync/empty-state)) + ([in out states initial-server-shadow] + (a/go-loop [server-shadow initial-server-shadow] + (when-let [msg (! out (message/full-sync state)) + (recur state)))) -;; :full-sync -;; (let [state (:state msg)] -;; (reset! states [state]) -;; (recur state)) + :full-sync + (let [state (:state msg)] + (reset! states [state]) + (recur state)) -;; :new-state -;; (let [{:keys [diff hash]} (sync/diff-states (:new-states msg) server-state)] -;; (>! out (message/diff-msg diff hash))) -;; (recur server-state)))))) + :new-state + (let [{:keys [diff hash]} (sync/diff-states (:new-states msg) server-shadow)] + (>! out (message/diff-msg diff hash)) + (recur server-shadow)) + (recur server-shadow)))))) ;; TODO: Remove watch, close up channels properly (defn sync-new-client! [>client client states))) + nil) + ;; (let [client-id (java.util.UUID/randomUUID) + ;; state-changes (chan) + ;; state-change-events (a/map< (fn [s] {:type :new-state :new-states s}) state-changes) + ;; client-events (chan)] + ;; (add-watch states client-id (fn [_ _ _ new-states] (a/put! state-changes new-states))) + ;; (a/pipe (a/merge [client states))) (defn init [to-db grubs recipes] - (reset! states (sync/initial-state grubs recipes)) - (add-watch states :to-db (fn [_ _ old-states new-states] - (a/put! to-db (sync/get-current-state new-states))))) +nil) +;; (reset! states (sync/initial-state grubs recipes)) +;; (add-watch states :to-db (fn [_ _ old-states new-states] +;; (a/put! to-db (sync/get-current-state new-states))))) diff --git a/src/test/grub/test/unit/state.clj b/src/test/grub/test/unit/state.clj index 416ae69..c7e7994 100644 --- a/src/test/grub/test/unit/state.clj +++ b/src/test/grub/test/unit/state.clj @@ -142,3 +142,65 @@ "3" {:text "milk" :completed false}}} :recipes {:deleted #{}, :updated nil}} :hash (hasch/uuid client-state)}))) + +(fact "Client-only changes synced with server" + (let [client-shadow {:grubs {"1" {:text "2 apples" :completed true}} :recipes {}} + client-states (states-atom + {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + {:grubs {"1" {:text "2 apples" :completed true}} :recipes {}}) + server-shadow {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + server-states (states-atom server-shadow) + client-in (chan) + client-out (chan) + server-in (chan) + server-out (chan) + client-state-changes (chan 1) + msg {:type :new-state + :new-states (hashed-states + {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + {:grubs {"1" {:text "2 apples" :completed true}} :recipes {}})}] + (a/pipe client-out server-in) + (a/pipe server-out client-in) + (state/make-client-agent client-in client-out client-states server-shadow) + (state/make-server-agent server-in server-out server-states client-shadow) + (add-watch client-states :test (fn [_ _ _ new-states] (a/put! client-state-changes new-states))) + (>!! client-in msg) + ( {:grubs {"1" {:completed true, :text "2 apples"}} + :recipes {}} + (:state (last @server-states)) => {:grubs {"1" {:completed true, :text "2 apples"}} + :recipes {}})) + +(fact "Client and server changes synced" + (let [client-shadow {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + client-states (states-atom + {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + {:grubs {"1" {:text "2 apples" :completed true}} :recipes {}}) + server-shadow {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + server-states (states-atom + server-shadow + {:grubs {"1" {:text "4 apples" :completed false}} :recipes {}}) + client-in (chan) + client-out (chan) + server-in (chan) + server-out (chan) + msg {:type :new-state + :new-states (hashed-states + {:grubs {"1" {:text "2 apples" :completed false}} :recipes {}} + {:grubs {"1" {:text "2 apples" :completed true}} :recipes {}})} + client-state-changes (chan 1)] + (a/pipe client-out server-in) + (a/pipe server-out client-in) + (state/make-client-agent client-in client-out client-states server-shadow) + (state/make-server-agent server-in server-out server-states client-shadow) + (add-watch client-states :test (fn [_ _ _ new-states] (a/put! client-state-changes new-states))) + (>!! client-in msg) + ( (hashed-states + {:grubs {"1" {:completed false, :text "2 apples"}}, :recipes {}} + {:grubs {"1" {:completed true, :text "2 apples"}}, :recipes {}} + {:grubs {"1" {:completed true, :text "4 apples"}}, :recipes {}}) + @server-states => (hashed-states + {:grubs {"1" {:completed false, :text "2 apples"}}, :recipes {}} + {:grubs {"1" {:completed false, :text "4 apples"}}, :recipes {}} + {:grubs {"1" {:completed true, :text "4 apples"}}, :recipes {}})))