1use crate::facade::DiskConfig;
4#[cfg(feature = "s3")]
5use crate::facade::DiskDriver;
6use std::collections::HashMap;
7use std::env;
8
9#[derive(Debug, Clone)]
11pub struct StorageConfig {
12 pub default: String,
14 pub disks: HashMap<String, DiskConfig>,
16}
17
18impl Default for StorageConfig {
19 fn default() -> Self {
20 let mut disks = HashMap::new();
21 disks.insert("local".to_string(), DiskConfig::local("./storage"));
22
23 Self {
24 default: "local".to_string(),
25 disks,
26 }
27 }
28}
29
30impl StorageConfig {
31 pub fn new(default: impl Into<String>) -> Self {
33 Self {
34 default: default.into(),
35 disks: HashMap::new(),
36 }
37 }
38
39 pub fn from_env() -> Self {
66 let default = env::var("FILESYSTEM_DISK").unwrap_or_else(|_| "local".to_string());
67 let mut disks = HashMap::new();
68
69 let local_root =
71 env::var("FILESYSTEM_LOCAL_ROOT").unwrap_or_else(|_| "./storage".to_string());
72 let mut local_config = DiskConfig::local(&local_root);
73 if let Ok(url) = env::var("FILESYSTEM_LOCAL_URL") {
74 local_config = local_config.with_url(url);
75 }
76 disks.insert("local".to_string(), local_config);
77
78 let public_root =
80 env::var("FILESYSTEM_PUBLIC_ROOT").unwrap_or_else(|_| "./storage/public".to_string());
81 let public_url =
82 env::var("FILESYSTEM_PUBLIC_URL").unwrap_or_else(|_| "/storage".to_string());
83 let public_config = DiskConfig::local(&public_root).with_url(public_url);
84 disks.insert("public".to_string(), public_config);
85
86 #[cfg(feature = "s3")]
88 if let Ok(bucket) = env::var("AWS_BUCKET") {
89 let region = env::var("AWS_DEFAULT_REGION").unwrap_or_else(|_| "us-east-1".to_string());
90 let mut s3_config = DiskConfig {
91 driver: DiskDriver::S3,
92 root: None,
93 url: None,
94 cdn_url: None,
95 bucket: Some(bucket.clone()),
96 region: Some(region),
97 };
98 let public_url = if let Ok(explicit) = env::var("AWS_PUBLIC_URL") {
104 Some(explicit)
105 } else if let Ok(api_url) = env::var("AWS_URL") {
106 let host = api_url
107 .trim_start_matches("https://")
108 .trim_start_matches("http://");
109 let scheme = if api_url.starts_with("https://") {
110 "https"
111 } else {
112 "http"
113 };
114 Some(format!("{scheme}://{bucket}.{host}"))
115 } else {
116 None
117 };
118 s3_config.url = public_url;
119 if let Ok(cdn) = env::var("AWS_CDN_URL") {
120 s3_config = s3_config.with_cdn_url(cdn);
121 }
122 disks.insert("s3".to_string(), s3_config);
123 }
124
125 Self { default, disks }
126 }
127
128 pub fn disk(mut self, name: impl Into<String>, config: DiskConfig) -> Self {
130 self.disks.insert(name.into(), config);
131 self
132 }
133
134 pub fn default_disk(mut self, name: impl Into<String>) -> Self {
136 self.default = name.into();
137 self
138 }
139
140 pub fn get_default(&self) -> &str {
142 &self.default
143 }
144
145 pub fn get_disk(&self, name: &str) -> Option<&DiskConfig> {
147 self.disks.get(name)
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_storage_config_defaults() {
157 let config = StorageConfig::default();
158 assert_eq!(config.default, "local");
159 assert!(config.disks.contains_key("local"));
160 }
161
162 #[test]
163 fn test_storage_config_builder() {
164 let config = StorageConfig::new("s3")
165 .disk("local", DiskConfig::local("./storage"))
166 .disk("public", DiskConfig::local("./public").with_url("/files"));
167
168 assert_eq!(config.default, "s3");
169 assert!(config.disks.contains_key("local"));
170 assert!(config.disks.contains_key("public"));
171 }
172
173 #[test]
174 fn test_storage_config_from_env() {
175 let config = StorageConfig::from_env();
177 assert_eq!(config.default, "local");
178 assert!(config.disks.contains_key("local"));
179 assert!(config.disks.contains_key("public"));
180 }
181
182 #[cfg(feature = "s3")]
183 #[test]
184 fn from_env_cdn_url() {
185 std::env::set_var("AWS_BUCKET", "test-bucket");
186 std::env::set_var("AWS_CDN_URL", "https://cdn.test.example.com");
187 let config = StorageConfig::from_env();
188 let s3_disk = config.get_disk("s3").expect("s3 disk should be configured");
189 assert_eq!(
190 s3_disk.cdn_url,
191 Some("https://cdn.test.example.com".to_string())
192 );
193 std::env::remove_var("AWS_BUCKET");
194 std::env::remove_var("AWS_CDN_URL");
195 }
196}