xt_oss/oss/api/bucket/
stand.rs

1use crate::oss;
2
3use self::builders::{
4    DeleteBucketBuilder, GetBucketInfoBuilder, GetBucketLocationBuilder, GetBucketStatBuilder,
5    ListObjectBuilder, ListObjectsV2Builder, PutBucketBuilder,
6};
7
8pub mod builders {
9    use crate::oss::{
10        self,
11        api::{self, insert_custom_header, ApiResponseFrom},
12        entities::{
13            bucket::{
14                BucketInfo, BucketStat, CreateBucketConfiguration, ListBucketResult,
15                ListBucketResult2, LocationConstraint,
16            },
17            DataRedundancyType, OssAcl, StorageClass,
18        },
19        http,
20    };
21    use reqwest::header::HeaderMap;
22    use serde::{Deserialize, Serialize};
23    use std::fmt;
24
25    #[derive(Debug)]
26    pub struct PutBucketBuilder<'a> {
27        client: &'a oss::Client<'a>,
28        region: Option<&'a str>,
29        bucket: Option<&'a str>,
30        acl: Option<OssAcl>,
31        group_id: Option<&'a str>,
32        storage_class: Option<StorageClass>,
33        data_redundancy_type: Option<DataRedundancyType>,
34    }
35
36    impl<'a> PutBucketBuilder<'a> {
37        pub(crate) fn new(client: &'a oss::Client) -> Self {
38            Self {
39                client,
40                region: None,
41                bucket: None,
42                acl: None,
43                group_id: None,
44                // config: None,
45                storage_class: None,
46                data_redundancy_type: None,
47            }
48        }
49
50        pub fn with_region(mut self, value: &'a str) -> Self {
51            self.region = Some(value);
52            self
53        }
54
55        pub fn with_bucket(mut self, value: &'a str) -> Self {
56            self.bucket = Some(value);
57            self
58        }
59
60        pub fn with_acl(mut self, value: OssAcl) -> Self {
61            self.acl = Some(value);
62            self
63        }
64
65        pub fn with_group_id(mut self, value: &'a str) -> Self {
66            self.group_id = Some(value);
67            self
68        }
69
70        pub fn with_storage_class(mut self, value: StorageClass) -> Self {
71            self.storage_class = Some(value);
72            self
73        }
74
75        pub fn with_data_redundancy_type(mut self, value: DataRedundancyType) -> Self {
76            self.data_redundancy_type = Some(value);
77            self
78        }
79
80        fn headers(&self) -> HeaderMap {
81            let mut headers = HeaderMap::default();
82            if let Some(acl) = &self.acl {
83                insert_custom_header(&mut headers, "x-oss-acl", acl.to_string());
84            }
85            if let Some(group_id) = &self.group_id {
86                insert_custom_header(&mut headers, "x-oss-resource-group-id", group_id);
87            }
88            headers
89        }
90
91        fn config(&self) -> String {
92            let config = CreateBucketConfiguration {
93                storage_class: self.storage_class.to_owned(),
94                data_redundancy_type: self.data_redundancy_type.to_owned(),
95            };
96            quick_xml::se::to_string(&config).unwrap()
97        }
98
99        /// 调用PutBucket接口创建存储空间(Bucket)。
100        pub async fn execute(&self) -> api::ApiResult {
101            let region = self.region.unwrap_or(self.client.options.region);
102            let bucket = self.bucket.unwrap_or(self.client.bucket());
103            let res = format!("/{}/", bucket);
104            let url = format!(
105                "{}://{}.{}",
106                self.client.options.schema(),
107                bucket,
108                format!(
109                    "{}{}.{}",
110                    region,
111                    match self.client.options.internal {
112                        true => "-internal",
113                        false => "",
114                    },
115                    oss::BASE_URL
116                )
117            );
118
119            let headers = self.headers();
120            let config = oss::Bytes::from(self.config());
121
122            let resp = self
123                .client
124                .request
125                .task()
126                .with_url(&url)
127                .with_method(http::Method::PUT)
128                .with_resource(&res)
129                .with_headers(headers)
130                .with_body(config)
131                .execute()
132                .await?;
133
134            Ok(ApiResponseFrom(resp).to_empty().await)
135        }
136    }
137
138    pub struct DeleteBucketBuilder<'a> {
139        client: &'a oss::Client<'a>,
140        region: Option<&'a str>,
141        bucket: Option<&'a str>,
142    }
143
144    impl<'a> DeleteBucketBuilder<'a> {
145        pub fn new(client: &'a oss::Client) -> Self {
146            Self {
147                client,
148                region: None,
149                bucket: None,
150            }
151        }
152
153        pub fn with_region(mut self, region: &'a str) -> Self {
154            self.region = Some(region);
155            self
156        }
157
158        pub fn with_bucket(mut self, bucket: &'a str) -> Self {
159            self.bucket = Some(bucket);
160            self
161        }
162
163        pub async fn execute(&self) -> api::ApiResult {
164            let region = self.region.unwrap_or(self.client.options.region);
165            let bucket = self.bucket.unwrap_or(self.client.bucket());
166            let res = format!("/{}/", bucket);
167            let url = format!(
168                "{}://{}.{}",
169                self.client.options.schema(),
170                bucket,
171                format!(
172                    "{}{}.{}",
173                    region,
174                    match self.client.options.internal {
175                        true => "-internal",
176                        false => "",
177                    },
178                    oss::BASE_URL
179                )
180            );
181            // dbg!(&res);
182            // dbg!(&url);
183
184            let resp = self
185                .client
186                .request
187                .task()
188                .with_url(&url)
189                .with_resource(&res)
190                .with_method(http::Method::DELETE)
191                .execute()
192                .await?;
193
194            Ok(ApiResponseFrom(resp).to_empty().await)
195        }
196    }
197
198    #[derive(Debug, Serialize, Deserialize)]
199    pub(crate) struct ListObjectQuery<'a> {
200        delimiter: Option<&'a str>,
201        marker: Option<&'a str>,
202        #[serde(rename = "max-keys")]
203        max_keys: Option<i32>,
204        prefix: Option<&'a str>,
205        #[serde(rename = "encoding-type")]
206        encoding_type: Option<&'a str>,
207    }
208
209    impl<'a> fmt::Display for ListObjectQuery<'a> {
210        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211            write!(f, "{}", serde_qs::to_string(self).unwrap())
212        }
213    }
214
215    impl<'a> Default for ListObjectQuery<'a> {
216        fn default() -> Self {
217            ListObjectQuery {
218                delimiter: None,
219                marker: None,
220                max_keys: Some(100),
221                prefix: None,
222                encoding_type: None,
223            }
224        }
225    }
226
227    pub struct ListObjectBuilder<'a> {
228        client: &'a oss::Client<'a>,
229        query: ListObjectQuery<'a>,
230    }
231
232    impl<'a> ListObjectBuilder<'a> {
233        pub fn new(client: &'a oss::Client) -> Self {
234            Self {
235                client,
236                query: ListObjectQuery::default(),
237            }
238        }
239
240        pub fn with_delimiter(mut self, value: &'a str) -> Self {
241            self.query.delimiter = Some(value);
242            self
243        }
244
245        pub fn with_marker(mut self, value: &'a str) -> Self {
246            self.query.marker = Some(value);
247            self
248        }
249
250        pub fn with_max_keys(mut self, value: i32) -> Self {
251            self.query.max_keys = Some(value);
252            self
253        }
254
255        pub fn with_prefix(mut self, value: &'a str) -> Self {
256            self.query.prefix = Some(value);
257            self
258        }
259
260        pub fn with_encoding_type(mut self, value: &'a str) -> Self {
261            self.query.encoding_type = Some(value);
262            self
263        }
264
265        pub async fn execute(&self) -> api::ApiResult<ListBucketResult> {
266            let res = format!("/{}/", self.client.bucket());
267            let mut url = self.client.base_url();
268            let query = self.query.to_string();
269            if !query.is_empty() {
270                url = format!("{}?{}", url, query);
271            }
272
273            let resp = self
274                .client
275                .request
276                .task()
277                .with_url(&url)
278                .with_resource(&res)
279                .execute()
280                .await?;
281
282            Ok(ApiResponseFrom(resp).to_type().await)
283        }
284    }
285
286    #[derive(Debug, Serialize, Deserialize)]
287    pub(crate) struct ListObjectsV2Query<'a> {
288        #[serde(rename = "list-type")]
289        pub list_type: u8,
290        pub delimiter: Option<&'a str>,
291        #[serde(rename = "start-after")]
292        pub start_after: Option<&'a str>,
293        #[serde(rename = "continuation-token")]
294        pub continuation_token: Option<&'a str>,
295        #[serde(rename = "max-keys")]
296        pub max_keys: Option<i32>,
297        pub prefix: Option<&'a str>,
298        #[serde(rename = "encoding-type")]
299        pub encoding_type: Option<&'a str>,
300        #[serde(rename = "fetch-owner")]
301        pub fetch_owner: Option<bool>,
302    }
303
304    impl<'a> Default for ListObjectsV2Query<'a> {
305        fn default() -> Self {
306            ListObjectsV2Query {
307                list_type: 2,
308                delimiter: None,
309                start_after: None,
310                continuation_token: None,
311                max_keys: Some(100),
312                prefix: None,
313                encoding_type: None,
314                fetch_owner: None,
315            }
316        }
317    }
318
319    impl<'a> fmt::Display for ListObjectsV2Query<'a> {
320        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321            write!(f, "{}", serde_qs::to_string(self).unwrap())
322        }
323    }
324
325    pub struct ListObjectsV2Builder<'a> {
326        client: &'a oss::Client<'a>,
327        query: ListObjectsV2Query<'a>,
328    }
329
330    impl<'a> ListObjectsV2Builder<'a> {
331        pub fn new(client: &'a oss::Client) -> Self {
332            Self {
333                client,
334                query: ListObjectsV2Query::default(),
335            }
336        }
337
338        pub fn with_delimiter(mut self, value: &'a str) -> Self {
339            self.query.delimiter = Some(value);
340            self
341        }
342
343        pub fn with_start_after(mut self, value: &'a str) -> Self {
344            self.query.delimiter = Some(value);
345            self
346        }
347
348        pub fn with_continuation_token(mut self, value: Option<&'a str>) -> Self {
349            self.query.continuation_token = value;
350            self
351        }
352
353        pub fn with_max_keys(mut self, value: i32) -> Self {
354            self.query.max_keys = Some(value);
355            self
356        }
357
358        pub fn with_prefix(mut self, value: &'a str) -> Self {
359            self.query.prefix = Some(value);
360            self
361        }
362
363        pub fn with_encoding_type(mut self, value: &'a str) -> Self {
364            self.query.encoding_type = Some(value);
365            self
366        }
367
368        pub fn with_fetch_owner(mut self, value: bool) -> Self {
369            self.query.fetch_owner = Some(value);
370            self
371        }
372
373        pub async fn execute(&self) -> api::ApiResult<ListBucketResult2> {
374            let mut res = format!("/{}/", self.client.bucket());
375            let mut url = self.client.base_url();
376            let query = self.query.to_string();
377            if !query.is_empty() {
378                if let Some(token) = self.query.continuation_token {
379                    res = format!("{}?continuation-token={}", res, token);
380                }
381                url = format!("{}?{}", url, query);
382            }
383
384            let resp = self
385                .client
386                .request
387                .task()
388                .with_url(&url)
389                .with_method(http::Method::GET)
390                .with_resource(&res)
391                .execute()
392                .await?;
393
394            Ok(ApiResponseFrom(resp).to_type().await)
395        }
396    }
397
398    pub struct GetBucketInfoBuilder<'a> {
399        client: &'a oss::Client<'a>,
400        bucket: Option<&'a str>,
401    }
402
403    impl<'a> GetBucketInfoBuilder<'a> {
404        pub fn new(client: &'a oss::Client) -> Self {
405            Self {
406                client,
407                bucket: None,
408            }
409        }
410
411        pub fn with_bucket(mut self, value: &'a str) -> Self {
412            self.bucket = Some(value);
413            self
414        }
415
416        pub async fn execute(&self) -> api::ApiResult<BucketInfo> {
417            let region = self.client.region();
418            let bucket = self.bucket.unwrap_or(self.client.bucket());
419            let res = format!("/{}/?bucketInfo", bucket);
420            let url = format!(
421                "{}://{}.{}?bucketInfo",
422                self.client.options.schema(),
423                bucket,
424                format!(
425                    "{}{}.{}",
426                    region,
427                    match self.client.options.internal {
428                        true => "-internal",
429                        false => "",
430                    },
431                    oss::BASE_URL
432                )
433            );
434
435            let resp = self
436                .client
437                .request
438                .task()
439                .with_url(&url)
440                .with_resource(&res)
441                .execute()
442                .await?;
443
444            Ok(ApiResponseFrom(resp).to_type().await)
445        }
446    }
447
448    pub struct GetBucketLocationBuilder<'a> {
449        client: &'a oss::Client<'a>,
450        bucket: Option<&'a str>,
451    }
452
453    impl<'a> GetBucketLocationBuilder<'a> {
454        pub fn new(client: &'a oss::Client) -> Self {
455            Self {
456                client,
457                bucket: None,
458            }
459        }
460
461        pub fn with_bucket(mut self, value: &'a str) -> Self {
462            self.bucket = Some(value);
463            self
464        }
465
466        pub async fn execute(&self) -> api::ApiResult<LocationConstraint> {
467            let region = self.client.options.region;
468            let bucket = self.bucket.unwrap_or(self.client.bucket());
469            let res = format!("/{}/?location", bucket);
470            let url = format!(
471                "{}://{}.{}/?location",
472                self.client.options.schema(),
473                bucket,
474                format!(
475                    "{}{}.{}",
476                    region,
477                    match self.client.options.internal {
478                        true => "-internal",
479                        false => "",
480                    },
481                    oss::BASE_URL
482                )
483            );
484            let resp = self
485                .client
486                .request
487                .task()
488                .with_url(&url)
489                .with_resource(&res)
490                .with_method(http::Method::GET)
491                .execute()
492                .await?;
493
494            Ok(ApiResponseFrom(resp).to_type().await)
495        }
496    }
497
498    pub struct GetBucketStatBuilder<'a> {
499        client: &'a oss::Client<'a>,
500        region: Option<&'a str>,
501        bucket: Option<&'a str>,
502    }
503
504    impl<'a> GetBucketStatBuilder<'a> {
505        pub fn new(client: &'a oss::Client) -> Self {
506            Self {
507                client,
508                region: None,
509                bucket: None,
510            }
511        }
512
513        pub fn with_region(mut self, region: &'a str) -> Self {
514            self.region = Some(region);
515            self
516        }
517
518        pub fn with_bucket(mut self, bucket: &'a str) -> Self {
519            self.bucket = Some(bucket);
520            self
521        }
522
523        pub async fn execute(&self) -> api::ApiResult<BucketStat> {
524            let region = self.region.unwrap_or(self.client.options.region);
525            let bucket = self.bucket.unwrap_or(self.client.bucket());
526            let res = format!("/{}/?stat", bucket);
527            let url = format!(
528                "{}://{}.{}/?stat",
529                self.client.options.schema(),
530                bucket,
531                format!(
532                    "{}{}.{}",
533                    region,
534                    match self.client.options.internal {
535                        true => "-internal",
536                        false => "",
537                    },
538                    oss::BASE_URL
539                )
540            );
541
542            let resp = self
543                .client
544                .request
545                .task()
546                .with_url(&url)
547                .with_resource(&res)
548                .with_method(http::Method::GET)
549                .execute()
550                .await?;
551
552            Ok(ApiResponseFrom(resp).to_type().await)
553        }
554    }
555}
556
557/// # 基础操作
558#[allow(non_snake_case)]
559impl<'a> oss::Client<'a> {
560    /// 调用PutBucket接口创建存储空间`Bucket`。
561    ///
562    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/putbucket)
563    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_put.rs)
564    pub fn PutBucket(&self) -> PutBucketBuilder<'_> {
565        PutBucketBuilder::new(self)
566    }
567
568    /// 调用DeleteBucket删除某个存储空间`Bucket`。
569    ///
570    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/deletebucket)
571    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_del.rs)
572    pub fn DeleteBucket(&self) -> DeleteBucketBuilder<'_> {
573        DeleteBucketBuilder::new(self)
574    }
575
576    /// GetBucket (ListObjects)接口用于列举存储空间`Bucket`中所有文件
577    /// `Object`的信息。
578    ///
579    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/listobjects)
580    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_list_object.rs)
581    pub fn ListObjects(&self) -> ListObjectBuilder<'_> {
582        ListObjectBuilder::new(self)
583    }
584
585    /// ListObjectsV2`GetBucketV2`接口用于列举存储空间`Bucket`中所有文件
586    ///`Object`的信息。
587    ///
588    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/listobjectsv2)
589    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_list_object_v2.rs)
590    pub fn ListObjectsV2(&self) -> ListObjectsV2Builder<'_> {
591        ListObjectsV2Builder::new(self)
592    }
593
594    /// 调用GetBucketInfo接口查看存储空间`Bucket`的相关信息。
595    ///
596    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/getbucketinfo)
597    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_get_info.rs)
598    pub fn GetBucketInfo(&self) -> GetBucketInfoBuilder<'_> {
599        GetBucketInfoBuilder::new(self)
600    }
601
602    /// GetBucketLocation接口用于查看存储空间`Bucket`的位置信息。
603    /// 只有Bucket的拥有者才能查看Bucket的位置信息。
604    ///
605    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/getbucketlocation)
606    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_get_location.rs)
607    pub fn GetBucketLocation(&self) -> GetBucketLocationBuilder<'_> {
608        GetBucketLocationBuilder::new(self)
609    }
610
611    /// 调用GetBucketStat接口获取指定存储空间`Bucket`的存储容量以及文件
612    /// `Object`数量
613    ///
614    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/getbucketstat)
615    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_bucket_stand_get_stat.rs)
616    pub fn GetBucketStat(&self) -> GetBucketStatBuilder<'_> {
617        GetBucketStatBuilder::new(self)
618    }
619}