use anyhow::{Context as _, Result}; use axum::extract::FromRef; use config::{Config, Environment}; use dotenvy::dotenv; use serde::Deserialize; use crate::app_state::AppState; #[derive(Clone, Debug, Deserialize)] pub struct Settings { #[serde(default)] pub base_path: String, pub database_url: String, /// When set to 1, embedded Diesel migrations will be run on startup. pub run_database_migrations: Option, #[serde(default = "default_host")] pub host: String, #[serde(default = "default_port")] pub port: u16, pub auth: AuthSettings, pub email: EmailSettings, } fn default_port() -> u16 { 3000 } fn default_host() -> String { "127.0.0.1".to_string() } #[derive(Clone, Debug, Deserialize)] pub struct AuthSettings { pub client_id: String, pub client_secret: String, pub redirect_url: String, pub auth_url: String, pub token_url: String, pub userinfo_url: String, pub logout_url: Option, #[serde(default = "default_cookie_name")] pub cookie_name: String, } fn default_cookie_name() -> String { "SHOUT_DOT_DEV_SESSION".to_string() } #[derive(Clone, Debug, Deserialize)] pub struct SmtpSettings { pub server: String, pub username: String, pub password: String, } #[derive(Clone, Debug, Deserialize)] pub struct PostmarkSettings { pub server_token: String, } #[derive(Clone, Debug, Deserialize)] pub struct EmailSettings { pub verification_from: lettre::message::Mailbox, pub message_from: lettre::message::Mailbox, pub smtp: Option, pub postmark: Option, } pub struct SlackSettings { pub client_id: String, pub client_secret: String, pub redirect_url: String, pub auth_url: String, pub token_url: String, } impl Settings { pub fn load() -> Result { match dotenv() { Err(err) => { if err.not_found() { tracing::info!("no .env file found"); } else { return Err(err).context("dotenvy error"); } } Ok(pathbuf) => { tracing::info!( "using env file {}", pathbuf .to_str() .ok_or(anyhow::anyhow!("pathbuf is not valid unicode"))? ); } } let s = Config::builder() .add_source(Environment::default().separator("__")) .build() .context("config error")?; s.try_deserialize().context("deserialize error") } } impl FromRef for Settings where S: Into + Clone, { fn from_ref(state: &S) -> Self { Into::::into(state.clone()).settings.clone() } }