       (log/error "Exception in devtools WebSocket receive, msg: " msg
                  ", throwable: " t))))
 
-(defn- fetch-ws-debugger-url [host port]
-  (let [response @(http/get (str "http://" host ":" port "/json/list"))
-        url (some-> response :body parse-json first :web-socket-debugger-url)]
-    (when-not url
-      (throw (ex-info "No chrome remote debugging URL found"
-                      {:host host :port port
-                       :response response})))
-    url))
-
 (defn- wait-for-remote-debugging-port [host port max-wait-time-ms]
   (let [wait-until (+ (System/currentTimeMillis) max-wait-time-ms)
-        url (str "http://" host ":" port "/json/version")]
+        url        (str "http://" host ":" port "/json/version")]
     (loop [response @(http/head url)]
       (cond
         (= (:status response) 200)

  (let [[domain event] (map (comp keyword camel->clojure)
                            (str/split (:method msg) #"\."))
        event {:domain domain
               :event event
               :params (:params msg)}]
    (async/go
      (async/>! event-chan event))))


        (> (System/currentTimeMillis) wait-until)
        (throw (ex-info "Chrome remote debugging port not up"
                        {:host             host :port port
                         :max-wait-time-ms max-wait-time-ms}))

        :default
        (do (Thread/sleep 100)
            (recur @(http/head url)))))))

(defn inspectable-pages
  "Collect the list of inspectable pages returned by the DevTools protocol."
  ([host port]
    (inspectable-pages host port 1000))
  ([host port max-wait-time-ms]
   (wait-for-remote-debugging-port host port max-wait-time-ms)
   (let [response @(http/get (str "http://" host ":" port "/json/list"))]
     (some->> response
              :body
              parse-json))))


(defn- first-inspectable-page [pages]
  (or (some->> pages
               (filter (comp #{"page"} :type))
               (keep :web-socket-debugger-url)
               first)
      (throw (ex-info "No debuggable pages found"
                      {:pages pages}))))

(defn connect-url
  "Establish a websocket connection to web-socket-debugger-url, as given by
   inspectable-pages."
  [web-socket-debugger-url]
  (assert web-socket-debugger-url)
  (let [client     (ws/client)
        ;; Request id to callback
        requests   (atom {})

        ;; Event pub/sub channel
        event-chan (async/chan)
        event-pub  (async/pub event-chan (juxt :domain :event))]

    ;; Configure max message size to 1mb (default 64kb is way too small)
    (doto (.getPolicy client)
      (.setMaxTextMessageSize (* 1024 1024)))

    (.start client)
    (->Connection (ws/connect web-socket-debugger-url
                              :on-receive (partial on-receive requests event-chan)
                              :client client)
                  requests
                  event-chan
                  event-pub)))

(defn connect
  "Establish a websocket connection to the DevTools protocol at host:port.
   Selects the first inspectable page returned; to attach to a specific page,
   see connect-url. Initial connection will be retried for up to
   max-wait-time-ms milliseconds (default 1000) before giving up."
  ([]
   (connect "localhost" 9222))
  ([host port]
   (connect host port 1000))
  ([host port max-wait-time-ms]
   (when max-wait-time-ms
     (wait-for-remote-debugging-port host port max-wait-time-ms))
    (let [url (-> (inspectable-pages host port)
                  (first-inspectable-page))]
      (connect-url url))))

(defn send-command [{requests :requests con :ws-connection} payload id callback]
  (swap! requests assoc id callback)
