             (remove invalid-link?))))))
 
 (defn- valid-selector?
+  "Only allow the most basic selector i.e. no whitespace, alphanumeric chars and div or id."
   [selector]
   (re-find #"^[\.#a-zA-Z0-9_-]+$" selector))
+
+(defn- send-final-message
+  "Sends a results event containing total row and message event summarizing checked links."
+  [send-to time links]
+  (send-to
+   "message"
+   (if (zero? (count links))
+     "No links found. Check your link and selector."
+     (let [invalid-links (count (remove #(successful-status? (:status %)) links))]
+       (format "%s It took %ss to fetch %s links."
+               (case invalid-links
+                 0 "All links are valid!"
+                 1 "1 link did not return a 2XX response."
+                 (str invalid-links " links did not return a 2XX response."))
+              time
+              (count links))))))
 
 (defn- stream-links*
   "Sends 3 different sse events (message, results, end-message) depending on


(def ^{:doc "Map of IDs to remaining links count"} link-counts (atom {}))

(defn- fetch-link-and-send-row [send-to url total-links client-id link]
  (let [result-map (fetch-link link)]
    (when (get @link-counts client-id)
      (swap! link-counts update-in [client-id] dec)

  [status]
  (and (integer? status) (> 300 status 199)))

(def default-clj-http-options
  {:max-redirects 5
   :throw-exceptions false
