This commit is contained in:
Adam Jeniski 2025-07-19 02:33:18 -09:00
parent 7c8a9793fe
commit b1d8a207ce
5 changed files with 66 additions and 76 deletions

View File

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

View File

@ -1,8 +1,8 @@
(ns example.core (ns example.core
(:require (:require
[example.utils :refer [html->str defpage defaction defaction-async] :as u] [example.utils :refer [html->str defpage defaction defaction-async] :as u]
[reitit.ring :as rr] [reitit.ring :as rr]
[ring.util.response :as ruresp])) [ring.util.response :as ruresp]))
(declare home-page page-2 hello-world) (declare home-page page-2 hello-world)
@ -11,7 +11,7 @@
{:url "/" {:url "/"
:view :view
(fn home-view [_] (fn home-view [_]
(html->str (html->str
[:main [:main
[:div [:div
[:input {:data-bind "msg"}] [:input {:data-bind "msg"}]
@ -24,7 +24,7 @@
{:url "/page2" {:url "/page2"
:view :view
(fn page2-view [_] (fn page2-view [_]
(html->str (html->str
[:main [:main
[:p "this is page2"] [:p "this is page2"]
[:button {:data-on-click (u/at-get home-page)} [:button {:data-on-click (u/at-get home-page)}
@ -38,17 +38,17 @@
(def hello-world (def hello-world
{:url "/hello-world" {:url "/hello-world"
:fn (fn hello-world [sse] :fn (fn 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)))})
;; http stuff ;; http stuff
(def routes (def routes
(concat (concat
(defpage home-page) (defpage home-page)
(defpage page-2) (defpage page-2)
(defaction hello-world) (defaction 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))
@ -56,6 +56,8 @@
;; repl it up ;P ;; repl it up ;P
(comment (comment
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")
@ -64,7 +66,6 @@
(u/kill-broadcast!) (u/kill-broadcast!)
(clojure.repl/dir d*) (clojure.repl/dir d*)
(clojure.repl/doc d*/patch-signals!)) (clojure.repl/doc d*/patch-signals!))

View File

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

View File

@ -1,27 +1,23 @@
(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])
(: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 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]

View File

@ -1,15 +1,15 @@
(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]))
(declare conns add-elements! sse-navigate!) (declare conns add-elements! sse-navigate!)
@ -21,8 +21,8 @@
;; html utils ;; html utils
(defn html->str [hiccup-forms] (defn html->str [hiccup-forms]
(h/html (h/html
(hc/compile (hc/compile
hiccup-forms))) hiccup-forms)))
(defn html-template [content] (defn html-template [content]
(-> (io/resource "public/index.html") (-> (io/resource "public/index.html")
@ -43,18 +43,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
@ -64,7 +64,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)))
@ -76,25 +75,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"}))
;; 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)
@ -123,34 +121,34 @@
([page] ([page]
(defpage (:url page) (:view page))) (defpage (:url page) (:view page)))
([endpoint view] ([endpoint view]
[[endpoint [[endpoint
{:handler (fn [request respond _] {:handler (fn [request respond _]
(page request respond endpoint view))}] (page request respond endpoint view))}]
[(str "/sse" endpoint) [(str "/sse" endpoint)
{:handler (fn [request respond _] {:handler (fn [request respond _]
(page request respond endpoint view))}]])) (page request respond endpoint view))}]]))
(defn defaction (defn defaction
([action] ([action]
(defaction (:url action) (:fn action))) (defaction (:url action) (:fn action)))
([url f] ([url 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 #(d*/with-open-sse % (f %))})))]
[[url sse-handler] [[url sse-handler]
[(str "/sse" url) sse-handler]]))) [(str "/sse" url) sse-handler]])))
(defn defaction-async [url on-open-f on-close-f] (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 on-open-f {on-open on-open-f
on-close on-close-f})))] on-close on-close-f})))]
[[url sse-handler] [[url sse-handler]
[(str "/sse" url) sse-handler]])) [(str "/sse" url) sse-handler]]))