Add builders for bucket methods: (#76)

- list buckets
- get bucket versioning
This commit is contained in:
Aditya Manthramurthy 2024-04-02 17:59:40 -07:00 committed by GitHub
parent 6a34d4c677
commit 35954da61d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 236 additions and 134 deletions

View File

@ -301,27 +301,6 @@ impl<'a> MakeBucketArgs<'a> {
}
}
#[derive(Clone, Debug, Default)]
/// Argument for [list_buckets()](crate::s3::client::Client::list_buckets) API
pub struct ListBucketsArgs<'a> {
pub extra_headers: Option<&'a Multimap>,
pub extra_query_params: Option<&'a Multimap>,
}
impl<'a> ListBucketsArgs<'a> {
/// Returns argument for [list_buckets()](crate::s3::client::Client::list_buckets) API
///
/// # Examples
///
/// ```
/// use minio::s3::args::*;
/// let args = ListBucketsArgs::new();
/// ```
pub fn new() -> ListBucketsArgs<'a> {
ListBucketsArgs::default()
}
}
#[derive(Clone, Debug, Default)]
/// Argument for [abort_multipart_upload()](crate::s3::client::Client::abort_multipart_upload) API
pub struct AbortMultipartUploadArgs<'a> {
@ -1767,9 +1746,6 @@ impl<'a> SetBucketTagsArgs<'a> {
}
}
/// Argument for [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning) API
pub type GetBucketVersioningArgs<'a> = BucketArgs<'a>;
/// Argument for [set_bucket_versioning()](crate::s3::client::Client::set_bucket_versioning) API
pub struct SetBucketVersioningArgs<'a> {
pub extra_headers: Option<&'a Multimap>,

View File

@ -12,8 +12,10 @@
//! Argument builders for [minio::s3::client::Client](crate::s3::client::Client) APIs
mod buckets;
mod list_objects;
mod listen_bucket_notification;
pub use buckets::*;
pub use list_objects::*;
pub use listen_bucket_notification::*;

140
src/s3/builders/buckets.rs Normal file
View File

@ -0,0 +1,140 @@
use http::Method;
use crate::s3::{
client::Client,
error::Error,
response::{GetBucketVersioningResponse, ListBucketsResponse},
types::{S3Api, S3Request, ToS3Request},
utils::{check_bucket_name, merge, Multimap},
};
/// Argument builder for
/// [list_buckets()](crate::s3::client::Client::list_buckets) API.
#[derive(Clone, Debug, Default)]
pub struct ListBuckets {
client: Option<Client>,
extra_headers: Option<Multimap>,
extra_query_params: Option<Multimap>,
}
impl S3Api for ListBuckets {
type S3Response = ListBucketsResponse;
}
impl ToS3Request for ListBuckets {
fn to_s3request(&self) -> Result<S3Request, Error> {
let mut headers = Multimap::new();
if let Some(v) = &self.extra_headers {
headers = v.clone();
}
let mut query_params = Multimap::new();
if let Some(v) = &self.extra_query_params {
query_params = v.clone();
}
let req = S3Request::new(
self.client.as_ref().ok_or(Error::NoClientProvided)?,
Method::GET,
)
.query_params(query_params)
.headers(headers);
Ok(req)
}
}
impl ListBuckets {
pub fn new() -> Self {
Default::default()
}
pub fn client(mut self, client: &Client) -> Self {
self.client = Some(client.clone());
self
}
pub fn extra_headers(mut self, extra_headers: Option<Multimap>) -> Self {
self.extra_headers = extra_headers;
self
}
pub fn extra_query_params(mut self, extra_query_params: Option<Multimap>) -> Self {
self.extra_query_params = extra_query_params;
self
}
}
#[derive(Clone, Debug, Default)]
pub struct BucketCommon {
client: Option<Client>,
extra_headers: Option<Multimap>,
extra_query_params: Option<Multimap>,
region: Option<String>,
bucket: String,
}
impl BucketCommon {
pub fn new(bucket_name: &str) -> Self {
BucketCommon {
bucket: bucket_name.to_owned(),
..Default::default()
}
}
pub fn client(mut self, client: &Client) -> Self {
self.client = Some(client.clone());
self
}
pub fn extra_headers(mut self, extra_headers: Option<Multimap>) -> Self {
self.extra_headers = extra_headers;
self
}
pub fn extra_query_params(mut self, extra_query_params: Option<Multimap>) -> Self {
self.extra_query_params = extra_query_params;
self
}
pub fn region(mut self, region: Option<String>) -> Self {
self.region = region;
self
}
}
/// Argument builder for
/// [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning)
/// API
pub type GetBucketVersioning = BucketCommon;
impl S3Api for GetBucketVersioning {
type S3Response = GetBucketVersioningResponse;
}
impl ToS3Request for GetBucketVersioning {
fn to_s3request(&self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?;
let mut headers = Multimap::new();
if let Some(v) = &self.extra_headers {
merge(&mut headers, v);
}
let mut query_params = Multimap::new();
if let Some(v) = &self.extra_query_params {
merge(&mut query_params, v);
}
query_params.insert(String::from("versioning"), String::new());
let req = S3Request::new(
self.client.as_ref().ok_or(Error::NoClientProvided)?,
Method::GET,
)
.region(self.region.as_deref())
.bucket(Some(&self.bucket))
.query_params(query_params)
.headers(headers);
Ok(req)
}
}

