Created
March 11, 2017 14:02
-
-
Save Conaws/a2b97321ff199a13aa5f250fc9c23bda to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns re-kindle.fire.router | |
(:require | |
[posh.reagent :as posh :refer [posh!]] | |
[datascript.core :as d] | |
[re-kindle.util :refer [safe]] | |
[re-kindle.fire.auth :refer [user]] | |
[cljs-time.format :as format] | |
[cljs.tools.reader.edn :as edn] | |
[re-kindle.fire.core :as core :refer [db-ref save]] | |
[cljs.core.async :as async] | |
[taoensso.timbre :as log] | |
[cljs.spec :as s] | |
[cljs-time.core :as time :refer [now]] | |
[reagent.core :as r]) | |
(:require-macros | |
[cljs.core.async.macros :refer [go]])) | |
(def formatter (format/formatters :basic-date-time)) | |
(defn save-snapshot [path tx conn] | |
(core/save path (pr-str {:snapshot-key tx | |
:conn @conn}))) | |
(s/def ::once-args (s/cat :path vector? | |
:startk :re-kindle.specs/RAtom | |
:startval :re-kindle.specs/RAtom | |
:schema map? | |
:component fn?)) | |
(defn load-conn [path startk startval schema component] | |
(try (assert (s/valid? ::once-args [path startk startval schema component])) | |
(catch js/Object e | |
(pr-str (s/explain ::once-args [path startk startval schema component])))) | |
(let [ref (db-ref path)] | |
(.. ref | |
(once "value" | |
(fn [x] | |
(try | |
(if-let [{k :snapshot-key db :conn} (edn/read-string {:readers d/data-readers} (.val x))] | |
(let [datoms (set (d/datoms db :eavt)) | |
;; _ (js/console.log datoms) | |
conn (d/conn-from-datoms datoms schema) | |
;; _ (js/console.log "schema" schema) | |
] | |
(do (posh! conn) | |
(reset! startval conn) | |
(reset! startk k) | |
(log/debugf "this is the k %s" (pr-str k)) | |
(log/debugf "this is the startval %s" (pr-str @startval)) | |
)) | |
(save-snapshot path ":NEW" (d/create-conn schema)) | |
) | |
(catch js/Object e | |
(js/console.log e) | |
(js/console.log "Odds are, your schema isn't working")))))) | |
(r/create-class | |
{:display-name "listener" | |
:component-will-unmount | |
(fn will-unmount-listener [this] | |
(.off ref)) | |
:reagent-render | |
(fn | |
[path startk startval schema component & args] | |
(into [component startk startval] args))}))) | |
(declare handle-event*) | |
(defn on-rolling [path startk startval snappath component] | |
(let [ref (db-ref path)] | |
(if (or (= ":NEW" | |
startk) | |
(nil? startk)) | |
(.. ref | |
(on "child_added" | |
(fn [x] | |
(let [val (.val x) | |
k (.getKey x) | |
parsed-val (edn/read-string {:readers d/data-readers} val) | |
tx (:tx parsed-val)] | |
(do | |
(log/debugf "running on all child-added %s" (pr-str parsed-val)) | |
(handle-event* @startval path parsed-val) | |
(save-snapshot snappath k @startval) | |
) | |
)))) | |
(.. ref | |
;; (limitToLast 1) | |
orderByKey | |
(startAt (clj->js startk)) | |
(on "child_added" | |
(fn [x] | |
(let [val (.val x) | |
k (.getKey x) | |
parsed-val (edn/read-string {:readers d/data-readers} val) | |
tx (:tx parsed-val)] | |
(do | |
(try | |
(do | |
(handle-event* @startval path parsed-val) | |
;; (d/transact! @startval tx) | |
(save-snapshot snappath k @startval) | |
;; (log/debugf "this is the startval %s" (pr-str @startval)) | |
) | |
(catch js/Object e | |
(println e))) | |
) | |
))))) | |
(r/create-class | |
{:display-name "listener" | |
:component-will-unmount | |
(fn will-unmount-listener [this] | |
(.off ref)) | |
:reagent-render | |
(fn | |
[path startk startval latestsnap component & args] | |
(into [component startval latestsnap] args))}))) | |
(defn transact! [path msg] | |
(core/push path (str {:user/email (:email @user nil) | |
:msg msg | |
:time (format/unparse formatter (now))}))) | |
(defmulti handle-event (fn [conn [ev-type & _]] ev-type)) | |
(defmethod handle-event :default | |
[_ msg] | |
(log/debugf "Unhandled event: %s" (pr-str msg)) | |
nil) | |
(defn handle-event* [conn txpath msg] | |
(log/debugf "handling event %s" msg) | |
(let [{:as ret :keys [tx followup]} (handle-event conn (:msg msg))] | |
;; handle-event | |
(log/tracef "Handler returned: %s" (pr-str ret)) | |
(when tx | |
(log/debugf "Transacting: %s" (pr-str tx)) | |
(let [x (d/transact! conn tx) | |
z (-> x :tempids)] | |
(when followup | |
(go (async/<! (async/timeout 1)) | |
(transact! txpath (conj followup z))) | |
) | |
)) | |
(doseq [new-msg (:dispatch ret)] | |
(transact! txpath new-msg)) | |
(doseq [[to new-msg] (:dispatch-later ret)] | |
(go | |
(async/<! (async/timeout to)) | |
(transact! txpath new-msg) | |
) | |
) | |
) | |
) | |
(defn mounter [{:keys [snappath | |
txpath | |
startk | |
connatom | |
schema | |
loading | |
main] | |
:as ctx}] | |
(let [latestsnap (r/atom nil)] | |
[load-conn snappath startk connatom schema | |
(fn [k connatom] | |
(if @k | |
[on-rolling txpath @k connatom snappath | |
(fn [connatom] | |
[main | |
(merge ctx {:conn @connatom | |
;; :email email | |
:dispatch (partial transact! txpath)})])] | |
[loading]))])) | |
(defn demo-mounter [schema c] | |
(safe [mounter | |
{:snappath ["re-kindle""snapshot-wf"] | |
:txpath ["re-kindle""txpath-wf"] | |
:main c | |
:schema schema | |
:loading (fn [] [:h1 "Loading mofo"]) | |
:connatom (r/atom nil) | |
:startk (r/atom nil) | |
:email "cwhitesullivan@gmail.com"}])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Mounter is a higher order react component, written using Reagent, a minimalist react wrapper for Clojurescript
The purpose of the component is to create a "poor-man's Datomic", using Datascript -- an in-memory database and datalog query engine, and Google's firebase for real-time collaboration.
This component makes it cheap and easy to build prototypes of user-interfaces based on graphs, it also stores an immutable event-log of all the transactions which impacted that graph, so it provides the developer with the option of building UIs based on the user's change-log -- such as notification feeds.