Move all logic to background script

This commit is contained in:
Jeremy Dormitzer 2018-01-11 07:37:18 -05:00
parent e46d295346
commit 12e9d50a45
No known key found for this signature in database
GPG Key ID: 04F17C0F5A32C320
6 changed files with 88 additions and 112 deletions

View File

@ -9,25 +9,16 @@
"96": "icons/icon96.png",
"128": "icons/icon128.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [
"js/browser-polyfill.min.js",
"js/generated/out/cljs_base.js",
"js/generated/content.js"
]
}
],
"background": {
"scripts": ["js/browser-polyfill.min.js",
"js/generated/out/cljs_base.js",
"js/generated/background.js"]
"js/generated/main.js"]
},
"browser_action": {
"default_icon": "icons/icon48.png",
"default_title": "Looped In"
},
"permissions": ["tabs"],
"content_security_policy": "script-src 'self'; object-src 'self'; connect-src 'self' https://hn.algolia.com",
"web_accessible_resources": ["js/*.map", "js/generated/*.map"]
}

View File

@ -14,11 +14,7 @@
:source-map true
:pretty-print true
:output-dir "ext/js/generated/out"
:language-in :es6
:modules
{:content
{:output-to "ext/js/generated/content.js"
:entries #{"looped-in.content"}}
:background
{:output-to "ext/js/generated/background.js"
:entries #{"looped-in.background"}}}}}]})
{:background
{:output-to "ext/js/generated/main.js"
:entries #{"looped-in.main"}}}}}]})

View File

@ -1,40 +0,0 @@
(ns looped-in.background
(:require [clojure.core.match :refer [match]]
[cljs.core.async :refer [go chan >! <!]]
[ajax.core :refer [GET]]
[looped-in.logging :as log]
[looped-in.promises :refer [channel->promise]]))
(enable-console-print!)
(def browser-action (.-browserAction js/browser))
(defn fetch-submission
"Fetches submissions from Hacker News by `url`"
[url]
(let [response-chan (chan)]
(GET "https://hn.algolia.com/api/v1/search"
{:params {"query" url
"hitsPerPage" 1000
"restrictSearchableAttributes" "url"}
:handler (fn [res] (go (>! response-chan res)))
:error-handler (fn [err] (log/error "Error fetching HN stories:"
(clj->js err)))})
response-chan))
(defn handle-message
"Handles messages from the content script"
[msg]
(match (.-type msg)
"urlVisited" (channel->promise (fetch-submission (.-url msg)))
x (log/warn "Ignoring unknown message type" x)))
(-> js/browser
(.-runtime)
(.-onMessage)
(.addListener handle-message
#_(fn [msg]
(prn msg)
(.setBadgeBackgroundColor browser-action #js {:color "#232323"})
(.setBadgeText browser-action
#js {:text (str (.-numComments msg))}))))

View File

@ -1,50 +0,0 @@
(ns looped-in.content
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [ajax.core :refer [GET]]
[cljs.core.async :as async :refer [go <!]]
[looped-in.logging :as log]
[looped-in.promises :refer [promise->channel]]))
(enable-console-print!)
(defn filter-response
"Filters a response from hn.algolia.com to give just the relevant results"
;; TODO implement a cache by URL and timestamp that caches the results of the
;; request and this method for 5 minutes using localStorage
[url response]
(let [{:strs [hits]} response]
(log/debug "response" response)
(filter #(= (get % "url") url) hits)))
(defn sort-hits
"Sorts hits from hn.algolia.com by post date descending"
[hits]
(sort-by #(get % "created_at_i") #(compare %2 %1) hits))
(defn total-num-comments
"Returns the total number of comments from some hits"
[hits]
(reduce (fn [acc {:strs [num_comments]}] (+ acc num_comments)) 0 hits))
(defn handle-hits
"Handles a filtered response"
[hits]
(log/debug (clj->js hits))
(let [num-comments (total-num-comments hits)]
(-> js/browser
(.-runtime)
(.sendMessage #js {:numComments num-comments}))))
#_(let [current-url (-> js/window (.-location) (.-href))
sub-chan (fetch-submission current-url)]
(go (->> (<! sub-chan)
(filter-response current-url)
(sort-hits)
(handle-hits))))
(let [current-url (-> js/window (.-location) (.-href))
results-chan (-> js/browser
(.-runtime)
(.sendMessage #js {:type "urlVisited" :url current-url})
(promise->channel))]
(go (log/debug "results:" (<! results-chan))))

View File

@ -1,13 +1,13 @@
(ns looped-in.logging)
(defn info [& args]
(apply js/console.info "[Looped In]" args))
(apply js/console.info "[Looped In]" (map clj->js args)))
(defn error [& args]
(apply js/console.error "[Looped In]" args))
(apply js/console.error "[Looped In]" (map clj->js args)))
(defn debug [& args]
(apply js/console.debug "[Looped In]" args))
(apply js/console.debug "[Looped In]" (map clj->js args)))
(defn warn [& args]
(apply js/console.warn "[Looped In]" args))
(apply js/console.warn "[Looped In]" (map clj->js args)))

79
src/looped_in/main.cljs Normal file
View File

@ -0,0 +1,79 @@
(ns looped-in.main
(:require [clojure.core.match :refer [match]]
[cljs.core.async :refer [go chan >! <!]]
[ajax.core :refer [GET]]
[looped-in.logging :as log]
[looped-in.promises :refer [channel->promise promise->channel]]))
(enable-console-print!)
(defn fetch-submission
"Fetches submissions from Hacker News by `url`"
[url]
(let [response-chan (chan)]
(GET "https://hn.algolia.com/api/v1/search"
{:params {"query" url
"hitsPerPage" 1000
"restrictSearchableAttributes" "url"}
:handler (fn [res] (go (>! response-chan res)))
:error-handler (fn [err] (log/error "Error fetching HN stories:"
(clj->js err)))})
response-chan))
(defn url-path [url]
(when (not (nil? url))
(second (re-matches #"http.*://(.*)" url))))
(defn filter-response
"Filters a response from hn.algolia.com to give just the relevant results"
[url response]
(let [{:strs [hits]} response]
(filter #(= (url-path (get % "url")) (url-path url)) hits)))
(defn sort-hits
"Sorts hits from hn.algolia.com by post date descending"
[hits]
(sort-by #(get % "created_at_i") #(compare %2 %1) hits))
(defn total-num-comments
"Returns the total number of comments from some hits"
[hits]
(reduce (fn [acc {:strs [num_comments]}] (+ acc num_comments)) 0 hits))
(defn set-badge-text! [text]
(.setBadgeBackgroundColor (.-browserAction js/browser) #js {:color "#232323"})
(.setBadgeText (.-browserAction js/browser) #js {:text text}))
;; TODO implement a cache on the result of the urlVisited message
(defn handle-update [tab-id]
(go (let [query-p (-> js/browser (.-tabs) (.query #js {:active true
:currentWindow true}))
query-chan (promise->channel query-p)
tab (first (<! query-chan))
url (.-url tab)
fetch-chan (fetch-submission url)
response (<! fetch-chan)
hits (->> response
(filter-response url)
(sort-hits))
num-comments (total-num-comments hits)]
(set-badge-text! (str num-comments)))))
(-> js/browser
(.-tabs)
(.-onActivated)
(.addListener handle-update))
(-> js/browser
(.-tabs)
(.-onUpdated)
(.addListener handle-update))
;; Application logic:
;; 1. Event comes in (new url)
;; 2. Fetch HN hits
;; 3. Filter and sort hits
;; 4. Count comments, update badge
;; 5. Fetch item details
;; 6. Construct popup (or sidebar?) html