perf: improve compression reliability and deployment safety
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::error::{AppError, ErrorCode};
|
||||
|
||||
static TRUST_PROXY_HEADERS: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub role: String,
|
||||
@@ -13,19 +15,18 @@ pub struct Config {
|
||||
pub redis_url: String,
|
||||
|
||||
pub worker_concurrency: u32,
|
||||
pub image_processing_concurrency: u32,
|
||||
|
||||
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,
|
||||
@@ -67,22 +68,41 @@ impl Config {
|
||||
.map(|v| v.get() as u32)
|
||||
.unwrap_or(4)
|
||||
});
|
||||
let image_processing_concurrency = env_u32("IMAGE_PROCESSING_CONCURRENCY")
|
||||
.filter(|value| *value > 0)
|
||||
.unwrap_or_else(|| {
|
||||
std::thread::available_parallelism()
|
||||
.map(|v| v.get() as u32)
|
||||
.unwrap_or(4)
|
||||
});
|
||||
|
||||
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 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());
|
||||
if !billing_provider.eq_ignore_ascii_case("stripe") {
|
||||
return Err(AppError::new(
|
||||
ErrorCode::InvalidRequest,
|
||||
"BILLING_PROVIDER 目前仅支持 stripe",
|
||||
));
|
||||
}
|
||||
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());
|
||||
if !storage_type.eq_ignore_ascii_case("local") {
|
||||
return Err(AppError::new(
|
||||
ErrorCode::InvalidRequest,
|
||||
"STORAGE_TYPE 目前仅支持 local",
|
||||
));
|
||||
}
|
||||
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);
|
||||
@@ -94,11 +114,14 @@ impl Config {
|
||||
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_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_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_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");
|
||||
@@ -112,15 +135,14 @@ impl Config {
|
||||
database_max_connections,
|
||||
redis_url,
|
||||
worker_concurrency,
|
||||
image_processing_concurrency,
|
||||
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,
|
||||
@@ -142,7 +164,9 @@ impl Config {
|
||||
}
|
||||
|
||||
fn env_string(key: &str) -> Option<String> {
|
||||
std::env::var(key).ok().filter(|value| !value.trim().is_empty())
|
||||
std::env::var(key)
|
||||
.ok()
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
}
|
||||
|
||||
fn env_u16(key: &str) -> Option<u16> {
|
||||
@@ -168,3 +192,7 @@ fn env_bool(key: &str) -> Option<bool> {
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trust_proxy_headers() -> bool {
|
||||
*TRUST_PROXY_HEADERS.get_or_init(|| env_bool("TRUST_PROXY_HEADERS").unwrap_or(false))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user