refactor, using cljx to share common server and client code

This commit is contained in:
Gered 2014-12-24 15:37:45 -05:00
parent 0a1ee1df25
commit 143939af61
4 changed files with 62 additions and 70 deletions

View file

@ -9,5 +9,16 @@
[org.clojure/core.async "0.1.346.0-17112a-alpha"] [org.clojure/core.async "0.1.346.0-17112a-alpha"]
[net.thegeez/clj-browserchannel-server "0.1.0"]] [net.thegeez/clj-browserchannel-server "0.1.0"]]
:source-paths ["src/clj"] :source-paths ["target/generated/src/clj" "src/clj"]
:resource-paths ["src/cljs"]) :resource-paths ["target/generated/src/cljs" "src/cljs"]
:profiles {:dev {:plugins [[com.keminglabs/cljx "0.5.0"]]}}
:cljx {:builds [{:source-paths ["src/cljx"]
:output-path "target/generated/src/clj"
:rules :clj}
{:source-paths ["src/cljx"]
:output-path "target/generated/src/cljs"
:rules :cljs}]}
:prep-tasks [["cljx" "once"]])

View file

@ -2,40 +2,14 @@
(:refer-clojure :exclude [send]) (:refer-clojure :exclude [send])
(:require [clojure.edn :as edn] (:require [clojure.edn :as edn]
[clojure.core.async :refer [chan pub sub <! put! go-loop]] [clojure.core.async :refer [chan pub sub <! put! go-loop]]
[net.thegeez.browserchannel :as browserchannel])) [net.thegeez.browserchannel :as browserchannel]
[clj-browserchannel-messaging.utils :refer [run-middleware get-handlers encode-message decode-message]]))
(defonce ^:private handler-middleware (atom nil)) (defonce ^:private handler-middleware (atom nil))
(defonce incoming-messages (chan)) (defonce incoming-messages (chan))
(defonce incoming-messages-pub (pub incoming-messages :topic)) (defonce incoming-messages-pub (pub incoming-messages :topic))
(defn- run-middleware [middleware final-handler & args]
(let [wrap (fn [handler [f & more]]
(if f
(recur (f handler) more)
handler))
handler (wrap final-handler middleware)]
(apply handler args)))
(defn encode-message
"encodes a message made up of a topic and body into a format that can be sent
via browserchannel to a client. topic should be a keyword, while body can be
any Clojure data structure. returns nil if the message could not be encoded."
[{:keys [topic body] :as msg}]
(if-let [topic (if topic (name topic))]
{"topic" topic
"body" (pr-str body)}))
(defn decode-message
"decodes a message received via browserchannel into a map composed of a
topic and body. returns nil if the message could not be decoded."
[msg]
(let [topic (get msg "topic")
body (get msg "body")]
(if topic
{:topic (keyword topic)
:body (edn/read-string body)})))
(defn send (defn send
"sends a browserchannel message to a client identified by the given "sends a browserchannel message to a client identified by the given
browserchannel session id. topic should be a keyword, while body can be browserchannel session id. topic should be a keyword, while body can be
@ -110,9 +84,7 @@
(this differs from net.thegeez.browserchannel/wrap-browserchannel). (this differs from net.thegeez.browserchannel/wrap-browserchannel).
In addition, you can pass event handler functions. Note that the return In addition, you can pass event handler functions. Note that the return
value for all of these handlers is not used. value for all of these handlers is not used."
"
[handler & [opts]] [handler & [opts]]
(-> handler (-> handler
(browserchannel/wrap-browserchannel (browserchannel/wrap-browserchannel
@ -123,9 +95,6 @@
(fn [browserchannel-session-id request] (fn [browserchannel-session-id request]
(handle-session browserchannel-session-id request)))))) (handle-session browserchannel-session-id request))))))
(defn- get-handlers [middleware k]
(->> middleware (map k) (remove nil?) (doall)))
(defn init! (defn init!
"Sets up browserchannel for server-side use. This function should be called "Sets up browserchannel for server-side use. This function should be called
once during application startup. once during application startup.

View file

@ -4,7 +4,8 @@
[cljs.reader :as reader] [cljs.reader :as reader]
[cljs.core.async :refer [pub sub chan <! put!]] [cljs.core.async :refer [pub sub chan <! put!]]
goog.net.BrowserChannel goog.net.BrowserChannel
[goog.events :as events])) [goog.events :as events]
[clj-browserchannel-messaging.utils :refer [run-middleware get-handlers encode-message decode-message]]))
(defonce ^:private handler-middleware (atom nil)) (defonce ^:private handler-middleware (atom nil))
@ -14,34 +15,6 @@
(defonce incoming-messages-pub (pub incoming-messages :topic)) (defonce incoming-messages-pub (pub incoming-messages :topic))
(defonce outgoing-messages (chan)) (defonce outgoing-messages (chan))
(defn- run-middleware [middleware final-handler & args]
(let [wrap (fn [handler [f & more]]
(if f
(recur (f handler) more)
handler))
handler (wrap final-handler middleware)]
(apply handler args)))
(defn encode-message
"encodes a message composed of a topic and body into a format that can be
sent via browserchannel. topic should be a keyword while body can be
anything. returns nil if the message could not be encoded."
[{:keys [topic body] :as msg}]
(if-let [topic (name topic)]
(clj->js {"topic" topic
"body" (pr-str body)})))
(defn decode-message
"decodes a message received via browserchannel into a map composed of a
topic and body. returns nil if the message could not be decoded."
[msg]
(let [msg (js->clj msg)
topic (keyword (get msg "topic"))
body (get msg "body")]
(if topic
{:topic topic
:body (reader/read-string body)})))
(defn send (defn send
"sends a browserchannel message to the server asynchronously." "sends a browserchannel message to the server asynchronously."
[topic body] [topic body]
@ -67,12 +40,12 @@
(:on-send @handler-middleware) (:on-send @handler-middleware)
(fn [msg] (fn [msg]
(if-let [encoded (encode-message msg)] (if-let [encoded (encode-message msg)]
(.sendMap channel encoded))) (.sendMap channel (clj->js encoded))))
msg) msg)
(recur)))) (recur))))
(defn- handle-incoming [channel msg] (defn- handle-incoming [channel msg]
(when-let [decoded (decode-message msg)] (when-let [decoded (decode-message (js->clj msg))]
(run-middleware (run-middleware
(:on-receive @handler-middleware) (:on-receive @handler-middleware)
(fn [msg] (fn [msg]
@ -129,9 +102,6 @@
(if-let [logger (-> browser-channel .getChannelDebug .getLogger)] (if-let [logger (-> browser-channel .getChannelDebug .getLogger)]
(.setLevel logger level))) (.setLevel logger level)))
(defn- get-handlers [middleware k]
(->> middleware (map k) (remove nil?) (doall)))
(defn- register-middleware! [middleware] (defn- register-middleware! [middleware]
(reset! (reset!
handler-middleware handler-middleware

View file

@ -0,0 +1,42 @@
(ns clj-browserchannel-messaging.utils
(:require
#+clj [clojure.edn :as edn]
#+cljs [cljs.reader :as reader]))
#+clj
(defn decode-edn [s]
(edn/read-string s))
#+cljs
(defn decode-edn [s]
(reader/read-string s))
(defn encode-message
"encodes a message made up of a topic and body into a format that can be sent
via browserchannel. topic should be a keyword, while body can be
any Clojure data structure. returns nil if the message could not be encoded."
[{:keys [topic body] :as msg}]
(if-let [topic (if topic (name topic))]
{"topic" topic
"body" (pr-str body)}))
(defn decode-message
"decodes a message received via browserchannel into a map composed of a
topic and body. returns nil if the message could not be decoded."
[msg]
(let [topic (get msg "topic")
body (get msg "body")]
(if topic
{:topic (keyword topic)
:body (decode-edn body)})))
(defn run-middleware [middleware final-handler & args]
(let [wrap (fn [handler [f & more]]
(if f
(recur (f handler) more)
handler))
handler (wrap final-handler middleware)]
(apply handler args)))
(defn get-handlers [middleware k]
(->> middleware (map k) (remove nil?) (doall)))