1use hyper::header;
2use hyper::Method;
3
4use super::args::ObjectLockConfig;
5use super::{BucketArgs, ListObjectVersionsArgs, ListObjectsArgs, Tags};
6use crate::datatype::AccessControlPolicy;
7use crate::datatype::CORSConfiguration;
8use crate::datatype::ListAllMyBucketsResult;
9use crate::datatype::ListBucketResult;
10use crate::datatype::ListVersionsResult;
11use crate::datatype::LocationConstraint;
12use crate::datatype::PublicAccessBlockConfiguration;
13use crate::datatype::ServerSideEncryptionConfiguration;
14use crate::datatype::{Bucket, Owner, VersioningConfiguration};
15use crate::error::{Error, Result};
16use crate::Minio;
17
18macro_rules! get_attr {
19 ($name:ident, $query:expr, $T:tt) => {
20 #[doc = concat!("Get [",stringify!($T),"] of a bucket")]
21 #[doc = concat!("let config = minio.", stringify!($name), r#"("bucket").await?;"#)]
26 #[inline]
30 pub async fn $name<B>(&self, bucket: B) -> Result<$T>
31 where
32 B: Into<BucketArgs>,
33 {
34 self._bucket_executor(bucket.into(), Method::GET)
35 .query($query, "")
36 .send_xml_ok()
37 .await
38 }
39 };
40}
41
42macro_rules! set_attr {
43 ($name:ident, $query:expr, $T:tt) => {
44 #[doc = concat!("Set [",stringify!($T),"] of a bucket")]
45 #[inline]
46 pub async fn $name<B>(&self, bucket: B, value: $T) -> Result<()>
47 where
48 B: Into<BucketArgs>,
49 {
50 self._bucket_executor(bucket.into(), Method::PUT)
51 .query($query, "")
52 .xml(&value)
53 .send_ok()
54 .await
55 .map(|_| ())
56 }
57 };
58}
59
60macro_rules! del_attr {
61 ($name:ident, $query:expr) => {
62 #[doc = concat!("Delete ",$query," of a bucket")]
63 #[inline]
64 pub async fn $name<B>(&self, bucket: B) -> Result<()>
65 where
66 B: Into<BucketArgs>,
67 {
68 self._bucket_executor(bucket.into(), Method::DELETE)
69 .query($query, "")
70 .send_ok()
71 .await
72 .map(|_| ())
73 }
74 };
75}
76
77impl Minio {
79 #[inline]
80 pub(crate) fn _bucket_executor(
81 &self,
82 bucket: BucketArgs,
83 method: Method,
84 ) -> super::BaseExecutor {
85 self.executor(method)
86 .bucket_name(bucket.name)
87 .headers_merge2(bucket.extra_headers)
88 .apply(|e| {
89 let e = if let Some(region) = bucket.region {
90 e.region(region)
91 } else {
92 e
93 };
94 if let Some(owner) = bucket.expected_bucket_owner {
95 e.header("x-amz-expected-bucket-owner", owner)
96 } else {
97 e
98 }
99 })
100 }
101
102 pub async fn bucket_exists<B>(&self, bucket: B) -> Result<bool>
116 where
117 B: Into<BucketArgs>,
118 {
119 let bucket: BucketArgs = bucket.into();
120 self._bucket_executor(bucket, Method::HEAD)
121 .send()
122 .await
123 .map(|res| res.status().is_success())
124 }
125
126 pub async fn list_buckets(&self) -> Result<(Vec<Bucket>, Owner)> {
135 let res = self
136 .executor(Method::GET)
137 .send_xml_ok::<ListAllMyBucketsResult>()
138 .await?;
139 Ok((res.buckets.bucket, res.owner))
140 }
141
142 pub async fn list_object_versions<B>(
154 &self,
155 bucket: B,
156 args: ListObjectVersionsArgs,
157 ) -> Result<ListVersionsResult>
158 where
159 B: Into<BucketArgs>,
160 {
161 let bucket: BucketArgs = bucket.into();
162 self._bucket_executor(bucket, Method::GET)
163 .querys(args.args_query_map())
164 .headers_merge2(args.extra_headers)
165 .send_xml_ok()
166 .await
167 }
168
169 pub async fn list_objects<B>(
180 &self,
181 bucket: B,
182 args: ListObjectsArgs,
183 ) -> Result<ListBucketResult>
184 where
185 B: Into<BucketArgs>,
186 {
187 let bucket: BucketArgs = bucket.into();
188 self._bucket_executor(bucket, Method::GET)
189 .querys(args.args_query_map())
190 .headers_merge2(args.extra_headers)
191 .send_xml_ok()
192 .await
193 }
194
195 get_attr!(get_bucket_acl, "acl", AccessControlPolicy);
196
197 pub async fn get_bucket_region<B>(&self, bucket: B) -> Result<String>
199 where
200 B: Into<BucketArgs>,
201 {
202 let bucket: BucketArgs = bucket.into();
203 self._bucket_executor(bucket, Method::GET)
204 .query("location", "")
205 .send_xml_ok::<LocationConstraint>()
206 .await
207 .map(|loc| loc.location_constraint)
208 }
209
210 pub async fn make_bucket<B>(&self, bucket: B, object_lock: bool) -> Result<String>
225 where
226 B: Into<BucketArgs>,
227 {
228 let bucket: BucketArgs = bucket.into();
229 let region = &bucket.region.unwrap_or(self.region().to_string());
230 let body = format!("<CreateBucketConfiguration><LocationConstraint>{}</LocationConstraint></CreateBucketConfiguration>",region);
231 self.executor(Method::PUT)
232 .bucket_name(bucket.name)
233 .headers_merge2(bucket.extra_headers)
234 .apply(|e| {
235 if object_lock {
236 e.header("x-amz-bucket-object-lock-enabled", "true")
237 } else {
238 e
239 }
240 })
241 .body(body)
242 .send_ok()
243 .await
244 .map(|res| {
245 let location = res.headers().get(header::LOCATION);
246 if let Some(loc) = location {
247 if let Ok(loc) = loc.to_str() {
248 return Ok(loc.to_string());
249 }
250 }
251 Err(res.into())
252 })?
253 }
254
255 pub async fn remove_bucket<B>(&self, bucket: B) -> Result<()>
267 where
268 B: Into<BucketArgs>,
269 {
270 let bucket: BucketArgs = bucket.into();
271 self._bucket_executor(bucket, Method::DELETE)
272 .send_ok()
273 .await
274 .map(|_| ())
275 }
276
277 get_attr!(get_bucket_cors, "cors", CORSConfiguration);
278 set_attr!(set_bucket_cors, "cors", CORSConfiguration);
279 del_attr!(del_bucket_cors, "cors");
280
281 #[rustfmt::skip]
282 get_attr!(get_bucket_encryption,"encryption",ServerSideEncryptionConfiguration);
283 #[rustfmt::skip]
284 set_attr!(set_bucket_encryption, "encryption", ServerSideEncryptionConfiguration);
285 del_attr!(del_bucket_encryption, "encryption");
286
287 #[rustfmt::skip]
288 get_attr!(get_public_access_block, "publicAccessBlock", PublicAccessBlockConfiguration);
289 #[rustfmt::skip]
290 set_attr!(set_public_access_block, "publicAccessBlock", PublicAccessBlockConfiguration);
291 del_attr!(del_public_access_block, "publicAccessBlock");
292
293 pub async fn get_bucket_tags<B>(&self, bucket: B) -> Result<Option<Tags>>
306 where
307 B: Into<BucketArgs>,
308 {
309 let bucket: BucketArgs = bucket.into();
310 let res = self
311 ._bucket_executor(bucket, Method::GET)
312 .query("tagging", "")
313 .send_xml_ok::<Tags>()
314 .await;
315 match res {
316 Ok(tags) => Ok(Some(tags)),
317 Err(Error::S3Error(s)) if s.code == "NoSuchTagSet" => Ok(None),
318 Err(err) => Err(err),
319 }
320 }
321
322 set_attr!(set_bucket_tags, "tagging", Tags);
323 del_attr!(del_bucket_tags, "tagging");
324
325 get_attr!(get_bucket_versioning, "versioning", VersioningConfiguration);
326 set_attr!(set_bucket_versioning, "versioning", VersioningConfiguration);
327
328 get_attr!(get_object_lock_config, "object-lock", ObjectLockConfig);
329 set_attr!(set_object_lock_config, "object-lock", ObjectLockConfig);
330
331 pub async fn del_object_lock_config<B>(&self, bucket: B) -> Result<()>
341 where
342 B: Into<BucketArgs>,
343 {
344 let config = ObjectLockConfig::default();
345 self.set_object_lock_config(bucket, config).await
346 }
347}