 
 (defn- new-request-session
   "Associates a new session with a request."
-  [request]
+  [repository request]
   (assoc request
-    :session (assoc-expiry (create-session))
+    :session (assoc-expiry (create-session repository))
     :new-session? true))
 
 (defn- get-request-session
   "Retrieve the session using the 'session' cookie in the request."
-  [request]
+  [repository request]
   (if-let [session-data (-> request :cookies :compojure-session)]
-    (read-session session-data)))
+    (read-session repository session-data)))
 
 (defn- assoc-request-session
   "Associate the session with the request."
-  [request]
-  (if-let [session (get-request-session request)]
+  [repository request]
+  (if-let [session (get-request-session repository request)]
     (if (session-expired? session)
       (do
-        (destroy-session session)
-        (new-request-session request))
-      (assoc request :session (assoc-expiry session)))
-    (new-request-session request)))
+        (destroy-session repository session)
+        (new-request-session repository request))
+      (assoc request :session
+        (assoc-expiry repository session)))
+    (new-request-session repository request)))
 
 (defn- assoc-request-flash
   "Associate the session flash with the request and remove it from the


(defn session-hmac
  "Calculate a HMAC for a marshalled session"
  [cookie-data]
  (let [secret-key (:secret-key *session-repo* *default-secret-key*)]
    (hmac secret-key "HmacSHA256" cookie-data)))

(defmethod create-session :cookie [] {})

(defmethod session-cookie :cookie
  [new? session]
  (let [cookie-data (marshal session)]
    (if (> (count cookie-data) 4000)
      (throwf "Session data exceeds 4K")
      (str cookie-data "--" (session-hmac cookie-data)))))

(defmethod read-session :cookie
  [data]
  (let [[session mac] (.split data "--")]
    (if (= mac (session-hmac session))
      (unmarshal session))))

; Do nothing for write or destroy
(defmethod write-session :cookie [session])
(defmethod destroy-session :cookie [session])

;; Session middleware


  (:use compojure.crypto)
  (:use clojure.contrib.except))

;; Override these mulitmethods to create your own session storage.
;; Uses the Compojure repository pattern.

(defmulti create-session
  "Create a new session map. Should not attempt to save the session."
  (fn [repository] (type repository)))

(defmulti read-session
  "Read in the session using the supplied data. Usually the data is a key used
  to find the session in a store."
  (fn [repository data] (type repository)))

(defmulti write-session
  "Write a new or existing session to the session store."
  (fn [repository session] (type repository)))

(defmulti destroy-session
  "Remove the session from the session store."
  (fn [repository session] (type repository)))

(defmulti session-cookie
  "Return the session data to be stored in the cookie. This is usually the
  session ID."
  (fn [repository new? session] (type repository)))

;; Default implementations of create-session and set-session-cookie

(defmethod create-session :default
  [repository]
  {:id (gen-uuid)})

(defmethod session-cookie :default
  [repository new? session]
  (if new?
    (session :id)))

