Skip to content

Commit

Permalink
Rewrite event bus using EventTarget.
Browse files Browse the repository at this point in the history
  • Loading branch information
samcf committed Oct 3, 2024
1 parent a99607a commit c9ede46
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 134 deletions.
2 changes: 1 addition & 1 deletion src/main/ogres/app/component/panel_tokens.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@
(use-callback
(fn [event]
(.preventDefault event)
(publish {:topic :image/change-thumbnail :args [hash bound]})) [publish hash bound])
(publish :image/change-thumbnail hash bound)) [publish hash bound])
on-drag-move
(use-callback
(fn [data]
Expand Down
7 changes: 4 additions & 3 deletions src/main/ogres/app/component/scene.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,11 @@
share (:session/share-cursors (:root/session result))
host (:session/host (:root/session result))
[points set-points] (use-state {})]
(use-subscribe :cursor/moved {:disabled (not share)}
(use-subscribe :cursor/moved
(use-callback
(fn [{[uuid x y] :args}]
(set-points (fn [points] (assoc points uuid [x y])))) []))
(fn [uuid x y]
(if share
(set-points (fn [points] (assoc points uuid [x y]))))) [share]))
(if share
($ :g.scene-cursors
(for [[uuid [x y]] points
Expand Down
4 changes: 2 additions & 2 deletions src/main/ogres/app/component/scene_objects.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
(fn []
(if (nil? uuid)
(set-point nil))) [uuid])
(use-subscribe :cursor/moved {:disabled (nil? uuid)}
(use-subscribe :cursor/moved
(use-callback
(fn [{[id cx cy] :args}]
(fn [id cx cy]
(if (= id uuid)
(set-point
(fn [[_ _ dx dy]]
Expand Down
19 changes: 13 additions & 6 deletions src/main/ogres/app/hooks.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,23 @@
use-query
provider.state/use-query)

(def ^{:doc "Returns a function which publishes the given event map
onto the global event publication."
(def ^{:doc "Returns a function which, when called with a topic and
any relevant arguments, publishes a new event on the
bus. Events and their listeners are called synchronously
and in the order they are added.
```
(let [publish (use-publish)]
(use-subscribe :foo/bar
(fn [a b c]
(prn a b c)))
(publish :foo/bar 1 2 3))
```"
:arglists '([])}
use-publish
provider.events/use-publish)

(def ^{:doc "Creates a new subscription to `topic`, calling the given
handler `f` with the event map when an event with that
topic is published."
:arglists '([f] [topic f] [topic options f])}
(def ^{:doc "Registers a new handler function to the given topic."
:arglists '([topic f])}
use-subscribe
provider.events/use-subscribe)

Expand Down
2 changes: 1 addition & 1 deletion src/main/ogres/app/provider/cursor.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@
dy (.-clientY event)
mx (int (+ (/ (- dx sx) scale) cx))
my (int (+ (/ (- dy sy) scale) cy))]
(publish {:topic :cursor/move :args [mx my]}))))))
(publish :cursor/move mx my))))))
[publish cx cy sx sy scale]))))
4 changes: 2 additions & 2 deletions src/main/ogres/app/provider/dispatch.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
conn (use-context state/context)]
(use-callback
(fn [topic & args]
(publish {:topic topic :args args})
(apply publish topic args)
(let [tx-data [[:db.fn/call tx-fn topic args]]
report (ds/transact! conn tx-data)]
(if (seq (:tx-data report))
(publish {:topic :tx/commit :args (list report)})))) ^:lint/disable [publish])))
(apply publish :tx/commit (list report))))) ^:lint/disable [publish])))

(defn use-dispatch []
(use-context context))
Expand Down
80 changes: 18 additions & 62 deletions src/main/ogres/app/provider/events.cljs
Original file line number Diff line number Diff line change
@@ -1,68 +1,24 @@
(ns ogres.app.provider.events
(:require [clojure.core.async :refer [chan mult tap untap pub sub unsub go-loop timeout put! <! close!]]
[uix.core :refer [defui $ create-context use-callback use-context use-effect]]))
(:require [uix.core :refer [$ defui create-context use-callback use-context use-effect]]))

