Skip to main content

ali_oss_rs/blocking/
bucket.rs

1use crate::{
2    bucket_common::{
3        build_list_buckets_request, build_list_objects_request, build_put_bucket_request, extract_bucket_location, BucketDetail, BucketStat,
4        ListBucketsOptions, ListBucketsResult, ListObjectsOptions, ListObjectsResult, PutBucketConfiguration, PutBucketOptions,
5    },
6    error::Error,
7    request::{OssRequest, RequestMethod},
8    util::validate_bucket_name,
9    Result,
10};
11
12use super::Client;
13
14pub trait BucketOperations {
15    fn put_bucket<S: AsRef<str>>(&self, bucket_name: S, config: PutBucketConfiguration, options: Option<PutBucketOptions>) -> Result<()>;
16    fn list_buckets(&self, options: Option<ListBucketsOptions>) -> Result<ListBucketsResult>;
17    fn get_bucket_info<S: AsRef<str>>(&self, bucket_name: S) -> Result<BucketDetail>;
18    fn get_bucket_location<S: AsRef<str>>(&self, bucket_name: S) -> Result<String>;
19    fn get_bucket_stat<S: AsRef<str>>(&self, bucket_name: S) -> Result<BucketStat>;
20    fn list_objects<S: AsRef<str>>(&self, bucket_name: S, options: Option<ListObjectsOptions>) -> Result<ListObjectsResult>;
21    fn delete_bucket<S: AsRef<str>>(&self, bucket_name: S) -> Result<()>;
22}
23
24impl BucketOperations for Client {
25    fn put_bucket<S: AsRef<str>>(&self, bucket_name: S, config: PutBucketConfiguration, options: Option<PutBucketOptions>) -> Result<()> {
26        if !validate_bucket_name(bucket_name.as_ref()) {
27            return Err(Error::Other(format!(
28                "invalid bucket name: {}. please see the official document for more details",
29                bucket_name.as_ref()
30            )));
31        }
32
33        let request_builder = build_put_bucket_request(bucket_name.as_ref(), &config, &options)?;
34
35        self.do_request::<()>(request_builder)?;
36
37        Ok(())
38    }
39
40    fn list_buckets(&self, options: Option<ListBucketsOptions>) -> Result<ListBucketsResult> {
41        let request_builder = build_list_buckets_request(&options);
42
43        let (_, content) = self.do_request::<String>(request_builder)?;
44
45        ListBucketsResult::from_xml(&content)
46    }
47
48    fn get_bucket_info<S: AsRef<str>>(&self, bucket_name: S) -> Result<BucketDetail> {
49        let bucket_name = bucket_name.as_ref();
50
51        if !validate_bucket_name(bucket_name) {
52            return Err(Error::Other(format!("invalid bucket name: {}", bucket_name)));
53        }
54
55        let request_builder = OssRequest::new().method(RequestMethod::Get).bucket(bucket_name).add_query("bucketInfo", "");
56
57        let (_, content) = self.do_request::<String>(request_builder)?;
58
59        BucketDetail::from_xml(&content)
60    }
61
62    fn get_bucket_location<S: AsRef<str>>(&self, bucket_name: S) -> Result<String> {
63        let bucket_name = bucket_name.as_ref();
64
65        if !validate_bucket_name(bucket_name) {
66            return Err(Error::Other(format!("invalid bucket name: {}", bucket_name)));
67        }
68
69        let request_builder = OssRequest::new().method(RequestMethod::Get).bucket(bucket_name).add_query("location", "");
70
71        let (_, content) = self.do_request::<String>(request_builder)?;
72
73        extract_bucket_location(content.as_str())
74    }
75
76    fn get_bucket_stat<S: AsRef<str>>(&self, bucket_name: S) -> Result<BucketStat> {
77        let bucket_name = bucket_name.as_ref();
78
79        if !validate_bucket_name(bucket_name) {
80            return Err(Error::Other(format!("invalid bucket name: {}", bucket_name)));
81        }
82
83        let request_builder = OssRequest::new().method(RequestMethod::Get).bucket(bucket_name).add_query("stat", "");
84
85        let (_, content) = self.do_request::<String>(request_builder)?;
86
87        BucketStat::from_xml(&content)
88    }
89
90    fn list_objects<S: AsRef<str>>(&self, bucket_name: S, options: Option<ListObjectsOptions>) -> Result<ListObjectsResult> {
91        let bucket_name = bucket_name.as_ref();
92
93        if !validate_bucket_name(bucket_name) {
94            return Err(Error::Other(format!("invalid bucket name: {}", bucket_name)));
95        }
96
97        let request = build_list_objects_request(bucket_name, &options)?;
98
99        let (_, content) = self.do_request::<String>(request)?;
100
101        ListObjectsResult::from_xml(&content)
102    }
103
104    fn delete_bucket<S: AsRef<str>>(&self, bucket_name: S) -> Result<()> {
105        let bucket_name = bucket_name.as_ref();
106
107        if !validate_bucket_name(bucket_name) {
108            return Err(Error::Other(format!("invalid bucket name: {}", bucket_name)));
109        }
110
111        let request_builder = OssRequest::new().method(RequestMethod::Delete).bucket(bucket_name);
112
113        self.do_request::<()>(request_builder)?;
114
115        Ok(())
116    }
117}
118
119#[cfg(all(test, feature = "blocking"))]
120mod test_bucket_blocking {
121    use std::sync::Once;
122
123    use crate::{
124        blocking::{bucket::BucketOperations, Client},
125        bucket_common::{ListBucketsOptions, ListObjectsOptions, ListObjectsOptionsBuilder},
126    };
127
128    static INIT: Once = Once::new();
129
130    fn setup() {
131        INIT.call_once(|| {
132            simple_logger::init_with_level(log::Level::Debug).unwrap();
133            dotenvy::dotenv().unwrap();
134        });
135    }
136
137    fn setup_comp() {
138        INIT.call_once(|| {
139            simple_logger::init_with_level(log::Level::Debug).unwrap();
140            dotenvy::from_filename(".env.comp").unwrap();
141        });
142    }
143
144    #[test]
145    fn test_list_buckets_blocking() {
146        setup();
147
148        let client = Client::from_env();
149        let result = client.list_buckets(None);
150        assert!(result.is_ok());
151        let buckets = result.unwrap().buckets;
152        assert!(!buckets.is_empty());
153    }
154
155    #[test]
156    fn test_list_objects_1_blocking() {
157        setup();
158
159        let client = Client::from_env();
160
161        let response = client.list_objects("mi-dev-public", None);
162        assert!(response.is_ok());
163
164        let result = response.unwrap();
165        log::debug!("{:?}", result);
166    }
167
168    #[test]
169    fn test_list_objects_2_blocking() {
170        setup();
171
172        let client = Client::from_env();
173
174        let options = ListObjectsOptions {
175            delimiter: Some('/'),
176            prefix: Some("yuanyu-test/".to_string()),
177            fetch_owner: Some(true),
178            ..Default::default()
179        };
180
181        let response = client.list_objects("mi-dev-public", Some(options));
182        assert!(response.is_ok());
183
184        let result = response.unwrap();
185        log::debug!("{:?}", result);
186    }
187
188    #[test]
189    fn test_list_buckets_with_options_blocking() {
190        setup_comp();
191        let client = crate::blocking::Client::from_env();
192
193        let options = ListBucketsOptions {
194            max_keys: Some(10),
195            ..Default::default()
196        };
197
198        let response = client.list_buckets(Some(options));
199        log::debug!("list buckets, page1: {:#?}", response);
200
201        assert!(response.is_ok());
202
203        let ret = response.unwrap();
204        assert_eq!(10, ret.buckets.len());
205
206        assert!(ret.next_marker.is_some());
207        assert!(ret.is_truncated);
208
209        let options = ListBucketsOptions {
210            max_keys: Some(10),
211            marker: ret.next_marker,
212            ..Default::default()
213        };
214
215        let response = client.list_buckets(Some(options));
216        log::debug!("list buckets, page2: {:#?}", response);
217        assert!(response.is_ok());
218
219        let ret = response.unwrap();
220        assert_eq!(9, ret.buckets.len());
221    }
222
223    #[test]
224    fn test_list_objects_blocking_1() {
225        setup_comp();
226        let client = crate::blocking::Client::from_env();
227
228        let options = ListObjectsOptionsBuilder::new().prefix("").delimiter('/').build();
229
230        let response = client.list_objects("mi-dev-public", Some(options));
231        assert!(response.is_ok());
232
233        let result = response.unwrap();
234        assert!(result.key_count > 0);
235        assert_eq!(result.key_count, (result.common_prefixes.len() + result.contents.len()) as u64);
236    }
237}