Refactor configuration loading.

This commit is contained in:
Andrey Antukh 2017-01-22 15:50:00 +01:00
parent 3092884525
commit 5a641e4629
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
12 changed files with 125 additions and 89 deletions

2
.gitignore vendored
View file

@ -10,7 +10,7 @@ pom.xml
.nrepl-port .nrepl-port
node_modules node_modules
/backend/target/ /backend/target/
/backend/resources/public/media /backend/resources/media
/backend/dist/ /backend/dist/
/frontend/target/ /frontend/target/
/frontend/dist/ /frontend/dist/

View file

@ -15,6 +15,8 @@
[funcool/suricatta "1.3.1"] [funcool/suricatta "1.3.1"]
[funcool/promesa "1.7.0"] [funcool/promesa "1.7.0"]
[funcool/catacumba "2.0.0-SNAPSHOT"] [funcool/catacumba "2.0.0-SNAPSHOT"]
[funcool/cuerdas "2.0.2"]
[funcool/datoteka "1.0.0-SNAPSHOT"]
[org.clojure/data.xml "0.1.0-beta2"] [org.clojure/data.xml "0.1.0-beta2"]
[org.jsoup/jsoup "1.10.2"] [org.jsoup/jsoup "1.10.2"]
@ -27,6 +29,7 @@
:exclusions [org.clojure/tools.reader]] :exclusions [org.clojure/tools.reader]]
[niwinz/migrante "0.1.0"] [niwinz/migrante "0.1.0"]
[buddy/buddy-sign "1.3.0" :exclusions [org.clojure/tools.reader]] [buddy/buddy-sign "1.3.0" :exclusions [org.clojure/tools.reader]]
[buddy/buddy-hashers "1.1.0"] [buddy/buddy-hashers "1.1.0"]

View file

@ -2,37 +2,69 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2017 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.config (ns uxbox.config
"A configuration management." "A configuration management."
(:require [mount.core :refer [defstate]] (:require [clojure.java.io :as io]
[environ.core :refer (env)] [clojure.tools.logging :as log]
[buddy.core.hash :as hash]
[clojure.java.io :as io]
[clojure.edn :as edn] [clojure.edn :as edn]
[cuerdas.core :as str]
[buddy.core.hash :as hash]
[environ.core :refer [env]]
[mount.core :refer [defstate]]
[uxbox.util.exceptions :as ex] [uxbox.util.exceptions :as ex]
[uxbox.util.data :refer [deep-merge]])) [uxbox.util.data :refer [deep-merge]]))
;; --- Configuration Loading & Parsing ;; --- Configuration Reading & Loading
(def ^:dynamic *default-config-path* "config/default.edn") (defn lookup-env
(def ^:dynamic *local-config-path* "config/local.edn") [env key default]
(let [value (get env key ::empty)]
(if (= value ::empty)
default
(try
(read-string value)
(catch Exception e
(log/warn (str/istr "can't parse `~{key}` env value"))
default)))))
;; --- Configuration Loading & Parsing
(defn read-config (defn read-config
[] []
(let [builtin (io/resource *default-config-path*) {:http-server-port (lookup-env env :uxbox-http-server-port 6060)
local (io/resource *local-config-path*) :http-server-debug (lookup-env env :uxbox-http-server-debug true)
external (io/file (:uxbox-config env))] :database-username (lookup-env env :uxbox-database-username "")
(deep-merge (edn/read-string (slurp builtin)) :database-password (lookup-env env :uxbox-database-password "")
(when local (edn/read-string (slurp local))) :database-name (lookup-env env :uxbox-database-name "uxbox")
(when (and external (.exists external)) :database-server (lookup-env env :uxbox-database-server "localhost")
(edn/read-string (slurp external)))))) :database-port (lookup-env env :uxbox-database-port 5432)
:media-directory (lookup-env env :uxbox-media-directory "media")
:media-uri (lookup-env env :uxbox-media-uri "http://localhost:6060/media/")
:assets-directory (lookup-env env :uxbox-assets-directory "static")
:assets-uri (lookup-env env :uxbox-assets-uri "http://localhost:6060/static/")
:email-reply-to (lookup-env env :uxbox-email-reply-to "no-reply@uxbox.io")
:email-from (lookup-env env :uxbox-email-from "no-reply@uxbox.io")
:smtp-host (lookup-env env :uxbox-smtp-host "localhost")
:smtp-port (lookup-env env :uxbox-smtp-port 25)
:smtp-user (lookup-env env :uxbox-smtp-user nil)
:smtp-password (lookup-env env :uxbox-smtp-password nil)
:smtp-tls (lookup-env env :uxbox-smtp-tls false)
:smtp-ssl (lookup-env env :uxbox-smtp-ssl false)
:smtp-enabled (lookup-env env :uxbox-smtp-enabled false)
:secret (lookup-env env :uxbox-secret "5qjiAndGY3")})
(defn read-test-config (defn read-test-config
[] []
(binding [*local-config-path* "config/test.edn"] (assoc (read-config)
(read-config))) :database-name "test"
:media-directory "/tmp/uxbox/media"
:assets-directory "/tmp/uxbox/static"
:migrations-verbose false))
(defstate config (defstate config
:start (read-config)) :start (read-config))

