Files
kakeibo/backend/src/config.rs
T

137 lines
4.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Ortam değişkenlerinden uygulama ayarlarını okur.
use std::{env, path::PathBuf};
#[derive(Debug, Clone)]
pub struct Config {
pub mongodb_uri: String,
pub jwt_secret: String,
pub app_url: String,
pub port: u16,
pub registration: RegistrationMode,
/// Derlenmiş frontend klasörü (`STATIC_DIR`). Tanımlıysa Axum arayüzü de sunar
/// (canlıda tek servis). Geliştirmede boş: arayüzü Vite sunar.
pub static_dir: Option<PathBuf>,
/// Otomatik kur yenileme aralığı (dakika, `RATES_REFRESH_MINUTES`, varsayılan 60); 0 → kapalı
pub rates_refresh_minutes: u64,
/// Cloudflare Turnstile (`TURNSTILE_SITE_KEY` + `TURNSTILE_SECRET_KEY`); ikisi de yoksa kapalı
pub turnstile_site_key: Option<String>,
pub turnstile_secret_key: Option<String>,
/// Ters vekil arkasında (Dokploy/Traefik) gerçek IP `X-Forwarded-For`'dan (`TRUST_PROXY`, varsayılan açık)
pub trust_proxy: bool,
}
/// Yeni hane kaydı politikası (`REGISTRATION` ortam değişkeni).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegistrationMode {
/// Varsayılan. Sistemde hiç hane yokken ilk kayıt yeni hane kurar;
/// sonrasında yalnızca davet koduyla katılınır.
InviteOnly,
/// Herkes yeni hane kurabilir.
Open,
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("{0} ortam değişkeni tanımlı değil (.env dosyasını kontrol edin)")]
Missing(&'static str),
#[error("{0} geçersiz: {1}")]
Invalid(&'static str, &'static str),
}
impl Config {
pub fn from_env() -> Result<Self, ConfigError> {
let mongodb_uri = required("MONGODB_URI")?;
let jwt_secret = required("JWT_SECRET")?;
if jwt_secret.len() < 32 {
return Err(ConfigError::Invalid(
"JWT_SECRET",
"en az 32 karakter olmalı (openssl rand -hex 32)",
));
}
let app_url = env::var("APP_URL").unwrap_or_else(|_| "http://localhost:5173".into());
let registration = match env::var("REGISTRATION").as_deref() {
Err(_) | Ok("") | Ok("invite_only") => RegistrationMode::InviteOnly,
Ok("open") => RegistrationMode::Open,
Ok(_) => {
return Err(ConfigError::Invalid(
"REGISTRATION",
"\"invite_only\" veya \"open\" olmalı",
));
}
};
let static_dir = env::var("STATIC_DIR")
.ok()
.filter(|v| !v.trim().is_empty())
.map(PathBuf::from);
let port = match env::var("PORT") {
Ok(p) => p
.parse()
.map_err(|_| ConfigError::Invalid("PORT", "sayı olmalı"))?,
Err(_) => 8080,
};
let rates_refresh_minutes = match env::var("RATES_REFRESH_MINUTES") {
Ok(m) if !m.trim().is_empty() => m.trim().parse().map_err(|_| {
ConfigError::Invalid("RATES_REFRESH_MINUTES", "dakika (sayı) olmalı")
})?,
_ => 60,
};
let opt = |k: &str| {
env::var(k)
.ok()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
};
let turnstile_site_key = opt("TURNSTILE_SITE_KEY");
let turnstile_secret_key = opt("TURNSTILE_SECRET_KEY");
if turnstile_site_key.is_some() != turnstile_secret_key.is_some() {
return Err(ConfigError::Invalid(
"TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY",
"ikisi birlikte tanımlanmalı (ya da ikisi de boş)",
));
}
let trust_proxy = match env::var("TRUST_PROXY").as_deref().map(str::trim) {
Err(_) | Ok("") | Ok("true") | Ok("1") => true,
Ok("false") | Ok("0") => false,
Ok(_) => {
return Err(ConfigError::Invalid(
"TRUST_PROXY",
"\"true\" veya \"false\" olmalı",
));
}
};
Ok(Self {
mongodb_uri,
jwt_secret,
app_url,
port,
registration,
static_dir,
rates_refresh_minutes,
turnstile_site_key,
turnstile_secret_key,
trust_proxy,
})
}
/// Cookie'lerde `Secure` bayrağı yalnızca HTTPS'te açılır.
pub fn is_https(&self) -> bool {
self.app_url.starts_with("https://")
}
}
fn required(key: &'static str) -> Result<String, ConfigError> {
env::var(key)
.ok()
.filter(|v| !v.trim().is_empty())
.ok_or(ConfigError::Missing(key))
}