121 lines
3 KiB
Rust
121 lines
3 KiB
Rust
//! Runtime application configuration values.
|
|
|
|
use anyhow::{Context as _, Result};
|
|
use axum::extract::FromRef;
|
|
use config::{Config, Environment};
|
|
use dotenvy::dotenv;
|
|
use serde::Deserialize;
|
|
use tracing::info;
|
|
use url::Url;
|
|
|
|
use crate::app::App;
|
|
|
|
/// Runtime application configuration values, typically read from environment
|
|
/// variables.
|
|
///
|
|
/// This may be used with the [`axum::extract::State`] extractor.
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
pub(crate) struct Settings {
|
|
/// Prefix under which to nest all routes. If specified, include leading
|
|
/// slash but no trailing slash, for example "/app". For default behavior,
|
|
/// leave as empty string.
|
|
#[serde(default)]
|
|
pub(crate) root_path: String,
|
|
|
|
/// postgresql:// URL for Phonograph's application database.
|
|
pub(crate) database_url: Url,
|
|
|
|
#[serde(default = "default_app_db_max_connections")]
|
|
pub(crate) app_db_max_connections: u32,
|
|
|
|
/// When set to 1, embedded SQLx migrations will be run on startup.
|
|
#[serde(default)]
|
|
pub(crate) run_database_migrations: u8,
|
|
|
|
/// Address for server to bind to
|
|
#[serde(default = "default_host")]
|
|
pub(crate) host: String,
|
|
|
|
/// Port for server to bind to
|
|
#[serde(default = "default_port")]
|
|
pub(crate) port: u16,
|
|
|
|
/// Host visible to end users, for example "https://phono.dev"
|
|
pub(crate) frontend_host: String,
|
|
|
|
pub(crate) auth: AuthSettings,
|
|
}
|
|
|
|
fn default_app_db_max_connections() -> u32 {
|
|
16
|
|
}
|
|
|
|
fn default_port() -> u16 {
|
|
8080
|
|
}
|
|
|
|
fn default_host() -> String {
|
|
"127.0.0.1".to_owned()
|
|
}
|
|
|
|
/// OAuth2 and session cookie settings.
|
|
#[derive(Clone, Debug, Deserialize)]
|
|
pub(crate) struct AuthSettings {
|
|
pub(crate) client_id: String,
|
|
|
|
pub(crate) client_secret: String,
|
|
|
|
pub(crate) auth_url: String,
|
|
|
|
pub(crate) token_url: String,
|
|
|
|
pub(crate) userinfo_url: String,
|
|
|
|
pub(crate) logout_url: Option<String>,
|
|
|
|
#[serde(default = "default_cookie_name")]
|
|
pub(crate) cookie_name: String,
|
|
}
|
|
|
|
fn default_cookie_name() -> String {
|
|
"PHONO_SESSION".to_string()
|
|
}
|
|
|
|
impl Settings {
|
|
/// Load environment variables into a [`Settings`] struct.
|
|
pub(crate) fn load() -> Result<Self> {
|
|
let s = Config::builder()
|
|
.add_source(Environment::default().separator("__"))
|
|
.build()
|
|
.context("config error")?;
|
|
s.try_deserialize().context("deserialize error")
|
|
}
|
|
}
|
|
|
|
impl FromRef<App> for Settings {
|
|
fn from_ref(state: &App) -> Self {
|
|
state.settings.clone()
|
|
}
|
|
}
|
|
|
|
/// Attempt to load environment variables from .env file.
|
|
pub(crate) fn load_dotenv() -> Result<()> {
|
|
dotenv()
|
|
.map(|pathbuf| {
|
|
info!(
|
|
"using env file {0}",
|
|
pathbuf
|
|
.to_str()
|
|
.ok_or(anyhow::anyhow!("pathbuf is not valid unicode"))?
|
|
);
|
|
Ok(())
|
|
})
|
|
.or_else(|err| {
|
|
if err.not_found() {
|
|
info!("no env file loaded");
|
|
Ok(Ok(()))
|
|
} else {
|
|
Err(err)
|
|
}
|
|
})?
|
|
}
|