        (debug "ignoring op" (ops->str current-ops) "->" (ops->str new-ops)))
      (.interestOps k new-ops))))
 
+(defmulti dispatch
+  (fn [_ _ event]
+    (first event)))
+
+(defmethod dispatch :default [_ _ [action & event]]
+  (warn "unknown action:" action "event:" event))
+
 (defn route-complete-op [op {:keys [^ConcurrentLinkedDeque dispatch-queue] :as client}]
   (let [reply (.get (.root (.parser op)) 0)]
     (if (reroute? reply)

              (.addFirst dispatch-queue [:resolve (ask op slot) address]))))
      (op reply))))

(defn read! [client ^SelectionKey k]
  (let [^SocketChannel channel (.channel k)
        {:keys [^ConcurrentLinkedDeque read-queue ^ByteBuffer read-buffer] :as conn} (.attachment k)]
    (loop [n (.read channel (doto read-buffer

                        (debug "key is not valid:" selected-key)
                        (do
                          (when (.isReadable selected-key)
                            (handle-read! client selected-key))
                          (when (and (.isValid selected-key) (.isWritable selected-key))
                            (handle-write! client selected-key))
                          (when (and (.isValid selected-key) (.isConnectable selected-key))
                            (handle-connect! client selected-key))))))
                  (recur))
                (recur))))
        (warn "Selector is closed")))