View File

@ -23,7 +23,7 @@ use crate::s3::response::*;
use crate::s3::signer::{presign_v4, sign_v4_s3};
use crate::s3::sse::SseCustomerKey;
use crate::s3::types::{
Bucket, DeleteObject, Directive, LifecycleConfig, NotificationConfig, ObjectLockConfig, Part,
DeleteObject, Directive, LifecycleConfig, NotificationConfig, ObjectLockConfig, Part,
ReplicationConfig, RetentionMode, SseConfig,
};
use crate::s3::utils::{
@ -46,6 +46,8 @@ use xmltree::Element;
mod list_objects;
mod listen_bucket_notification;
use super::builders::{GetBucketVersioning, ListBuckets};
/// Client Builder manufactures a Client using given parameters.
#[derive(Debug, Default)]
pub struct ClientBuilder {
@ -1846,46 +1848,8 @@ impl Client {
}
}
pub async fn get_bucket_versioning(
&self,
args: &GetBucketVersioningArgs<'_>,
) -> Result<GetBucketVersioningResponse, Error> {
let region = self.get_region(args.bucket, args.region).await?;
let mut headers = Multimap::new();
if let Some(v) = &args.extra_headers {
merge(&mut headers, v);
}
let mut query_params = Multimap::new();
if let Some(v) = &args.extra_query_params {
merge(&mut query_params, v);
}
query_params.insert(String::from("versioning"), String::new());
let resp = self
.execute(
Method::GET,
&region,
&mut headers,
&query_params,
Some(args.bucket),
None,
None,
)
.await?;
let header_map = resp.headers().clone();
let body = resp.bytes().await?;
let root = Element::parse(body.reader())?;
Ok(GetBucketVersioningResponse {
headers: header_map.clone(),
region: region.clone(),
bucket_name: args.bucket.to_string(),
status: get_option_text(&root, "Status").map(|v| v == "Enabled"),
mfa_delete: get_option_text(&root, "MFADelete").map(|v| v == "Enabled"),
})
pub fn get_bucket_versioning(&self, bucket: &str) -> GetBucketVersioning {
GetBucketVersioning::new(bucket).client(self)
}
pub async fn get_object(&self, args: &GetObjectArgs<'_>) -> Result<reqwest::Response, Error> {
@ -2230,49 +2194,8 @@ impl Client {
}
}
pub async fn list_buckets(
&self,
args: &ListBucketsArgs<'_>,
) -> Result<ListBucketsResponse, Error> {
let mut headers = Multimap::new();
if let Some(v) = &args.extra_headers {
merge(&mut headers, v);
}
let mut query_params = &Multimap::new();
if let Some(v) = &args.extra_query_params {
query_params = v;
}
let resp = self
.execute(
Method::GET,
&String::from("us-east-1"),
&mut headers,
query_params,
None,
None,
None,
)
.await?;
let header_map = resp.headers().clone();
let body = resp.bytes().await?;
let mut root = Element::parse(body.reader())?;
let buckets = root
.get_mut_child("Buckets")
.ok_or(Error::XmlError(String::from("<Buckets> tag not found")))?;
let mut bucket_list: Vec<Bucket> = Vec::new();
while let Some(b) = buckets.take_child("Bucket") {
let bucket = b;
bucket_list.push(Bucket {
name: get_text(&bucket, "Name")?,
creation_date: from_iso8601utc(&get_text(&bucket, "CreationDate")?)?,
})
}
Ok(ListBucketsResponse {
headers: header_map.clone(),
buckets: bucket_list,
})
pub fn list_buckets(&self) -> ListBuckets {
ListBuckets::new().client(self)
}
pub async fn make_bucket(

View File

@ -24,28 +24,23 @@ use xmltree::Element;
use crate::s3::error::Error;
use crate::s3::types::{
parse_legal_hold, Bucket, LifecycleConfig, NotificationConfig, ObjectLockConfig,
ReplicationConfig, RetentionMode, SelectProgress, SseConfig,
parse_legal_hold, LifecycleConfig, NotificationConfig, ObjectLockConfig, ReplicationConfig,
RetentionMode, SelectProgress, SseConfig,
};
use crate::s3::utils::{
copy_slice, crc32, from_http_header_value, from_iso8601utc, get_text, uint32, UtcTime,
};
mod buckets;
mod list_objects;
mod listen_bucket_notification;
pub use buckets::{GetBucketVersioningResponse, ListBucketsResponse};
pub use list_objects::{
ListObjectVersionsResponse, ListObjectsResponse, ListObjectsV1Response, ListObjectsV2Response,
};
pub use listen_bucket_notification::ListenBucketNotificationResponse;
#[derive(Debug)]
/// Response of [list_buckets()](crate::s3::client::Client::list_buckets) API
pub struct ListBucketsResponse {
pub headers: HeaderMap,
pub buckets: Vec<Bucket>,
}
#[derive(Debug)]
/// Base response for bucket operation
pub struct BucketResponse {
@ -675,16 +670,6 @@ pub struct GetBucketTagsResponse {
/// Response of [set_bucket_tags()](crate::s3::client::Client::set_bucket_tags) API
pub type SetBucketTagsResponse = BucketResponse;
#[derive(Clone, Debug)]
/// Response of [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning) API
pub struct GetBucketVersioningResponse {
pub headers: HeaderMap,
pub region: String,
pub bucket_name: String,
pub status: Option<bool>,
pub mfa_delete: Option<bool>,
}
/// Response of [set_bucket_versioning()](crate::s3::client::Client::set_bucket_versioning) API
pub type SetBucketVersioningResponse = BucketResponse;

View File

@ -0,0 +1,78 @@
use async_trait::async_trait;
use bytes::Buf;
use http::HeaderMap;
use xmltree::Element;
use crate::s3::{
error::Error,
types::{Bucket, FromS3Response, S3Request},
utils::{from_iso8601utc, get_option_text, get_text},
};
/// Response of [list_buckets()](crate::s3::client::Client::list_buckets) API
#[derive(Debug, Clone)]
pub struct ListBucketsResponse {
pub headers: HeaderMap,
pub buckets: Vec<Bucket>,
}
#[async_trait]
impl FromS3Response for ListBucketsResponse {
async fn from_s3response<'a>(
_req: S3Request<'a>,
resp: reqwest::Response,
) -> Result<Self, Error> {
let header_map = resp.headers().clone();
let body = resp.bytes().await?;
let mut root = Element::parse(body.reader())?;
let buckets = root
.get_mut_child("Buckets")
.ok_or(Error::XmlError(String::from("<Buckets> tag not found")))?;
let mut bucket_list: Vec<Bucket> = Vec::new();
while let Some(b) = buckets.take_child("Bucket") {
let bucket = b;
bucket_list.push(Bucket {
name: get_text(&bucket, "Name")?,
creation_date: from_iso8601utc(&get_text(&bucket, "CreationDate")?)?,
})
}
Ok(ListBucketsResponse {
headers: header_map.clone(),
buckets: bucket_list,
})
}
}
/// Response of
/// [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning)
/// API
#[derive(Clone, Debug)]
pub struct GetBucketVersioningResponse {
pub headers: HeaderMap,
pub region: String,
pub bucket: String,
pub status: Option<bool>,
pub mfa_delete: Option<bool>,
}
#[async_trait]
impl FromS3Response for GetBucketVersioningResponse {
async fn from_s3response<'a>(
req: S3Request<'a>,
resp: reqwest::Response,
) -> Result<Self, Error> {
let headers = resp.headers().clone();
let body = resp.bytes().await?;
let root = Element::parse(body.reader())?;
Ok(GetBucketVersioningResponse {
headers,
region: req.get_computed_region(),
bucket: req.bucket.unwrap().to_string(),
status: get_option_text(&root, "Status").map(|v| v == "Enabled"),
mfa_delete: get_option_text(&root, "MFADelete").map(|v| v == "Enabled"),
})
}
}

View File

@ -163,11 +163,7 @@ impl ClientTest {
}
let mut count = 0;
let resp = self
.client
.list_buckets(&ListBucketsArgs::new())
.await
.unwrap();
let resp = self.client.list_buckets().send().await.unwrap();
for bucket in resp.buckets.iter() {
if names.contains(&bucket.name) {
count += 1;
@ -1016,7 +1012,8 @@ impl ClientTest {
let resp = self
.client
.get_bucket_versioning(&GetBucketVersioningArgs::new(&bucket_name).unwrap())
.get_bucket_versioning(&bucket_name)
.send()
.await
.unwrap();
assert!(match resp.status {
@ -1031,7 +1028,8 @@ impl ClientTest {
let resp = self
.client
.get_bucket_versioning(&GetBucketVersioningArgs::new(&bucket_name).unwrap())
.get_bucket_versioning(&bucket_name)
.send()
.await
.unwrap();
assert!(