Who is logged in?

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

I got my “Who is logged in?” app running. I am still learning how concise Clojure can be. Aaron Cohen described one of my functions as “too ugly to live”. He gave some good advice about making the code simpler. I still need to add a check on the PHP sessions to be sure they are valid, but in every other way this app seems to be working. (I have it running on the TMA server right now.)

Here is my code so far:

(ns who-is-logged-in.core
(:import (java.util Date))
(:require clojure.string clojure.java.io who-is-logged-in.memory_display
[clojure.data.json :as json])
(:use [net.cgrand.moustache :only [app delegate]]
[ring.adapter.jetty :only [run-jetty]]))

(def registry (atom {}))

(defn add-to-logged-in-registry [this-users-params]
“We assume some user is looking at a site such as wpquestions.com and the Javascript on that site is sending an Ajax request to this app, every 10 seconds, with a map of information about the user, which we need to store in the registry.”
(let [right-now (. (Date.) getTime)
new-user-entry (conj this-users-params { “updated” right-now })]
(if-not (nil? (get new-user-entry “username”))
(swap! registry assoc (get new-user-entry “username”) new-user-entry))))

(defn is-current? [this-users-map]
“If we have not received an Ajax request from a user during the last 15 seconds then we can assume they have left the site. We need to remove them from registry.”
(let [most-recent-ping (get this-users-map “updated”)
allowed-cutoff (- (. (Date.) getTime) 15000)]
(if (> most-recent-ping allowed-cutoff)

(defn remove-old-registrants []
“The registry should only show people who have pinged this app during the last 15 seconds. We rebuild the registry with only those users whose maps return true from is-current? 2012-10-22: I got some great advice for cleaning up this function here: https://groups.google.com/forum/?fromgroups=#!topic/clojure/xlbjGGk8qsY”
(swap! registry (fn [map-of-all-user-maps]
(into {} (filter #(-> % val is-current?) map-of-all-user-maps)))))

(defn current-users [request]
“The default action of this app. Add new users to the registry, and delete the ones that are more than 15 seconds old”
(let [this-users-params (:params request)]
(add-to-logged-in-registry this-users-params)
(response (apply str (json/write-str @registry)))))

(defn show-stats-regarding-resources-used-by-this-app [request]
(response (apply str “Memory in use (percentage/used/max-heap): ” (who-is-logged-in.memory_display/memory-usage) ” CPU usage (how-many-cpu’s/load-average): ” (who-is-logged-in.memory_display/cpu-load-usage) ” free memory in jvm: ” (conj [] (who-is-logged-in.memory_display/free-memory-in-jvm)))))

(def my-app-handler
[“”] (delegate current-users)
[“show-resources”] (delegate show-stats-regarding-resources-used-by-this-app)))

(defn -main [& args]
(let [port (Integer/parseInt (first args))]
(println “App ‘Who is logged in?’ is starting”)
(println “port: ” port)
(run-jetty #’my-app-handler {:port port
:join? false})))

Post external references

  1. 1