Start client code like server side

This commit is contained in:
Nicholas Kariniemi 2014-10-12 22:57:00 +03:00
parent 73cf89f9d5
commit 64b1bb05a7
6 changed files with 71 additions and 35 deletions

View file

@ -12,7 +12,7 @@
(defn start (defn start
"Starts the current development system." "Starts the current development system."
[] []
(alter-var-root #'system system/start system/dev-config)) (alter-var-root #'system system/start system/dev-system))
(defn stop (defn stop
"Shuts down and destroys the current development system." "Shuts down and destroys the current development system."

View file

@ -38,15 +38,23 @@
(include-js "/js/grub.js") (include-js "/js/grub.js")
[:script {:type "text/javascript"} "goog.require(\"grub.core\")"]])) [:script {:type "text/javascript"} "goog.require(\"grub.core\")"]]))
(def prod-config (def prod-system
{:index prod-index-page {:index prod-index-page
:db {:name "grub"} :db {:name "grub"
:port 3000}) :db nil
:conn nil}
:port 3000
:stop-server nil
:states nil})
(def dev-config (def dev-system
{:index dev-index-page {:index dev-index-page
:db {:name "grub-dev"} :db {:name "grub-dev"
:port 3000}) :db nil
:conn nil}
:port 3000
:stop-server nil
:states nil})
(defn handle-websocket [handler states] (defn handle-websocket [handler states]
(fn [{:keys [websocket?] :as request}] (fn [{:keys [websocket?] :as request}]
@ -71,14 +79,14 @@
(handle-root index) (handle-root index)
(handle-websocket states))) (handle-websocket states)))
(defn start [current {:keys [port db] :as config}] (defn start [current {:keys [port db] :as system}]
(let [to-db (chan) (let [to-db (chan)
db (db/connect-and-handle-events to-db (:name db)) db (db/connect-and-handle-events to-db (:name db))
states (state/init-server to-db (db/get-current-state (:db db))) states (state/init-server to-db (db/get-current-state (:db db)))
stop-server (httpkit/run-server (make-handler config states) {:port port})] stop-server (httpkit/run-server (make-handler system states) {:port port})]
(println "Started server on localhost:" port) (println "Started server on localhost:" port)
(assoc config (assoc system
:db (merge (:db config) db) :db (merge (:db system) db)
:stop-server stop-server :stop-server stop-server
:states states))) :states states)))
@ -121,8 +129,8 @@
(not= (count arguments) 1) (exit 1 (usage summary)) (not= (count arguments) 1) (exit 1 (usage summary))
errors (exit 1 (error-msg errors))) errors (exit 1 (error-msg errors)))
(case (first arguments) (case (first arguments)
"development" (start (merge dev-config options)) "development" (start (merge dev-system options))
"dev" (start (merge dev-config options)) "dev" (start (merge dev-system options))
"production" (start (merge prod-config options)) "production" (start (merge prod-system options))
"prod" (start (merge prod-config options)) "prod" (start (merge prod-system options))
(exit 1 (usage summary))))) (exit 1 (usage summary)))))

View file

@ -1,17 +1,38 @@
(ns grub.core (ns grub.core
(:require [grub.state :as state] (:require [grub.state :as state]
[grub.websocket :as ws] [grub.websocket :as websocket]
[grub.view.app :as view] [grub.view.app :as view]
[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 init-app [] (def system
{:pending-msg (atom nil)
:ws (atom nil)
:channels {:local-states (chan)
:remote-states (chan)
:to-remote (chan)
:from-remote (chan)}
:view-state nil})
(defn start [system]
(let [local-states (chan) (let [local-states (chan)
remote-states (chan) remote-states (chan)
to-remote (chan) to-remote (chan)
from-remote (chan)] from-remote (chan)
(view/render-app state/empty-state remote-states local-states) view-state (view/render-app state/empty-state remote-states local-states)
(ws/connect-client! to-remote from-remote) ws (websocket/connect (:pending-msg system) to-remote from-remote)
(state/init-client from-remote to-remote local-states remote-states))) agent-states (state/init-client from-remote to-remote local-states remote-states)]
(assoc system
:ws ws
:channels {:local-states local-states
:remote-states remote-states
:to-remote to-remote
:from-remote from-remote}
:view-state view-state
:agent-states agent-states)))
(init-app) (defn stop [{:keys [channels ws]} system]
(doseq [c (vals channels)] (a/close! c))
(websocket/disconnect ws))
(start system)

View file

@ -40,4 +40,5 @@
(when (= tag :local) (put! >remote new-state)))}) (when (= tag :local) (put! >remote new-state)))})
(go (loop [] (when-let [new-state (<! <remote)] (go (loop [] (when-let [new-state (<! <remote)]
(reset! state new-state) (reset! state new-state)
(recur)))))) (recur))))
state))