(defn ^:private create-initial-value []
(let [ch-src (chan 1)
ch-pub (chan 1)
multi (mult ch-src)]
(tap multi ch-pub)
[(pub ch-pub :topic) ch-src multi]))
(def ^:private context (create-context (js/EventTarget.)))

(def ^:private context
(create-context (create-initial-value)))
(defn use-subscribe [topic f]
(let [target (use-context context)
topic (str topic)]
(use-effect
(fn []
(let [handler (fn [event] (apply f (.-detail event)))]
(.addEventListener target topic handler)
(fn []
(.removeEventListener target topic handler)))) [target topic f])))

(defonce context-value (create-initial-value))

(defui provider
"Provides an event publication object, write channel, and channel multiplexer
for the given children. Refer to `use-publish` and `use-subscribe` to publish
and subscribe to events, respectively."
[{:keys [children]}]
($ context {:value context-value} children))

(defui use-publish
"Returns a function that must be called with a topic as the first argument
and the event arguments as the rest. Components may subscribe to published
events with `use-subscribe`."
[]
(let [[_ ch] (use-context context)]
(defn use-publish []
(let [target (use-context context)]
(use-callback
(fn [event]
(put! ch event)) ^:lint/disable [])))
(fn [topic & args]
(.dispatchEvent target (js/CustomEvent. (str topic) #js {"detail" args}))) [target])))

(defn use-subscribe
"Subscribes the given handler to the event bus, optionally given a topic.
May be passed a topic and channel for more nuanced control."
([f]
(let [[_ _ multi] (use-context context)]
(use-effect
(fn []
(let [ch (chan 1)]
(tap multi ch)
(go-loop []
(if-some [event (<! ch)]
(do (f event)
(recur))))
(fn []
(close! ch)
(untap multi ch)))) [multi f pub])))
([topic f]
(use-subscribe topic {:chan (chan 1)} f))
([topic opts f]
(let [disabled (:disabled opts)
rate (:rate-limit opts)
[pub _] (use-context context)
dst (or (:chan opts) (chan 1))]
(use-effect
(fn []
(when (not disabled)
(sub pub topic dst)
(go-loop []
(when-some [event (<! dst)]
(if (> rate 0)
(<! (timeout rate)))
(f event)
(recur))))
(fn []
(unsub pub topic dst))) ^:lint/disable [f rate disabled]))))
(defui provider [props]
($ context {:value (js/EventTarget.)}
(:children props)))
10 changes: 5 additions & 5 deletions src/main/ogres/app/provider/image.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,26 @@
(.get hash)
(.then (fn [rec] (js/URL.createObjectURL (.-data rec))))
(.then (fn [url] (set-url (fn [urls] (assoc urls hash url)))))
(.catch (fn [] (publish {:topic :image/request :args [hash]})))))
(.catch (fn [] (publish :image/request hash)))))
url))) ^:lint/disable [])]
(use-subscribe :image/create-token
(use-callback
(fn [{[hash blob] :args}]
(fn [hash blob]
(.then
(js/createImageBitmap blob)
(fn [image]
(let [record {:hash hash :name "" :size (.-size blob) :width (.-width image) :height (.-height image)}]
(dispatch :token-images/create-many [[record record]] :public))))) [dispatch]))
(use-subscribe :image/cache
(use-callback
(fn [{[image callback] :args}]
(fn [image callback]
(-> (create-hash image)
(.then (fn [hash] (.put (.table store "images") #js {"checksum" hash "data" image})))
(.then (fn [hash] (set-url (fn [urls] (assoc urls hash (js/URL.createObjectURL image)))) hash))
(.then (fn [hash] (when (fn? callback) (callback hash)))))) [store]))
(use-subscribe :image/change-thumbnail
(use-callback
(fn [{[hash [ax ay bx by :as rect]] :args}]
(fn [hash [ax ay bx by :as rect]]
(let [entity (ds/entity (ds/db conn) [:image/hash hash])
images (.table store "images")]
(-> (.get images hash)
Expand Down Expand Up @@ -218,7 +218,7 @@
(.then (js/Promise.all (into-array (into [] (map process-file) files)))
(fn [files]
(doseq [[_ _ thumbnail] files]
(publish {:topic :image/create :args [(:data thumbnail)]}))))) [publish]))))
(publish :image/create (:data thumbnail)))))) [publish]))))

