Fork me on GitHub
#hyperfiddle
<
2023-05-10
>
Hendrik06:05:15

I have a question about the startup of an electric program during development. Where is the compiled electric program injected into the ring middleware stack? What I found out from the sources:

start fn user(.clj)/main .
main loads shadow and later starts the server.
shadow compiles cljs from entry user(.cljs)/start.
start calls electric-boot.
because electric functions are macros, they are compiled and because clj and shadow use the same Repl the compiled electric program is available in clj.
and from here: how does it get into the ring stack?.
I like electric, but at the moment it feels a little magic. Of course it is not and I would like to understand, what is happening there :)

1
Dustin Getz10:05:14

search for “jetty” we have an example jetty server which hosts the websocket, each websocket gets an instance of the server DAG

Hendrik11:05:53

Thanks for your answer. ok there is electric-ws-message-handler and electric-ws-message-handler . I looked into the hyperfiddle source code, but I am not able to figure out how the DAG is arriving there. Is there a def dag (atom) or def ^dynamic dag or how is this achieved? Maybe I am just blind and missing some simple statement?

Dustin Getz13:05:28

Today IIRC the clojurescript build is responsible for both server and client • the client is compiled all the way down: Electric -> DAG IR -> CLJS -> JS • the server is compiled by the clojurescript build Electric -> DAG IR, and the server DAG value (IR, think bytecode) is embedded into the javascript artifact. The browser client will bootstrap the server by sending up the DAG value to the server in the first frame of the websocket, and then the server interprets the DAG IR at runtime. (Yes, that means the Electric frontend is compiled all the way to JS but the Electric backend is only partially compiled and then interpreted) There may be minor errors in this explanation but this is the gist of it. We have a branch that bakes the server DAG into the java artifact rather than bootstrapping from the client, i forget our exact plans for this but there will be changes this summer

🙂 1
Hendrik15:05:58

Cool 🙂 Thanks for this explanation. This answers why I could not find anything. I have one more question. If the DAG is provided by the frontend to the server, would n’t this be a security issue or at least an entry point to a DOS attack? I mean, how does the server check, that the DAG is not manipulated?

Dustin Getz15:05:30

As I said, this summer this is all getting rewritten, the current strategy is convenient for hot code reloading etc. In the meantime we can help you assert the hash in prod if you think this is a credible attack vector and you are using Electric for something serious.

Hendrik16:05:50

Currently I am using it on a small hobby project to explore and learn about electric. I only use libraries in production, which I understand and where I have a sense for the implications of using x or y. I am not at the point yet, where I understand the electric system and its implications well enough to use it for production. However, I see the potential of electric and your answers on this channel already helped me a lot to get a better understanding of electric. So thanks again for answering my questions 🙂

braai engineer15:05:37

hyperfiddle.electric-ui4/date seems to throw when pressing the “Clear” button in browser’s native date picker (using Brave) because it tries to parse NaN:

core.cljs:200 "date input:" #inst "0NaN-NaN-NaNTNaN:NaN:NaN.NaN-00:00"
12:24:34.349 user.cljs:21 Reactor failure: cljs$core$ExceptionInfo {message: 'Remote error - 1011 java.lang.NumberFormatException: For input string: "NaN"', 
e.g.:
(ui/date date-query (e/fn [v]
                                  (prn "date input:" v)
                                  (if (string/blank? v)
                                    (reset! !date nil)
                                    (reset! !date v)))
              (dom/props {:placeholder "Date"}))
Fell back to dom/input.

1
Dustin Getz15:05:04

I ticketed it, you can probably easily PR this if urgent

braai engineer15:05:17

thx, not urgent

Erich Ocean19:05:31

When I run, e.g. XTDB_ENABLE_BYTEUTILS_SHA1=true clj -A:dev -X user/main, there's this printout shadow-cljs - nREPL server started on port 9001. I assume that's the normal JavaScript browser REPL, correct? If so, how are people getting a REPL up for the JVM (i.e. so they can run one of the comment forms)?

2
Dustin Getz19:05:14

it is a JVM nrepl

Dustin Getz19:05:36

you can also jack in from your editor in the usual way to get a REPL and run shadow from inside that, like here: https://github.com/hyperfiddle/electric-starter-app/blob/main/src/user.clj

Dustin Getz19:05:08

use :dev alias

Erich Ocean19:05:15

Okay, thanks, got it working. I needed to execute (def db (xt/db !xtdb)) in the user namespace before the comment forms in app.todo-list would work.

Dustin Getz19:05:34

Feel free to PR if you want to improve something

Erich Ocean19:05:25

One thing that's weird is I initially got the todos I had added in the browser client (there were two), but after adding a third, re-running the same query in the REPL returned the previous results (browser shows three).

Erich Ocean19:05:45

Even weirder, running queries in user return no items.

Dustin Getz19:05:44

did you refresh the db val?

Erich Ocean19:05:08

LOL, nope. Idiot moment.

🙂 1