Fork me on GitHub
#clojurescript
<
2021-01-21
>
Gustavo Bertolino00:01:48

Hi guys, I'm building a react demo appl with cljs (to practice cljs) and I'm thinking about changing this very appl on the fly via a remote repl. Is that possible? For example, suppose I want to change a component to correct it and re-rendering it with my appl running in production. Is it possible to make these things via repl?

Gustavo Bertolino00:01:49

obs.: the repl I'd connect with remotely is the one fired by the start of my appl

dpsutton01:01:26

A repl can only change the running instance. For a long running clj process this would be fine. But a cljs process is just someone’s browser. So if you repld to a particular users browser you could change it but the next load of a page would just get the originally compiled code without any changes. The same as restarting a clj process.

👀 3
👍 3
Gustavo Bertolino03:01:15

Yes, I see. I made some tests here with my appl and re-rendering its component via repl and it works but only for one particular browser's tab or window that opens my appl. And after reloading the page, the browser takes the initial compiled code. Opening other tabs/windows and calling my appl also cause the same effect. I didn't notice that in the case of setting the browser as the target means that the repl (fired during the build) will be connected to that instance/process of the browser through I eventually open my appl.

Gustavo Bertolino13:01:26

But if this appl is a Electron appl which runs in a single JS process (a node process), or even a controlled number of JS processes. So in this case, in theory, I could make changes on the fly via a remote repl to inject this change on the node process running my appl and all the clients would take this change, wouldn't they? @dpsutton

Gustavo Bertolino13:01:04

obs.: in the case of a controlled number of node processes, each one running an appl's instance, I'd enter in the repl of each instance to make the change

zendevil.eth04:01:23

I am uploading a video to the server like so:

zendevil.eth04:01:11

(reg-event-fx
 :upload-shot-video
 (fn [coeffects _]
   (prn "uploading video")
   (let [video {:uri (-> coeffects :db :shot-video-uri)}
         body (js/FormData.)]
     (prn "uri is " (-> coeffects :db :shot-video-uri))
     (.append body "video" video)
     {:http-xhrio {:method :post
                   :uri (str "" "/api/upload-shot-video")
                   :body body
                   :on-success [:upload-success]
                   :on-failure [:upload-error]
                   :response-format (edn/edn-response-format)}})))
where (-> coeffects :db :shot-video-uri) is the temporary uri of the image in the ios device

zendevil.eth04:01:49

the handler that I have is the following:

zendevil.eth04:01:51

For saving the input stream into a file video.mov

(defn upload-shot-video [req]
  (prn "uploading video")
  (prn "video is! " (-> req :params))
  (prn "video is " (-> req :body))
  ( (-> req :body) ( "./resources/public/video.mov"))


  (r/response {:res "okay!"}))

zendevil.eth04:01:19

But the size of the file is turning out to be 0 bytes, whereas I expect a size greater than 0 bytes

zendevil.eth04:01:37

How to correctly send the video to the server?

dpsutton04:01:11

did you look into the extensive info noisesmith provided about the middleware? How it takes the body and creates a temporary file for you?

zendevil.eth04:01:41

@dpsutton I removed the middleware and created a copy manually/

zendevil.eth04:01:08

the video is in (-> req :body). At least there’s an inputstream in there

zendevil.eth04:01:33

copying that input stream to the file system as a file is giving a file of 0 bytes

dpsutton04:01:09

add a prn statement on your request. just see what's in there. i suspect you've got more middleware going on. there might be more information

zendevil.eth04:01:16

@dpsutton Here’s the request:

zendevil.eth04:01:16

