Fork me on GitHub
#hyperfiddle
<
2023-12-22
>
JAtkins03:12:40

I may have just missed it somewhere, but how can an electric user avoid the danger of remote code execution vulnerabilities? Especially with the dynamic nature of CLJ, it seems rather easy to get electric on the server to call any function with any args. Even if at compile time the list of acceptable fns is constrained to what the electric compiler identifies as existing fn calls, the api size is far larger than with a normal rest api.

Dustin Getz11:12:11

server is fully determined and baked at compile time as of the new incremental compilation changes. not just the list of functions but also the access patterns

JAtkins17:12:24

so, each unique context change from e/client to e/server is named and identified? cool, that sounds good.

đź‘Ť 1
Dustin Getz17:12:26

yes the electric analyzer slices the system DAG in half, the cut edges are pub/sub (input/output) pairs with addresses used by the wire protocol

joshcho10:12:06

I am trying to get video working via dom/video, and I can't fast-forward. Can't distinguish if this is an Electric issue or something else.

(dom/video (props {:controls true :width "100%"})
           (dom/element :source
             (props {:src  "southwell1.mp4"
                     :type "video/mp4"})))

Dustin Getz14:12:19

if you suspect an electric interaction, you can always drop to vanilla js like (doto (js/document.createElement "video") (.appendChild dom/node) (.setProperty "src" "southwel1.mp4") ...)

Geoffrey Gaillard14:12:37

It's not electric, it's jetty / ring. Fast forward requires the web server to support https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests. IIRC there's a ring middleware for that. S3 / CloudFront supports it ootb, also IIRC

❤️ 1
Dag Norberg18:12:02

I encountered the same thing, check this: https://github.com/formicagreen/electric-media-player

❤️ 1
joshcho23:12:13

what is the best way to query for current time of the video as a missionary flow/electric value?

joshcho00:12:44

if one can point me to any similar resources, that'd also help

Dag Norberg19:12:46

Some thoughts and questions… Apologies if none of this makes sense… Not an expert developer, just a curious person :) Apart from the whole frontend/backend transparency, one thing that makes Electric so nice is it lets you think of your app sort of like a spreadsheet. Ideally this would also be true for React et al, but in reality you end up with a lot of accidental complexity, lifecycle management etc. Less so with Electric. This made me think about “computed values” in a spreadsheet. This is sort of like a pure function operating on the db. My question is if Electric could “solve” cache invalidation for these kinds of values? Let’s say you have an “order” item that contains a bunch of product ids. And you want to show some compound information about the order and products. Normally you have to choose between: • Recomputing on every request • Caching the results, and having to come up with a strategy for invalidating the cache Could Electric potentially do this in an “ideal” way? I.e. you set a watcher on the db and updates “trickle down” to wherever they are needed? I’m not talking about frontend/backend sync here, just cache invalidation in general. Another example is a CMS / static site generator. Most of these have very simplistic models for how cache invalidation / partial regeneration are done. But on a large site, content may be interweaved in all kinds of ways, and predicting what pages are affected when a piece of content is updated becomes more complex. Taking this a step further, could you implement a kind of “event sourcing” system purely in Electric? E.g. “send email on new order”. I have been reading about Rama and from my limited understanding this is somewhat similar. But it seems difficult to learn and a bit overkill for the type of work I’m doing. I like that Electric looks like regular Clojure code.

Dustin Getz19:12:04

Yes, most of this is already true in Electric v2, and with Differential Electric becomes fully true. With Differential Electric, instead of cache invalidation + recompute, you propagate diffs through the system and each "cache" (view) is incrementally maintained

Dustin Getz19:12:59

the database watcher, if the database supports it, is the source of diffs (along with any other user events, atoms or sources of variability)

Dustin Getz19:12:13

