Fork me on GitHub
#hyperfiddle
<
2023-05-03
>
Vincent00:05:37

Hey, I figured out my websocket issue. Turns out you can proxypass everything to whatever port the server is running and it should just work 😄 So that's good! So now I just need to figure out how to retroactively add session support to the electric-starter-app

Dustin Getz00:05:34

what specifically do you mean by “session state”, is there a framework you are referring to?

Vincent00:05:32

Jetty / Ring I guess

Vincent00:05:48

/auth endpoint from the examples

Vincent00:05:57

not exactly sure which examplse that is in...

Dustin Getz01:05:38

ah that used a cookie

Vincent00:05:31

then I think, a way to handle notifications & emailing stuff [via SparkPost] and a "nice to have" would be how much time users spend on pages and a "heatmap" for where the mouse is / what links they click. I wonder if it makes sense to work on an open-source version of that for the community

Dustin Getz00:05:03

i think there are js saas analytics tools that do the heat map stuff

Dustin Getz01:05:44

when i think of notifications i think mostly of mobile apps and slack notifications, are you making a mobile app?

Vincent01:05:54

community musician place, so sorta

Vincent01:05:42

yeah maybe can do heat maps with after party tool, just figured with a web socket already there, probably a lot that can be done

markaddleman14:05:29

Should metadata survive a transport between client and server?

2
Dustin Getz14:05:06

I believe so, have you encountered an issue? We transport with transit

markaddleman14:05:39

I don’t think it does. I’ll have a repro case in a minute (or I will have my bug 🙂 )

markaddleman14:05:28

(e/defn Main []
  (e/client
    (let [m (e/server (with-meta {:key "value"}
                                 {:metadata true}))]
      (println m (meta m)))))

markaddleman14:05:00

the console shows {:key value} nil

Dustin Getz14:05:54

i logged a ticket to look into it

Dustin Getz15:05:28

what are you using this for btw?

markaddleman15:05:05

I have a server-side function that makes a rest call. If the rest call fails, I catch the exception on the server side and create an error map and return that error map to the client as a return value (not an exception). The error map has metadata on it that allows the client to know if the value it receives is an error or not.

👀 2
markaddleman15:05:51

As I write this, I realize I should try throwing an ex-info object from the server to the client.

Dustin Getz15:05:03

Yeah, we will look into fixing it, a workaround would be to unpack the metadata in some way (into an ex-info or just a tuple)

👍 2
markaddleman15:05:16

btw, after a quick experiment, it doesn’t look like ex-info objects can be transmitted from server to client. I get error

