From e871d1a6c4ea3e3755c0c076d99f8d34a38a883a Mon Sep 17 00:00:00 2001 From: Felisp Date: Tue, 10 Sep 2024 17:15:49 +0200 Subject: [PATCH] Refactor config utils into it's own file and namespace Everything /seems/ to be working --- project.clj | 2 +- src/rss_thread_watch/config.clj | 88 ++++++++++++++++++++++++ src/rss_thread_watch/core.clj | 90 +++---------------------- src/rss_thread_watch/feed_generator.clj | 15 +++-- src/rss_thread_watch/watcher.clj | 6 -- 5 files changed, 106 insertions(+), 95 deletions(-) create mode 100644 src/rss_thread_watch/config.clj diff --git a/project.clj b/project.clj index c8701a2..9208f29 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject rss-thread-watch "0.4.5-SNAPSHOT" +(defproject rss-thread-watch "0.4.6-SNAPSHOT" :description "RSS based thread watcher" :url "http://example.com/FIXME" :license {:name "AGPL-3.0-only" diff --git a/src/rss_thread_watch/config.clj b/src/rss_thread_watch/config.clj new file mode 100644 index 0000000..f6f867b --- /dev/null +++ b/src/rss_thread_watch/config.clj @@ -0,0 +1,88 @@ +(ns rss-thread-watch.config + "Functions for working with configuration" + (:require [clojure.java.io :as io] + [clojure.edn :as edn] + [clojure.string :as s] + [rss-thread-watch.utils :as u]) + (:gen-class)) + +(def VERSION "0.4.6") + +(def GLOBAL-CONFIG + "Global config with defaults for missing entires" + ;; I know globals are ew in Clojure but I don't know any + ;; better way of doing this + (atom nil)) + +;; Internal default config +(def CONFIG-DEFAULT + "Internal default config" + {:port 6969 + :default-board "/mlp/" + :enable-board-listing true + :board-disabled-message "This board is not enabled for feed generation.\n\nYou can contact me here: [contact] and I may enable it for you" + :boards-defaults {:refresh-rate 300 + :starting-page 7 + :default-chod 94 + :target "https://api.4chan.org/{board}/catalog.json" + :host "https://boards.4chan.org/{board}/thread/{threadnum}" + :lazy-load true} + :boards-enabled {"/mlp/" {:lazy-load false} + "/g/" {:starting-page 7} + "/po/" {:starting-page 8 + :refresh-rate 86400} + "/p/" {:starting-page 8 + :refresh-rate 1800}}}) + +(defn load-config + "Attempts to load config from file [f]. + Returns loaded config map or nil if failed" + [f] + (let [fl (io/as-file f)] + (when (.exists fl) + (with-open [r (io/reader fl)] + (edn/read (java.io.PushbackReader. r)))))) + + +(defn config-url-expand + "Expands substitution in :target and :host fields" + [filled-config] + (let [boards (get filled-config :boards-enabled) + selecting '(:target :host) + pattern "{board}"] + (assoc filled-config + :boards-enabled + (u/fmap (fn [board confs] + (->> (select-keys confs selecting) + (u/fmap (fn [k v] + (s/replace v pattern (s/replace board "/" "")))) + (merge confs))) + boards)))) + +(defn config-fill-board-defaults + "Fills every enabled board with default config values" + [config] + (let [defaults (:boards-defaults config)] + (as-> config conf + (update-in conf + '(:boards-enabled) + (fn [mp] + (u/fmap (fn [k v] + (assoc (u/map-apply-defaults v defaults) :name k)) + mp))) + (dissoc conf :boards-defaults) + (config-url-expand conf)))) + +(defn get-some-config + "Attempts to get config somehow, + first from [custom-file], if it's nil, + then from ./config.edn file. + If is neither exists, default internal one is used." + [custom-file] + (config-fill-board-defaults + ;; TODO: There has to be try/catch for when file is invalid edn + ;; This is gonna be done when config validation comes in Beta 2 + (let [file-to-try (u/nil?-else custom-file + "./config.edn")] + (u/when-else (load-config file-to-try) + CONFIG-DEFAULT)))) diff --git a/src/rss_thread_watch/core.clj b/src/rss_thread_watch/core.clj index 338eab5..4fab9df 100644 --- a/src/rss_thread_watch/core.clj +++ b/src/rss_thread_watch/core.clj @@ -21,30 +21,10 @@ [ring.middleware.params :as rp] [rss-thread-watch.watcher :as watcher] [rss-thread-watch.feed-generator :as feed] - [rss-thread-watch.utils :as u]) + [rss-thread-watch.utils :as u] + [rss-thread-watch.config :as conf]) (:gen-class)) -(def VERSION "0.4.5") - -;; Internal default config -(def CONFIG-DEFAULT - "Internal default config" - {:port 6969 - :default-board "/mlp/" - :enable-board-listing true - :board-disabled-message "This board is not enabled for feed generation.\n\nYou can contact me here: [contact] and I may enable it for you" - :boards-defaults {:refresh-rate 300 - :starting-page 7 - :default-chod 94 - :target "https://api.4chan.org/{board}/catalog.json" - :host "https://boards.4chan.org/{board}/thread/{threadnum}" - :lazy-load true} - :boards-enabled {"/mlp/" {:lazy-load false} - "/g/" {:starting-page 7} - "/po/" {:starting-page 8 - :refresh-rate 86400} - "/p/" {:starting-page 8 - :refresh-rate 1800}}}) (def cli-options "Configuration defining program arguments for cli.tools" @@ -68,58 +48,6 @@ (println "Error while updating cache: " e ", retrying in " (/ ms 1000 60) " minutes")))) (Thread/sleep ms))))) -(defn load-config - "Attempts to load config from file [f]. - Returns loaded config map or nil if failed" - [f] - (let [fl (io/as-file f)] - (when (.exists fl) - (with-open [r (io/reader fl)] - (edn/read (java.io.PushbackReader. r)))))) - -(defn config-url-expand - "Expands substitution in :target and :host fields" - [filled-config] - (let [boards (get filled-config :boards-enabled) - selecting '(:target :host) - pattern "{board}"] - (assoc filled-config - :boards-enabled - (u/fmap (fn [board confs] - (->> (select-keys confs selecting) - (u/fmap (fn [k v] - (s/replace v pattern (s/replace board "/" "")))) - (merge confs))) - boards)))) - -(defn config-fill-board-defaults - "Fills every enabled board with default config values" - [config] - (let [defaults (:boards-defaults config)] - (as-> config conf - (update-in conf - '(:boards-enabled) - (fn [mp] - (u/fmap (fn [k v] - (assoc (u/map-apply-defaults v defaults) :name k)) - mp))) - (dissoc conf :boards-defaults) - (config-url-expand conf)))) - -(defn get-some-config - "Attempts to get config somehow, - first from [custom-file], if it's nil, - then from ./config.edn file. - If is neither exists, default internal one is used." - [custom-file] - (config-fill-board-defaults - ;; TODO: There has to be try/catch for when file is invalid edn - ;; This is gonna be done when config validation comes in Beta 2 - (let [file-to-try (u/nil?-else custom-file - "./config.edn")] - (u/when-else (load-config file-to-try) - CONFIG-DEFAULT)))) - (defn -main "Entry point, starts webserver" [& args] @@ -129,26 +57,26 @@ (println "Error: " err) (System/exit 1)) (when (get options :version) - (println "RSS Thread Watcher " VERSION " Licensed under AGPL-3.0-only") + (println "RSS Thread Watcher " conf/VERSION " Licensed under AGPL-3.0-only") (System/exit 0)) (when (get options :help) (println "RSS Thread Watcher help:\n" (get parsed-args :summary)) (System/exit 0)) (when (get options :print-default-config) - (println ";;Default internal config file from RSS Thread Watcher " VERSION) - (clojure.pprint/pprint CONFIG-DEFAULT) + (println ";;Default internal config file from RSS Thread Watcher " conf/VERSION) + (clojure.pprint/pprint conf/CONFIG-DEFAULT) ;; In case someone was copying by hand, this might be useful (println ";;END of Default internal config file") (System/exit 0)) - (let [config (get-some-config (:config options))] + (let [config (conf/get-some-config (:config options))] ;; TODO: probably refactor to use separate config.clj file when validation will be added ;; Init the few globals we have - (reset! watcher/GLOBAL-CONFIG config) + (reset! conf/GLOBAL-CONFIG config) (reset! feed/boards-enabled-cache (set (keys (get config :boards-enabled)))) (reset! watcher/chod-threads-cache (watcher/generate-chod-cache-structure config)) (clojure.pprint/pprint config) - (jetty/run-jetty (rp/wrap-params feed/http-handler) {:port (:port CONFIG-DEFAULT) + (jetty/run-jetty (rp/wrap-params feed/http-handler) {:port (:port conf/CONFIG-DEFAULT) :join? true})))) ;; Docs: https://github.com/ring-clojure/ring/wiki/Getting-Started @@ -156,7 +84,7 @@ "Development entry point" [] (jetty/run-jetty (rp/wrap-params #'feed/http-handler) - {:port (:port CONFIG-DEFAULT) + {:port (:port conf/CONFIG-DEFAULT) ;; Dont block REPL thread :join? false})) ;; (repl-main) diff --git a/src/rss_thread_watch/feed_generator.clj b/src/rss_thread_watch/feed_generator.clj index 6342a2c..42bf686 100644 --- a/src/rss_thread_watch/feed_generator.clj +++ b/src/rss_thread_watch/feed_generator.clj @@ -19,7 +19,8 @@ [clj-rss.core :as rss] [clojure.string :as s] [rss-thread-watch.watcher :as watcher] - [rss-thread-watch.utils :as ut]) + [rss-thread-watch.utils :as ut] + [rss-thread-watch.config :as conf]) (:gen-class)) (def boards-enabled-cache @@ -98,7 +99,7 @@ "Generates feed from matching items" [query-vec chod-treshold repeat? cache board-config] (let [items (filter-chod-posts query-vec chod-treshold repeat? cache) - head {:title "RSS Thread watcher v0.4.5" ;TODO: hardcoded string here, remake to reference to config.clj + head {:title (str "RSS Thread watcher v" conf/VERSION) :link "https://tools.treebrary.org/thread-watcher/feed.xml" :feed-url "https://tools.treebrary.org/thread-watcher/feed.xml" :description "RSS based thread watcher"} @@ -113,12 +114,12 @@ READS FROM GLOBALS: rss-thread-watch.watcher.chod-threads-cache - rss-thread-watch.watcher.GLOBAL-CONFIG" ;TODO: Update if it really reads from there anymore + rss-thread-watch.config.GLOBAL-CONFIG" ;TODO: Update if it really reads from there anymore [rqst] (try (let [{{chod "chod" board "board" repeat? "repeat" :or {chod "94" - board (get @watcher/GLOBAL-CONFIG :default-board) + board (get @conf/GLOBAL-CONFIG :default-board) repeat? false} :as prms} :params uri :uri} rqst @@ -134,7 +135,7 @@ 60 (Integer/parseInt chod)) (catch Exception e 94))) - board-config (get-in @watcher/GLOBAL-CONFIG [:boards-enabled board]) + board-config (get-in @conf/GLOBAL-CONFIG [:boards-enabled board]) cache @watcher/chod-threads-cache] (println "\n\nRCVD: " rqst) ;; (println rqst) @@ -147,7 +148,7 @@ (when-not (contains? @boards-enabled-cache board) (throw (ex-info "403" {:status 403 :header {"Content-Type" "text/plain"} - :body (get @watcher/GLOBAL-CONFIG :board-disabled-message)}))) + :body (get @conf/GLOBAL-CONFIG :board-disabled-message)}))) ;; No url params -> we redirect to documentation about params (when (empty? prms) (throw (ex-info "302" @@ -171,7 +172,7 @@ ;; There shouldn't be any problems with this mime type but if there are ;; replace with "text/xml", or even better, get RSS reader that is not utter shit :header {"Content-Type" "application/rss+xml"} - :body (generate-feed queries real-chod repeat? (watcher/get-thread-data board @watcher/GLOBAL-CONFIG) board-config)}) + :body (generate-feed queries real-chod repeat? (watcher/get-thread-data board @conf/GLOBAL-CONFIG) board-config)}) (catch Exception e ;; Ex-info has been crafted to match HTTP response body so we can send it (if-let [caught (ex-data e)] diff --git a/src/rss_thread_watch/watcher.clj b/src/rss_thread_watch/watcher.clj index e87058a..ebee19a 100644 --- a/src/rss_thread_watch/watcher.clj +++ b/src/rss_thread_watch/watcher.clj @@ -18,12 +18,6 @@ [clojure.data.json :as js]) (:gen-class)) -(def GLOBAL-CONFIG - "Global config with defaults for missing entires" - ;; I know globals are ew in Clojure but I don't know any - ;; better way of doing this - (atom nil)) - (def chod-threads-cache "Cached map of threads that have CHanceOfDeath > configured" (atom {}))