Inside of a donut.system <https://donut.party/docs/system/> component's :start function I need to do some asynchronous work (i.e. await promise(s)).
In the JS prototype of this app I have a top-level async function that (through calling various application start-up functions) eventually does an await LedgerTransportHid.create() then uses the result to perform other start-up steps.
In the CLJS code I am struggling to get this asynchronous setup working.
Specifically, I am struggling to get the promise(s) to be resolved/rejected, they are always pending.
Code in ๐งต thread.
(ns my.main
(:require
[clojure.pprint :refer [pprint]]
[donut.system :as ds]
[my.systems :as systems]))
(def *running-system (atom nil))
(defn start-system ([system & args] (reset! *running-system (apply ds/start system args))))
(defn stop-system ([& args] (reset! *running-system (apply ds/stop @*running-system args))))
(defn -main
([& _args]
(pprint (systems/system))
(start-system (systems/system))
(stop-system)))(ns my.systems
(:require
[clojure.pprint :refer [pprint]]
[promesa.core :as p]
["@ledgerhq/hw-transport-node-hid" :default LedgerTransportHid-js]
["@ledgerhq/hw-app-eth" :default LedgerEthApp-js]
[donut.system :as ds]))
(defonce ^:private LedgerTransportHid (js->clj LedgerTransportHid-js))
(defonce ^:private LedgerEthApp (js->clj LedgerEthApp-js))
(defn- hid-transport-start
([{::ds/keys [config]}]
(pprint {['hid-transport ::ds/start 'config] config})
(p/let [instance (.create LedgerTransportHid)]
(pprint {['hid-transport ::ds/start 'config] config
['hid-transport ::ds/start 'instance] instance})
instance)))
(defn- hid-transport-stop
([{::ds/keys [config instance]}]
(pprint {['hid-transport ::ds/stop 'config] config
['hid-transport ::ds/stop 'instance] instance})
instance))
(defn- hid-transport
([]
#::ds{:config {}
:start hid-transport-start
:stop hid-transport-stop}))
(defn- eth-app-start
([{::ds/keys [config]}]
(pprint {['eth-app ::ds/start 'config] config})
(p/let [instance (LedgerEthApp. (:transport config))]
(pprint {['eth-app ::ds/start 'config] config
['eth-app ::ds/start 'instance] instance})
instance)))
(defn- eth-app-stop
([{::ds/keys [config instance]}]
(pprint {['eth-app ::ds/stop 'config] config
['eth-app ::ds/stop 'instance] instance})
instance))
(defn- eth-app
([]
#::ds{:config {:transport (ds/local-ref [:transport])}
:start eth-app-start
:stop eth-app-stop}))
(defn system
([]
#::ds{:defs
{:ledger {:transport (hid-transport)
:eth-app (eth-app)}}}))Here is the output of running the above code (the -main function):
{:donut.system/defs
{:ledger
{:transport
{:donut.system/config {},
:donut.system/start #object[hid_transport_start],
:donut.system/stop #object[hid_transport_stop]},
:eth-app
{:donut.system/config {:transport [:donut.system/local-ref [:transport]]},
:donut.system/start #object[eth_app_start],
:donut.system/stop #object[eth_app_stop]}}}}
{[hid-transport :donut.system/start config] {}}
{[eth-app :donut.system/start config] {:transport #<Promise[pending:65]>}}
{[eth-app :donut.system/stop config] {:transport #<Promise[pending:65]>},
[eth-app :donut.system/stop instance] #<Promise[pending:78]>}
{[hid-transport :donut.system/stop config] {},
[hid-transport :donut.system/stop instance] #<Promise[pending:65]>}And the deps.edn's :deps (which are brought in via shadow-cljs's :deps true):
org.clojure/clojure {:mvn/version "1.12.1"}
org.clojure/clojurescript {:mvn/version "1.12.42"}
org.clojure/core.async {:mvn/version "1.8.741"}
funcool/promesa {:mvn/version "11.0.678"}
party.donut/system {:mvn/version "1.0.255"}I'd try asking in #donut.
I did not realize such a channel existed, thank you!
Anyone can create channels here, and authors of libraries often do. :)
For posterity, here is this question in #donut: https://clojurians.slack.com/archives/C030C4Z2W0Y/p1751720081503229