perf: improve compression reliability and deployment safety

This commit is contained in:
237899745
2026-07-25 10:29:49 +08:00
parent 06220ca921
commit 9d7668bdee
34 changed files with 1391 additions and 1042 deletions

View File

@@ -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))
}