View file

@ -21,7 +21,7 @@
;; --- State ;; --- State
(def ^:const +defaults+ (def connection-defaults
{:connection-timeout 30000 {:connection-timeout 30000
:idle-timeout 600000 :idle-timeout 600000
:max-lifetime 1800000 :max-lifetime 1800000
@ -34,9 +34,18 @@
:server-name "localhost" :server-name "localhost"
:port-number 5432}) :port-number 5432})
(defn get-db-config
[config]
(assoc connection-defaults
:username (:database-username config)
:password (:database-password config)
:database-name (:database-name config)
:server-name (:database-server config)
:port-number (:database-port config)))
(defn create-datasource (defn create-datasource
[config] [config]
(let [dbconf (merge +defaults+ config)] (let [dbconf (get-db-config config)]
(hikari/make-datasource dbconf))) (hikari/make-datasource dbconf)))
(defstate datasource (defstate datasource

View file

@ -5,8 +5,8 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.emails.core (ns uxbox.emails.core
(:require [hiccup.core :refer (html)] (:require [hiccup.core :refer [html]]
[hiccup.page :refer (html4)] [hiccup.page :refer [html4]]
[suricatta.core :as sc] [suricatta.core :as sc]
[uxbox.db :as db] [uxbox.db :as db]
[uxbox.config :as cfg] [uxbox.config :as cfg]
@ -49,11 +49,10 @@
(defn render-email (defn render-email
[email context] [email context]
(let [config (:email cfg/config) (let [from (or (:email/from context)
from (or (:email/from context) (:email-from cfg/config))
(:from config))
reply-to (or (:email/reply-to context) reply-to (or (:email/reply-to context)
(:reply-to config) (:email-reply-to cfg/config)
from)] from)]
{:subject (render-subject email context) {:subject (render-subject email context)
:body (render-body-alternatives email context) :body (render-body-alternatives email context)

View file

@ -2,7 +2,7 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016-2017 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.frontend (ns uxbox.frontend
(:require [mount.core :refer [defstate]] (:require [mount.core :refer [defstate]]
@ -23,6 +23,7 @@
[uxbox.frontend.kvstore :as kvstore] [uxbox.frontend.kvstore :as kvstore]
[uxbox.frontend.svgparse :as svgparse] [uxbox.frontend.svgparse :as svgparse]
[uxbox.frontend.debug-emails :as dbgemails] [uxbox.frontend.debug-emails :as dbgemails]
[uxbox.services.auth :refer [auth-opts]]
[uxbox.util.response :refer [rsp]] [uxbox.util.response :refer [rsp]]
[uxbox.util.uuid :as uuid])) [uxbox.util.uuid :as uuid]))
@ -56,14 +57,16 @@
([] (routes cfg/config)) ([] (routes cfg/config))
([config] ([config]
(let [auth-opts {:secret cfg/secret (let [auth-opts {:secret cfg/secret
:options (:auth-options cfg/config)}] :options auth-opts}]
(ct/routes (ct/routes
[[:any (cauth/auth (cauth/jwe-backend auth-opts))] [[:any (cauth/auth (cauth/jwe-backend auth-opts))]
[:any (cmisc/autoreloader)] [:any (cmisc/autoreloader)]
[:get "api" #'welcome-api] [:get "api" #'welcome-api]
[:assets "media" {:dir "public/media"}]
[:assets "static" {:dir "public/static"}] ;; Serve assets on development server
[:assets "media" {:dir "media"}]
[:assets "static" {:dir "static"}]
[:prefix "debug" [:prefix "debug"
[:any debug-only] [:any debug-only]
@ -148,7 +151,9 @@
(defn- start-server (defn- start-server
[config] [config]
(let [config (:http config)] (let [config {:port (:http-server-port config)
:debug (:http-server-debug config)
:max-body-size 52428800}]
(ct/run-server (routes config) config))) (ct/run-server (routes config) config)))
(defstate server (defstate server

View file

@ -5,6 +5,7 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main (ns uxbox.main
(:refer-clojure :exclude [test])
(:require [clojure.tools.namespace.repl :as repl] (:require [clojure.tools.namespace.repl :as repl]
[clojure.walk :refer [macroexpand-all]] [clojure.walk :refer [macroexpand-all]]
[clojure.pprint :refer [pprint]] [clojure.pprint :refer [pprint]]
@ -27,6 +28,10 @@
[] []
(mount/start)) (mount/start))
(defn- stop
[]
(mount/stop))
(defn- start-minimal (defn- start-minimal
[] []
(-> (mount/only #{#'uxbox.config/config (-> (mount/only #{#'uxbox.config/config
@ -34,56 +39,25 @@
#'uxbox.migrations/migrations}) #'uxbox.migrations/migrations})
(mount/start))) (mount/start)))
(defn- stop (defn- make-secret
[]
(mount/stop))
(defn- refresh
[]
(stop)
(repl/refresh))
(defn- refresh-all
[]
(stop)
(repl/refresh-all))
(defn- go
"starts all states defined by defstate"
[]
(start)
:ready)
(defn- reset
[]
(stop)
(repl/refresh :after 'uxbox.main/start))
(defn make-secret
[] []
(-> (nonce/random-bytes 64) (-> (nonce/random-bytes 64)
(b64/encode true) (b64/encode true)
(codecs/bytes->str))) (codecs/bytes->str)))
;; --- Entry point (only for uberjar) (defn- test
([] (test #"^uxbox.tests.*"))
(defn test-vars ([o]
[& vars]
(repl/refresh) (repl/refresh)
(test/test-vars (cond
(map (fn [sym] (instance? java.util.regex.Pattern o)
(require (symbol (namespace sym))) (test/run-all-tests o)
(resolve sym))
vars)))
(defn test-ns (symbol? o)
[ns] (if-let [sns (namespace o)]
(repl/refresh) (do (require (symbol sns))
(test/test-ns ns)) (test/test-vars [(resolve o)]))
(test/test-ns o)))))
(defn test-all
([] (test/run-all-tests #"^uxbox.tests.*"))
([re] (test/run-all-tests re)))
;; --- Entry point (only for uberjar) ;; --- Entry point (only for uberjar)

View file

@ -2,7 +2,7 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2017 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.media (ns uxbox.media
"A media storage impl for uxbox." "A media storage impl for uxbox."
@ -14,15 +14,17 @@
[storages.backend.misc :refer (hashed scoped)] [storages.backend.misc :refer (hashed scoped)]
[uxbox.config :refer (config)])) [uxbox.config :refer (config)]))
;; FIXME: migrate from storages to datoteka
;; --- State ;; --- State
(defstate static-storage (defstate assets-storage
:start (let [{:keys [basedir baseuri]} (:static config)] :start (localfs {:basedir (:assets-directory config)
(localfs {:basedir basedir :baseuri baseuri}))) :baseuri (:assets-uri config)}))
(defstate media-storage (defstate media-storage
:start (let [{:keys [basedir baseuri]} (:media config)] :start (localfs {:basedir (:media-directory config)
(localfs {:basedir basedir :baseuri baseuri}))) :baseuri (:media-uri config)}))
(defstate images-storage (defstate images-storage
:start (-> media-storage :start (-> media-storage
@ -36,4 +38,4 @@
(defn resolve-asset (defn resolve-asset
[path] [path]
(str (st/public-url static-storage path))) (str (st/public-url assets-storage path)))

View file

@ -69,7 +69,7 @@
(defn- migrate (defn- migrate
[] []
(let [options (:migrations cfg/config {})] (let [options {:verbose (:migrations-verbose cfg/config true)}]
(with-open [mctx (mg/context db/datasource options)] (with-open [mctx (mg/context db/datasource options)]
(mg/migrate mctx +migrations+) (mg/migrate mctx +migrations+)
nil))) nil)))

View file

@ -65,9 +65,19 @@
(println "********** end email:" id "**********") (println "********** end email:" id "**********")
{:error :SUCCESS}) {:error :SUCCESS})
(defn- get-smtp-config
[config]
{:host (:smtp-host config)
:port (:smtp-port config)
:user (:smtp-user config)
:pass (:smtp-password config)
:ssl (:smtp-ssl config)
:tls (:smtp-tls config)
:noop (not (:smtp-enabled config))})
(defn- send-email (defn- send-email
[{:keys [id data] :as entry}] [{:keys [id data] :as entry}]
(let [config (:smtp cfg/config) (let [config (get-smtp-config cfg/config)
result (if (:noop config) result (if (:noop config)
(send-email-to-console entry) (send-email-to-console entry)
(postal/send-message config data))] (postal/send-message config data))]

View file

@ -17,6 +17,9 @@
[uxbox.services.users :as users] [uxbox.services.users :as users]
[uxbox.util.exceptions :as ex])) [uxbox.util.exceptions :as ex]))
(def auth-opts
{:alg :a256kw :enc :a128cbc-hs256})
;; --- Login ;; --- Login
(defn- check-user-password (defn- check-user-password
@ -25,9 +28,8 @@
(defn generate-token (defn generate-token
[user] [user]
(let [data {:id (:id user)} (let [data {:id (:id user) :scope :auth}]
opts (:auth-options cfg/config)] (jwt/encrypt data cfg/secret auth-opts)))
(jwt/encrypt data cfg/secret opts)))
(s/def ::scope string?) (s/def ::scope string?)
(s/def ::login (s/def ::login

View file

@ -24,7 +24,7 @@
#'uxbox.config/secret #'uxbox.config/secret
#'uxbox.db/datasource #'uxbox.db/datasource
#'uxbox.migrations/migrations #'uxbox.migrations/migrations
#'uxbox.media/static-storage #'uxbox.media/assets-storage
#'uxbox.media/media-storage #'uxbox.media/media-storage
#'uxbox.media/images-storage #'uxbox.media/images-storage
#'uxbox.media/thumbnails-storage}) #'uxbox.media/thumbnails-storage})
@ -53,7 +53,7 @@
(next) (next)
(finally (finally
(st/clear! uxbox.media/media-storage) (st/clear! uxbox.media/media-storage)
(st/clear! uxbox.media/static-storage)))))) (st/clear! uxbox.media/assets-storage))))))
(defmacro await (defmacro await
[expr] [expr]