From af3f5430a0b0f1834228b28fd89848959512e718 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Mon, 12 Sep 2022 15:30:19 +0200 Subject: Use configuration for environment variables --- Cargo.lock | 166 +++++++++++++++++++++++++++++++++++++++++++++++----- Cargo.toml | 3 + src/config.rs | 38 ++++++++++-- src/db.rs | 3 +- src/files.rs | 8 +-- src/logger.rs | 3 +- src/main.rs | 19 ++++-- src/models/auth.rs | 2 +- src/models/model.rs | 6 +- src/models/user.rs | 6 +- src/routes/model.rs | 3 +- 11 files changed, 216 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c98ff4b..0900b7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "async-compression" version = "0.3.14" @@ -85,7 +91,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" dependencies = [ - "num-traits", + "num-traits 0.2.15", ] [[package]] @@ -116,7 +122,7 @@ dependencies = [ "multer", "percent-encoding", "pin-project-lite", - "serde", + "serde 1.0.144", "serde_json", "serde_urlencoded", "sync_wrapper", @@ -231,13 +237,29 @@ dependencies = [ "iana-time-zone", "js-sys", "num-integer", - "num-traits", - "serde", + "num-traits 0.2.15", + "serde 1.0.144", "time 0.1.44", "wasm-bindgen", "winapi", ] +[[package]] +name = "config" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" +dependencies = [ + "lazy_static", + "nom 5.1.2", + "rust-ini", + "serde 1.0.144", + "serde-hjson", + "serde_json", + "toml", + "yaml-rust", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -338,6 +360,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dotenvy" version = "0.15.1" @@ -687,7 +715,7 @@ dependencies = [ "base64", "pem", "ring", - "serde", + "serde 1.0.144", "serde_json", "simple_asn1", ] @@ -698,12 +726,41 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +[[package]] +name = "linked-hash-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" +dependencies = [ + "serde 0.8.23", + "serde_test", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lock_api" version = "0.4.7" @@ -801,6 +858,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "nom" version = "7.1.1" @@ -819,7 +887,7 @@ checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", "num-integer", - "num-traits", + "num-traits 0.2.15", ] [[package]] @@ -829,7 +897,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", - "num-traits", + "num-traits 0.2.15", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.15", ] [[package]] @@ -1112,6 +1189,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + [[package]] name = "rustls" version = "0.20.6" @@ -1155,6 +1238,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" + [[package]] name = "serde" version = "1.0.144" @@ -1164,6 +1253,19 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-hjson" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" +dependencies = [ + "lazy_static", + "linked-hash-map 0.3.0", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + [[package]] name = "serde_derive" version = "1.0.144" @@ -1183,7 +1285,16 @@ checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "itoa", "ryu", - "serde", + "serde 1.0.144", +] + +[[package]] +name = "serde_test" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" +dependencies = [ + "serde 0.8.23", ] [[package]] @@ -1195,7 +1306,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde", + "serde 1.0.144", ] [[package]] @@ -1268,7 +1379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", - "num-traits", + "num-traits 0.2.15", "thiserror", "time 0.3.13", ] @@ -1308,7 +1419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" dependencies = [ "itertools", - "nom", + "nom 7.1.1", "unicode_categories", ] @@ -1361,7 +1472,7 @@ dependencies = [ "rand", "rustls", "rustls-pemfile", - "serde", + "serde 1.0.144", "serde_json", "sha-1", "sha2 0.10.2", @@ -1407,6 +1518,12 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" version = "0.1.2" @@ -1580,6 +1697,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde 1.0.144", +] + [[package]] name = "tower" version = "0.4.13" @@ -1766,7 +1892,7 @@ dependencies = [ "idna", "lazy_static", "regex", - "serde", + "serde 1.0.144", "serde_derive", "serde_json", "url", @@ -1812,11 +1938,14 @@ dependencies = [ "async-trait", "axum", "chrono", + "config", + "dotenv", "http-body", "jsonwebtoken", + "lazy_static", "once_cell", "rand", - "serde", + "serde 1.0.144", "serde_json", "sha256", "sqlx", @@ -2012,3 +2141,12 @@ name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map 0.5.6", +] diff --git a/Cargo.toml b/Cargo.toml index 736ec20..0cf6a32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,6 @@ sha256 = "1.0.3" validator = { version = "0.16.0", features = ["derive"] } chrono = { version = "0.4", features = ["serde"] } rand = "0.8.5" +dotenv = "0.15.0" +config = "0.10" +lazy_static = "1.4.0" diff --git a/src/config.rs b/src/config.rs index 02ae63d..7e67214 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,34 @@ -// TODO: Everything here must be a std::env +pub use config::ConfigError; +use lazy_static::lazy_static; +use serde::Deserialize; -pub static PAGE_LIMIT: i64 = 20; -pub const MAX_UPLOAD_FILE_SIZE: u64 = 1024 * 1024; // 1 MB -pub const SAVE_FILE_BASE_PATH: &str = "./uploads"; -pub const UPLOADS_ENDPOINT: &str = "/uploads"; +// pub static PAGE_LIMIT: i64 = std::env::var("PAGE_LIMIT") +// .unwrap_or_else(|_| "20".to_string()) +// .parse::() +// .unwrap(); +// pub const MAX_UPLOAD_FILE_SIZE: u64 = 1024 * 1024; // 1 MB +// pub const SAVE_FILE_BASE_PATH: &str = &std::env::var("SAVE_FILE_BASE_PATH").unwrap(); +// pub const UPLOADS_ENDPOINT: &str = &std::env::var("UPLOADS_ENDPOINT").unwrap(); + +#[derive(Deserialize)] +pub struct Configuration { + pub page_limit: i64, + pub save_file_base_path: String, + pub uploads_endpoint: String, + pub rust_log: String, + pub database_url: String, + pub jwt_secret: String, + pub allowed_host: String, +} + +impl Configuration { + pub fn new() -> Result { + let mut cfg = config::Config::new(); + cfg.merge(config::Environment::default())?; + cfg.try_into() + } +} + +lazy_static! { + pub static ref CONFIG: Configuration = Configuration::new().expect("Config can be loaded"); +} diff --git a/src/db.rs b/src/db.rs index 43c3bd9..f157187 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,8 +9,7 @@ static mut CONNECTION: Option = None; /// Setup database connection. Get variable `DATABASE_URL` from the environment. Sqlx crate already /// defines an error for environments without DATABASE_URL. pub async fn setup() -> Result<(), AppError> { - let database_url = - std::env::var("DATABASE_URL").expect("Define `DATABASE_URL` environment variable."); + let database_url = &crate::config::CONFIG.database_url; unsafe { CONNECTION = Some(PgPool::connect(&database_url).await?); diff --git a/src/files.rs b/src/files.rs index 616a75d..73e0497 100644 --- a/src/files.rs +++ b/src/files.rs @@ -1,4 +1,4 @@ -use crate::config::{SAVE_FILE_BASE_PATH, UPLOADS_ENDPOINT}; +use crate::config::CONFIG; use crate::errors::AppError; use axum::{ extract::{Multipart, Path}, @@ -30,8 +30,8 @@ pub async fn upload( { let rnd = (random::() * 1000000000 as f32) as i32; - let save_filename = format!("{}/{}.{}", SAVE_FILE_BASE_PATH, rnd, ext_name); - uploaded_file = format!("{}/{}.{}", UPLOADS_ENDPOINT, rnd, ext_name); + let save_filename = format!("{}/{}.{}", CONFIG.save_file_base_path, rnd, ext_name); + uploaded_file = format!("{}/{}.{}", CONFIG.uploads_endpoint, rnd, ext_name); let data = file.bytes().await.unwrap(); @@ -70,6 +70,6 @@ pub async fn show_uploads(Path(id): Path) -> (HeaderMap, Vec) { HeaderValue::from_str(&content_type).unwrap(), ); } - let file_name = format!("{}/{}", SAVE_FILE_BASE_PATH, id); + let file_name = format!("{}/{}", CONFIG.save_file_base_path, id); (headers, read(&file_name).unwrap()) } diff --git a/src/logger.rs b/src/logger.rs index 151803f..3f3ff0f 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -4,8 +4,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub fn setup() { tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new( - std::env::var("RUST_LOG") - .unwrap_or_else(|_| "verden=debug,tower_http=debug".into()), + crate::config::CONFIG.rust_log.clone(), )) .with(tracing_subscriber::fmt::layer()) .init(); diff --git a/src/main.rs b/src/main.rs index c20f667..39c6738 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,13 +7,14 @@ mod models; mod pagination; mod routes; -use crate::config::UPLOADS_ENDPOINT; +use crate::config::CONFIG; use axum::{ handler::Handler, http::{header, Request}, routing::get, Router, }; +use std::net::{SocketAddr, ToSocketAddrs}; use std::time::Duration; use tower_http::sensitive_headers::SetSensitiveHeadersLayer; use tower_http::{classify::ServerErrorsFailureClass, trace::TraceLayer}; @@ -24,11 +25,19 @@ use tracing::Span; async fn main() { let app = create_app().await; - // By default the server is bind at "127.0.0.1:3000" - let addr = std::env::var("ALLOWED_HOST").unwrap_or_else(|_| "127.0.0.1:3000".to_string()); + let host = &CONFIG.allowed_host; + let addr = match host.parse::() { + Ok(addr) => addr, + Err(_) => match host.to_socket_addrs() { + Ok(mut addr) => addr.next().unwrap(), + Err(e) => { + panic!("{}", e); + } + }, + }; tracing::info!("Listening on {}", addr); - axum::Server::bind(&addr.parse().unwrap()) + axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); @@ -46,7 +55,7 @@ async fn create_app() -> Router { Router::new() .route( - &format!("{}/:id", UPLOADS_ENDPOINT), + &format!("{}/:id", CONFIG.uploads_endpoint), get(crate::files::show_uploads), ) // Map all routes to `/v1/*` namespace diff --git a/src/models/auth.rs b/src/models/auth.rs index 36a0175..8a70244 100644 --- a/src/models/auth.rs +++ b/src/models/auth.rs @@ -40,7 +40,7 @@ pub struct LoginCredentials { } static KEYS: Lazy = Lazy::new(|| { - let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); + let secret = &crate::config::CONFIG.jwt_secret; Keys::new(secret.as_bytes()) }); diff --git a/src/models/model.rs b/src/models/model.rs index 5b47f5c..f686192 100644 --- a/src/models/model.rs +++ b/src/models/model.rs @@ -1,4 +1,4 @@ -use crate::config::PAGE_LIMIT; +use crate::config::CONFIG; use crate::db::get_client; use crate::errors::AppError; @@ -163,8 +163,8 @@ impl Model { GROUP BY models.id, users.id LIMIT $1 OFFSET $2 "#, - PAGE_LIMIT, - PAGE_LIMIT * page + CONFIG.page_limit, + CONFIG.page_limit * page ) .fetch_all(pool) .await?; diff --git a/src/models/user.rs b/src/models/user.rs index 22bd130..55abc97 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -1,4 +1,4 @@ -use crate::config::PAGE_LIMIT; +use crate::config::CONFIG; use crate::db::get_client; use crate::errors::AppError; @@ -121,8 +121,8 @@ impl User { r#"SELECT id, email, username, is_staff FROM users LIMIT $1 OFFSET $2 "#, - PAGE_LIMIT, - PAGE_LIMIT * page + CONFIG.page_limit, + CONFIG.page_limit * page ) .fetch_all(pool) .await?; diff --git a/src/routes/model.rs b/src/routes/model.rs index d1ac197..34e896d 100644 --- a/src/routes/model.rs +++ b/src/routes/model.rs @@ -1,4 +1,3 @@ -use crate::config::MAX_UPLOAD_FILE_SIZE; use crate::errors::AppError; use crate::files::upload; use crate::models::{ @@ -69,7 +68,7 @@ async fn get_model(Path(model_id): Path) -> Result, AppErro async fn upload_model_file( claims: Claims, Path(model_id): Path, - ContentLengthLimit(multipart): ContentLengthLimit, + ContentLengthLimit(multipart): ContentLengthLimit, ) -> Result, AppError> { let model = match Model::find_by_id(model_id).await { Ok(model) => model, -- cgit v1.2.3-71-g8e6c