Implement compression quota refunds and admin manual subscription
This commit is contained in:
161
src/config.rs
Normal file
161
src/config.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
use crate::error::{AppError, ErrorCode};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub role: String,
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
pub public_base_url: String,
|
||||
|
||||
pub database_url: String,
|
||||
pub database_max_connections: u32,
|
||||
|
||||
pub redis_url: String,
|
||||
|
||||
pub jwt_secret: String,
|
||||
pub jwt_expiry_hours: i64,
|
||||
|
||||
pub api_key_pepper: String,
|
||||
|
||||
pub billing_provider: String,
|
||||
pub stripe_secret_key: Option<String>,
|
||||
pub stripe_webhook_secret: Option<String>,
|
||||
|
||||
pub storage_type: String,
|
||||
pub storage_path: String,
|
||||
pub signed_url_ttl_minutes: u64,
|
||||
|
||||
pub allow_anonymous_upload: bool,
|
||||
pub anon_max_file_size_mb: u64,
|
||||
pub anon_max_files_per_batch: u32,
|
||||
pub anon_daily_units: u32,
|
||||
pub anon_retention_hours: u64,
|
||||
|
||||
pub max_image_pixels: u64,
|
||||
pub idempotency_ttl_hours: u64,
|
||||
|
||||
pub mail_enabled: bool,
|
||||
pub mail_log_links_when_disabled: bool,
|
||||
pub mail_provider: String,
|
||||
pub mail_from: String,
|
||||
pub mail_password: String,
|
||||
pub mail_from_name: String,
|
||||
pub mail_smtp_host: Option<String>,
|
||||
pub mail_smtp_port: Option<u16>,
|
||||
pub mail_smtp_encryption: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_env() -> Result<Self, AppError> {
|
||||
let role = env_string("IMAGEFORGE_ROLE").unwrap_or_else(|| "api".to_string());
|
||||
let host = env_string("HOST").unwrap_or_else(|| "0.0.0.0".to_string());
|
||||
let port = env_u16("PORT").unwrap_or(8080);
|
||||
let public_base_url =
|
||||
env_string("PUBLIC_BASE_URL").unwrap_or_else(|| "http://localhost:8080".to_string());
|
||||
|
||||
let database_url = env_string("DATABASE_URL")
|
||||
.ok_or_else(|| AppError::new(ErrorCode::InvalidRequest, "缺少环境变量 DATABASE_URL"))?;
|
||||
let database_max_connections = env_u32("DATABASE_MAX_CONNECTIONS").unwrap_or(10);
|
||||
|
||||
let redis_url = env_string("REDIS_URL")
|
||||
.ok_or_else(|| AppError::new(ErrorCode::InvalidRequest, "缺少环境变量 REDIS_URL"))?;
|
||||
|
||||
let jwt_secret = env_string("JWT_SECRET")
|
||||
.ok_or_else(|| AppError::new(ErrorCode::InvalidRequest, "缺少环境变量 JWT_SECRET"))?;
|
||||
let jwt_expiry_hours = env_i64("JWT_EXPIRY_HOURS").unwrap_or(168);
|
||||
|
||||
let api_key_pepper = env_string("API_KEY_PEPPER")
|
||||
.ok_or_else(|| AppError::new(ErrorCode::InvalidRequest, "缺少环境变量 API_KEY_PEPPER"))?;
|
||||
|
||||
let billing_provider =
|
||||
env_string("BILLING_PROVIDER").unwrap_or_else(|| "stripe".to_string());
|
||||
let stripe_secret_key = env_string("STRIPE_SECRET_KEY");
|
||||
let stripe_webhook_secret = env_string("STRIPE_WEBHOOK_SECRET");
|
||||
|
||||
let storage_type = env_string("STORAGE_TYPE").unwrap_or_else(|| "local".to_string());
|
||||
let storage_path = env_string("STORAGE_PATH").unwrap_or_else(|| "./uploads".to_string());
|
||||
let signed_url_ttl_minutes = env_u64("SIGNED_URL_TTL_MINUTES").unwrap_or(60);
|
||||
|
||||
let allow_anonymous_upload = env_bool("ALLOW_ANONYMOUS_UPLOAD").unwrap_or(true);
|
||||
let anon_max_file_size_mb = env_u64("ANON_MAX_FILE_SIZE_MB").unwrap_or(5);
|
||||
let anon_max_files_per_batch = env_u32("ANON_MAX_FILES_PER_BATCH").unwrap_or(5);
|
||||
let anon_daily_units = env_u32("ANON_DAILY_UNITS").unwrap_or(10);
|
||||
let anon_retention_hours = env_u64("ANON_RETENTION_HOURS").unwrap_or(24);
|
||||
|
||||
let max_image_pixels = env_u64("MAX_IMAGE_PIXELS").unwrap_or(40_000_000);
|
||||
let idempotency_ttl_hours = env_u64("IDEMPOTENCY_TTL_HOURS").unwrap_or(24);
|
||||
|
||||
let mail_enabled = env_bool("MAIL_ENABLED").unwrap_or(false);
|
||||
let mail_log_links_when_disabled = env_bool("MAIL_LOG_LINKS_WHEN_DISABLED").unwrap_or(false);
|
||||
let mail_provider = env_string("MAIL_PROVIDER").unwrap_or_else(|| "qq".to_string());
|
||||
let mail_from = env_string("MAIL_FROM").unwrap_or_else(|| "noreply@example.com".to_string());
|
||||
let mail_password = env_string("MAIL_PASSWORD").unwrap_or_default();
|
||||
let mail_from_name = env_string("MAIL_FROM_NAME").unwrap_or_else(|| "ImageForge".to_string());
|
||||
let mail_smtp_host = env_string("MAIL_SMTP_HOST");
|
||||
let mail_smtp_port = env_u16("MAIL_SMTP_PORT");
|
||||
let mail_smtp_encryption = env_string("MAIL_SMTP_ENCRYPTION");
|
||||
|
||||
Ok(Self {
|
||||
role,
|
||||
host,
|
||||
port,
|
||||
public_base_url,
|
||||
database_url,
|
||||
database_max_connections,
|
||||
redis_url,
|
||||
jwt_secret,
|
||||
jwt_expiry_hours,
|
||||
api_key_pepper,
|
||||
billing_provider,
|
||||
stripe_secret_key,
|
||||
stripe_webhook_secret,
|
||||
storage_type,
|
||||
storage_path,
|
||||
signed_url_ttl_minutes,
|
||||
allow_anonymous_upload,
|
||||
anon_max_file_size_mb,
|
||||
anon_max_files_per_batch,
|
||||
anon_daily_units,
|
||||
anon_retention_hours,
|
||||
max_image_pixels,
|
||||
idempotency_ttl_hours,
|
||||
mail_enabled,
|
||||
mail_log_links_when_disabled,
|
||||
mail_provider,
|
||||
mail_from,
|
||||
mail_password,
|
||||
mail_from_name,
|
||||
mail_smtp_host,
|
||||
mail_smtp_port,
|
||||
mail_smtp_encryption,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn env_string(key: &str) -> Option<String> {
|
||||
std::env::var(key).ok().filter(|value| !value.trim().is_empty())
|
||||
}
|
||||
|
||||
fn env_u16(key: &str) -> Option<u16> {
|
||||
env_string(key).and_then(|v| v.parse::<u16>().ok())
|
||||
}
|
||||
|
||||
fn env_u32(key: &str) -> Option<u32> {
|
||||
env_string(key).and_then(|v| v.parse::<u32>().ok())
|
||||
}
|
||||
|
||||
fn env_i64(key: &str) -> Option<i64> {
|
||||
env_string(key).and_then(|v| v.parse::<i64>().ok())
|
||||
}
|
||||
|
||||
fn env_u64(key: &str) -> Option<u64> {
|
||||
env_string(key).and_then(|v| v.parse::<u64>().ok())
|
||||
}
|
||||
|
||||
fn env_bool(key: &str) -> Option<bool> {
|
||||
env_string(key).and_then(|v| match v.trim().to_ascii_lowercase().as_str() {
|
||||
"1" | "true" | "yes" | "y" | "on" => Some(true),
|
||||
"0" | "false" | "no" | "n" | "off" => Some(false),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user