 
 (defn auto-respond
   [session msg dispatch]
+  ;; FIXME: Really shouldn't run dispatched things in a dosync,
+  ;; there's no reason to believe they won't do side-effects!
+  ;; However, it does provide the convenience of not releasing msg
+  ;; sends until the state has been altered...
   (dosync
    (when-let [pre-handler (get dispatch :pre)]
      (pre-handler session msg))

            [clojure.java.io :as io]
            [clojure.string :as str]
            [manifold.stream :as s]))

(defn pencode
  "Percent-encode for URLs (conservatively.)"

                                        :data m}))))
    (.flush w)))

(defn do-send-event
  "Log a single new message to file."
  [session msg]
  (log-messages session [(get-in msg [:data])]))

(defn oldest-msg-id
  [msgs]
  (:id (max-1 (fn compare-times [x y]
                ;; Reverse sort, get msg with min time
                (- (:time y) (:time x)))
              msgs)))

(defn ask-for-backlog
  [session before-id]
  (println "Asking for backlog before" before-id)
  (send-message session
                {:type "log"
                 :data {:n 1000
                        :before before-id}}))

(defn do-snapshot-event
  "Log an entire snapshot to file."
  [session msg]
  (let [recent-log (get-in msg [:data :log])]
    (log-messages session recent-log)
    ;; Start downloading entire room history
    (println "Switching to full catchup mode!")
    ;; Should maybe check if lifecycle is :waiting-for-snapshot ?
    (alter (:state session) assoc-in [:logger :lifecycle] :full-catchup)
    (ask-for-backlog session (oldest-msg-id recent-log))))

(defn do-log-reply
  "Write backlog to file, ask for more if possible."
  [session msg]
  (let [recent-log (get-in msg [:data :log])]
    (if (empty? recent-log)
      (do (println "All caught up, no more backlog. Now just tailing.")
          (alter (:state session) assoc-in [:logger :lifecycle] :tailing))
      (do (log-messages session recent-log)
          (ask-for-backlog session (oldest-msg-id recent-log))))))

(def logger-dispatch
  "Reactive dispatch overlay for logger."
  (merge
   (base-dispatch "hillbot")
   {"send-event"
    #'do-send-event

    "snapshot-event"
    #'do-snapshot-event

    "log-reply"
    #'do-log-reply

    :unknown-type
    ;; (fn [session msg]