View file

@ -8,34 +8,37 @@
[grub.macros :refer [log logs]])) [grub.macros :refer [log logs]]))
(def server-url (str "ws://" (.-host (.-location js/document)))) (def server-url (str "ws://" (.-host (.-location js/document))))
(def pending-msg (atom nil))
(def reader (t/reader :json)) (def reader (t/reader :json))
(def writer (t/writer :json)) (def writer (t/writer :json))
(defn send-pending-msg [websocket] (defn send-pending-msg [websocket pending-msg]
(when (and (.isOpen websocket) (when (and (.isOpen websocket)
(not (nil? @pending-msg))) (not (nil? @pending-msg)))
(.send websocket (t/write writer @pending-msg)) (.send websocket (t/write writer @pending-msg))
(reset! pending-msg nil))) (reset! pending-msg nil)))
(defn on-connected [websocket event] (defn on-connected [websocket pending-msg event]
(log "Connected:" event) (log "Connected:" event)
(send-pending-msg websocket)) (send-pending-msg websocket pending-msg))
(defn read-msg [msg] (defn read-msg [msg]
(t/read reader (.-message msg))) (t/read reader (.-message msg)))
(defn connect-client! [in out] (defn connect [pending-msg in out]
(let [handler (goog.events.EventHandler.) (let [ws (goog.net.WebSocket.)
websocket (goog.net.WebSocket.) handler (goog.events.EventHandler.)
listen (fn [type fun] (.listen handler websocket type fun false))] listen (fn [type fun] (.listen handler ws type fun false))]
(listen goog.net.WebSocket.EventType.OPENED (partial on-connected websocket)) (listen goog.net.WebSocket.EventType.OPENED (partial on-connected ws pending-msg))
(listen goog.net.WebSocket.EventType.MESSAGE #(a/put! out (read-msg %))) (listen goog.net.WebSocket.EventType.MESSAGE #(a/put! out (read-msg %)))
(listen goog.net.WebSocket.EventType.CLOSED #(log "Closed:" %)) (listen goog.net.WebSocket.EventType.CLOSED #(log "Closed:" %))
(listen goog.net.WebSocket.EventType.ERROR #(log "Error:" %)) (listen goog.net.WebSocket.EventType.ERROR #(log "Error:" %))
(go (loop [] (go (loop []
(when-let [msg (<! in)] (when-let [msg (<! in)]
(reset! pending-msg msg) (reset! pending-msg msg)
(send-pending-msg websocket) (send-pending-msg ws pending-msg)
(recur)))) (recur))))
(.open websocket server-url))) (.open ws server-url)
ws))
(defn disconnect [ws]
(.close ws))

View file

@ -7,6 +7,8 @@
#+cljs (:require-macros [grub.macros :refer [log logs]] #+cljs (:require-macros [grub.macros :refer [log logs]]
[cljs.core.async.macros :refer [go]])) [cljs.core.async.macros :refer [go]]))
(def empty-state sync/empty-state)
(defmulti handle-event (fn [event] (defmulti handle-event (fn [event]
#+cljs (logs (:type event)) #+cljs (logs (:type event))
(:type event))) (:type event)))
@ -98,4 +100,5 @@
(a/put! >view new-state)))) (a/put! >view new-state))))
(a/pipe <view local-events) (a/pipe <view local-events)
(make-client-agent (a/merge [local-events <remote]) >remote states) (make-client-agent (a/merge [local-events <remote]) >remote states)
(a/put! >remote message/full-sync-request))) (a/put! >remote message/full-sync-request)
states))