   (def ring-ajax-get-ws ajax-get-or-ws-handshake-fn)
   (def ch-chsk          ch-recv)
   (def chsk-send!       send-fn))
+
+;; session cache to maintain authentication - so we can rely
+;; entirely on socket communication instead of needing to login
+;; to the application first: 5 minutes of inactive will log you out
+
+(def session-map (atom (cache/ttl-cache-factory {} :ttl (* 5 60 1000))))
+
+(defn keep-alive
+  "Given a UID, keep it alive."
+  [uid]
+  (println "keep-alive" uid (java.util.Date.))
+  (when-let [token (get @session-map uid)]
+    (swap! session-map assoc uid token)))
+
+(defn add-token
+  "Given a UID and a token, remember it."
+  [uid token]
+  (println "add-token" uid token (java.util.Date.))
+  (swap! session-map assoc uid token))
+
+(defn get-token
+  "Given a UID, retrieve the associated token, if any."
+  [uid]
+  (let [token (get @session-map uid)]
+    (println "get-token" uid token (java.util.Date.))
+    token))
 
 (defn root
   "Return the absolute (root-relative) version of the given path."

  "Handle inbound events."
  []
  (go (loop [{:keys [client-uuid ring-req event] :as data} (<! ch-chsk)]
        (handle-event event ring-req)
        (recur (<! ch-chsk)))))


  "Handle events based on the event ID."
  (fn [[ev-id ev-arg] ring-req] ev-id))

(defn session-status
  "Tell the server what state this user's session is in."
  [req]
  (chsk-send! (session-uid req)
              [:session/state (if (get-token (session-uid req))
                                :secure
                                :open)]))

;; Reply with the session state - either open or secure.

(defmethod handle-event :session/status
  [_ req]
  (session-status req))

;; Reply with authentication failure or success.
;; For a successful authentication, remember the login.

(defmethod handle-event :session/auth
  [[_ [username password]] req]
  (let [valid (and (= "admin" username)
                   (= "secret" password))
        uid (session-uid req)]
    (when valid
      (add-token uid (unique-id)))
    (chsk-send! (session-uid req)
                [(if valid :auth/success :auth/fail)])))

;; Reply with the message in angle brackets.
;; Also record activity to keep session alive.

(defmethod handle-event :test/echo
  [[_ msg] req]
  (let [uid (session-uid)]
    (keep-alive uid)
    (chsk-send! uid [:test/reply (str "<" msg ">")])))

;; When the client pings us, send back the session state:

(defmethod handle-event :chsk/ping
  [_ req]
  (session-status req))

;; Handle unknown events.
;; Note: this includes the Sente implementation events like:
;; - :chsk/uidport-open
;; - :chsk/uidport-close

