Skip to main content

sz_orm_storage/
storage.rs

1use crate::aliyun::AliyunOssStorage;
2use crate::error::StorageError;
3use crate::huawei::HuaweiObsStorage;
4use crate::local::LocalStorage;
5use crate::qiniu::QiniuKodoStorage;
6use crate::s3::S3Storage;
7use crate::tencent::TencentCosStorage;
8use crate::upyun::UpYunStorage;
9use async_trait::async_trait;
10
11#[async_trait]
12pub trait Storage: Send + Sync {
13    async fn put(&self, key: &str, data: &[u8], content_type: &str)
14        -> Result<String, StorageError>;
15    async fn get(&self, key: &str) -> Result<Vec<u8>, StorageError>;
16    async fn delete(&self, key: &str) -> Result<(), StorageError>;
17    async fn exists(&self, key: &str) -> Result<bool, StorageError>;
18}
19
20pub struct StorageBuilder {
21    provider: StorageProvider,
22    config: StorageConfig,
23}
24
25impl StorageBuilder {
26    pub fn new(provider: StorageProvider) -> Self {
27        Self {
28            provider,
29            config: StorageConfig::default(),
30        }
31    }
32
33    pub fn with_bucket(mut self, bucket: impl Into<String>) -> Self {
34        self.config.bucket = bucket.into();
35        self
36    }
37
38    pub fn with_region(mut self, region: impl Into<String>) -> Self {
39        self.config.region = region.into();
40        self
41    }
42
43    pub fn with_endpoint(mut self, endpoint: impl Into<String>) -> Self {
44        self.config.endpoint = Some(endpoint.into());
45        self
46    }
47
48    pub fn with_access_key(mut self, key: impl Into<String>) -> Self {
49        self.config.access_key = Some(key.into());
50        self
51    }
52
53    pub fn with_secret_key(mut self, key: impl Into<String>) -> Self {
54        self.config.secret_key = Some(key.into());
55        self
56    }
57
58    pub fn with_path_prefix(mut self, prefix: impl Into<String>) -> Self {
59        self.config.path_prefix = Some(prefix.into());
60        self
61    }
62
63    pub fn with_base_path(mut self, base_path: impl Into<String>) -> Self {
64        self.config.base_path = Some(base_path.into());
65        self
66    }
67
68    pub fn build(self) -> Result<StorageWrapper, StorageError> {
69        match self.provider {
70            StorageProvider::Local => {
71                let base_path = self
72                    .config
73                    .base_path
74                    .clone()
75                    .unwrap_or_else(|| ".".to_string());
76                Ok(StorageWrapper::Local(LocalStorage::new(base_path)))
77            }
78            StorageProvider::S3(_) => {
79                let bucket = self.config.bucket.clone();
80                let region = self.config.region.clone();
81                Ok(StorageWrapper::S3(S3Storage::new(bucket, region)))
82            }
83            StorageProvider::AliyunOss(_) => {
84                let bucket = self.config.bucket.clone();
85                let endpoint = self.config.endpoint.clone().unwrap_or_default();
86                Ok(StorageWrapper::Aliyun(AliyunOssStorage::new(
87                    bucket, endpoint,
88                )))
89            }
90            StorageProvider::TencentCos(_) => {
91                let bucket = self.config.bucket.clone();
92                let region = self.config.region.clone();
93                Ok(StorageWrapper::Tencent(TencentCosStorage::new(
94                    bucket, region,
95                )))
96            }
97            StorageProvider::QiniuKodo(_) => {
98                let bucket = self.config.bucket.clone();
99                Ok(StorageWrapper::Qiniu(QiniuKodoStorage::new(bucket)))
100            }
101            StorageProvider::HuaweiObs(_) => {
102                let bucket = self.config.bucket.clone();
103                let endpoint = self.config.endpoint.clone().unwrap_or_default();
104                Ok(StorageWrapper::Huawei(HuaweiObsStorage::new(
105                    bucket, endpoint,
106                )))
107            }
108            StorageProvider::UpYun(_) => {
109                let bucket = self.config.bucket.clone();
110                Ok(StorageWrapper::Upyun(UpYunStorage::new(bucket)))
111            }
112        }
113    }
114}
115
116#[derive(Clone)]
117pub struct StorageConfig {
118    pub bucket: String,
119    pub region: String,
120    pub endpoint: Option<String>,
121    pub access_key: Option<String>,
122    pub secret_key: Option<String>,
123    pub path_prefix: Option<String>,
124    pub base_path: Option<String>,
125}
126
127impl std::fmt::Debug for StorageConfig {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        f.debug_struct("StorageConfig")
130            .field("bucket", &self.bucket)
131            .field("region", &self.region)
132            .field("endpoint", &self.endpoint)
133            .field("access_key", &"***")
134            .field("secret_key", &"***")
135            .field("path_prefix", &self.path_prefix)
136            .field("base_path", &self.base_path)
137            .finish()
138    }
139}
140
141impl Default for StorageConfig {
142    fn default() -> Self {
143        Self {
144            bucket: "default-bucket".to_string(),
145            region: "us-east-1".to_string(),
146            endpoint: None,
147            access_key: None,
148            secret_key: None,
149            path_prefix: None,
150            base_path: None,
151        }
152    }
153}
154
155#[derive(Debug, Clone)]
156pub enum StorageProvider {
157    Local,
158    S3(S3Config),
159    AliyunOss(AliyunConfig),
160    TencentCos(TencentConfig),
161    QiniuKodo(QiniuConfig),
162    HuaweiObs(HuaweiConfig),
163    UpYun(UpYunConfig),
164}
165
166#[derive(Debug, Clone, Default)]
167pub struct S3Config {
168    pub region: String,
169    pub access_key: Option<String>,
170    pub secret_key: Option<String>,
171}
172
173#[derive(Debug, Clone, Default)]
174pub struct AliyunConfig {
175    pub endpoint: String,
176    pub access_key: Option<String>,
177    pub secret_key: Option<String>,
178}
179
180#[derive(Debug, Clone, Default)]
181pub struct TencentConfig {
182    pub region: String,
183    pub secret_id: Option<String>,
184    pub secret_key: Option<String>,
185}
186
187#[derive(Debug, Clone, Default)]
188pub struct QiniuConfig {
189    pub access_key: Option<String>,
190    pub secret_key: Option<String>,
191}
192
193#[derive(Debug, Clone, Default)]
194pub struct HuaweiConfig {
195    pub endpoint: String,
196    pub access_key: Option<String>,
197    pub secret_key: Option<String>,
198}
199
200#[derive(Debug, Clone, Default)]
201pub struct UpYunConfig {
202    pub operator: Option<String>,
203    pub password: Option<String>,
204}
205
206pub enum StorageWrapper {
207    Local(LocalStorage),
208    S3(S3Storage),
209    Aliyun(AliyunOssStorage),
210    Tencent(TencentCosStorage),
211    Qiniu(QiniuKodoStorage),
212    Huawei(HuaweiObsStorage),
213    Upyun(UpYunStorage),
214}
215
216#[async_trait]
217impl Storage for StorageWrapper {
218    async fn put(
219        &self,
220        key: &str,
221        data: &[u8],
222        content_type: &str,
223    ) -> Result<String, StorageError> {
224        match self {
225            StorageWrapper::Local(s) => s.put(key, data, content_type).await,
226            StorageWrapper::S3(s) => s.put(key, data, content_type).await,
227            StorageWrapper::Aliyun(s) => s.put(key, data, content_type).await,
228            StorageWrapper::Tencent(s) => s.put(key, data, content_type).await,
229            StorageWrapper::Qiniu(s) => s.put(key, data, content_type).await,
230            StorageWrapper::Huawei(s) => s.put(key, data, content_type).await,
231            StorageWrapper::Upyun(s) => s.put(key, data, content_type).await,
232        }
233    }
234
235    async fn get(&self, key: &str) -> Result<Vec<u8>, StorageError> {
236        match self {
237            StorageWrapper::Local(s) => s.get(key).await,
238            StorageWrapper::S3(s) => s.get(key).await,
239            StorageWrapper::Aliyun(s) => s.get(key).await,
240            StorageWrapper::Tencent(s) => s.get(key).await,
241            StorageWrapper::Qiniu(s) => s.get(key).await,
242            StorageWrapper::Huawei(s) => s.get(key).await,
243            StorageWrapper::Upyun(s) => s.get(key).await,
244        }
245    }
246
247    async fn delete(&self, key: &str) -> Result<(), StorageError> {
248        match self {
249            StorageWrapper::Local(s) => s.delete(key).await,
250            StorageWrapper::S3(s) => s.delete(key).await,
251            StorageWrapper::Aliyun(s) => s.delete(key).await,
252            StorageWrapper::Tencent(s) => s.delete(key).await,
253            StorageWrapper::Qiniu(s) => s.delete(key).await,
254            StorageWrapper::Huawei(s) => s.delete(key).await,
255            StorageWrapper::Upyun(s) => s.delete(key).await,
256        }
257    }
258
259    async fn exists(&self, key: &str) -> Result<bool, StorageError> {
260        match self {
261            StorageWrapper::Local(s) => s.exists(key).await,
262            StorageWrapper::S3(s) => s.exists(key).await,
263            StorageWrapper::Aliyun(s) => s.exists(key).await,
264            StorageWrapper::Tencent(s) => s.exists(key).await,
265            StorageWrapper::Qiniu(s) => s.exists(key).await,
266            StorageWrapper::Huawei(s) => s.exists(key).await,
267            StorageWrapper::Upyun(s) => s.exists(key).await,
268        }
269    }
270}