fulcro

vasilisk 2025-03-18T17:22:34.555999Z

is`df/load!` supposed to work same way with pathom3? for some reason it does not load the data but when i restart the server despite the data being returned when i run EQL query from fulcro inspect

(defonce APP (-> (app/fulcro-app {:remotes {:remote           (http/fulcro-http-remote {})
                                            :client-did-mount (fn [app]
                                                                (df/load! app :all-products toto.ui.root/Product))}})
                 with-react18))

tony.kay 2025-03-19T13:54:27.512629Z

Tying I/O to UI is one of the things Fulcro is trying to help you divide out. As soon as you start tying application lifecycle to UI lifecycle all sorts of badness occurs (over time). This is why I made UI state machines, and then statecharts. Having a better abstraction of larger lifecycles within your app that are NOT tied to UI behavior is very helpful. These days I’m using statecharts for kind of everything that isn’t trivial logic in my new code.

vasilisk 2025-03-18T17:23:00.033689Z

tony.kay 2025-03-18T19:28:12.195919Z

nothing I can think of would be a problem on the Fulcro end, and Fulcro and Pathom both follow the EQL standard (we defined it)…so no, I don’t expect this is a problem with either library.

danieroux 2025-03-18T19:55:34.392369Z

Can confirm that Fulcro and Pathom3 plays well together, including df/load!

vasilisk 2025-03-18T21:06:08.682819Z

what am i doing wrong? After watching Fulcro – Part 6 : Full Stack Part One, my expectation is that if i use load! like so:

(defonce APP (-> (app/fulcro-app 
                  {:remotes 
                   {:remote (http/fulcro-http-remote {})
                    :client-did-mount (fn [app]
                                      (df/load! app :all-products toto.ui.root/Product
                                                {:target [:component/id :toto.ui.root/ProductList :product-list/products]}))}})
                 with-react18))
I should see a list of 2 products in the ui and in local db when the page is loaded. Maybe my setup is wrong? see h.clj

vasilisk 2025-03-18T21:07:48.831919Z

and it's strange when the eql queries work in fulcro inspect as expected. Also both, manually pass some products to initial state or using merge, work fine

vasilisk 2025-03-18T23:26:35.573849Z

I put the df/load! in the init function instead(after mount), as per documentation and it worked. No i wonder why in part 6 video, it's mentioned as not a good idea to place in init since it's called every time the client remounts 🤔

(defn ^:export init
  []
  (reset! SPA APP)
  (app/mount! APP Root "app")
  (df/load! APP :all-products toto.ui.root/Product
            {:target [:component/id :toto.ui.root/ProductList :product-list/products]})
  (ido
    (it/add-fulcro-inspect! APP))
  (js/console.log "Loaded"))

michaelwhitford 2025-03-18T19:37:09.949139Z

Is there a way to poll stdin from a statechart? I can do this from -main:

(while true
  (when-let [line (.readLine (BufferedReader. clojure.core/*in*))]
    (simple/send! env {:event :stdin/recieve :target session-id :data line})))
I cannot seem to figure out how to do this operation inside the statechart so starting the statechart will poll *in*. I can only seem to make it work from outside the statechart.

michaelwhitford 2025-03-20T19:05:56.405349Z

I do want to add a timer for the MCP ping, and need to delay events as well. Would an Invocation processor that reads from stdin on a timer work instead of blocking the main thread? It would block but in a go-loop so could be parked?

tony.kay 2025-03-20T19:11:00.136879Z

invocations are about statecharts starting other things/services/charts…so no, that’s not what I’d use

tony.kay 2025-03-20T19:12:09.106509Z

What you want is a thread that processes an event queue (possibly the core async one I provide). The main loop would be the I/O, and it would turn the data into events. The statechart, in turn, could trigger outputs if you needed.

tony.kay 2025-03-20T19:12:37.387419Z

the point is to NOT think of the statechart as “running” in the sense of blocking/consuming CPU. The statechart runs on events…period

michaelwhitford 2025-03-20T19:13:05.846529Z

That's how I have it now with the (while true (read-line)) That main thread blocking loop just read-lines and spits it into an event.

tony.kay 2025-03-20T19:14:57.385579Z

ok, sounds right…so what is the question?

tony.kay 2025-03-20T19:15:25.421499Z

I mean, it sounds like starting a new thread that does the event processing in a loop is the way to go

michaelwhitford 2025-03-20T19:16:49.590129Z

I wanted to see if it's possible to move the poll of stdin to a series of states, instead of just blocking the main thread with a stdin->event handler.

michaelwhitford 2025-03-20T19:17:48.465949Z

I think if I background the stdin loop it won't work in babashka, I would still need to block the main loop for babashka.

michaelwhitford 2025-03-20T19:20:59.146249Z

I'm sure I'm over thinking it, it's working with the simple block on the main thread. Thank you.

michaelwhitford 2025-03-18T19:43:39.127779Z

I am actually doing it just a bit different, I create a let outside the while loop to create the bufferedreader for *in* I just shortened it for the example above.

tony.kay 2025-03-18T19:56:48.351939Z

isn’t that just (read-line) in clj? 😄

tony.kay 2025-03-18T19:57:09.355739Z

BUT, blocking the statechart logic this way is very bad idea (i.e. putting it IN a statechart)

michaelwhitford 2025-03-18T19:57:58.827259Z

Babashka does not wait on background threads so blocking -main this way is actually the only way I have been able to make it work in clojure and babashka both.

tony.kay 2025-03-18T19:58:08.037669Z

read the manual….statecharts are pure-state -> event -> new pure state. If you block in the event handling, you’re blocking the entire chart

michaelwhitford 2025-03-18T19:58:50.221269Z

I block -main at the end, after the statechart is running on a background thread.

tony.kay 2025-03-18T19:59:11.019769Z

https://github.com/fulcrologic/statecharts/blob/main/src/examples/traffic_light.cljc See the bottom of that file. You want to write a loop that reads input, turns that into an event, and does a “swap!” on an atom holding the statechart

tony.kay 2025-03-18T19:59:28.686999Z

then you don’t need threads at all

tony.kay 2025-03-18T19:59:47.076079Z

well, unless you use delayed events…then you would

tony.kay 2025-03-18T20:00:26.172209Z

is babashka graal, or sci?

tony.kay 2025-03-18T20:00:28.533039Z

I don’t remember

michaelwhitford 2025-03-18T20:01:24.373189Z

I think it's both? I see a lot of sci. namespaces in exceptions, and it's for sure compiled to a single graal binary.

tony.kay 2025-03-18T20:01:51.751949Z

right, so (.wait obj) won’t work?

tony.kay 2025-03-18T20:02:04.434199Z

(to block a thread)

tony.kay 2025-03-18T20:02:59.401159Z

but if you’re really just wanting to treat the lines of stdin as event data, and you don’t have deferred events, then don’t make a thread, process it more like the example I showed you

michaelwhitford 2025-03-18T20:06:05.588159Z

Thank you for the pointers I will keep playing with this. It's for an MCP server that does json-rpc on stdin/stdout.