how to communicate through channels in clojure's core.async?

294 Views Asked by At

I’m trying to build a chat-like feature using websockets, and I need users (only 2) to send some initial data to each other. this is an example of what I’ve done so far, but i’m missing something:

(def signals (chan))
(def publication (pub signals :source))
(defn user-handler [signals publication room user_id other_id data]
  (let [user-chan (chan)
        topic (keyword (str room "_" user_id))]
    (sub publication topic user-chan)
    (go
      (>! signals {:source   (keyword (str room "_" other_id))
                   :room     room
                   :user_id  user_id
                   :other_id other_id
                   :data     data}))
    (go
      (let [timeout-chan (timeout 15000)]
        (alt!
          timeout-chan :timeout
          user-chan ([received-data] (println received-data)))))))
(comment
  (user-handler signals publication "room1" 1 2 "Hello from user1")
  (user-handler signals publication "room1" 2 1 "Hello from user2")
  )
;; expect to print:
{:source :room1_2, :room "room1", :user_id 1, :other_id 2, :data "Hello from user1"}
{:source :room1_1, :room "room1", :user_id 2, :other_id 1, :data "Hello from user2"}

;; got:
{:source :room1_1, :room "room1", :user_id 2, :other_id 1, :data "Hello from user2"} 

Edit

Finally, I decided to go with a different approach, instead of using pub and sub with channels, I just use one channel per user:

(def all-channels (atom {}))

(defn user-handler [room user_id other_id data]
  (let [data {:room     room
              :user_id  user_id
              :other_id other_id
              :data     data}
        user-chan (chan)
        other-chan (get @all-channels other_id)]
    (swap! all-channels assoc user_id user-chan)
    (when other-chan (go (>! other-chan data)))
    (go
      (let [timeout-chan (timeout 30000)]
        (alt!
          timeout-chan (println user_id " Timeout !")
          user-chan ([received-data]
                     (println received-data)
                     (>! (get @all-channels other_id) data)))))))



(user-handler "room1" 1 2 "Hello from user1")
(user-handler "room1" 2 1 "Hello from user2")

it prints:

{:room room1, :user_id 2, :other_id 1, :data Hello from user2}
{:room room1, :user_id 1, :other_id 2, :data Hello from user1}
0

There are 0 best solutions below