1use std::path::PathBuf;
4
5#[derive(Debug)]
10pub struct Config {
11 pub host: String,
12 pub port: u16,
13 pub files_dir: PathBuf,
14 pub database_path: String,
15 pub default_ttl_hours: u32,
16 pub max_ttl_hours: u32,
17 pub max_file_size_bytes: u64,
18 pub rate_limit_per_minute: u32,
19 pub db_pool_size: u32,
20 pub public_base_url: String,
21 pub log_level: String,
22 pub cleanup_interval_minutes: u64,
23 pub juicehost_api_key: String,
24 pub juicehost_url: String,
25 pub juiceback_origin: String,
26 pub jwt_secret: String,
27}
28
29impl Config {
30 pub fn load() -> Result<Self, String> {
50 let host = std::env::var("HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
51 let port = std::env::var("PORT")
52 .unwrap_or_else(|_| "6401".to_string())
53 .parse::<u16>()
54 .map_err(|e| format!("Invalid PORT: {}", e))?;
55
56 let files_dir = PathBuf::from(std::env::var("FILES_DIR").unwrap_or_else(|_| "./files".to_string()));
57
58 let database_path = std::env::var("DATABASE_PATH").unwrap_or_else(|_| "./delta.db".to_string());
59
60 let default_ttl_hours = std::env::var("DEFAULT_TTL_HOURS")
61 .unwrap_or_else(|_| "72".to_string())
62 .parse::<u32>()
63 .map_err(|e| format!("Invalid DEFAULT_TTL_HOURS: {}", e))?;
64
65 let max_ttl_hours = std::env::var("MAX_TTL_HOURS")
66 .unwrap_or_else(|_| "168".to_string())
67 .parse::<u32>()
68 .map_err(|e| format!("Invalid MAX_TTL_HOURS: {}", e))?;
69
70 let max_file_size_mb = std::env::var("MAX_FILE_SIZE_MB")
71 .unwrap_or_else(|_| "500".to_string())
72 .parse::<u64>()
73 .map_err(|e| format!("Invalid MAX_FILE_SIZE_MB: {}", e))?;
74 let max_file_size_bytes = max_file_size_mb * 1024 * 1024;
75
76 let rate_limit_per_minute = std::env::var("RATE_LIMIT_PER_MINUTE")
77 .unwrap_or_else(|_| "10".to_string())
78 .parse::<u32>()
79 .map_err(|e| format!("Invalid RATE_LIMIT_PER_MINUTE: {}", e))?;
80
81 let db_pool_size = std::env::var("DB_POOL_SIZE")
82 .unwrap_or_else(|_| "8".to_string())
83 .parse::<u32>()
84 .map_err(|e| format!("Invalid DB_POOL_SIZE: {}", e))?;
85
86 let public_base_url = std::env::var("PUBLIC_BASE_URL")
87 .unwrap_or_else(|_| "http://localhost:6402".to_string())
88 .trim_end_matches('/')
89 .to_string();
90
91 let log_level = std::env::var("LOG_LEVEL").unwrap_or_else(|_| "info".to_string());
92
93 let cleanup_interval_minutes = std::env::var("CLEANUP_INTERVAL_MINUTES")
94 .unwrap_or_else(|_| "30".to_string())
95 .parse::<u64>()
96 .map_err(|e| format!("Invalid CLEANUP_INTERVAL_MINUTES: {}", e))?;
97
98 let juicehost_api_key = std::env::var("JUICEHOST_API_KEY").unwrap_or_else(|_| {
99 tracing::warn!("JUICEHOST_API_KEY not set, internal API endpoints are unprotected");
100 String::new()
101 });
102
103 let juicehost_url = std::env::var("JUICEHOST_URL")
104 .unwrap_or_else(|_| "http://127.0.0.1:6402".to_string())
105 .trim_end_matches('/')
106 .to_string();
107
108 let juiceback_origin = std::env::var("JUICEBACK_ORIGIN")
109 .unwrap_or_else(|_| format!("http://{}:{}", host, port))
110 .trim_end_matches('/')
111 .to_string();
112
113 let jwt_secret = std::env::var("JWT_SECRET").unwrap_or_else(|_| {
114 let generated = uuid::Uuid::new_v4().to_string();
115 tracing::warn!(
116 "JWT_SECRET not set, using generated random secret (admins will be invalidated on restart)"
117 );
118 generated
119 });
120
121 Ok(Self {
122 host,
123 port,
124 files_dir,
125 database_path,
126 default_ttl_hours,
127 max_ttl_hours,
128 max_file_size_bytes,
129 rate_limit_per_minute,
130 db_pool_size,
131 public_base_url,
132 log_level,
133 cleanup_interval_minutes,
134 juicehost_api_key,
135 juicehost_url,
136 juiceback_origin,
137 jwt_secret,
138 })
139 }
140}