Fork me on GitHub
#clojure-sweden
<
2021-12-31
>
jherrlin10:12:38

Gott Nytt År! 🔥 😃

jherrlin10:12:40

Sitter och rekreationsprogrammerar på en ClojureScript app (Re-frame, Reitit, Sente) och stött på ett problem. I en Reitit route så vill jag hämta data genom websocketen. Detta funkar fint om jag navigerar till routen från en annan route då Sente har hunnit sätta upp websocket connectionen. Men om jag kommer cold boot till routen som ska hämta data från websocketen så går det inte då Sente inte hunnit sätta upp en connection innan Reitit controllen körs. Någon som har tips på hur jag kan lösa detta på ett bra sätt? För JVM Clojure så brukar jag använda Component för dessa saker. Component är cljc så det kanske är ett alternativ att köra även i webbappen (browserappen)?

David Vujic11:12:40

Jag kanske inte förstår problemet, men chansar 😄 Är det ClojureScript-appen som frågar backend (som råkar vara en socket), lite som ett vanligt REST-anrop? Kanske går att vänta in ett ”socket connected” då?

emil0r11:12:11

Reitit kan ju köras på både frontend och Backend, så jag är lite osäker på vad du menar när du referar till reitit

jherrlin11:12:56

@U018VMC8T0W Ja precis. Det blir precis som ett REST-anrop men över websocketen. Det är just problemet att vänta in socket statet som jag skulle vilja ha en bra lösning på 🙂

jherrlin11:12:22

@U0545PBND I detta fallet så är det Reitit i en browserapp.

David Vujic11:12:01

Jag har gjort någon variant på setInterval för att vänta in ett connected. Har för mig att det var med re-frame och re-frame-10x. (Har inte tillgång till koden längre)

David Vujic11:12:46

Alltså köra anrop och sådant när den aktuella vyn är ”ready”.

emil0r11:12:49

Lite stateful component som väntar på att det startats korrekt? Efter att det är igång korrekt kör du igång systemet

jherrlin11:12:05

Ja det skulle kanske funka fint. Sente har fint stöd för att beskriva websocket statet och jag har det statet i Re-frames datastore. Om jag skickar ner hela ratomen i routern så kan jag kolla om websocket statet är redo och då göra min request. Om det inte är redo så kör jag igång en setInterval som kollar om en liten stund igen

jherrlin11:12:05

Just det ja @U0545PBND. Eftersom jag har det statet i Re-frame ratomen så skulle jag kunna ha en React komponent som styr uppstarten

jherrlin11:01:33

Tack för tipsen! Jag testar med spåret setInterval. La det i en Component komponent och tycker det blev rätt bra. I Reitit komponenten så väntar den in så att websocketen är öppen innan den kör igång Reitit router komponenten. Koden för Reitit komponenten ser ut såhär:

(defrecord Reitit [args websocket]
  component/Lifecycle
  (start [this]
    (timbre/info "Starting Reitit router component.")
    (if-not (:handler this)
      (let [{:keys [handler]}         args
            {:keys [websocket-open?]} websocket
            interval-id               :websocket-open?
            intervals                 (atom {})
            add-interval!             (fn [id f]
                                        (swap! intervals assoc id (js/setInterval f 500)))
            remove-interval!          (fn [id]
                                        (js/clearInterval (get @intervals id))
                                        (swap! intervals dissoc id))]
        (add-interval!
         interval-id
         (fn [_]
           ;; Wait for websocket to connect before starting Reitit
           ;; router.
           (when (websocket-open?)
             (start! (handler))
             (remove-interval! interval-id))))

        (assoc this :handler handler))
      (do
        (timbre/info "Starting Reitit router component but system is already runnig.")
        this)))

  (stop [this]
    (timbre/info "Stopping Reitit router component.")
    (assoc this :handler nil)))
Det ser ut att funka fint det lilla jag testat 🙂