use std::env; use std::path::PathBuf; use std::str::FromStr; use time::ext::NumericalDuration; use time::Duration; use tokio::fs; #[derive(Clone)] pub struct Config { pub static_dir: PathBuf, pub files_dir: PathBuf, pub max_file_size: Option, pub no_auth_limits: Option, pub enable_rate_limit: bool, pub proxied: bool, pub rate_limit_replenish_seconds: u64, pub rate_limit_burst: u32, } #[derive(Clone)] pub struct NoAuthLimits { pub auth_password: String, pub max_time: Duration, pub large_file_max_time: Duration, pub large_file_size: u64, } pub async fn from_env() -> Config { let max_file_size = env::var("UPLOAD_MAX_BYTES") .ok() .and_then(|variable| variable.parse().ok()) .or(Some(8 * 1024 * 1024)) .filter(|&max_file_size| max_file_size != 0); let static_dir = PathBuf::from(env::var("STATIC_DIR").unwrap_or_else(|_| "./static".to_owned())); let files_dir = PathBuf::from(env::var("FILES_DIR").unwrap_or_else(|_| "./files".to_owned())); fs::create_dir_all(&files_dir) .await .expect("could not create directory for storing files"); let no_auth_limits = get_no_auth_limits(); // default to 480requests/8h let enable_rate_limit = matches!(env::var("RATE_LIMIT").as_deref(), Ok("true") | Err(_)); let proxied = env::var("RATE_LIMIT_PROXIED").as_deref() == Ok("true"); let rate_limit_replenish_seconds = env::var("RATE_LIMIT_REPLENISH_SECONDS") .ok() .and_then(|rate_limit| rate_limit.parse().ok()) .unwrap_or(60); let rate_limit_burst = env::var("RATE_LIMIT_BURST") .ok() .and_then(|burst| burst.parse().ok()) .unwrap_or(480); Config { static_dir, files_dir, max_file_size, no_auth_limits, enable_rate_limit, proxied, rate_limit_replenish_seconds, rate_limit_burst, } } fn get_no_auth_limits() -> Option { match ( env::var("AUTH_PASSWORD").ok(), env_number::("NO_AUTH_MAX_TIME"), env_number::("NO_AUTH_LARGE_FILE_MAX_TIME"), env_number("NO_AUTH_LARGE_FILE_SIZE"), ) { (Some(auth_password), Some(max_time), Some(large_file_max_time), Some(large_file_size)) => { Some(NoAuthLimits { auth_password, max_time: max_time.seconds(), large_file_max_time: large_file_max_time.seconds(), large_file_size, }) } (None, None, None, None) => None, _ => { panic!("Incomplete NO_AUTH configuration: All environment variables must be specified") } } } fn env_number(variable: &str) -> Option { env::var(variable).ok().and_then(|n| n.parse::().ok()) }