ali_oss_rs/blocking/
bucket.rs1use 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}