shoreleave/shoreleave-remote-ring0.3.0A smarter client-side with ClojureScript : Ring- (and Compojure-) server-side Remotes support dependencies
dev dependencies
| (this space intentionally left almost blank) | |||||||||
Server-side RPC support for use with shoreleave (and maybe fetch?). Mostly copied from https://github.com/shoreleave/shoreleave-remote-noir; changed to eliminate the noir-isms... | (ns
cemerick.shoreleave.rpc) | |||||||||
ATTENTIONThis is here for backwards compatibility only, please use | ||||||||||
(def default-remote-uri "/_fetch")
(def remotes (atom {})) | ||||||||||
(defn add-remote [key func] (swap! remotes assoc key func)) | ||||||||||
(defn safe-read [s]
;; can we please have a civilization!?
(binding [*read-eval* false]
(read-string s))) | ||||||||||
Same as defn, but also registers the defined function as a remote. The name of the remote is the same as the function's name by default; You can optionally specify a different name by adding :remote-name metadata to the function name, e.g.: (defremote ^{:remote-name :your-fn} my-fn [] ...) | (defmacro defremote
[& [name :as body]]
`(do
(defn ~@body)
(add-remote
(keyword (or (-> (var ~name) meta :remote-name)
'~name))
~name)
(var ~name))) | |||||||||
(defn call-remote
[remote-key params]
(if-let [func (@remotes remote-key)]
(let [result (apply func params)]
{:status 202
:headers {"Content-Type" "application/edn; charset=utf-8"}
:body (pr-str result)})
{:status 404})) | ||||||||||
(defn handle-rpc
[{{:keys [params remote]} :params :as request}]
(call-remote (keyword remote) (safe-read params))) | ||||||||||
(defn wrap-rpc
([app] (wrap-rpc app default-remote-uri))
([app remote-uri]
(fn [{:keys [request-method uri] :as request}]
(if (and (= :post request-method) (= remote-uri uri))
(handle-rpc request)
(app request))))) | ||||||||||
Server-side RPC support for use with Shoreleave, that works at the Ring level | (ns shoreleave.middleware.rpc (:require [shoreleave.server-helpers :refer [safe-read]])) | |||||||||
By default, remotes will hit | (def default-remote-uri "/_shoreleave") | |||||||||
The remotes get collected in a hashmap: | (def remotes (atom {})) | |||||||||
(defn add-remote [key func] (swap! remotes assoc key func)) | ||||||||||
Same as defn, but also registers the defined function as a remote. The name of the remote is the same as the function's name by default; You can optionally specify a different name by adding :remote-name metadata to the function name, e.g.: (defremote ^{:remote-name :your-fn} my-fn [] ...) | (defmacro defremote
[& [name :as body]]
`(do
(defn ~@body)
(add-remote
(keyword (or (-> (var ~name) meta :remote-name)
'~name))
~name)
(var ~name))) | |||||||||
Exposes an entire namespace as a remote API and optionally aliases for use on the client side. For example: | (defn remote-ns
[namesp-sym & opts]
(let [{:keys [as]} (apply hash-map opts)
namesp (try
(require namesp-sym)
(find-ns namesp-sym)
(catch Exception e
(throw (Exception. (str "Could not locate a namespace when aliasing remotes: " namesp-sym))
e)))
public-fns (ns-publics namesp)]
(doseq [[fn-name fn-var] public-fns]
(when (fn? (var-get fn-var))
(add-remote (keyword (str (or as namesp-sym) "/" fn-name)) fn-var))))) | |||||||||
(defn call-remote
[remote-key params]
(if-let [func (@remotes remote-key)]
(let [result (apply func params)]
{:status 202
:headers {"Content-Type" "application/edn; charset=utf-8"}
:body (pr-str result)})
{:status 404
:body "Remote not found."})) | ||||||||||
(defn handle-rpc
[{{:keys [params remote]} :params :as request}]
(call-remote (keyword remote) (safe-read params))) | ||||||||||
Top-level Ring middleware to enable Shoreleave RPC calls | (defn wrap-rpc
([app] (wrap-rpc app default-remote-uri))
([app remote-uri]
(fn [{:keys [request-method uri] :as request}]
(if (and (= :post request-method) (= remote-uri uri))
(handle-rpc request)
(app request))))) | |||||||||
Simple functions to smooth over server idioms | (ns shoreleave.server-helpers (:require [clojure.tools.reader.edn :as edn])) | |||||||||
This causes precious-file.txt to be created if it doesn't
exist, or if it does exist, its contents will be erased (given
appropriate JVM sandboxing permissions, and underlying OS file
permissions).
| ||||||||||
This is a data-only // edn-only read. It takes a string of data (s) and returns Clojure/EDN data | (defn safe-read [s] (edn/read-string s)) | |||||||||