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)) | |||||||||