java is not defined

 in <unknown interop> {: :, :hyperfiddle.electric.debug/type :eval, :hyperfiddle.electric.debug/args (nil), :hyperfiddle.electric.debug/origin #uuid "2c01b195-c85a-4166-9d01-b26d44503c23"}

Dustin Getz15:05:53

ok, please paste the snippet you used

markaddleman15:05:59

My simple repro case fails differently:

(e/defn Main []
  (e/client
    (try
      (e/server
        (throw (ex-info "Does this survive?" {:some "data"})))
      (catch js/Error ex
        (println (ex-message ex))
        (println (ex-data ex))))))
The first println shows the “Does this survive?” as expected. The second println is a bunch of electric internal data:
{:hyperfiddle.electric.debug/trace [{: :, :hyperfiddle.electric.debug/meta {:file app/plotly_interop.cljc}, :hyperfiddle.electric.debug/type :apply, :hyperfiddle.electric.debug/name hyperfiddle.electric.impl.runtime/fail, :hyperfiddle.electric.debug/args [<exception>], :hyperfiddle.electric.debug/origin #uuid "15aa5f8b-d49b-4b6a-b69d-9c5a3d9139e9", :hyperfiddle.electric.debug/serializable true} {: :, :hyperfiddle.electric.debug/meta {:file app/plotly_interop.cljc, :line 146, :column 7, :end-line 147, :end-column 63, :hyperfiddle.electric.debug/type :transfer, :hyperfiddle.electric.debug/name :hyperfiddle.electric/server}, :hyperfiddle.electric.debug/origin #uuid "15aa5f8b-d49b-4b6a-b69d-9c5a3d9139e9", :hyperfiddle.electric.debug/args [], :hyperfiddle.electric.debug/serializable true}], :hyperfiddle.electric/type :hyperfiddle.electric.debug/trace}

👀 2
markaddleman15:05:32

I’ll try to repro the java is not defined case later today

Dustin Getz15:05:08

this is probably just a bug, we may not have enough test cases for catching exceptions remotely

markaddleman15:05:40

Here’s the java is not defined repro case:

(e/defn Error [ex]
  (dom/pre (prn-str ex)))

(e/defn Main []
  (e/client
    (try
      (new (e/fn [] (throw (ex-info "Some error" {:key "value"}))))
      (catch js/Error ex (new Error (ex-data ex)))))

markaddleman15:05:11

Yeah, I was just looking at that

markaddleman15:05:28

This code does not error:

e/defn Main []
  (e/client
    (try
      (new (e/fn [] (throw (ex-info "Some error" {:key "value"}))))
      (catch js/Error ex (new (e/fn [] (ex-data ex))))))

Dustin Getz15:05:38

Does Error shadow anything from js? js/Error

markaddleman15:05:02

Yes, I think so

Dustin Getz15:05:31

Yeah I dunno if this is a bug or what, I will capture the ticket. I don't see signs of the original issue here

markaddleman15:05:05

Original issue being metadata? That’s right. These are two separate issues

Dustin Getz15:05:50

"it doesn’t look like ex-info objects can be transmitted from server to client. I get error"

markaddleman18:05:49

I’m trying more javascript interop. This time with a library that depends on jquery. Specifically, I’m trying to translate this jsfiddle to electric http://jsfiddle.net/astrapi69/md1xztks/

2
markaddleman18:05:55

I’m not sure if my problem is related to electric or not. There’s a good changce that I’m just doing the interop incorrectly

markaddleman18:05:40

This is my attempt so far. It’s failing with Uncaught TypeError: $(...).gridster is not a function

xificurC19:05:37

try just

(-> (js/$ ".gridster ul")
  (.gridster (clj->js {:widget_margins [10 10]
                       :widget_base_dimensions [140 140]})))

markaddleman19:05:02

Now getting this

inst__30220__auto__.gridster is not a function

 in ( .gridster (js/$ ".gridster ul") #js {:widget_base_dimensions #, :widget_margins #} )
 in case default branch
 in reactive (defn Main [] ...) in app/plotly_interop.cljc line 135
 in (try ...) 

xificurC19:05:42

if you comment the gridster interop out completely and open the web console can you call it from there with the js sample?

markaddleman19:05:35

again with Uncaught TypeError: $(...).gridster is not a function

markaddleman19:05:48

It’s as if something isn’t initializing correctly.

markaddleman19:05:29

I don’t understand jquery well enough to know how it’s supposed to work

xificurC19:05:07

did you do what the readme said > Gridster is currently written as a jQuery plugin, so you need to include it in the head of the document. Download the latest release at http://jquery.com/.

markaddleman19:05:49

ah, that’s probably the problem. Thanks for the pointer!

xificurC19:05:33

maybe it should go in package.json

xificurC19:05:50

not quite sure either, sorry

markaddleman19:05:08

You gave me something to investigate - which is more than I had before!

markaddleman22:05:53

fyi, that was the issue. Thanks again for the pointer!

😉 2
grav19:05:38

In the https://github.com/hyperfiddle/electric-starter-app, how come ws messages are passed when I edit the text in the input field (for each key press)?

2
grav19:05:46

There's nothing that indicates to me that the F function is called, except when Enter is pressed:

(dom/on "keydown" (e/fn [e]
                        (when (= "Enter" (.-key e))
                          (when-some [v (contrib.str/empty->nil (-> e .-target .-value))]
                            (new F v)
                            (set! (.-value dom/node) "")))))
(from https://github.com/hyperfiddle/electric-starter-app/blob/main/src/app/todo_list.cljc#L30)

xificurC19:05:42

dom/on calls new on the supplied e/fn for each keydown event. new creates a new node in the graph. The graph is kept in sync between the client and the server

grav19:05:26

Ah, okay. I think I'm still not fully understanding why the server needs to know about this part of the graph on runtime

xificurC20:05:12

any node can request data from the remote peer. At that point you need to know who is requesting it. Having the same graph means you can reference it directly. As a theoretical optimization, if you can prove statically there will be no remote requests, one might be able to skip this step.

👍 4
Dustin Getz20:05:54

I endorse what Peter said, and will add that we haven't invested much in optimizations yet because we haven't seen any real world performance impact in our testing outside of 1-2 very specific cases that we're working to address. It's really only request/response waterfalls that damage performance as far as we are aware

Dustin Getz20:05:35

Obviously as the compiler matures there is a path to making this hyper-optimized

👍 2
Vincent22:05:50

Are there alternate strategies to managing logins / logged-in state?

👀 2
Dustin Getz17:05:58

We don't provide out of the box integrations for anything at this time, but happy to track requests

Vincent04:05:47

Cool. Turns out probably totally unnecessary ^^ I think /auth is plenty, and I see it actually exists in all the examples I need x) I am just slow to the grip sometimes! x)