Re. Rama, Nathan is the right person to be building that, we have no interest in hyperscale backends, Electric is exclusively a UI technology, BYO data tier. Nonetheless, sure, hypothetically an Electric backend can "send email on new order", in the abstract this is the same as "add dom element for new order", however the devil is in the details. Rama offers a bunch of strong operational guarantees (like you'd get from a database) which Electric does not

Dag Norberg09:12:20

Thanks for the explanation!

Dag Norberg10:02:20

Hi, reviving this... thinking about the example again of a cms / static site generator. Would it be a viable to use electric (+ datomic or something) to generate a bunch of html files and minimally regenerate stuff when the database is updated? I.e. instead of "update dom when x y or z changes" it's "spit html file". Or would there be similar issues with operational guarantees? It seems like incremental maintenance + effects would be incredibly powerful in a bunch of contexts outside of ui. Like being able to model your entire app as a reactive system. Or are there established solutions for this that I'm not aware of? Again Rama seems very cool but I have no need for that kind of scaling. Another thing, do you think differential electric could potentially fix the perf issues I had with the drawing app?

Dustin Getz11:02:30

yes, differential will fix some of the Painter app perf issues (the slowdown with eg. 1000 objects). the local first update issue will become possible to fix as well but will require a bit more work

Dustin Getz11:02:42

yes, i think using electric to render and maintain static html files on disk should work in principle - you may hit edge cases though that need smoothing out

Dag Norberg14:02:48

thanks again for taking the time to answer! really cool following this stuff

denik19:12:49

is there a way to ensure an that a e/defn flow invoked from within a dom handler completes? It currently appears that something refreshing in the UI cancels the flow which in turn cancels necessary DB transactions

Dustin Getz19:12:26

ah, the rule here is: the e/fn is unmounted when the first non-Pending value is seen by the client

Dustin Getz19:12:47

one of your snippets showed basically smashing d/transact as fast as the user types iirc – not sure if i read it properly – this is probably a bad fit for dom/on (which we want to replace anyway due to all these surprising semantics)

Dustin Getz19:12:58

the dom/on! pattern bypasses all the surprising machinery, we like this primitive better

Dustin Getz20:12:30

I may be mistaken, reading the src I see that dom/on uses the strategy for each subsequent event to supersede the previous event, canceling and discarding the prior result, so that should be fine for smashing d/transact

Dustin Getz20:12:21

upon re-reading this, i'm not sure that the behavior @U050CJFRU reports ("something refreshing in the UI cancels the flow") matches the intended behavior of dom/on, I think there still may be a userland mistake that is fixable. As far as we are aware, dom/on does the right thing OOTB for this use case of streaming rapid data entry to the server. @U050CJFRU if you want to dig deeper, i'd request a minimal repro in the form of a single file in a fork of the https://github.com/hyperfiddle/electric-fiddle, with no added dependencies (no datahike), just println on the server. I believe we will find that the println is called in the intended way without "data loss"

denik20:12:20

thanks @U09K620SG you might be right. I tried boiling it down to a minimal repro without extra deps and couldn’t find the issue yet. Planning to rewrite that part of the code which might help resolving the issue. I also wonder if this has to do with the way a datalevin database is watched. a while ago Leo suggesting using this https://github.com/lumberdev/tesserae/blob/master/src/tesserae/ui/electric_util.cljc#L115-L127 impl rather than e/watch. Does that still apply?

Dustin Getz20:12:27

i don’t understand what that is working around

denik20:12:34

Same here. I remember the UI would lock up sometimes without it

Dustin Getz20:12:05

do you have the original thread with leo?

Dustin Getz20:12:55

ok, I don't see how this could be related

Dustin Getz20:12:14

oh, actually maybe it can be related

Dustin Getz20:12:55

Ok i dont know if this is going to impact your issue, but I detect a minor correctness issue in the transact snippet from the other thread

Dustin Getz20:12:39

presumably that call can block for some period of time, and you are hitting it rapidly, this could cause a backup of blocking calls, which will block the electric server process

Dustin Getz20:12:10

I wouldn't expect the missing e/offload to impact your issue (just slow down your app because each transact will block any queries from proceeding in parallel), but the datalevin async-watch locking workaround might have some deep interaction with this that i dont undertand

Dustin Getz20:12:32

also the report of "data loss" is a hint, i don't have an explanation for that yet

Dustin Getz20:12:10

a bunch of backed up blocking calls will be racing against new messages from network that queues up more blocking calls and we potentially desire to cancel stale calls, that is a complex interaction

Dustin Getz20:12:56

the e/offload, by moving the d/transact! to a thread, makes it cancellable in the first place – without the m/via, i don't think the effect can be cancelled at all it just blocks until it suceeds

Dustin Getz20:12:22

maybe somehow the wrong one is winning, i'd have to think a lot harder, but the point is – i see a potential interaction

denik23:12:05

The part that is cancelled is not the transact but a missionary task eval/eval-cell-task that already runs using m/via internally https://github.com/lumberdev/tesserae/blob/master/src/tesserae/ui/sheet.cljc#L78-L96