Liking cljdoc? Tell your friends :D

This project use the cljs lib ftravers/transit-websocket-client. It should be paired with ftravers/websocket-server

Setup

Add to project:

Foo

    (ns ...
      (:require [reframe-websocket.core :as reframe-websocket]))

Reframe :set and :get event/subscription registration

This will create an event handler called :get and a subscription handler called :set to be used like:

    (reframe/dispatch-sync [:set [:some :path] "abc123"])
    ;; sets the path [:some :path] to value "abc123" in the app-db
    @(reframe/subscribe [:get [:some :path]])
    ;; => "abc123"

Send/Recv to Server

Define your endpoint

    (def my-aws (reframe-websocket/async-websocket "ws://localhost:7890"))

Send to Server

    ;; Send a message, specify where to store the response
    (let [my-message {:my-message "blah" :some-param 12345}
          my-store-location [:store :path]]
      (reframe-websocket/send-msg my-message my-store-location my-aws))        
    
    ;; retrieve the response
    @(reframe/subscribe [:get [:store :path]])

Send/Recv to Server in a re-frame event

Define your endpoint

    (def my-aws (reframe-websocket/async-websocket "ws://localhost:7890"))

Write an interceptor

    (defn ws-send-msg
      [path-msg path-resp db]
      (reframe-websocket/send-msg (get-in db path-msg) path-resp aws))

    (def path-msg [:send-msg :msg])
    (def path-resp [:send-msg :resp])
    (def ws-send-msg-interceptor (rf/after (partial ws-send-msg path-msg path-resp)))

Add it to an event

    (rf/reg-event-db
      ::send-msg
      [ws-send-msg-interceptor]
      (fn-traced [db [_ msg]]
        (assoc-in db path-msg msg)))

Subscribing to server message

If you use ftravers/websocket-server as the server websocket, you should start your server with these input and output functions:

    (start-ws-server
        port
        :on-receive
        (fn [[store-path data]]
          [store-path (handle data)])
        :in-fn
        (fn [s]
          (let [[_ rf-msg] (json/read-str s)]
            (read-string rf-msg)))
        :out-fn
        (fn [msg]
          (json/write-str
            ["~#'" (str msg)])))

You can then send message from the backend with send-all. They will be stored in [:store :path] of your app-db and trigger the subscribes.

    ; String
    (send-all! port [[:store :path] "Message from backend"])])

    ; EDN
    (send-all! port [[:store :path] {:map "Hello" :text "EDN from backend"}])])

    ; You can subscribe to them as for responses to client requests:
    @(reframe/subscribe [:get [:store :path]])

If you need to do something else when receiving a message (more than just set the value into app-db at store-path), you can add a key to reframe-websocket/async-websocket. This event key will be dispatched each time a message is received with the store-path and msg.

    ; Register a custom event to handle received messages from websocket
    (rf/reg-event-db
     :set-ws
     (fn [db [_ store-path data]]
       (if (= store-path [:ws :hello])
        (assoc db :hello (hello data))))

    ; Give the key of this event to
    (def my-aws (reframe-websocket/async-websocket "ws://localhost:7890" :set-ws))

In this case, pay attention to a few things:

  • :set is still executed and data will be set in app-db store-path
  • :set-ws event will be executed both for messages coming from the server as for the responses to messages from client

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close