{:reitit.core/match #reitit.core.Match{:template "/api/upload-shot-video", :data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :result #reitit.ring.Methods{:get #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :get, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :head #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :head, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :post #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :post, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :put #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :put, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :delete #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :delete, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :connect #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :connect, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :options #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :options, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :trace #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :trace, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}, :patch #reitit.ring.Endpoint{:data {:middleware [#function[humboiserver.middleware/wrap-formats]], :handler #function[humboiserver.routes.home/upload-shot-video]}, :handler #function[humboiserver.middleware/wrap-formats/fn--9418], :path "/api/upload-shot-video", :method :patch, :middleware [#reitit.middleware.Middleware{:name nil, :wrap #function[humboiserver.middleware/wrap-formats], :spec nil}]}}, :path-params {}, :path "/api/upload-shot-video"}, :reitit.core/router #object[reitit.core$lookup_router$reify__11769 0x667531a6 "reitit.core$lookup_router$reify__11769@667531a6"], :aleph/request-arrived 166349045051244, :aleph/keep-alive? true, :cookies {}, :remote-addr "0:0:0:0:0:0:0:1", :params {:video ""}, :flash nil, :headers {"host" "", "user-agent" "Humboi/1 CFNetwork/1206 Darwin/20.1.0", "content-type" "multipart/form-data; boundary=BrxekIJ39.PWpQVKqWBWuBAz5KUTH7jhXk67qEssuW4LZbO4Df535XFNLmYDbDGWT73QsP", "content-length" "200", "accept" "application/edn", "accept-language" "en-us", "x-forwarded-for" "110.225.238.196", "accept-encoding" "gzip, deflate"}, :server-port 3000, :muuntaja/request #FormatAndCharset{:format nil, :charset "utf-8", :raw-format "multipart/form-data"}, :form-params {}, :session/key nil, :query-params {}, :uri "/api/upload-shot-video", :server-name "localhost", :query-string nil, :path-params {}, :muuntaja/response #FormatAndCharset{:format "application/edn", :charset "utf-8", :raw-format "application/edn"}, :body #object[java.io.ByteArrayInputStream 0x222b0412 "java.io.ByteArrayInputStream@222b0412"], :multipart-params {"video" ""}, :scheme :http, :request-method :post, :session {}}

zendevil.eth04:01:32

The only middleware is wrap-formats

dpsutton04:01:09

can you open up the browser network pane and make sure you're actually sending bytes across the wire?

zendevil.eth04:01:49

I don’t know how to do that. How does one open a browser network pane?

seancorfield04:01:48

@ps What browser are you using?

seancorfield04:01:41

Ah... been many years since I used that... I'm sure it has developer tools but no memory of how to get at them...

zendevil.eth04:01:49

command option I

seancorfield04:01:27

I have been using Microsoft Edge on macOS for ages -- and cmd-opt-i is what Edge uses to open dev tools 🙂

zendevil.eth04:01:53

@dpsutton You mean open the developer console here?: http://localhost:8081/debugger-ui/

seancorfield04:01:05

Chrome has "dev tools" (as does Microsoft Edge for macOS).

dpsutton04:01:08

Develop > Show Web Inspector. then click on the network tab

zendevil.eth04:01:38

wouldn’t http://localhost:8081/debugger-ui/ open the simulator debugging and not the device? I’m recording the video on the device

zendevil.eth04:01:05

which is supposed to be sent to the server after video stops recording

zendevil.eth04:01:22

I have a feeling that http://localhost:8081/debugger-ui/ doesn’t open debugging for the device

zendevil.eth04:01:39

no actually the debugger is working with the device

zendevil.eth04:01:13

but @dpsutton what should I be looking for in the network tab?

dpsutton04:01:36

the request that has a big video payload. look for it having some form data, try to find the size of the request, etc

dpsutton04:01:40

identify if the video is getting to your backend and the problem is finding it in the request or if the frontend is sending it and you need to fix that first. just general debugging steps. cut the problem in half and then figure out a way to cut that remaining problem in half, etc

zendevil.eth05:01:19

I don’t see any new requests in the console, whereas the server is receiving the request

dpsutton05:01:43

if you're on the network pane and its correctly hooked up and you hit refresh you should see requests to load your js and html. i don't know what you're looking at so can't help you further

zendevil.eth05:01:37

I do see the other requests

zendevil.eth05:01:47

but apparently not the one with the video

zendevil.eth05:01:46

and the number of requests isn’t increased either

zendevil.eth05:01:26

I read this on cljs-ajax which the http-xhrio library wraps

zendevil.eth05:01:35

cljs-ajax doesn’t have any other support for file uploads (although pull requests are welcome).

zendevil.eth05:01:48

but in this issue the user successfully uploads the file: https://github.com/JulianBirch/cljs-ajax/issues/122

zendevil.eth05:01:10

This is confusing

fmnoise14:01:14

hi everyone, probably stupid question asked million times but

(= (hash 1) (hash 1.7))
;; => true
is that expected?

fmnoise14:01:52

Clojure has different behavior

Alex Miller (Clojure team)14:01:16

hashes are not guaranteed consistent across platforms

dnolen14:01:55

you can fudge that a little bit with ClojureScript

Alex Miller (Clojure team)14:01:56

and having hashes collide is certainly normal

dnolen14:01:11

for various reasons we do try to generate identical hashes where practical

dnolen14:01:55

numbers are problematic of course because JavaScript only has double

dnolen15:01:39

so aligning things here is not really worth the other complications

fmnoise19:01:58

thanks for explanation :thumbsup::skin-tone-3:

andy.fingerhut15:01:40

A quick cljs REPL experiment shows that cljs vectors appear to be more like Clojure 1.5.1 and earlier, in that they collide often for a set of vectors like:

(def grid-keys (for [x (range 100), y (range 100)]
                        [x y]))

andy.fingerhut15:01:31

That was one example of the kind of hash collisions that led Clojure to change its hash function in Clojure 1.6.0

andy.fingerhut15:01:55

I don't know whether the performance tradeoffs for fancier hashing is the same in cljs -- just thought I'd mention the results of that experiment, since the code demonstrating the problem with older Clojure versions was easy to copy and paste.

Gustavo Bertolino15:01:52

Hi guys, could someone validate this scenario for me? I was thinking if it's correct or feasible The context is to see if it make sense my thought of accessing the JS process on which is running my cljs appl so that I can make changes in it on the fly

dnolen16:01:47

@andy.fingerhut we use the same hashing functions as Clojure at the bottom

dnolen16:01:14

so we have the post 1.6 stuff, whether we have the vector specific tweaks is another investigation

andy.fingerhut16:01:37

Is a CLJS ticket that at first simply collects some observations on latest CLJS version hash behavior as compared to latest Clojure version perhaps useful?

Brian Kelly18:01:34

Morning everyone - a member invited me and thought it would valuable to do a quick Post. I am hiring a few full time software engineers specifically with closure experience. Also looking for a UI Developer with Clojurescript experience. Please DM me if you are interested in hearing more. Thank you

p-himik18:01:29

There are special channels for that - #jobs and #remote-jobs

p-himik18:01:48

Make sure to read the channels' descriptions.

Brian Kelly18:01:56

Absolutely and this will be my only post in here. 2 members asked me to do it to help others in the community that may be looking for work !

👍 3
seancorfield18:01:35

@U01K8867LH2 This is the second time you've been told not to post jobs in general channels -- and the second time I've deleted your post. If you want to post a job, do it in the appropriate channel and provide details about location/remote and any other criteria. Just saying "DM me for more details" just wastes people's time. /admin

☝️ 4