2

During my quest to learn Clojure I am currently facing problems with setting up websocket communitation. After many different approaches, I ended up using aleph.

What I managed to achieve:

  • handling of a new client connecting
  • handling a client disconnection
  • talking from the server to clients at will

What I lack is means to trigger a handler function whenever one of the connected clients sends something via the websocket.

My code so far:

(ns wonders7.core.handler
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
            [aleph.http :as http]
            [manifold.stream :as stream]
            [clojure.tools.logging :refer [info]]))

(defn uuid [] (str (java.util.UUID/randomUUID)))

(def clients (atom {}))

(defn ws-create-handler [req]
  (let [ws @(http/websocket-connection req)]
    (info "ws-create-handler")
    (stream/on-closed ws #(swap! clients dissoc ws))
    (swap! clients assoc ws (uuid))))

(defroutes app-routes
  (GET "/ws" [] ws-create-handler)
  (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

(defn msg-to-client [[client-stream uuid]]
  (stream/put! client-stream "The server side says hello!"))

(defn msg-broadcast []
  (map #(msg-to-client %) @clients))

;(stream/take! (first (first @clients)))
;(http/start-server app {:port 8080})

I start the Netty server with the commented out http/start-server aleph call. I also managed to fetch messages from the client via manual stream/take! call (also commented out). What I need to figure out is how to trigger this taking automatically when something comes in.

Thanks in advance for any help!

Apo
  • 140
  • 6

2 Answers2

4

The function you're looking for is (manifold.stream/consume callback stream), which will invoke the callback for each message that comes off the stream.

ztellman
  • 756
  • 4
  • 7
  • One more question. Is it possible to send a message to the client from within a consume callback function body? This doesn't seem to work for me (nothing happens). On the other hand if I evaluate the sending code manually, the client receives it without any trouble. – Apo Nov 11 '14 at 10:22
  • Ok, figured that out. Was sending out messages by "mapping" the sending function to streams. Switching to doseq (which is intended for side effects) instead of mapping did the trick. – Apo Nov 12 '14 at 10:02
1

in This example the author uses recieve-all and siphon from aleph to accomplish a very similar task which I'll roughly paraphrase as:

(let [chat (named-channel room (receive-all ch #(println "message: " %)))]
  (siphon chat ch)
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284