Compare commits
13 Commits
bd6bd11519
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bb64ddf6e6 | |||
| b5b8259257 | |||
| 159bf1613c | |||
| b83287fb76 | |||
| 7b0b0673b4 | |||
| 7eacce84c7 | |||
| 59ad03f123 | |||
| 32fcf7a6e9 | |||
| 7af519c788 | |||
| b1d8a207ce | |||
| 7c8a9793fe | |||
| 43f3a530eb | |||
| a967de6d75 |
@@ -0,0 +1,2 @@
|
|||||||
|
{:lint-as {example.utils/defaction clojure.core/defn
|
||||||
|
example.utils/defpage clojure.core/def}}
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
.nrepl-port
|
.nrepl-port
|
||||||
.cpcache
|
.cpcache
|
||||||
|
.clj-kondo/*
|
||||||
|
!.clj-kondo/config.edn
|
||||||
|
.lsp
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
{:paths ["src/main" "resources"]
|
{:paths ["src/main" "resources"]
|
||||||
|
|
||||||
:deps {
|
:deps {starfederation.datastar/sdk {:git/url "https://github.com/starfederation/datastar/"
|
||||||
starfederation.datastar/sdk {:git/url "https://github.com/starfederation/datastar/"
|
|
||||||
:git/sha "376c4e2411706b942ea0ab937e4c6218d24fb30f"
|
:git/sha "376c4e2411706b942ea0ab937e4c6218d24fb30f"
|
||||||
:deps/root "sdk/clojure/sdk"}
|
:deps/root "sdk/clojure/sdk"}
|
||||||
starfederation.datastar/ring {:git/url "https://github.com/starfederation/datastar/"
|
starfederation.datastar/ring {:git/url "https://github.com/starfederation/datastar/"
|
||||||
:git/sha "376c4e2411706b942ea0ab937e4c6218d24fb30f"
|
:git/sha "376c4e2411706b942ea0ab937e4c6218d24fb30f"
|
||||||
:deps/root "sdk/clojure/adapter-ring"}
|
:deps/root "sdk/clojure/adapter-ring"}
|
||||||
|
datastar/expressions {:git/url "https://github.com/ramblurr/datastar-expressions/"
|
||||||
|
:git/sha "79027495e385a92ce968494b748adbdc65a780a1"}
|
||||||
ring/ring-jetty-adapter {:mvn/version "1.13.0"}
|
ring/ring-jetty-adapter {:mvn/version "1.13.0"}
|
||||||
metosin/reitit {:mvn/version "0.7.2"}
|
metosin/reitit {:mvn/version "0.7.2"}
|
||||||
dev.onionpancakes/chassis {:mvn/version "1.0.365"}
|
dev.onionpancakes/chassis {:mvn/version "1.0.365"}
|
||||||
com.cnuernber/charred {:mvn/version "1.034"}
|
com.cnuernber/charred {:mvn/version "1.034"}
|
||||||
org.clojure/data.json {:mvn/version "2.5.1"}}
|
org.clojure/data.json {:mvn/version "2.5.1"}
|
||||||
|
ring-logger/ring-logger {:mvn/version "1.1.1"}
|
||||||
|
org.slf4j/slf4j-api {:mvn/version "2.0.17"}
|
||||||
|
org.slf4j/slf4j-simple {:mvn/version "2.0.17"}}
|
||||||
|
|
||||||
:aliases
|
:aliases
|
||||||
{:repl {:extra-paths ["src/dev"]
|
{:repl {:extra-paths ["src/dev"]
|
||||||
:extra-deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
:extra-deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||||
nrepl/nrepl {:mvn/version "1.3.0"}
|
nrepl/nrepl {:mvn/version "1.3.0"}
|
||||||
cider/cider-nrepl {:mvn/version "0.50.2"}
|
cider/cider-nrepl {:mvn/version "0.50.2"}
|
||||||
io.github.tonsky/clj-reload {:mvn/version "0.7.1"}}
|
io.github.tonsky/clj-reload {:mvn/version "0.7.1"}
|
||||||
:main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware]"]}}}
|
djblue/portal {:mvn/version "0.60.2"}}
|
||||||
|
:main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware]"]}}}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>hello world d*</title>
|
|
||||||
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"></script>
|
|
||||||
<link rel="icon" type="image/x-icon" href="https://data-star.dev/cdn-cgi/image/format=auto,width=24/static/images/rocket-48x48-4c739bfaffe86a6ffcc3a6d77e3c5547730f03d74c11aa460209596d1811f7a3.png">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
%%content%%
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
(ns dev.portal
|
||||||
|
(:require
|
||||||
|
[clojure.string :as s]
|
||||||
|
[portal.api :as inspect]))
|
||||||
|
|
||||||
|
(def p (inspect/open))
|
||||||
|
(add-tap #'inspect/submit)
|
||||||
|
|
||||||
|
(def devbox-ip "100.77.151.44")
|
||||||
|
|
||||||
|
(defn print-url []
|
||||||
|
(prn "portal server started on:" (s/replace (inspect/url p) #"localhost" devbox-ip)))
|
||||||
|
|
||||||
|
(defn tap-html> [data]
|
||||||
|
(tap> (with-meta data
|
||||||
|
{:portal.viewer/default :portal.viewer/hiccup})))
|
||||||
|
|
||||||
|
(print-url)
|
||||||
|
(tap> :connected)
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(inspect/clear)
|
||||||
|
|
||||||
|
(tap> :ping)
|
||||||
|
|
||||||
|
(def hiccup [:div
|
||||||
|
[:p "some html!"]
|
||||||
|
[:label "my-button:"]
|
||||||
|
[:button "test"]])
|
||||||
|
(tap> hiccup)
|
||||||
|
(tap-html> hiccup)
|
||||||
|
|
||||||
|
;; use your editor, tap> some data to introspect
|
||||||
|
{:some :complex
|
||||||
|
:data {:foo :bar
|
||||||
|
:baz "franz.zip"
|
||||||
|
:fn-handler 'my-fn}}
|
||||||
|
|
||||||
|
;; bring that data back into the repl
|
||||||
|
(deref p)
|
||||||
|
(prn @p)
|
||||||
|
|
||||||
|
;; ========================
|
||||||
|
;; restart (changes port)
|
||||||
|
;; ========================
|
||||||
|
(do
|
||||||
|
(inspect/stop)
|
||||||
|
(def p (p/open))
|
||||||
|
(print-url)))
|
||||||
|
|
||||||
|
|
||||||
+2
-6
@@ -1,19 +1,15 @@
|
|||||||
(ns user
|
(ns user
|
||||||
(:require
|
(:require
|
||||||
[clj-reload.core :as reload]))
|
[clj-reload.core :as reload]))
|
||||||
|
|
||||||
|
|
||||||
(alter-var-root #'*warn-on-reflection* (constantly true))
|
(alter-var-root #'*warn-on-reflection* (constantly true))
|
||||||
|
|
||||||
|
|
||||||
(reload/init
|
(reload/init
|
||||||
{:no-reload ['user]})
|
{:no-reload ['user]})
|
||||||
|
|
||||||
|
|
||||||
(defn reload! []
|
(defn reload! []
|
||||||
(reload/reload))
|
(reload/reload))
|
||||||
|
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(reload!)
|
(reload!)
|
||||||
*e)
|
*e)
|
||||||
|
|||||||
+60
-34
@@ -1,59 +1,85 @@
|
|||||||
(ns example.core
|
(ns example.core
|
||||||
(:require
|
(:require
|
||||||
[example.utils :refer [html->str defpage defaction defaction-async] :as u]
|
[example.utils
|
||||||
[reitit.ring :as rr]
|
:refer [html->str defpage defaction defaction-async
|
||||||
[ring.util.response :as ruresp]))
|
keep-open action-on-click navigate-on-click]
|
||||||
|
:as u]
|
||||||
|
[starfederation.datastar.clojure.api :as d*]
|
||||||
|
[starfederation.datastar.clojure.expressions :refer [->expr]]
|
||||||
|
[reitit.ring :as rr]
|
||||||
|
[ring.util.response :as ruresp]))
|
||||||
|
|
||||||
|
(declare home-page page-2 hello-world)
|
||||||
|
|
||||||
;; views
|
|
||||||
(defn home-view [_]
|
|
||||||
(html->str
|
|
||||||
[:main
|
|
||||||
[:div
|
|
||||||
[:input {:data-bind "msg"}]
|
|
||||||
[:div {:data-text "$msg"}]
|
|
||||||
[:button {:data-on-click "@get('/hello-world')"} "click for text animation"]]
|
|
||||||
[:button {:data-on-click "@get('/page2')"} "go to page 2"]]))
|
|
||||||
|
|
||||||
|
|
||||||
(defn page2-view [_]
|
|
||||||
(html->str
|
|
||||||
[:main
|
|
||||||
[:p "this is page2"]
|
|
||||||
[:button {:data-on-click "@get('/')"} "go back to home"]]))
|
|
||||||
|
|
||||||
;; hello world animation
|
|
||||||
(def message "Hello, world!")
|
(def message "Hello, world!")
|
||||||
|
|
||||||
(def msg-count (count message))
|
(def msg-count (count message))
|
||||||
|
|
||||||
(defn hello-world [sse]
|
;; actions
|
||||||
|
(defaction hello-world [sse]
|
||||||
(dotimes [i msg-count]
|
(dotimes [i msg-count]
|
||||||
(u/patch-signals-edn! sse {:msg (subs message 0 (inc i))})
|
(u/patch-signals-edn! sse {:msg (subs message 0 (inc i))})
|
||||||
(Thread/sleep 500)))
|
(Thread/sleep 500)))
|
||||||
|
|
||||||
|
(defaction say-hi [sse_]
|
||||||
|
(u/broadcast-signals! {:msg "hello from the great beyond!"}))
|
||||||
|
|
||||||
|
;; pages
|
||||||
|
(defpage home-page
|
||||||
|
(html->str
|
||||||
|
[:main
|
||||||
|
[:pre {:data-json-signals true}]
|
||||||
|
[:div
|
||||||
|
[:h2 "server side fun:"]
|
||||||
|
[:div {:data-signal "msg"}]
|
||||||
|
[:p {:data-text "$msg"}]
|
||||||
|
[:button (action-on-click hello-world)
|
||||||
|
"click for text animation"]]
|
||||||
|
[:div
|
||||||
|
[:button (action-on-click say-hi)
|
||||||
|
"say hi to everyone"]]
|
||||||
|
[:a {:href page-2}
|
||||||
|
"go to back page 2"]]))
|
||||||
|
|
||||||
|
(defpage page-2
|
||||||
|
(html->str
|
||||||
|
[:main
|
||||||
|
[:pre {:data-json-signals true}]
|
||||||
|
[:div {:data-signals (->expr {:count 0})}]
|
||||||
|
[:div {:data-on-interval__duration.500ms
|
||||||
|
(->expr (set! $count (inc (int $count))))}]
|
||||||
|
[:div {:data-computed-msg2 (->expr (.substring "hello, world!" 0 $count))}]
|
||||||
|
[:div
|
||||||
|
[:h2 "client side fun:"]
|
||||||
|
[:p {:data-text "$msg2"}]
|
||||||
|
[:button {:data-on-click (->expr (set! $count 0))}
|
||||||
|
"click for text animation"]]
|
||||||
|
[:a {:href home-page}
|
||||||
|
"go back home"]]))
|
||||||
|
|
||||||
|
;; http app server
|
||||||
(def routes
|
(def routes
|
||||||
(concat
|
(concat
|
||||||
(defpage "/" home-view)
|
(u/app-routes home-page)
|
||||||
(defpage "/page2" page2-view)
|
;; todo frameworkify the aysnc & broadcast stuffs then all the http things
|
||||||
(defaction "/hello-world" hello-world)
|
(defaction-async "/connect" u/connect-sse! u/disconnect-sse!)))
|
||||||
(defaction-async "/connect" u/connect-sse! u/disconnect-sse!)))
|
|
||||||
|
|
||||||
(def router (rr/router routes))
|
(def router (rr/router routes))
|
||||||
|
|
||||||
(def handler (rr/ring-handler router))
|
(def handler (rr/ring-handler router))
|
||||||
|
|
||||||
|
|
||||||
;; repl it up ;P
|
;; repl it up ;P
|
||||||
(comment
|
(comment
|
||||||
|
(declare d* clojure.repl)
|
||||||
|
|
||||||
|
routes
|
||||||
|
|
||||||
(u/broadcast-signals! {:msg "hi franz"})
|
(u/broadcast-signals! {:msg "hi franz"})
|
||||||
(u/broadcast-signals! {:msg "hi ty"})
|
(u/broadcast-signals! {:msg "hi ty"})
|
||||||
(u/broadcast! d*/console-log! "hi franz")
|
(u/broadcast! d*/console-log! "hi franz")
|
||||||
(u/broadcast-js! "console.log('test')")
|
(u/broadcast-js! "console.log('test')")
|
||||||
(u/broadcast-reload!)
|
(u/broadcast-reload!)
|
||||||
|
|
||||||
(kill-broadcast!)
|
(u/kill-broadcast!)
|
||||||
|
d*/patch-signals!
|
||||||
|
d*
|
||||||
|
|
||||||
(clojure.repl/dir d*)
|
(clojure.repl/dir d*)
|
||||||
(clojure.repl/doc d*/patch-signals!))
|
(clojure.repl/doc d*/patch-signals!))
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
(ns example.main
|
(ns example.main
|
||||||
(:require
|
(:require
|
||||||
[example.core :as c]
|
[example.core :as c]
|
||||||
[example.server :as server]))
|
[example.server :as server]))
|
||||||
|
|
||||||
|
|
||||||
(defn -main [& _]
|
(defn -main [& _]
|
||||||
(let [server (server/start! c/handler)]
|
(let [server (server/start! c/handler)]
|
||||||
(.addShutdownHook (Runtime/getRuntime)
|
(.addShutdownHook (Runtime/getRuntime)
|
||||||
(Thread. (fn []
|
(Thread. (fn []
|
||||||
(server/stop! server)
|
(server/stop! server)
|
||||||
(shutdown-agents))))))
|
(shutdown-agents))))))
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
(ns example.server
|
(ns example.server
|
||||||
(:require
|
(:require
|
||||||
[example.core :as c]
|
[example.core :as c]
|
||||||
[ring.adapter.jetty :as jetty])
|
[ring.adapter.jetty :as jetty]
|
||||||
|
[ring.logger :as logger])
|
||||||
(:import
|
(:import
|
||||||
org.eclipse.jetty.server.Server))
|
org.eclipse.jetty.server.Server))
|
||||||
|
|
||||||
|
|
||||||
(defonce !jetty-server (atom nil))
|
(defonce !jetty-server (atom nil))
|
||||||
|
|
||||||
|
|
||||||
(defn start! [handler & {:as opts}]
|
(defn start! [handler & {:as opts}]
|
||||||
(let [opts (merge {:port 80 :join? false}
|
(let [opts (merge {:port 80 :join? false}
|
||||||
opts)]
|
opts)]
|
||||||
(println "Starting server on port:" (:port opts))
|
(println "Starting server on port:" (:port opts))
|
||||||
(jetty/run-jetty handler opts)))
|
(jetty/run-jetty (logger/wrap-with-logger handler) opts)))
|
||||||
|
|
||||||
|
|
||||||
(defn stop! [server]
|
(defn stop! [server]
|
||||||
(println "Stopping server")
|
(println "Stopping server")
|
||||||
(println server)
|
(println server)
|
||||||
(.stop ^Server server))
|
(.stop ^Server server))
|
||||||
|
|
||||||
|
|
||||||
(defn reboot-jetty-server! [handler & {:as opts}]
|
(defn reboot-jetty-server! [handler & {:as opts}]
|
||||||
(swap! !jetty-server
|
(swap! !jetty-server
|
||||||
(fn [server]
|
(fn [server]
|
||||||
@@ -29,5 +26,8 @@
|
|||||||
(stop! server))
|
(stop! server))
|
||||||
(start! handler opts))))
|
(start! handler opts))))
|
||||||
|
|
||||||
|
(defn -main [& _args]
|
||||||
|
(reboot-jetty-server! #'c/handler {:async? true}))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(reboot-jetty-server! #'c/handler {:async? true}))
|
(reboot-jetty-server! #'c/handler {:async? true}))
|
||||||
|
|||||||
+99
-63
@@ -1,17 +1,18 @@
|
|||||||
(ns example.utils
|
(ns example.utils
|
||||||
(:require
|
(:require
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[dev.onionpancakes.chassis.compiler :as hc]
|
[dev.onionpancakes.chassis.compiler :as hc]
|
||||||
[dev.onionpancakes.chassis.core :as h]
|
[dev.onionpancakes.chassis.core :as h]
|
||||||
[reitit.ring.middleware.parameters :as rmparams]
|
[reitit.ring.middleware.parameters :as rmparams]
|
||||||
[reitit.ring :as rr]
|
[reitit.ring :as rr]
|
||||||
[ring.util.response :as ruresp]
|
[ring.util.response :as ruresp]
|
||||||
[starfederation.datastar.clojure.api :as d*]
|
[starfederation.datastar.clojure.api :as d*]
|
||||||
[starfederation.datastar.clojure.adapter.ring :refer [->sse-response on-open on-close] :as dr]
|
[starfederation.datastar.clojure.adapter.ring :refer [->sse-response on-open on-close] :as dr]
|
||||||
[clojure.data.json :as json]))
|
[clojure.data.json :as json]
|
||||||
|
[starfederation.datastar.clojure.expressions :refer [->expr]]))
|
||||||
|
|
||||||
(declare conns add-elements! sse-navigate!)
|
(declare conns add-elements! sse-navigate! disconnect-sse!)
|
||||||
|
|
||||||
;; global utils
|
;; global utils
|
||||||
(defn tap! [x]
|
(defn tap! [x]
|
||||||
@@ -20,18 +21,32 @@
|
|||||||
|
|
||||||
;; html utils
|
;; html utils
|
||||||
(defn html->str [hiccup-forms]
|
(defn html->str [hiccup-forms]
|
||||||
(h/html
|
(h/html (hc/compile hiccup-forms)))
|
||||||
(hc/compile
|
|
||||||
hiccup-forms)))
|
|
||||||
|
|
||||||
(defn html-template [content]
|
(defn html-template [content]
|
||||||
(-> (io/resource "public/index.html")
|
(html->str
|
||||||
slurp
|
[:html {:lang "en"}
|
||||||
(string/split-lines)
|
[:head
|
||||||
(->> (drop 3)
|
[:title "hello world d*"]
|
||||||
(apply str))
|
[:script {:type "module"
|
||||||
(str "<div data-on-load=\"@get('connect')\"></div>")
|
:src "https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"}]
|
||||||
(string/replace "%%content%%" content)))
|
[:link {:rel "icon"
|
||||||
|
:type "image/x-icon"
|
||||||
|
:href "https://data-star.dev/cdn-cgi/image/format=auto,width=24/static/images/rocket-48x48-4c739bfaffe86a6ffcc3a6d77e3c5547730f03d74c11aa460209596d1811f7a3.png"}]]
|
||||||
|
[:body
|
||||||
|
(h/raw content)
|
||||||
|
[:div {:data-on-load (->expr (@get "/connect"))}]]]))
|
||||||
|
|
||||||
|
(defn at-get [page-or-action]
|
||||||
|
(format "@get('%s')" (:url page-or-action)))
|
||||||
|
|
||||||
|
(def keep-open {:openWhenHidden true})
|
||||||
|
|
||||||
|
(defn navigate-on-click [url]
|
||||||
|
{:data-on-click (->expr (@get ~url))})
|
||||||
|
|
||||||
|
(defn action-on-click [url]
|
||||||
|
{:data-on-click (->expr (@post ~url ~keep-open))})
|
||||||
|
|
||||||
;; fix. use replaceState api? or push some real state? back button doesn't work yet
|
;; fix. use replaceState api? or push some real state? back button doesn't work yet
|
||||||
(defn update-url-frag [url]
|
(defn update-url-frag [url]
|
||||||
@@ -40,18 +55,18 @@
|
|||||||
|
|
||||||
(defn sse-page [request respond view url]
|
(defn sse-page [request respond view url]
|
||||||
(respond
|
(respond
|
||||||
(->sse-response request
|
(->sse-response request
|
||||||
{on-open
|
{on-open
|
||||||
(fn [sse]
|
(fn [sse]
|
||||||
(d*/with-open-sse sse
|
(d*/with-open-sse sse
|
||||||
(sse-navigate! sse (view {}))
|
(sse-navigate! sse (view {}))
|
||||||
(add-elements! sse (update-url-frag url))))})))
|
(add-elements! sse (update-url-frag url))))})))
|
||||||
|
|
||||||
(defn text-html-page [request respond view]
|
(defn text-html-page [request respond view]
|
||||||
(-> (html-template (view {}))
|
(-> (html-template (view {}))
|
||||||
ruresp/response
|
ruresp/response
|
||||||
(ruresp/content-type "text/html")
|
(ruresp/content-type "text/html")
|
||||||
respond))
|
respond))
|
||||||
|
|
||||||
(defn page [request respond url view]
|
(defn page [request respond url view]
|
||||||
(if (-> request
|
(if (-> request
|
||||||
@@ -61,7 +76,6 @@
|
|||||||
(sse-page request respond view url)
|
(sse-page request respond view url)
|
||||||
(text-html-page request respond view)))
|
(text-html-page request respond view)))
|
||||||
|
|
||||||
|
|
||||||
;; d* api utils
|
;; d* api utils
|
||||||
(defn patch-signals-edn! [sse edn]
|
(defn patch-signals-edn! [sse edn]
|
||||||
(d*/patch-signals! sse (json/write-str edn)))
|
(d*/patch-signals! sse (json/write-str edn)))
|
||||||
@@ -73,36 +87,24 @@
|
|||||||
(d*/patch-elements! sse elems #:d*.elements{:patch-mode "replace"
|
(d*/patch-elements! sse elems #:d*.elements{:patch-mode "replace"
|
||||||
:selector "main"}))
|
:selector "main"}))
|
||||||
|
|
||||||
(defn defaction-async [url on-open-f on-close-f]
|
|
||||||
(let [sse-handler
|
|
||||||
(fn [request respond raise_]
|
|
||||||
(respond
|
|
||||||
(->sse-response
|
|
||||||
request
|
|
||||||
{on-open on-open-f
|
|
||||||
on-close on-close-f})))]
|
|
||||||
[[url sse-handler]
|
|
||||||
[(str "/sse" url) sse-handler]]))
|
|
||||||
|
|
||||||
|
|
||||||
;; broadcast utils
|
;; broadcast utils
|
||||||
(defn try!
|
(defn try!
|
||||||
[d*-f! sse & args]
|
[d*-f! sse & args]
|
||||||
(try (apply d*-f! sse args)
|
(try (when (not (apply d*-f! sse args))
|
||||||
|
(disconnect-sse! sse))
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(println "exception occured. dropping connection. error:" e)
|
(println "exception occured. dropping connection. error:" e)
|
||||||
(d*/close-sse! sse)
|
(disconnect-sse! sse))))
|
||||||
(swap! conns disj sse))))
|
|
||||||
|
|
||||||
(defonce conns (atom #{}))
|
(defonce conns (atom #{}))
|
||||||
|
|
||||||
(defn broadcast!
|
(defn broadcast!
|
||||||
([f]
|
([f]
|
||||||
(doseq [conn @conns]
|
(doseq [conn @conns]
|
||||||
(try! f conn)))
|
(try! f conn)))
|
||||||
([f arg & args]
|
([f arg & args]
|
||||||
(doseq [conn @conns]
|
(doseq [conn @conns]
|
||||||
(apply try! f conn arg args))))
|
(apply try! f conn arg args))))
|
||||||
|
|
||||||
(defn connect-sse! [sse]
|
(defn connect-sse! [sse]
|
||||||
(swap! conns conj sse)
|
(swap! conns conj sse)
|
||||||
@@ -127,21 +129,55 @@
|
|||||||
(swap! conns disj conn)))
|
(swap! conns disj conn)))
|
||||||
|
|
||||||
;; http stuffs
|
;; http stuffs
|
||||||
(defn defaction [url f]
|
(defonce !ma-routes (atom {}))
|
||||||
|
|
||||||
|
(defn add-route! [url f]
|
||||||
|
(swap! !ma-routes assoc url f))
|
||||||
|
|
||||||
|
;; todo, custom url support
|
||||||
|
(defmacro defpage
|
||||||
|
[name-sym & body]
|
||||||
|
(let [route-str (str "/" name-sym)
|
||||||
|
route-str-sse (str "/sse" route-str)]
|
||||||
|
`(let [view# (fn [_#]
|
||||||
|
~@body)]
|
||||||
|
|
||||||
|
(add-route! ~route-str
|
||||||
|
(fn [request# respond# _#]
|
||||||
|
(page request# respond# ~route-str view#)))
|
||||||
|
(add-route! ~route-str-sse
|
||||||
|
(fn [request# respond# _#]
|
||||||
|
(sse-page request# respond# view# ~route-str-sse)))
|
||||||
|
(def ~name-sym ~route-str))))
|
||||||
|
|
||||||
|
(defn app-routes
|
||||||
|
([]
|
||||||
|
(->> @!ma-routes
|
||||||
|
vec))
|
||||||
|
([index-route]
|
||||||
|
(concat (app-routes)
|
||||||
|
[["/" (@!ma-routes index-route)]])))
|
||||||
|
|
||||||
|
(defmacro defaction [action-sym args & body]
|
||||||
|
(let [url (str "/sse/" action-sym)]
|
||||||
|
`(let [sse-handler#
|
||||||
|
(fn [request# respond# raise_#]
|
||||||
|
(respond#
|
||||||
|
(->sse-response
|
||||||
|
request#
|
||||||
|
{on-open (fn ~args (d*/with-open-sse ~(get args 0)
|
||||||
|
~@body))})))]
|
||||||
|
(add-route! ~url sse-handler#)
|
||||||
|
(def ~action-sym ~url))))
|
||||||
|
|
||||||
|
(defn defaction-async [url on-open-f on-close-f]
|
||||||
(let [sse-handler
|
(let [sse-handler
|
||||||
(fn [request respond raise_]
|
(fn [request respond raise_]
|
||||||
(respond
|
(respond
|
||||||
(->sse-response
|
(->sse-response
|
||||||
request
|
request
|
||||||
{on-open #(d*/with-open-sse % (f %))})))]
|
{on-open on-open-f
|
||||||
[[url sse-handler]
|
on-close on-close-f})))]
|
||||||
[(str "/sse" url) sse-handler]]))
|
[[url sse-handler]
|
||||||
|
[(str "/sse" url) sse-handler]]))
|
||||||
|
|
||||||
|
|
||||||
(defn defpage [endpoint view]
|
|
||||||
[[endpoint
|
|
||||||
{:handler (fn [request respond _]
|
|
||||||
(page request respond endpoint view))}]
|
|
||||||
[(str "/sse" endpoint)
|
|
||||||
{:handler (fn [request respond _]
|
|
||||||
(page request respond endpoint view))}]])
|
|
||||||
|
|||||||
Reference in New Issue
Block a user