(defn use-image
"React hook which accepts a string that uniquely identifies an image
Expand Down
10 changes: 5 additions & 5 deletions src/main/ogres/app/provider/storage.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
[dexie-export-import
:refer [exportDB importDB peakImportFile]
:rename {exportDB export-db importDB import-db peakImportFile peek-import-file}]
[goog.functions :refer [throttle]]
[ogres.app.const :refer [VERSION]]
[ogres.app.dom :refer [user-type]]
[ogres.app.provider.events :refer [use-subscribe]]
[ogres.app.provider.state :as state :refer [use-query]]
[ogres.app.util :refer [debounce]]
[uix.core :refer [defui $ create-context use-callback use-context use-effect]]))

(def ^:private context (create-context))
Expand Down Expand Up @@ -43,7 +43,7 @@
(use-effect
(fn []
(ds/listen! conn :marshaller
(debounce
(throttle
(fn [{:keys [db-after]}]
(if (= (:user/status (ds/entity db-after [:db/ident :user])) :ready)
(-> db-after
Expand Down Expand Up @@ -93,11 +93,11 @@
(let [store (use-store)
on-remove
(use-callback
(fn [{[image thumb] :args}]
(fn [image thumb]
(.bulkDelete (.table store "images") #js [image thumb])) [store])
on-remove-all
(use-callback
(fn [{[hashes] :args}]
(fn [hashes]
(.bulkDelete (.table store "images") (into-array hashes))) [store])]
(use-subscribe :scene-images/remove on-remove)
(use-subscribe :token-images/remove on-remove)
Expand All @@ -124,7 +124,7 @@
(let [store (use-store)]
(use-subscribe :storage/restore
(use-callback
(fn [{[file] :args}]
(fn [file]
(-> (peek-import-file file)
(.then
(fn [metadata]
Expand Down
19 changes: 10 additions & 9 deletions src/main/ogres/app/provider/window.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
(:require [cognitect.transit :as t]
[datascript.core :as ds]
[datascript.transit :as dst]
[goog.functions :refer [throttle]]
[ogres.app.hooks :refer [use-event-listener use-subscribe use-dispatch use-query]]
[ogres.app.provider.state :as provider.state]
[ogres.app.util :refer [debounce]]
[uix.core :refer [defui $ create-context use-callback use-context use-state use-effect]]))
[uix.core :refer [defui $ create-context use-callback use-context use-memo use-state use-effect]]))

(def ^:private context (create-context))

Expand Down Expand Up @@ -41,7 +41,7 @@
host window to the view window." []
(let [{:keys [view]} (use-context context)]
(use-subscribe :tx/commit
(fn [{[{tx-data :tx-data}] :args}]
(fn [{tx-data :tx-data}]
(->>
#js {:detail (t/write writer tx-data)}
(js/CustomEvent. "AppStateTx")
Expand All @@ -66,12 +66,13 @@
of the form [x y width height]."
[{:keys [target type]}]
(let [dispatch (use-dispatch)
handler (debounce
(fn []
(if-let [element (.. target -document (querySelector ".layout-scene"))]
(->> (.getBoundingClientRect element)
(bounds->vector)
(dispatch :bounds/change type)))) 100)
handler (use-memo
#(throttle
(fn []
(if-let [element (.. target -document (querySelector ".layout-scene"))]
(->> (.getBoundingClientRect element)
(bounds->vector)
(dispatch :bounds/change type)))) 100) [dispatch type target])
[observer] (use-state (js/ResizeObserver. handler))
[scene set-scene] (use-state nil)]
(use-event-listener "resize" handler)
Expand Down
Loading

0 comments on commit c9ede46

Please sign in to comment.