A minimal server
Well, we now have a minimal client, but what about the server? Currently, it only accepts a connection and prints a message. Let’s have it do a bit more than that, shall we? In particular, let’s create an event loop for each client connection that will:
- Greet the client upon connection.
- Echo back any messages the client sends
About the server
The server for the tutorial is a fairly standard Clojure web application built using Ring, Compojure, and Enlive. However, unlike Ring’s default, it uses http-kit. One of the nice thing about http-kit is that its HTTP server supports WebSockets, and adding a WebSocket endpoint is as easy as using a special handler for a Compojure route.
In our application, this handler can be found at
(defn chatroom-handler [req] ; 1 (let [user (get-in req [:session ::friend/identity :current])] ; 2 (web-socket/with-channel req socket ; 3 (println user "logged in"))))
reqis the Ring request
- We set
userto the value of the user’s name from the session
with-channelis a macro that will take the request and provide a ‘channel’ that the application can use from that point on. We’ll talk about this in more detail in the next section.
Just like the client-side counterpart, http-kit uses a similar callback-driven approach for working with WebSockets. The mechanism for setting up these is as follows:
- Unlike the client, there is no opened/connected event. That is implicit in the handler invocation.
To process messages from the client, use
org.httpkit.server/on-receive. This function takes two arguments: the socket, and a function that takes a single argument containing the message content.
To know when the client closes the connection, use
org.httpkit.server/on-close. This takes two arguments: the socket, and a function that takes a single argument describing how the connection was closed.
Finally, to send a message to the client, just use
org.httpkit.server/send!. This function
takes two arguments: the web socket, and the message to send to the socket.
Implement the server
Now, it’s your turn to implement the server-side event loop. Here’s a few tips:
- In Clojure, all core.async vars are in
When you create the channel, you may want to provide an argument, e.g.
(chan 4). This gives the channel a buffer so that requests can back up a small bit before causing the server to hang.
- For now, just send the messages to the client directly using
- Again, you may want to create your own event maps to place into the channel.
- When you get the socket-closed event, you will probably want to close the event channel you created.
Once you have updated the server, you should be able to reload the chat client page and see the greeting from the server to the user.
There wasn’t much new to learn in this section, as most of the ideas from the previous section apply here as well. However, there are some points for thought/discussion:
In Clojure there are three ways to put values into a channel:
put!. Do you know the differences? Which one is missing from ClojureScript and why?
In Clojure, there are alternatives to using
thread-call. Under what circumstances should you use these?
Now, let’s get the client to send something more interesting to the server.