108 lines
2.7 KiB
Rust
108 lines
2.7 KiB
Rust
|
|
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 {
|
||
|
|
/// 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 base_path: String,
|
||
|
|
|
||
|
|
/// postgresql:// URL.
|
||
|
|
pub database_url: String,
|
||
|
|
|
||
|
|
/// Super-user role the server will use to create new user roles and manage
|
||
|
|
/// database resources.
|
||
|
|
pub pg_root_role: String,
|
||
|
|
|
||
|
|
#[serde(default = "default_pg_user_role_prefix")]
|
||
|
|
pub pg_user_role_prefix: String,
|
||
|
|
|
||
|
|
/// When set to 1, embedded Diesel migrations will be run on startup.
|
||
|
|
pub run_database_migrations: Option<u8>,
|
||
|
|
|
||
|
|
/// Address for server to bind to
|
||
|
|
#[serde(default = "default_host")]
|
||
|
|
pub host: String,
|
||
|
|
|
||
|
|
/// Port for server to bind to
|
||
|
|
#[serde(default = "default_port")]
|
||
|
|
pub port: u16,
|
||
|
|
|
||
|
|
/// Host visible to end users, for example "https://shout.dev"
|
||
|
|
pub frontend_host: String,
|
||
|
|
|
||
|
|
pub auth: AuthSettings,
|
||
|
|
}
|
||
|
|
|
||
|
|
fn default_port() -> u16 {
|
||
|
|
8080
|
||
|
|
}
|
||
|
|
|
||
|
|
fn default_host() -> String {
|
||
|
|
"127.0.0.1".to_owned()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn default_pg_user_role_prefix() -> String {
|
||
|
|
"__interim_user__".to_owned()
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Clone, Debug, Deserialize)]
|
||
|
|
pub struct AuthSettings {
|
||
|
|
pub client_id: String,
|
||
|
|
pub client_secret: String,
|
||
|
|
pub auth_url: String,
|
||
|
|
pub token_url: String,
|
||
|
|
pub userinfo_url: String,
|
||
|
|
pub logout_url: Option<String>,
|
||
|
|
|
||
|
|
#[serde(default = "default_cookie_name")]
|
||
|
|
pub cookie_name: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
fn default_cookie_name() -> String {
|
||
|
|
"INTERIM_SESSION".to_string()
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Settings {
|
||
|
|
pub fn load() -> Result<Self> {
|
||
|
|
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<S> FromRef<S> for Settings
|
||
|
|
where
|
||
|
|
S: Into<AppState> + Clone,
|
||
|
|
{
|
||
|
|
fn from_ref(state: &S) -> Self {
|
||
|
|
Into::<AppState>::into(state.clone()).settings.clone()
|
||
|
|
}
|
||
|
|
}
|