mirror of
https://github.com/minio/minio-rs.git
synced 2026-01-23 16:12:07 +08:00
Duplicated code removed, and lazy response evaluation (#162)
* Duplicated code removed, and lazy response evaluation * moved Tokio runtime from general dependency to dev dependency
This commit is contained in:
parent
6f904b452a
commit
720943b4bb
1
.github/workflows/rust.yml
vendored
1
.github/workflows/rust.yml
vendored
@ -7,6 +7,7 @@ on:
|
|||||||
branches: [ "master" ]
|
branches: [ "master" ]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
RUST_LOG: debug
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@ -43,7 +43,7 @@ pub(crate) async fn bench_object_append(criterion: &mut Criterion) {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let offset_bytes: u64 = resp.size;
|
let offset_bytes: u64 = resp.size().unwrap();
|
||||||
AppendObject::new(
|
AppendObject::new(
|
||||||
ctx.client.clone(),
|
ctx.client.clone(),
|
||||||
ctx.bucket.clone(),
|
ctx.bucket.clone(),
|
||||||
|
|||||||
@ -17,6 +17,7 @@ mod common;
|
|||||||
|
|
||||||
use crate::common::{create_bucket_if_not_exists, create_client_on_localhost};
|
use crate::common::{create_bucket_if_not_exists, create_client_on_localhost};
|
||||||
use minio::s3::Client;
|
use minio::s3::Client;
|
||||||
|
use minio::s3::response::a_response_traits::HasObjectSize;
|
||||||
use minio::s3::response::{AppendObjectResponse, StatObjectResponse};
|
use minio::s3::response::{AppendObjectResponse, StatObjectResponse};
|
||||||
use minio::s3::segmented_bytes::SegmentedBytes;
|
use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
use minio::s3::types::S3Api;
|
use minio::s3::types::S3Api;
|
||||||
@ -54,19 +55,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
offset_bytes += data_size;
|
offset_bytes += data_size;
|
||||||
if resp.object_size != offset_bytes {
|
if resp.object_size() != offset_bytes {
|
||||||
panic!(
|
panic!(
|
||||||
"from the append_object: size mismatch: expected {}, got {}",
|
"from the append_object: size mismatch: expected {}, got {}",
|
||||||
resp.object_size, offset_bytes
|
resp.object_size(),
|
||||||
|
offset_bytes
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
//println!("Append response: {:#?}", resp);
|
//println!("Append response: {:#?}", resp);
|
||||||
|
|
||||||
let resp: StatObjectResponse = client.stat_object(bucket_name, object_name).send().await?;
|
let resp: StatObjectResponse = client.stat_object(bucket_name, object_name).send().await?;
|
||||||
if resp.size != offset_bytes {
|
if resp.size()? != offset_bytes {
|
||||||
panic!(
|
panic!(
|
||||||
"from the stat_Object: size mismatch: expected {}, got {}",
|
"from the stat_Object: size mismatch: expected {}, got {}",
|
||||||
resp.size, offset_bytes
|
resp.size()?,
|
||||||
|
offset_bytes
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
println!("{}/{}", i, n_segments);
|
println!("{}/{}", i, n_segments);
|
||||||
|
|||||||
@ -30,7 +30,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
let resp: GetBucketEncryptionResponse =
|
let resp: GetBucketEncryptionResponse =
|
||||||
client.get_bucket_encryption(bucket_name).send().await?;
|
client.get_bucket_encryption(bucket_name).send().await?;
|
||||||
log::info!("encryption before: config={:?}", resp.config);
|
log::info!("encryption before: config={:?}", resp.config());
|
||||||
|
|
||||||
let config = SseConfig::default();
|
let config = SseConfig::default();
|
||||||
log::info!("going to set encryption config={:?}", config);
|
log::info!("going to set encryption config={:?}", config);
|
||||||
@ -43,7 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
let resp: GetBucketEncryptionResponse =
|
let resp: GetBucketEncryptionResponse =
|
||||||
client.get_bucket_encryption(bucket_name).send().await?;
|
client.get_bucket_encryption(bucket_name).send().await?;
|
||||||
log::info!("encryption after: config={:?}", resp.config);
|
log::info!("encryption after: config={:?}", resp.config());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,8 +33,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
client.get_bucket_versioning(bucket_name).send().await?;
|
client.get_bucket_versioning(bucket_name).send().await?;
|
||||||
log::info!(
|
log::info!(
|
||||||
"versioning before: status={:?}, mfa_delete={:?}",
|
"versioning before: status={:?}, mfa_delete={:?}",
|
||||||
resp.status,
|
resp.status(),
|
||||||
resp.mfa_delete
|
resp.mfa_delete()
|
||||||
);
|
);
|
||||||
|
|
||||||
let _resp: PutBucketVersioningResponse = client
|
let _resp: PutBucketVersioningResponse = client
|
||||||
@ -48,8 +48,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"versioning after setting to Enabled: status={:?}, mfa_delete={:?}",
|
"versioning after setting to Enabled: status={:?}, mfa_delete={:?}",
|
||||||
resp.status,
|
resp.status(),
|
||||||
resp.mfa_delete
|
resp.mfa_delete()
|
||||||
);
|
);
|
||||||
|
|
||||||
let _resp: PutBucketVersioningResponse = client
|
let _resp: PutBucketVersioningResponse = client
|
||||||
@ -63,8 +63,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"versioning after setting to Suspended: status={:?}, mfa_delete={:?}",
|
"versioning after setting to Suspended: status={:?}, mfa_delete={:?}",
|
||||||
resp.status,
|
resp.status(),
|
||||||
resp.mfa_delete
|
resp.mfa_delete()
|
||||||
);
|
);
|
||||||
|
|
||||||
let _resp: PutBucketVersioningResponse = client
|
let _resp: PutBucketVersioningResponse = client
|
||||||
@ -78,8 +78,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"versioning after setting to None: status={:?}, mfa_delete={:?}",
|
"versioning after setting to None: status={:?}, mfa_delete={:?}",
|
||||||
resp.status,
|
resp.status(),
|
||||||
resp.mfa_delete
|
resp.mfa_delete()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -42,7 +42,7 @@ pub async fn create_bucket_if_not_exists(
|
|||||||
let resp: BucketExistsResponse = client.bucket_exists(bucket_name).send().await?;
|
let resp: BucketExistsResponse = client.bucket_exists(bucket_name).send().await?;
|
||||||
|
|
||||||
// Make 'bucket_name' bucket if not exist.
|
// Make 'bucket_name' bucket if not exist.
|
||||||
if !resp.exists {
|
if !resp.exists() {
|
||||||
client.create_bucket(bucket_name).send().await.unwrap();
|
client.create_bucket(bucket_name).send().await.unwrap();
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -55,7 +55,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
let get_object = client.get_object(bucket_name, object_name).send().await?;
|
let get_object = client.get_object(bucket_name, object_name).send().await?;
|
||||||
|
|
||||||
get_object.content.to_file(Path::new(download_path)).await?;
|
get_object
|
||||||
|
.content()?
|
||||||
|
.to_file(Path::new(download_path))
|
||||||
|
.await?;
|
||||||
|
|
||||||
log::info!("Object '{object_name}' is successfully downloaded to file '{download_path}'.");
|
log::info!("Object '{object_name}' is successfully downloaded to file '{download_path}'.");
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
log::info!("Object prompt result: '{}'", resp.prompt_response);
|
log::info!("Object prompt result: '{}'", resp.prompt_response()?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
let resp: BucketExistsResponse = client.bucket_exists(&args.bucket).send().await.unwrap();
|
let resp: BucketExistsResponse = client.bucket_exists(&args.bucket).send().await.unwrap();
|
||||||
|
|
||||||
if !resp.exists {
|
if !resp.exists() {
|
||||||
client.create_bucket(&args.bucket).send().await.unwrap();
|
client.create_bucket(&args.bucket).send().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
//! .await
|
//! .await
|
||||||
//! .expect("request failed");
|
//! .expect("request failed");
|
||||||
//!
|
//!
|
||||||
//! println!("Bucket exists: {}", exists.exists);
|
//! println!("Bucket exists: {}", exists.exists());
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use crate::s3::builders::{
|
|||||||
};
|
};
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::{Multimap, MultimapExt};
|
use crate::s3::multimap::{Multimap, MultimapExt};
|
||||||
|
use crate::s3::response::a_response_traits::HasObjectSize;
|
||||||
use crate::s3::response::{AppendObjectResponse, StatObjectResponse};
|
use crate::s3::response::{AppendObjectResponse, StatObjectResponse};
|
||||||
use crate::s3::segmented_bytes::SegmentedBytes;
|
use crate::s3::segmented_bytes::SegmentedBytes;
|
||||||
use crate::s3::sse::Sse;
|
use crate::s3::sse::Sse;
|
||||||
@ -26,7 +27,6 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
|
|||||||
use crate::s3::utils::{check_bucket_name, check_object_name};
|
use crate::s3::utils::{check_bucket_name, check_object_name};
|
||||||
use http::Method;
|
use http::Method;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// region: append-object
|
// region: append-object
|
||||||
|
|
||||||
/// Argument builder for the [`AppendObject`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-append.html) S3 API operation.
|
/// Argument builder for the [`AppendObject`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-append.html) S3 API operation.
|
||||||
@ -234,7 +234,7 @@ impl AppendObjectContent {
|
|||||||
.await?;
|
.await?;
|
||||||
//println!("statObjectResponse={:#?}", resp);
|
//println!("statObjectResponse={:#?}", resp);
|
||||||
|
|
||||||
let current_file_size = resp.size;
|
let current_file_size = resp.size()?;
|
||||||
|
|
||||||
// In the first part read, if:
|
// In the first part read, if:
|
||||||
//
|
//
|
||||||
@ -322,7 +322,7 @@ impl AppendObjectContent {
|
|||||||
let resp: AppendObjectResponse = append_object.send().await?;
|
let resp: AppendObjectResponse = append_object.send().await?;
|
||||||
//println!("AppendObjectResponse: object_size={:?}", resp.object_size);
|
//println!("AppendObjectResponse: object_size={:?}", resp.object_size);
|
||||||
|
|
||||||
next_offset_bytes = resp.object_size;
|
next_offset_bytes = resp.object_size();
|
||||||
|
|
||||||
// Finally check if we are done.
|
// Finally check if we are done.
|
||||||
if buffer_size < part_size {
|
if buffer_size < part_size {
|
||||||
|
|||||||
@ -17,9 +17,11 @@ use crate::s3::Client;
|
|||||||
use crate::s3::client::{MAX_MULTIPART_COUNT, MAX_PART_SIZE};
|
use crate::s3::client::{MAX_MULTIPART_COUNT, MAX_PART_SIZE};
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::{Multimap, MultimapExt};
|
use crate::s3::multimap::{Multimap, MultimapExt};
|
||||||
|
use crate::s3::response::a_response_traits::HasEtagFromBody;
|
||||||
use crate::s3::response::{
|
use crate::s3::response::{
|
||||||
AbortMultipartUploadResponse, ComposeObjectResponse, CopyObjectInternalResponse,
|
AbortMultipartUploadResponse, CompleteMultipartUploadResponse, ComposeObjectResponse,
|
||||||
CopyObjectResponse, CreateMultipartUploadResponse, StatObjectResponse, UploadPartCopyResponse,
|
CopyObjectInternalResponse, CopyObjectResponse, CreateMultipartUploadResponse,
|
||||||
|
StatObjectResponse, UploadPartCopyResponse,
|
||||||
};
|
};
|
||||||
use crate::s3::sse::{Sse, SseCustomerKey};
|
use crate::s3::sse::{Sse, SseCustomerKey};
|
||||||
use crate::s3::types::{Directive, PartInfo, Retention, S3Api, S3Request, ToS3Request};
|
use crate::s3::types::{Directive, PartInfo, Retention, S3Api, S3Request, ToS3Request};
|
||||||
@ -445,7 +447,7 @@ impl CopyObject {
|
|||||||
|
|
||||||
if self.source.offset.is_some()
|
if self.source.offset.is_some()
|
||||||
|| self.source.length.is_some()
|
|| self.source.length.is_some()
|
||||||
|| stat_resp.size > MAX_PART_SIZE
|
|| stat_resp.size()? > MAX_PART_SIZE
|
||||||
{
|
{
|
||||||
if let Some(v) = &self.metadata_directive {
|
if let Some(v) = &self.metadata_directive {
|
||||||
match v {
|
match v {
|
||||||
@ -499,14 +501,8 @@ impl CopyObject {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(CopyObjectResponse {
|
let resp: CopyObjectResponse = resp; // retype to CopyObjectResponse
|
||||||
headers: resp.headers,
|
Ok(resp)
|
||||||
bucket: resp.bucket,
|
|
||||||
object: resp.object,
|
|
||||||
region: resp.region,
|
|
||||||
etag: resp.etag,
|
|
||||||
version_id: resp.version_id,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
let resp: CopyObjectInternalResponse = self
|
let resp: CopyObjectInternalResponse = self
|
||||||
.client
|
.client
|
||||||
@ -526,14 +522,8 @@ impl CopyObject {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(CopyObjectResponse {
|
let resp: CopyObjectResponse = resp; // retype to CopyObjectResponse
|
||||||
headers: resp.headers,
|
Ok(resp)
|
||||||
bucket: resp.bucket,
|
|
||||||
object: resp.object,
|
|
||||||
region: resp.region,
|
|
||||||
etag: resp.etag,
|
|
||||||
version_id: resp.version_id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,17 +642,9 @@ impl ComposeObjectInternal {
|
|||||||
Err(e) => return (Err(e), upload_id),
|
Err(e) => return (Err(e), upload_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
let resp: ComposeObjectResponse = resp; // retype to ComposeObjectResponse
|
||||||
Ok(ComposeObjectResponse {
|
|
||||||
headers: resp.headers,
|
(Ok(resp), upload_id)
|
||||||
bucket: resp.bucket,
|
|
||||||
object: resp.object,
|
|
||||||
region: resp.region,
|
|
||||||
etag: resp.etag,
|
|
||||||
version_id: resp.version_id,
|
|
||||||
}),
|
|
||||||
upload_id,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let headers: Multimap = into_headers_copy_object(
|
let headers: Multimap = into_headers_copy_object(
|
||||||
self.extra_headers,
|
self.extra_headers,
|
||||||
@ -687,7 +669,11 @@ impl ComposeObjectInternal {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// the multipart upload was successful: update the upload_id
|
// the multipart upload was successful: update the upload_id
|
||||||
upload_id.push_str(&cmu.upload_id);
|
let upload_id_cmu: String = match cmu.upload_id().await {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return (Err(e), upload_id),
|
||||||
|
};
|
||||||
|
upload_id.push_str(&upload_id_cmu);
|
||||||
|
|
||||||
let mut part_number = 0_u16;
|
let mut part_number = 0_u16;
|
||||||
let ssec_headers: Multimap = match self.sse {
|
let ssec_headers: Multimap = match self.sse {
|
||||||
@ -739,9 +725,14 @@ impl ComposeObjectInternal {
|
|||||||
Err(e) => return (Err(e), upload_id),
|
Err(e) => return (Err(e), upload_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let etag = match resp.etag() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return (Err(e), upload_id),
|
||||||
|
};
|
||||||
|
|
||||||
parts.push(PartInfo {
|
parts.push(PartInfo {
|
||||||
number: part_number,
|
number: part_number,
|
||||||
etag: resp.etag,
|
etag,
|
||||||
size,
|
size,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -773,9 +764,14 @@ impl ComposeObjectInternal {
|
|||||||
Err(e) => return (Err(e), upload_id),
|
Err(e) => return (Err(e), upload_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let etag = match resp.etag() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return (Err(e), upload_id),
|
||||||
|
};
|
||||||
|
|
||||||
parts.push(PartInfo {
|
parts.push(PartInfo {
|
||||||
number: part_number,
|
number: part_number,
|
||||||
etag: resp.etag,
|
etag,
|
||||||
size,
|
size,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -785,7 +781,7 @@ impl ComposeObjectInternal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let resp = self
|
let resp: Result<CompleteMultipartUploadResponse, Error> = self
|
||||||
.client
|
.client
|
||||||
.complete_multipart_upload(&self.bucket, &self.object, &upload_id, parts)
|
.complete_multipart_upload(&self.bucket, &self.object, &upload_id, parts)
|
||||||
.region(self.region)
|
.region(self.region)
|
||||||
@ -793,17 +789,14 @@ impl ComposeObjectInternal {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
match resp {
|
match resp {
|
||||||
Ok(v) => (
|
Ok(v) => {
|
||||||
Ok(ComposeObjectResponse {
|
let resp = ComposeObjectResponse {
|
||||||
|
request: v.request,
|
||||||
headers: v.headers,
|
headers: v.headers,
|
||||||
bucket: v.bucket,
|
body: v.body,
|
||||||
object: v.object,
|
};
|
||||||
region: v.region,
|
(Ok(resp), upload_id)
|
||||||
etag: v.etag,
|
}
|
||||||
version_id: v.version_id,
|
|
||||||
}),
|
|
||||||
upload_id,
|
|
||||||
),
|
|
||||||
Err(e) => (Err(e), upload_id),
|
Err(e) => (Err(e), upload_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -241,7 +241,7 @@ impl ToS3Request for DeleteObjects {
|
|||||||
fn to_s3request(self) -> Result<S3Request, Error> {
|
fn to_s3request(self) -> Result<S3Request, Error> {
|
||||||
check_bucket_name(&self.bucket, true)?;
|
check_bucket_name(&self.bucket, true)?;
|
||||||
|
|
||||||
let mut data = String::from("<Delete>");
|
let mut data: String = String::from("<Delete>");
|
||||||
if !self.verbose_mode {
|
if !self.verbose_mode {
|
||||||
data.push_str("<Quiet>true</Quiet>");
|
data.push_str("<Quiet>true</Quiet>");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
use super::ObjectContent;
|
use super::ObjectContent;
|
||||||
use crate::s3::multimap::{Multimap, MultimapExt};
|
use crate::s3::multimap::{Multimap, MultimapExt};
|
||||||
|
use crate::s3::response::a_response_traits::HasEtagFromHeaders;
|
||||||
use crate::s3::segmented_bytes::SegmentedBytes;
|
use crate::s3::segmented_bytes::SegmentedBytes;
|
||||||
use crate::s3::utils::{check_object_name, insert};
|
use crate::s3::utils::{check_object_name, insert};
|
||||||
use crate::s3::{
|
use crate::s3::{
|
||||||
@ -665,7 +666,7 @@ impl PutObjectContent {
|
|||||||
{
|
{
|
||||||
let size = seg_bytes.len() as u64;
|
let size = seg_bytes.len() as u64;
|
||||||
|
|
||||||
let res: PutObjectResponse = PutObject(UploadPart {
|
let resp: PutObjectResponse = PutObject(UploadPart {
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
extra_headers: self.extra_headers.clone(),
|
extra_headers: self.extra_headers.clone(),
|
||||||
extra_query_params: self.extra_query_params.clone(),
|
extra_query_params: self.extra_query_params.clone(),
|
||||||
@ -685,15 +686,7 @@ impl PutObjectContent {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(PutObjectContentResponse {
|
Ok(PutObjectContentResponse::new(resp, size))
|
||||||
headers: res.headers,
|
|
||||||
bucket: res.bucket,
|
|
||||||
object: res.object,
|
|
||||||
region: res.region,
|
|
||||||
object_size: size,
|
|
||||||
etag: res.etag,
|
|
||||||
version_id: res.version_id,
|
|
||||||
})
|
|
||||||
} else if object_size.is_known() && (seg_bytes.len() as u64) < part_size {
|
} else if object_size.is_known() && (seg_bytes.len() as u64) < part_size {
|
||||||
// Not enough data!
|
// Not enough data!
|
||||||
let expected: u64 = object_size.as_u64().unwrap();
|
let expected: u64 = object_size.as_u64().unwrap();
|
||||||
@ -722,21 +715,17 @@ impl PutObjectContent {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
|
let upload_id: String = create_mpu_resp.upload_id().await?;
|
||||||
|
|
||||||
let mpu_res = self
|
let mpu_res = self
|
||||||
.send_mpu(
|
.send_mpu(part_size, upload_id.clone(), object_size, seg_bytes)
|
||||||
part_size,
|
|
||||||
create_mpu_resp.upload_id.clone(),
|
|
||||||
object_size,
|
|
||||||
seg_bytes,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if mpu_res.is_err() {
|
if mpu_res.is_err() {
|
||||||
// If we failed to complete the multipart upload, we should abort it.
|
// If we failed to complete the multipart upload, we should abort it.
|
||||||
let _ =
|
let _ = AbortMultipartUpload::new(client, bucket, object, upload_id)
|
||||||
AbortMultipartUpload::new(client, bucket, object, create_mpu_resp.upload_id)
|
.send()
|
||||||
.send()
|
.await;
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
mpu_res
|
mpu_res
|
||||||
}
|
}
|
||||||
@ -815,7 +804,7 @@ impl PutObjectContent {
|
|||||||
|
|
||||||
parts.push(PartInfo {
|
parts.push(PartInfo {
|
||||||
number: part_number,
|
number: part_number,
|
||||||
etag: resp.etag,
|
etag: resp.etag()?,
|
||||||
size: buffer_size,
|
size: buffer_size,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -835,7 +824,7 @@ impl PutObjectContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let res: CompleteMultipartUploadResponse = CompleteMultipartUpload {
|
let resp: CompleteMultipartUploadResponse = CompleteMultipartUpload {
|
||||||
client: self.client,
|
client: self.client,
|
||||||
extra_headers: self.extra_headers,
|
extra_headers: self.extra_headers,
|
||||||
extra_query_params: self.extra_query_params,
|
extra_query_params: self.extra_query_params,
|
||||||
@ -848,15 +837,7 @@ impl PutObjectContent {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(PutObjectContentResponse {
|
Ok(PutObjectContentResponse::new(resp, size))
|
||||||
headers: res.headers,
|
|
||||||
bucket: res.bucket,
|
|
||||||
object: res.object,
|
|
||||||
region: res.region,
|
|
||||||
object_size: size,
|
|
||||||
etag: res.etag,
|
|
||||||
version_id: res.version_id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,16 +21,17 @@ use std::mem;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
|
use crate::s3::builders::{BucketExists, ComposeSource};
|
||||||
use crate::s3::creds::Provider;
|
use crate::s3::creds::Provider;
|
||||||
use crate::s3::error::{Error, ErrorCode, ErrorResponse};
|
use crate::s3::error::{Error, ErrorCode, ErrorResponse};
|
||||||
use crate::s3::http::BaseUrl;
|
use crate::s3::http::BaseUrl;
|
||||||
|
use crate::s3::multimap::{Multimap, MultimapExt};
|
||||||
|
use crate::s3::response::a_response_traits::{HasEtagFromHeaders, HasS3Fields};
|
||||||
use crate::s3::response::*;
|
use crate::s3::response::*;
|
||||||
|
use crate::s3::segmented_bytes::SegmentedBytes;
|
||||||
use crate::s3::signer::sign_v4_s3;
|
use crate::s3::signer::sign_v4_s3;
|
||||||
use crate::s3::utils::{EMPTY_SHA256, sha256_hash_sb, to_amz_date, utc_now};
|
use crate::s3::utils::{EMPTY_SHA256, sha256_hash_sb, to_amz_date, utc_now};
|
||||||
|
|
||||||
use crate::s3::builders::{BucketExists, ComposeSource};
|
|
||||||
use crate::s3::multimap::{Multimap, MultimapExt};
|
|
||||||
use crate::s3::segmented_bytes::SegmentedBytes;
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
@ -280,7 +281,7 @@ impl Client {
|
|||||||
|
|
||||||
let express = match BucketExists::new(self.clone(), bucket_name).send().await {
|
let express = match BucketExists::new(self.clone(), bucket_name).send().await {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
if let Some(server) = v.headers.get("server") {
|
if let Some(server) = v.headers().get("server") {
|
||||||
if let Ok(s) = server.to_str() {
|
if let Ok(s) = server.to_str() {
|
||||||
s.eq_ignore_ascii_case("MinIO Enterprise/S3Express")
|
s.eq_ignore_ascii_case("MinIO Enterprise/S3Express")
|
||||||
} else {
|
} else {
|
||||||
@ -300,7 +301,6 @@ impl Client {
|
|||||||
express
|
express
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a bucket-region pair to the region cache if it does not exist.
|
/// Add a bucket-region pair to the region cache if it does not exist.
|
||||||
pub(crate) fn add_bucket_region(&mut self, bucket: &str, region: impl Into<String>) {
|
pub(crate) fn add_bucket_region(&mut self, bucket: &str, region: impl Into<String>) {
|
||||||
self.shared
|
self.shared
|
||||||
@ -360,9 +360,9 @@ impl Client {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
source.build_headers(stat_resp.size, stat_resp.etag)?;
|
let mut size = stat_resp.size()?;
|
||||||
|
source.build_headers(size, stat_resp.etag()?)?;
|
||||||
|
|
||||||
let mut size = stat_resp.size;
|
|
||||||
if let Some(l) = source.length {
|
if let Some(l) = source.length {
|
||||||
size = l;
|
size = l;
|
||||||
} else if let Some(o) = source.offset {
|
} else if let Some(o) = source.offset {
|
||||||
@ -493,15 +493,12 @@ impl Client {
|
|||||||
// Sort headers alphabetically by name
|
// Sort headers alphabetically by name
|
||||||
header_strings.sort();
|
header_strings.sort();
|
||||||
|
|
||||||
let body_str: String =
|
|
||||||
String::from_utf8(body.unwrap_or(&SegmentedBytes::new()).to_bytes().to_vec())?;
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"S3 request: {} url={:?}; headers={:?}; body={}\n",
|
"S3 request: {} url={:?}; headers={:?}; body={}\n",
|
||||||
method,
|
method,
|
||||||
url.path,
|
url.path,
|
||||||
header_strings.join("; "),
|
header_strings.join("; "),
|
||||||
body_str
|
body.unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ impl Client {
|
|||||||
/// use minio::s3::response::{AppendObjectResponse, PutObjectResponse};
|
/// use minio::s3::response::{AppendObjectResponse, PutObjectResponse};
|
||||||
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObjectSize;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -49,7 +50,7 @@ impl Client {
|
|||||||
/// let resp: AppendObjectResponse = client
|
/// let resp: AppendObjectResponse = client
|
||||||
/// .append_object("bucket-name", "object-name", data2, offset_bytes)
|
/// .append_object("bucket-name", "object-name", data2, offset_bytes)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("size of the final object is {} bytes", resp.object_size);
|
/// println!("size of the final object is {} bytes", resp.object_size());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn append_object<S1: Into<String>, S2: Into<String>>(
|
pub fn append_object<S1: Into<String>, S2: Into<String>>(
|
||||||
@ -85,10 +86,11 @@ impl Client {
|
|||||||
/// use minio::s3::builders::ObjectContent;
|
/// use minio::s3::builders::ObjectContent;
|
||||||
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObjectSize;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let data1: SegmentedBytes = SegmentedBytes::from("aaaa".to_string());
|
/// let data1: SegmentedBytes = SegmentedBytes::from("aaaa".to_string());
|
||||||
/// let content2: String = "bbbb".to_string();
|
/// let content2: String = "bbbb".to_string();
|
||||||
/// let resp: PutObjectResponse = client
|
/// let resp: PutObjectResponse = client
|
||||||
@ -97,7 +99,7 @@ impl Client {
|
|||||||
/// let resp: AppendObjectResponse = client
|
/// let resp: AppendObjectResponse = client
|
||||||
/// .append_object_content("bucket-name", "object-name", content2)
|
/// .append_object_content("bucket-name", "object-name", content2)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("size of the final object is {} bytes", resp.object_size);
|
/// println!("size of the final object is {} bytes", resp.object_size());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn append_object_content<S1: Into<String>, S2: Into<String>, C: Into<ObjectContent>>(
|
pub fn append_object_content<S1: Into<String>, S2: Into<String>, C: Into<ObjectContent>>(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::BucketExistsResponse;
|
/// use minio::s3::response::BucketExistsResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: BucketExistsResponse = client
|
/// let resp: BucketExistsResponse = client
|
||||||
/// .bucket_exists("bucket-name")
|
/// .bucket_exists("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("bucket '{}' exists: {}", resp.bucket, resp.exists);
|
/// println!("bucket '{}' exists: {}", resp.bucket(), resp.exists());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn bucket_exists<S: Into<String>>(&self, bucket: S) -> BucketExists {
|
pub fn bucket_exists<S: Into<String>>(&self, bucket: S) -> BucketExists {
|
||||||
|
|||||||
@ -33,6 +33,7 @@ impl Client {
|
|||||||
/// use minio::s3::response::{UploadPartCopyResponse};
|
/// use minio::s3::response::{UploadPartCopyResponse};
|
||||||
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -42,7 +43,7 @@ impl Client {
|
|||||||
/// let resp: UploadPartCopyResponse = client
|
/// let resp: UploadPartCopyResponse = client
|
||||||
/// .upload_part_copy("bucket-name", "object-name", "TODO")
|
/// .upload_part_copy("bucket-name", "object-name", "TODO")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("uploaded {}", resp.object);
|
/// println!("uploaded {}", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn upload_part_copy<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
pub fn upload_part_copy<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::CreateBucketResponse;
|
/// use minio::s3::response::CreateBucketResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasRegion};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: CreateBucketResponse = client
|
/// let resp: CreateBucketResponse = client
|
||||||
/// .create_bucket("bucket-name")
|
/// .create_bucket("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("Made bucket '{}' in region '{}'", resp.bucket, resp.region);
|
/// println!("Made bucket '{}' in region '{}'", resp.bucket(), resp.region());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn create_bucket<S: Into<String>>(&self, bucket: S) -> CreateBucket {
|
pub fn create_bucket<S: Into<String>>(&self, bucket: S) -> CreateBucket {
|
||||||
|
|||||||
@ -21,6 +21,7 @@ use crate::s3::response::{
|
|||||||
DeleteBucketResponse, DeleteObjectResponse, DeleteObjectsResponse, PutObjectLegalHoldResponse,
|
DeleteBucketResponse, DeleteObjectResponse, DeleteObjectsResponse, PutObjectLegalHoldResponse,
|
||||||
};
|
};
|
||||||
use crate::s3::types::{S3Api, ToStream};
|
use crate::s3::types::{S3Api, ToStream};
|
||||||
|
use bytes::Bytes;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
@ -35,13 +36,14 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketResponse;
|
/// use minio::s3::response::DeleteBucketResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasRegion};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let resp: DeleteBucketResponse =
|
/// let resp: DeleteBucketResponse =
|
||||||
/// client.delete_bucket("bucket-name").send().await.unwrap();
|
/// client.delete_bucket("bucket-name").send().await.unwrap();
|
||||||
/// println!("bucket '{}' in region '{}' is removed", resp.bucket, resp.region);
|
/// println!("bucket '{}' in region '{}' is removed", resp.bucket(), resp.region());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket<S: Into<String>>(&self, bucket: S) -> DeleteBucket {
|
pub fn delete_bucket<S: Into<String>>(&self, bucket: S) -> DeleteBucket {
|
||||||
@ -90,7 +92,7 @@ impl Client {
|
|||||||
|
|
||||||
while let Some(item) = resp.next().await {
|
while let Some(item) = resp.next().await {
|
||||||
let resp: DeleteObjectsResponse = item?;
|
let resp: DeleteObjectsResponse = item?;
|
||||||
for obj in resp.result.into_iter() {
|
for obj in resp.result()?.into_iter() {
|
||||||
match obj {
|
match obj {
|
||||||
DeleteResult::Deleted(_) => {}
|
DeleteResult::Deleted(_) => {}
|
||||||
DeleteResult::Error(v) => {
|
DeleteResult::Error(v) => {
|
||||||
@ -115,14 +117,15 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.delete_bucket(bucket).send().await {
|
let request: DeleteBucket = self.delete_bucket(bucket);
|
||||||
|
match request.send().await {
|
||||||
Ok(resp) => Ok(resp),
|
Ok(resp) => Ok(resp),
|
||||||
Err(Error::S3Error(e)) => {
|
Err(Error::S3Error(e)) => {
|
||||||
if e.code == ErrorCode::NoSuchBucket {
|
if e.code == ErrorCode::NoSuchBucket {
|
||||||
Ok(DeleteBucketResponse {
|
Ok(DeleteBucketResponse {
|
||||||
|
request: Default::default(), //TODO consider how to handle this
|
||||||
|
body: Bytes::new(),
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
bucket: e.bucket_name,
|
|
||||||
region: String::new(),
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::S3Error(e))
|
Err(Error::S3Error(e))
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketEncryptionResponse;
|
/// use minio::s3::response::DeleteBucketEncryptionResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketEncryptionResponse = client
|
/// let resp: DeleteBucketEncryptionResponse = client
|
||||||
/// .delete_bucket_encryption("bucket-name")
|
/// .delete_bucket_encryption("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("bucket '{}' is deleted", resp.bucket);
|
/// println!("bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_encryption<S: Into<String>>(&self, bucket: S) -> DeleteBucketEncryption {
|
pub fn delete_bucket_encryption<S: Into<String>>(&self, bucket: S) -> DeleteBucketEncryption {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketLifecycleResponse;
|
/// use minio::s3::response::DeleteBucketLifecycleResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketLifecycleResponse = client
|
/// let resp: DeleteBucketLifecycleResponse = client
|
||||||
/// .delete_bucket_lifecycle("bucket-name")
|
/// .delete_bucket_lifecycle("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("lifecycle of bucket '{}' is deleted", resp.bucket);
|
/// println!("lifecycle of bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> DeleteBucketLifecycle {
|
pub fn delete_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> DeleteBucketLifecycle {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketNotificationResponse;
|
/// use minio::s3::response::DeleteBucketNotificationResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketNotificationResponse = client
|
/// let resp: DeleteBucketNotificationResponse = client
|
||||||
/// .delete_bucket_notification("bucket-name")
|
/// .delete_bucket_notification("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("notification of bucket '{}' is deleted", resp.bucket);
|
/// println!("notification of bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_notification<S: Into<String>>(
|
pub fn delete_bucket_notification<S: Into<String>>(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketPolicyResponse;
|
/// use minio::s3::response::DeleteBucketPolicyResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketPolicyResponse = client
|
/// let resp: DeleteBucketPolicyResponse = client
|
||||||
/// .delete_bucket_policy("bucket-name")
|
/// .delete_bucket_policy("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("policy of bucket '{}' is deleted", resp.bucket);
|
/// println!("policy of bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_policy<S: Into<String>>(&self, bucket: S) -> DeleteBucketPolicy {
|
pub fn delete_bucket_policy<S: Into<String>>(&self, bucket: S) -> DeleteBucketPolicy {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketReplicationResponse;
|
/// use minio::s3::response::DeleteBucketReplicationResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketReplicationResponse = client
|
/// let resp: DeleteBucketReplicationResponse = client
|
||||||
/// .delete_bucket_replication("bucket-name")
|
/// .delete_bucket_replication("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("replication of bucket '{}' is deleted", resp.bucket);
|
/// println!("replication of bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_replication<S: Into<String>>(&self, bucket: S) -> DeleteBucketReplication {
|
pub fn delete_bucket_replication<S: Into<String>>(&self, bucket: S) -> DeleteBucketReplication {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteBucketTaggingResponse;
|
/// use minio::s3::response::DeleteBucketTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: DeleteBucketTaggingResponse = client
|
/// let resp: DeleteBucketTaggingResponse = client
|
||||||
/// .delete_bucket_tagging("bucket-name")
|
/// .delete_bucket_tagging("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("tags of bucket '{}' are deleted", resp.bucket);
|
/// println!("tags of bucket '{}' are deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_bucket_tagging<S: Into<String>>(&self, bucket: S) -> DeleteBucketTagging {
|
pub fn delete_bucket_tagging<S: Into<String>>(&self, bucket: S) -> DeleteBucketTagging {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::{DeleteObjectLockConfigResponse, CreateBucketResponse, PutObjectLockConfigResponse};
|
/// use minio::s3::response::{DeleteObjectLockConfigResponse, CreateBucketResponse, PutObjectLockConfigResponse};
|
||||||
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -38,18 +39,19 @@ impl Client {
|
|||||||
///
|
///
|
||||||
/// let resp: CreateBucketResponse =
|
/// let resp: CreateBucketResponse =
|
||||||
/// client.create_bucket(bucket_name).object_lock(true).send().await.unwrap();
|
/// client.create_bucket(bucket_name).object_lock(true).send().await.unwrap();
|
||||||
/// println!("created bucket '{}' with object locking enabled", resp.bucket);
|
/// println!("created bucket '{}' with object locking enabled", resp.bucket());
|
||||||
///
|
///
|
||||||
/// const DURATION_DAYS: i32 = 7;
|
///
|
||||||
|
/// const DURATION_DAYS: i32 = 7;
|
||||||
/// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap();
|
/// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap();
|
||||||
///
|
///
|
||||||
/// let resp: PutObjectLockConfigResponse =
|
/// let resp: PutObjectLockConfigResponse =
|
||||||
/// client.put_object_lock_config(bucket_name).config(config).send().await.unwrap();
|
/// client.put_object_lock_config(bucket_name).config(config).send().await.unwrap();
|
||||||
/// println!("configured object locking for bucket '{}'", resp.bucket);
|
/// println!("configured object locking for bucket '{}'", resp.bucket());
|
||||||
///
|
///
|
||||||
/// let resp: DeleteObjectLockConfigResponse =
|
/// let resp: DeleteObjectLockConfigResponse =
|
||||||
/// client.delete_object_lock_config(bucket_name).send().await.unwrap();
|
/// client.delete_object_lock_config(bucket_name).send().await.unwrap();
|
||||||
/// println!("object locking of bucket '{}' is deleted", resp.bucket);
|
/// println!("object locking of bucket '{}' is deleted", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_object_lock_config<S: Into<String>>(&self, bucket: S) -> DeleteObjectLockConfig {
|
pub fn delete_object_lock_config<S: Into<String>>(&self, bucket: S) -> DeleteObjectLockConfig {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::DeleteObjectTaggingResponse;
|
/// use minio::s3::response::DeleteObjectTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasObject};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: DeleteObjectTaggingResponse = client
|
/// let resp: DeleteObjectTaggingResponse = client
|
||||||
/// .delete_object_tagging("bucket-name", "object_name")
|
/// .delete_object_tagging("bucket-name", "object_name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("legal hold of object '{}' in bucket '{}' is deleted", resp.object, resp.bucket);
|
/// println!("legal hold of object '{}' in bucket '{}' is deleted", resp.object(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_object_tagging<S1: Into<String>, S2: Into<String>>(
|
pub fn delete_object_tagging<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -33,14 +33,15 @@ impl Client {
|
|||||||
/// use minio::s3::response::DeleteObjectResponse;
|
/// use minio::s3::response::DeleteObjectResponse;
|
||||||
/// use minio::s3::builders::ObjectToDelete;
|
/// use minio::s3::builders::ObjectToDelete;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasVersion;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let resp: DeleteObjectResponse = client
|
/// let resp: DeleteObjectResponse = client
|
||||||
/// .delete_object("bucket-name", ObjectToDelete::from("object-name"))
|
/// .delete_object("bucket-name", ObjectToDelete::from("object-name"))
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("the object is deleted. The delete marker has version '{:?}'", resp.version_id);
|
/// println!("the object is deleted. The delete marker has version '{:?}'", resp.version_id());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn delete_object<S: Into<String>, D: Into<ObjectToDelete>>(
|
pub fn delete_object<S: Into<String>, D: Into<ObjectToDelete>>(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketEncryptionResponse;
|
/// use minio::s3::response::GetBucketEncryptionResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketEncryptionResponse = client
|
/// let resp: GetBucketEncryptionResponse = client
|
||||||
/// .get_bucket_encryption("bucket-name")
|
/// .get_bucket_encryption("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved SseConfig '{:?}' from bucket '{}'", resp.config, resp.bucket);
|
/// println!("retrieved SseConfig '{:?}' from bucket '{}'", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_encryption<S: Into<String>>(&self, bucket: S) -> GetBucketEncryption {
|
pub fn get_bucket_encryption<S: Into<String>>(&self, bucket: S) -> GetBucketEncryption {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketLifecycleResponse;
|
/// use minio::s3::response::GetBucketLifecycleResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketLifecycleResponse = client
|
/// let resp: GetBucketLifecycleResponse = client
|
||||||
/// .get_bucket_lifecycle("bucket-name")
|
/// .get_bucket_lifecycle("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved bucket lifecycle config '{:?}' from bucket '{}'", resp.config, resp.bucket);
|
/// println!("retrieved bucket lifecycle config '{:?}' from bucket '{}'", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> GetBucketLifecycle {
|
pub fn get_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> GetBucketLifecycle {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketNotificationResponse;
|
/// use minio::s3::response::GetBucketNotificationResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketNotificationResponse = client
|
/// let resp: GetBucketNotificationResponse = client
|
||||||
/// .get_bucket_notification("bucket-name")
|
/// .get_bucket_notification("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved bucket notification config '{:?}' from bucket '{}'", resp.config, resp.bucket);
|
/// println!("retrieved bucket notification config '{:?}' from bucket '{}'", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_notification<S: Into<String>>(&self, bucket: S) -> GetBucketNotification {
|
pub fn get_bucket_notification<S: Into<String>>(&self, bucket: S) -> GetBucketNotification {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketPolicyResponse;
|
/// use minio::s3::response::GetBucketPolicyResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -35,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketPolicyResponse = client
|
/// let resp: GetBucketPolicyResponse = client
|
||||||
/// .get_bucket_policy("bucket-name")
|
/// .get_bucket_policy("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved bucket policy config '{:?}' from bucket '{}'", resp.config, resp.bucket);
|
/// println!("retrieved bucket policy config '{:?}' from bucket '{}'", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_policy<S: Into<String>>(&self, bucket: S) -> GetBucketPolicy {
|
pub fn get_bucket_policy<S: Into<String>>(&self, bucket: S) -> GetBucketPolicy {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketReplicationResponse;
|
/// use minio::s3::response::GetBucketReplicationResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketReplicationResponse = client
|
/// let resp: GetBucketReplicationResponse = client
|
||||||
/// .get_bucket_replication("bucket-name")
|
/// .get_bucket_replication("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved bucket replication config '{:?}' from bucket '{}'", resp.config, resp.bucket);
|
/// println!("retrieved bucket replication config '{:?}' from bucket '{}'", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_replication<S: Into<String>>(&self, bucket: S) -> GetBucketReplication {
|
pub fn get_bucket_replication<S: Into<String>>(&self, bucket: S) -> GetBucketReplication {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketTaggingResponse;
|
/// use minio::s3::response::GetBucketTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasTagging};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketTaggingResponse = client
|
/// let resp: GetBucketTaggingResponse = client
|
||||||
/// .get_bucket_tagging("bucket-name")
|
/// .get_bucket_tagging("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved bucket tags '{:?}' from bucket '{}'", resp.tags, resp.bucket);
|
/// println!("retrieved bucket tags '{:?}' from bucket '{}'", resp.tags(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_tagging<S: Into<String>>(&self, bucket: S) -> GetBucketTagging {
|
pub fn get_bucket_tagging<S: Into<String>>(&self, bucket: S) -> GetBucketTagging {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetBucketVersioningResponse;
|
/// use minio::s3::response::GetBucketVersioningResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetBucketVersioningResponse = client
|
/// let resp: GetBucketVersioningResponse = client
|
||||||
/// .get_bucket_versioning("bucket-name")
|
/// .get_bucket_versioning("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved versioning status '{:?}' from bucket '{}'", resp.status, resp.bucket);
|
/// println!("retrieved versioning status '{:?}' from bucket '{}'", resp.status(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_bucket_versioning<S: Into<String>>(&self, bucket: S) -> GetBucketVersioning {
|
pub fn get_bucket_versioning<S: Into<String>>(&self, bucket: S) -> GetBucketVersioning {
|
||||||
|
|||||||
@ -38,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectResponse = client
|
/// let resp: GetObjectResponse = client
|
||||||
/// .get_object("bucket-name", "object-name")
|
/// .get_object("bucket-name", "object-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// let content_bytes = resp.content.to_segmented_bytes().await.unwrap().to_bytes();
|
/// let content_bytes = resp.content().unwrap().to_segmented_bytes().await.unwrap().to_bytes();
|
||||||
/// let content_str = String::from_utf8(content_bytes.to_vec()).unwrap();
|
/// let content_str = String::from_utf8(content_bytes.to_vec()).unwrap();
|
||||||
/// println!("retrieved content '{content_str}'");
|
/// println!("retrieved content '{content_str}'");
|
||||||
/// }
|
/// }
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetObjectLegalHoldResponse;
|
/// use minio::s3::response::GetObjectLegalHoldResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasObject};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectLegalHoldResponse = client
|
/// let resp: GetObjectLegalHoldResponse = client
|
||||||
/// .get_object_legal_hold("bucket-name", "object-name")
|
/// .get_object_legal_hold("bucket-name", "object-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("legal hold of object '{}' in bucket '{}' is enabled: {}", resp.object, resp.bucket, resp.enabled);
|
/// println!("legal hold of object '{}' in bucket '{}' is enabled: {:?}", resp.object(), resp.bucket(), resp.enabled());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_object_legal_hold<S1: Into<String>, S2: Into<String>>(
|
pub fn get_object_legal_hold<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetObjectLockConfigResponse;
|
/// use minio::s3::response::GetObjectLockConfigResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectLockConfigResponse = client
|
/// let resp: GetObjectLockConfigResponse = client
|
||||||
/// .get_object_lock_config("bucket-name")
|
/// .get_object_lock_config("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved object lock config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket);
|
/// println!("retrieved object lock config '{:?}' from bucket '{}' is enabled", resp.config(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_object_lock_config<S: Into<String>>(&self, bucket: S) -> GetObjectLockConfig {
|
pub fn get_object_lock_config<S: Into<String>>(&self, bucket: S) -> GetObjectLockConfig {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectPromptResponse = client
|
/// let resp: GetObjectPromptResponse = client
|
||||||
/// .get_object_prompt("bucket-name", "object-name", "What is it about?")
|
/// .get_object_prompt("bucket-name", "object-name", "What is it about?")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("the prompt response is: '{}'", resp.prompt_response);
|
/// println!("the prompt response is: '{:?}'", resp.prompt_response());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_object_prompt<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
pub fn get_object_prompt<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetObjectRetentionResponse;
|
/// use minio::s3::response::GetObjectRetentionResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectRetentionResponse = client
|
/// let resp: GetObjectRetentionResponse = client
|
||||||
/// .get_object_retention("bucket-name", "object-name")
|
/// .get_object_retention("bucket-name", "object-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved retention mode '{:?}' until '{:?}' from bucket '{}' is enabled", resp.retention_mode, resp.retain_until_date, resp.bucket);
|
/// println!("retrieved retention mode '{:?}' until '{:?}' from bucket '{}' is enabled", resp.retention_mode(), resp.retain_until_date(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_object_retention<S1: Into<String>, S2: Into<String>>(
|
pub fn get_object_retention<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetObjectTaggingResponse;
|
/// use minio::s3::response::GetObjectTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasBucket, HasObject, HasTagging};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetObjectTaggingResponse = client
|
/// let resp: GetObjectTaggingResponse = client
|
||||||
/// .get_object_tagging("bucket-name", "object-name")
|
/// .get_object_tagging("bucket-name", "object-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved object tags '{:?}' from object '{}' in bucket '{}' is enabled", resp.tags, resp.object, resp.bucket);
|
/// println!("retrieved object tags '{:?}' from object '{}' in bucket '{}' is enabled", resp.tags(), resp.object(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_object_tagging<S1: Into<String>, S2: Into<String>>(
|
pub fn get_object_tagging<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
use super::{Client, DEFAULT_REGION};
|
use super::{Client, DEFAULT_REGION};
|
||||||
use crate::s3::builders::GetRegion;
|
use crate::s3::builders::GetRegion;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::response::GetRegionResponse;
|
|
||||||
use crate::s3::types::S3Api;
|
use crate::s3::types::S3Api;
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
@ -31,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::GetRegionResponse;
|
/// use minio::s3::response::GetRegionResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -38,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: GetRegionResponse = client
|
/// let resp: GetRegionResponse = client
|
||||||
/// .get_region("bucket-name")
|
/// .get_region("bucket-name")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved region '{:?}' for bucket '{}'", resp.region_response, resp.bucket);
|
/// println!("retrieved region '{:?}' for bucket '{}'", resp.region_response(), resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_region<S: Into<String>>(&self, bucket: S) -> GetRegion {
|
pub fn get_region<S: Into<String>>(&self, bucket: S) -> GetRegion {
|
||||||
@ -82,18 +82,20 @@ impl Client {
|
|||||||
return Ok(v.value().clone());
|
return Ok(v.value().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, fetch the region and cache it
|
// Otherwise, fetch the region from the server and cache it
|
||||||
let resp: GetRegionResponse = self.get_region(&bucket).send().await?;
|
let resolved_region: String = {
|
||||||
|
let region = self.get_region(&bucket).send().await?.region_response()?;
|
||||||
let resolved_region: String = if resp.region_response.is_empty() {
|
if !region.is_empty() {
|
||||||
DEFAULT_REGION.to_owned()
|
region
|
||||||
} else {
|
} else {
|
||||||
resp.region_response
|
DEFAULT_REGION.to_owned()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.shared
|
self.shared
|
||||||
.region_map
|
.region_map
|
||||||
.insert(bucket, resolved_region.clone());
|
.insert(bucket, resolved_region.clone());
|
||||||
|
|
||||||
Ok(resolved_region)
|
Ok(resolved_region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ impl Client {
|
|||||||
/// let resp: ListBucketsResponse = client
|
/// let resp: ListBucketsResponse = client
|
||||||
/// .list_buckets()
|
/// .list_buckets()
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("retrieved buckets '{:?}'", resp.buckets);
|
/// println!("retrieved buckets '{:?}'", resp.buckets());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn list_buckets(&self) -> ListBuckets {
|
pub fn list_buckets(&self) -> ListBuckets {
|
||||||
|
|||||||
@ -31,6 +31,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::PutBucketEncryptionResponse;
|
/// use minio::s3::response::PutBucketEncryptionResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -40,7 +41,7 @@ impl Client {
|
|||||||
/// .put_bucket_encryption("bucket-name")
|
/// .put_bucket_encryption("bucket-name")
|
||||||
/// .sse_config(config)
|
/// .sse_config(config)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set encryption on bucket '{}'", resp.bucket);
|
/// println!("set encryption on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_encryption<S: Into<String>>(&self, bucket: S) -> PutBucketEncryption {
|
pub fn put_bucket_encryption<S: Into<String>>(&self, bucket: S) -> PutBucketEncryption {
|
||||||
|
|||||||
@ -31,11 +31,11 @@ impl Client {
|
|||||||
/// use minio::s3::response::PutBucketLifecycleResponse;
|
/// use minio::s3::response::PutBucketLifecycleResponse;
|
||||||
/// use minio::s3::types::{Filter, S3Api};
|
/// use minio::s3::types::{Filter, S3Api};
|
||||||
/// use minio::s3::lifecycle_config::{LifecycleRule, LifecycleConfig};
|
/// use minio::s3::lifecycle_config::{LifecycleRule, LifecycleConfig};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
///
|
|
||||||
/// let rules: Vec<LifecycleRule> = vec![LifecycleRule {
|
/// let rules: Vec<LifecycleRule> = vec![LifecycleRule {
|
||||||
/// id: String::from("rule1"),
|
/// id: String::from("rule1"),
|
||||||
/// filter: Filter {and_operator: None, prefix: Some(String::from("logs/")), tag: None},
|
/// filter: Filter {and_operator: None, prefix: Some(String::from("logs/")), tag: None},
|
||||||
@ -48,7 +48,7 @@ impl Client {
|
|||||||
/// .put_bucket_lifecycle("bucket-name")
|
/// .put_bucket_lifecycle("bucket-name")
|
||||||
/// .life_cycle_config(LifecycleConfig { rules })
|
/// .life_cycle_config(LifecycleConfig { rules })
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set bucket replication policy on bucket '{}'", resp.bucket);
|
/// println!("set bucket replication policy on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> PutBucketLifecycle {
|
pub fn put_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> PutBucketLifecycle {
|
||||||
|
|||||||
@ -28,11 +28,11 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::types::{NotificationConfig, PrefixFilterRule, QueueConfig, S3Api, SuffixFilterRule};
|
/// use minio::s3::types::{NotificationConfig, PrefixFilterRule, QueueConfig, S3Api, SuffixFilterRule};
|
||||||
/// use minio::s3::response::PutBucketNotificationResponse;
|
/// use minio::s3::response::PutBucketNotificationResponse;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
///
|
|
||||||
/// let config = NotificationConfig {
|
/// let config = NotificationConfig {
|
||||||
/// cloud_func_config_list: None,
|
/// cloud_func_config_list: None,
|
||||||
/// queue_config_list: Some(vec![QueueConfig {
|
/// queue_config_list: Some(vec![QueueConfig {
|
||||||
@ -56,7 +56,7 @@ impl Client {
|
|||||||
/// .put_bucket_notification("bucket-name")
|
/// .put_bucket_notification("bucket-name")
|
||||||
/// .notification_config(config)
|
/// .notification_config(config)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set bucket notification for bucket '{:?}'", resp.bucket);
|
/// println!("set bucket notification for bucket '{:?}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_notification<S: Into<String>>(&self, bucket: S) -> PutBucketNotification {
|
pub fn put_bucket_notification<S: Into<String>>(&self, bucket: S) -> PutBucketNotification {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::builders::VersioningStatus;
|
/// use minio::s3::builders::VersioningStatus;
|
||||||
/// use minio::s3::response::PutBucketPolicyResponse;
|
/// use minio::s3::response::PutBucketPolicyResponse;
|
||||||
/// use minio::s3::types::{S3Api, AndOperator, Destination, Filter, ReplicationConfig, ReplicationRule};
|
/// use minio::s3::types::{S3Api, AndOperator, Destination, Filter, ReplicationConfig, ReplicationRule};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -63,7 +64,7 @@ impl Client {
|
|||||||
/// .put_bucket_policy("bucket-name")
|
/// .put_bucket_policy("bucket-name")
|
||||||
/// .config(config.to_owned())
|
/// .config(config.to_owned())
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set bucket replication policy on bucket '{}'", resp.bucket);
|
/// println!("set bucket replication policy on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_policy<S: Into<String>>(&self, bucket: S) -> PutBucketPolicy {
|
pub fn put_bucket_policy<S: Into<String>>(&self, bucket: S) -> PutBucketPolicy {
|
||||||
|
|||||||
@ -31,12 +31,13 @@ impl Client {
|
|||||||
/// use minio::s3::builders::VersioningStatus;
|
/// use minio::s3::builders::VersioningStatus;
|
||||||
/// use minio::s3::response::PutBucketReplicationResponse;
|
/// use minio::s3::response::PutBucketReplicationResponse;
|
||||||
/// use minio::s3::types::{S3Api, AndOperator, Destination, Filter, ReplicationConfig, ReplicationRule};
|
/// use minio::s3::types::{S3Api, AndOperator, Destination, Filter, ReplicationConfig, ReplicationRule};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// use std::collections::HashMap;
|
/// use std::collections::HashMap;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
///
|
///
|
||||||
/// let mut tags: HashMap<String, String> = HashMap::new();
|
/// let mut tags: HashMap<String, String> = HashMap::new();
|
||||||
/// tags.insert(String::from("key1"), String::from("value1"));
|
/// tags.insert(String::from("key1"), String::from("value1"));
|
||||||
@ -75,7 +76,7 @@ impl Client {
|
|||||||
/// .put_bucket_replication("bucket-name")
|
/// .put_bucket_replication("bucket-name")
|
||||||
/// .replication_config(ReplicationConfig {role: None, rules})
|
/// .replication_config(ReplicationConfig {role: None, rules})
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("enabled versioning on bucket '{}'", resp.bucket);
|
/// println!("enabled versioning on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_replication<S: Into<String>>(&self, bucket: S) -> PutBucketReplication {
|
pub fn put_bucket_replication<S: Into<String>>(&self, bucket: S) -> PutBucketReplication {
|
||||||
|
|||||||
@ -31,12 +31,13 @@ impl Client {
|
|||||||
/// use minio::s3::builders::VersioningStatus;
|
/// use minio::s3::builders::VersioningStatus;
|
||||||
/// use minio::s3::response::PutBucketTaggingResponse;
|
/// use minio::s3::response::PutBucketTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// use std::collections::HashMap;
|
/// use std::collections::HashMap;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
///
|
///
|
||||||
/// let mut tags: HashMap<String, String> = HashMap::new();
|
/// let mut tags: HashMap<String, String> = HashMap::new();
|
||||||
/// tags.insert(String::from("Project"), String::from("Project One"));
|
/// tags.insert(String::from("Project"), String::from("Project One"));
|
||||||
@ -46,7 +47,7 @@ impl Client {
|
|||||||
/// .put_bucket_tagging("bucket-name")
|
/// .put_bucket_tagging("bucket-name")
|
||||||
/// .tags(tags)
|
/// .tags(tags)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set tags on bucket '{}'", resp.bucket);
|
/// println!("set tags on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_tagging<S: Into<String>>(&self, bucket: S) -> PutBucketTagging {
|
pub fn put_bucket_tagging<S: Into<String>>(&self, bucket: S) -> PutBucketTagging {
|
||||||
|
|||||||
@ -31,6 +31,7 @@ impl Client {
|
|||||||
/// use minio::s3::builders::VersioningStatus;
|
/// use minio::s3::builders::VersioningStatus;
|
||||||
/// use minio::s3::response::PutBucketVersioningResponse;
|
/// use minio::s3::response::PutBucketVersioningResponse;
|
||||||
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -40,7 +41,7 @@ impl Client {
|
|||||||
/// .put_bucket_versioning("bucket-name")
|
/// .put_bucket_versioning("bucket-name")
|
||||||
/// .versioning_status(VersioningStatus::Enabled)
|
/// .versioning_status(VersioningStatus::Enabled)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("enabled versioning on bucket '{}'", resp.bucket);
|
/// println!("enabled versioning on bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_bucket_versioning<S: Into<String>>(&self, bucket: S) -> PutBucketVersioning {
|
pub fn put_bucket_versioning<S: Into<String>>(&self, bucket: S) -> PutBucketVersioning {
|
||||||
|
|||||||
@ -29,7 +29,11 @@ impl Client {
|
|||||||
///
|
///
|
||||||
/// For handling large files requiring multipart upload, see [`create_multipart_upload`](#method.create_multipart_upload).
|
/// For handling large files requiring multipart upload, see [`create_multipart_upload`](#method.create_multipart_upload).
|
||||||
///
|
///
|
||||||
/// To execute the request, call [`PutObject::send()`](crate::s3::types::S3Api::send),
|
/// For handling large files requiring multipart upload, see [`create_multipart_upload`](#method.create_multipart_upload).
|
||||||
|
///
|
||||||
|
/// For handling large files requiring multipart upload, see [`create_multipart_upload`](#method.create_multipart_upload).
|
||||||
|
///
|
||||||
|
/// To execute the request, call [`PutObjects::send()`](crate::s3::types::S3Api::send),
|
||||||
/// which returns a [`Result`] containing a [`PutObjectResponse`](crate::s3::response::PutObjectResponse).
|
/// which returns a [`Result`] containing a [`PutObjectResponse`](crate::s3::response::PutObjectResponse).
|
||||||
///
|
///
|
||||||
/// For more information, refer to the [AWS S3 PutObject API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html).
|
/// For more information, refer to the [AWS S3 PutObject API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html).
|
||||||
@ -41,6 +45,7 @@ impl Client {
|
|||||||
/// use minio::s3::response::PutObjectResponse;
|
/// use minio::s3::response::PutObjectResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -48,7 +53,7 @@ impl Client {
|
|||||||
/// let data = SegmentedBytes::from("Hello world".to_string());
|
/// let data = SegmentedBytes::from("Hello world".to_string());
|
||||||
/// let resp: PutObjectResponse =
|
/// let resp: PutObjectResponse =
|
||||||
/// client.put_object("bucket-name", "object-name", data).send().await.unwrap();
|
/// client.put_object("bucket-name", "object-name", data).send().await.unwrap();
|
||||||
/// println!("successfully put object '{}'", resp.object);
|
/// println!("successfully put object '{}'", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object<S1: Into<String>, S2: Into<String>>(
|
pub fn put_object<S1: Into<String>, S2: Into<String>>(
|
||||||
@ -80,7 +85,7 @@ impl Client {
|
|||||||
/// let resp: CreateMultipartUploadResponse = client
|
/// let resp: CreateMultipartUploadResponse = client
|
||||||
/// .create_multipart_upload("bucket-name", "large-object")
|
/// .create_multipart_upload("bucket-name", "large-object")
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("Initiated multipart upload with UploadId '{}'", resp.upload_id);
|
/// println!("Initiated multipart upload with UploadId '{:?}'", resp.upload_id().await);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn create_multipart_upload<S1: Into<String>, S2: Into<String>>(
|
pub fn create_multipart_upload<S1: Into<String>, S2: Into<String>>(
|
||||||
@ -135,8 +140,8 @@ impl Client {
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::CompleteMultipartUploadResponse;
|
/// use minio::s3::response::CompleteMultipartUploadResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::{S3Api, PartInfo};
|
||||||
/// use minio::s3::types::PartInfo;
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -145,7 +150,7 @@ impl Client {
|
|||||||
/// let resp: CompleteMultipartUploadResponse = client
|
/// let resp: CompleteMultipartUploadResponse = client
|
||||||
/// .complete_multipart_upload("bucket-name", "object-name", "upload-id-123", parts)
|
/// .complete_multipart_upload("bucket-name", "object-name", "upload-id-123", parts)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("Completed multipart upload for '{}'", resp.object);
|
/// println!("Completed multipart upload for '{}'", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn complete_multipart_upload<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
pub fn complete_multipart_upload<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
||||||
@ -178,6 +183,7 @@ impl Client {
|
|||||||
/// use minio::s3::response::UploadPartResponse;
|
/// use minio::s3::response::UploadPartResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
/// use minio::s3::segmented_bytes::SegmentedBytes;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -186,7 +192,7 @@ impl Client {
|
|||||||
/// let resp: UploadPartResponse = client
|
/// let resp: UploadPartResponse = client
|
||||||
/// .upload_part("bucket-name", "object-name", "upload-id", 1, data)
|
/// .upload_part("bucket-name", "object-name", "upload-id", 1, data)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("Uploaded object: {}", resp.object);
|
/// println!("Uploaded object: {}", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn upload_part<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
pub fn upload_part<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
|
||||||
@ -220,6 +226,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::PutObjectContentResponse;
|
/// use minio::s3::response::PutObjectContentResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::{HasObject, HasEtagFromHeaders};
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -228,7 +235,7 @@ impl Client {
|
|||||||
/// let resp: PutObjectContentResponse = client
|
/// let resp: PutObjectContentResponse = client
|
||||||
/// .put_object_content("bucket", "object", content)
|
/// .put_object_content("bucket", "object", content)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("Uploaded object '{}' with ETag '{}'", resp.object, resp.etag);
|
/// println!("Uploaded object '{}' with ETag '{:?}'", resp.object(), resp.etag());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object_content<S1: Into<String>, S2: Into<String>, C: Into<ObjectContent>>(
|
pub fn put_object_content<S1: Into<String>, S2: Into<String>, C: Into<ObjectContent>>(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::PutObjectLegalHoldResponse;
|
/// use minio::s3::response::PutObjectLegalHoldResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -37,7 +38,7 @@ impl Client {
|
|||||||
/// let resp: PutObjectLegalHoldResponse = client
|
/// let resp: PutObjectLegalHoldResponse = client
|
||||||
/// .put_object_legal_hold("bucket-name", "object-name", true)
|
/// .put_object_legal_hold("bucket-name", "object-name", true)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("legal hold of bucket '{}' is enabled", resp.bucket);
|
/// println!("legal hold of bucket '{}' is enabled", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object_legal_hold<S1: Into<String>, S2: Into<String>>(
|
pub fn put_object_legal_hold<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -30,6 +30,7 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::{CreateBucketResponse, PutObjectLockConfigResponse};
|
/// use minio::s3::response::{CreateBucketResponse, PutObjectLockConfigResponse};
|
||||||
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
|
||||||
|
/// use minio::s3::response::a_response_traits::HasBucket;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
@ -38,14 +39,14 @@ impl Client {
|
|||||||
///
|
///
|
||||||
/// let resp: CreateBucketResponse =
|
/// let resp: CreateBucketResponse =
|
||||||
/// client.create_bucket(bucket_name).object_lock(true).send().await.unwrap();
|
/// client.create_bucket(bucket_name).object_lock(true).send().await.unwrap();
|
||||||
/// println!("created bucket '{}' with object locking enabled", resp.bucket);
|
/// println!("created bucket '{}' with object locking enabled", resp.bucket());
|
||||||
///
|
///
|
||||||
/// const DURATION_DAYS: i32 = 7;
|
/// const DURATION_DAYS: i32 = 7;
|
||||||
/// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap();
|
/// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap();
|
||||||
///
|
///
|
||||||
/// let resp: PutObjectLockConfigResponse =
|
/// let resp: PutObjectLockConfigResponse =
|
||||||
/// client.put_object_lock_config(bucket_name).config(config).send().await.unwrap();
|
/// client.put_object_lock_config(bucket_name).config(config).send().await.unwrap();
|
||||||
/// println!("configured object locking for bucket '{}'", resp.bucket);
|
/// println!("configured object locking for bucket '{}'", resp.bucket());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object_lock_config<S: Into<String>>(&self, bucket: S) -> PutObjectLockConfig {
|
pub fn put_object_lock_config<S: Into<String>>(&self, bucket: S) -> PutObjectLockConfig {
|
||||||
|
|||||||
@ -32,17 +32,18 @@ impl Client {
|
|||||||
/// use minio::s3::builders::ObjectToDelete;
|
/// use minio::s3::builders::ObjectToDelete;
|
||||||
/// use minio::s3::types::{S3Api, RetentionMode};
|
/// use minio::s3::types::{S3Api, RetentionMode};
|
||||||
/// use minio::s3::utils::utc_now;
|
/// use minio::s3::utils::utc_now;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let retain_until_date = utc_now() + chrono::Duration::days(1);
|
/// let retain_until_date = utc_now() + chrono::Duration::days(1);
|
||||||
/// let resp: PutObjectRetentionResponse = client
|
/// let resp: PutObjectRetentionResponse = client
|
||||||
/// .put_object_retention("bucket-name", "object-name")
|
/// .put_object_retention("bucket-name", "object-name")
|
||||||
/// .retention_mode(Some(RetentionMode::GOVERNANCE))
|
/// .retention_mode(Some(RetentionMode::GOVERNANCE))
|
||||||
/// .retain_until_date(Some(retain_until_date))
|
/// .retain_until_date(Some(retain_until_date))
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set the object retention for object '{}'", resp.object);
|
/// println!("set the object retention for object '{}'", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object_retention<S1: Into<String>, S2: Into<String>>(
|
pub fn put_object_retention<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -31,10 +31,11 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::PutObjectTaggingResponse;
|
/// use minio::s3::response::PutObjectTaggingResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let tags = HashMap::from([
|
/// let tags = HashMap::from([
|
||||||
/// (String::from("Project"), String::from("Project One")),
|
/// (String::from("Project"), String::from("Project One")),
|
||||||
/// (String::from("User"), String::from("jsmith")),
|
/// (String::from("User"), String::from("jsmith")),
|
||||||
@ -43,7 +44,7 @@ impl Client {
|
|||||||
/// .put_object_tagging("bucket-name", "object-name")
|
/// .put_object_tagging("bucket-name", "object-name")
|
||||||
/// .tags(tags)
|
/// .tags(tags)
|
||||||
/// .send().await.unwrap();
|
/// .send().await.unwrap();
|
||||||
/// println!("set the object tags for object '{}'", resp.object);
|
/// println!("set the object tags for object '{}'", resp.object());
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn put_object_tagging<S: Into<String>>(&self, bucket: S, object: S) -> PutObjectTagging {
|
pub fn put_object_tagging<S: Into<String>>(&self, bucket: S, object: S) -> PutObjectTagging {
|
||||||
|
|||||||
@ -28,13 +28,14 @@ impl Client {
|
|||||||
/// use minio::s3::Client;
|
/// use minio::s3::Client;
|
||||||
/// use minio::s3::response::StatObjectResponse;
|
/// use minio::s3::response::StatObjectResponse;
|
||||||
/// use minio::s3::types::S3Api;
|
/// use minio::s3::types::S3Api;
|
||||||
|
/// use minio::s3::response::a_response_traits::HasObject;
|
||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let client: Client = Default::default(); // configure your client here
|
/// let client: Client = Default::default(); // configure your client here
|
||||||
/// let resp: StatObjectResponse =
|
/// let resp: StatObjectResponse =
|
||||||
/// client.stat_object("bucket-name", "object-name").send().await.unwrap();
|
/// client.stat_object("bucket-name", "object-name").send().await.unwrap();
|
||||||
/// println!("stat of object '{}' are {:#?}", resp.object, resp);
|
/// println!("stat of object '{}' are {:#?}", resp.object(), resp);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn stat_object<S1: Into<String>, S2: Into<String>>(
|
pub fn stat_object<S1: Into<String>, S2: Into<String>>(
|
||||||
|
|||||||
@ -129,12 +129,7 @@ pub enum Error {
|
|||||||
StrError(reqwest::header::ToStrError),
|
StrError(reqwest::header::ToStrError),
|
||||||
IntError(std::num::ParseIntError),
|
IntError(std::num::ParseIntError),
|
||||||
BoolError(std::str::ParseBoolError),
|
BoolError(std::str::ParseBoolError),
|
||||||
|
|
||||||
Utf8Error(Box<dyn std::error::Error + Send + Sync + 'static>),
|
Utf8Error(Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||||
/// Occurs when converting Vec<u8> to String (e.g. String::from_utf8)
|
|
||||||
//FromUtf8Error(alloc::string::FromUtf8Error),
|
|
||||||
/// Occurs when converting &[u8] to &str (e.g. std::str::from_utf8)
|
|
||||||
//Utf8Error(std::str::Utf8Error),
|
|
||||||
JsonError(serde_json::Error),
|
JsonError(serde_json::Error),
|
||||||
XmlError(String),
|
XmlError(String),
|
||||||
InvalidBaseUrl(String),
|
InvalidBaseUrl(String),
|
||||||
@ -203,7 +198,6 @@ impl fmt::Display for Error {
|
|||||||
Error::IntError(e) => write!(f, "{e}"),
|
Error::IntError(e) => write!(f, "{e}"),
|
||||||
Error::BoolError(e) => write!(f, "{e}"),
|
Error::BoolError(e) => write!(f, "{e}"),
|
||||||
Error::Utf8Error(e) => write!(f, "{e}"),
|
Error::Utf8Error(e) => write!(f, "{e}"),
|
||||||
//Error::FromUtf8Error(e) => write!(f, "{e}"),
|
|
||||||
Error::JsonError(e) => write!(f, "{e}"),
|
Error::JsonError(e) => write!(f, "{e}"),
|
||||||
Error::XmlError(m) => write!(f, "{m}"),
|
Error::XmlError(m) => write!(f, "{m}"),
|
||||||
Error::InvalidBucketName(m) => write!(f, "{m}"),
|
Error::InvalidBucketName(m) => write!(f, "{m}"),
|
||||||
|
|||||||
@ -60,6 +60,9 @@ mod put_object_tagging;
|
|||||||
mod select_object_content;
|
mod select_object_content;
|
||||||
mod stat_object;
|
mod stat_object;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod a_response_traits;
|
||||||
|
|
||||||
pub use append_object::AppendObjectResponse;
|
pub use append_object::AppendObjectResponse;
|
||||||
pub use bucket_exists::BucketExistsResponse;
|
pub use bucket_exists::BucketExistsResponse;
|
||||||
pub use copy_object::*;
|
pub use copy_object::*;
|
||||||
|
|||||||
219
src/s3/response/a_response_traits.rs
Normal file
219
src/s3/response/a_response_traits.rs
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::types::S3Request;
|
||||||
|
use crate::s3::utils::{get_text, trim_quotes};
|
||||||
|
use bytes::{Buf, Bytes};
|
||||||
|
use http::HeaderMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use xmltree::Element;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Implements the `FromS3Response` trait for the specified types.
|
||||||
|
macro_rules! impl_from_s3response {
|
||||||
|
($($ty:ty),* $(,)?) => {
|
||||||
|
$(
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl FromS3Response for $ty {
|
||||||
|
async fn from_s3response(
|
||||||
|
request: S3Request,
|
||||||
|
response: Result<reqwest::Response, Error>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let mut resp: reqwest::Response = response?;
|
||||||
|
Ok(Self {
|
||||||
|
request,
|
||||||
|
headers: mem::take(resp.headers_mut()),
|
||||||
|
body: resp.bytes().await?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Implements the `FromS3Response` trait for the specified types with an additional `object_size` field.
|
||||||
|
macro_rules! impl_from_s3response_with_size {
|
||||||
|
($($ty:ty),* $(,)?) => {
|
||||||
|
$(
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl FromS3Response for $ty {
|
||||||
|
async fn from_s3response(
|
||||||
|
request: S3Request,
|
||||||
|
response: Result<reqwest::Response, Error>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let mut resp: reqwest::Response = response?;
|
||||||
|
Ok(Self {
|
||||||
|
request,
|
||||||
|
headers: mem::take(resp.headers_mut()),
|
||||||
|
body: resp.bytes().await?,
|
||||||
|
object_size: 0, // Default value, can be set later
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Implements the `HasS3Fields` trait for the specified types.
|
||||||
|
macro_rules! impl_has_s3fields {
|
||||||
|
($($ty:ty),* $(,)?) => {
|
||||||
|
$(
|
||||||
|
impl HasS3Fields for $ty {
|
||||||
|
/// The request that was sent to the S3 API.
|
||||||
|
fn request(&self) -> &S3Request {
|
||||||
|
&self.request
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The response of the S3 API.
|
||||||
|
fn headers(&self) -> &HeaderMap {
|
||||||
|
&self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The response of the S3 API.
|
||||||
|
fn body(&self) -> &Bytes {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasS3Fields {
|
||||||
|
/// The request that was sent to the S3 API.
|
||||||
|
fn request(&self) -> &S3Request;
|
||||||
|
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
||||||
|
fn headers(&self) -> &HeaderMap;
|
||||||
|
/// The response body returned by the server, which may contain the object data or other information.
|
||||||
|
fn body(&self) -> &Bytes;
|
||||||
|
}
|
||||||
|
/// Returns the name of the S3 bucket.
|
||||||
|
pub trait HasBucket: HasS3Fields {
|
||||||
|
/// Returns the name of the S3 bucket.
|
||||||
|
#[inline]
|
||||||
|
fn bucket(&self) -> &str {
|
||||||
|
self.request().bucket.as_deref().unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Returns the object key (name) of the S3 object.
|
||||||
|
pub trait HasObject: HasS3Fields {
|
||||||
|
/// Returns the object key (name) of the S3 object.
|
||||||
|
#[inline]
|
||||||
|
fn object(&self) -> &str {
|
||||||
|
self.request().object.as_deref().unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Returns the region of the S3 bucket.
|
||||||
|
pub trait HasRegion: HasS3Fields {
|
||||||
|
/// Returns the region of the S3 bucket.
|
||||||
|
#[inline]
|
||||||
|
fn region(&self) -> &str {
|
||||||
|
&self.request().inner_region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the version ID of the object (`x-amz-version-id`), if versioning is enabled for the bucket.
|
||||||
|
pub trait HasVersion: HasS3Fields {
|
||||||
|
/// Returns the version ID of the object (`x-amz-version-id`), if versioning is enabled for the bucket.
|
||||||
|
#[inline]
|
||||||
|
fn version_id(&self) -> Option<&str> {
|
||||||
|
self.headers()
|
||||||
|
.get("x-amz-version-id")
|
||||||
|
.and_then(|v| v.to_str().ok())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of the `ETag` header from response headers (for operations that return ETag in headers).
|
||||||
|
/// The ETag is typically a hash of the object content, but it may vary based on the storage backend.
|
||||||
|
pub trait HasEtagFromHeaders: HasS3Fields {
|
||||||
|
/// Returns the value of the `ETag` header from response headers (for operations that return ETag in headers).
|
||||||
|
/// The ETag is typically a hash of the object content, but it may vary based on the storage backend.
|
||||||
|
#[inline]
|
||||||
|
fn etag(&self) -> Result<String, Error> {
|
||||||
|
// Retrieve the ETag from the response headers.
|
||||||
|
let etag = self
|
||||||
|
.headers()
|
||||||
|
.get("etag")
|
||||||
|
.and_then(|v| v.to_str().ok())
|
||||||
|
.map(|s| s.trim_matches('"'))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string();
|
||||||
|
Ok(etag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of the `ETag` from the response body, which is a unique identifier for
|
||||||
|
/// the object version. The ETag is typically a hash of the object content, but it may vary
|
||||||
|
/// based on the storage backend.
|
||||||
|
pub trait HasEtagFromBody: HasS3Fields {
|
||||||
|
/// Returns the value of the `ETag` from the response body, which is a unique identifier for
|
||||||
|
/// the object version. The ETag is typically a hash of the object content, but it may vary
|
||||||
|
/// based on the storage backend.
|
||||||
|
fn etag(&self) -> Result<String, Error> {
|
||||||
|
// Retrieve the ETag from the response body.
|
||||||
|
let root = xmltree::Element::parse(self.body().clone().reader())?;
|
||||||
|
let etag: String = get_text(&root, "ETag")?;
|
||||||
|
Ok(trim_quotes(etag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size of the object in bytes, as specified by the `x-amz-object-size` header.
|
||||||
|
pub trait HasObjectSize: HasS3Fields {
|
||||||
|
/// Returns the size of the object in bytes, as specified by the `x-amz-object-size` header.
|
||||||
|
#[inline]
|
||||||
|
fn object_size(&self) -> u64 {
|
||||||
|
self.headers()
|
||||||
|
.get("x-amz-object-size")
|
||||||
|
.and_then(|v| v.to_str().ok())
|
||||||
|
.and_then(|s| s.parse::<u64>().ok())
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Value of the `x-amz-delete-marker` header.
|
||||||
|
/// Indicates whether the specified object version that was permanently deleted was (true) or
|
||||||
|
/// was not (false) a delete marker before deletion. In a simple DELETE, this header indicates
|
||||||
|
/// whether (true) or not (false) the current version of the object is a delete marker.
|
||||||
|
pub trait HasIsDeleteMarker: HasS3Fields {
|
||||||
|
/// Returns `true` if the object is a delete marker, `false` otherwise.
|
||||||
|
///
|
||||||
|
/// Value of the `x-amz-delete-marker` header.
|
||||||
|
/// Indicates whether the specified object version that was permanently deleted was (true) or
|
||||||
|
/// was not (false) a delete marker before deletion. In a simple DELETE, this header indicates
|
||||||
|
/// whether (true) or not (false) the current version of the object is a delete marker.
|
||||||
|
#[inline]
|
||||||
|
fn is_delete_marker(&self) -> Result<Option<bool>, Error> {
|
||||||
|
Ok(Some(
|
||||||
|
self.headers()
|
||||||
|
.get("x-amz-delete-marker")
|
||||||
|
.map(|v| v == "true")
|
||||||
|
.unwrap_or(false),
|
||||||
|
))
|
||||||
|
|
||||||
|
//Ok(match self.headers().get("x-amz-delete-marker") {
|
||||||
|
// Some(v) => Some(v.to_str()?.parse::<bool>()?),
|
||||||
|
// None => None,
|
||||||
|
//})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasTagging: HasS3Fields {
|
||||||
|
/// Returns the tags associated with the bucket.
|
||||||
|
///
|
||||||
|
/// If the bucket has no tags, this will return an empty `HashMap`.
|
||||||
|
#[inline]
|
||||||
|
fn tags(&self) -> Result<HashMap<String, String>, Error> {
|
||||||
|
let mut tags = HashMap::new();
|
||||||
|
if self.body().is_empty() {
|
||||||
|
// Note: body is empty when server responses with NoSuchTagSet
|
||||||
|
return Ok(tags);
|
||||||
|
}
|
||||||
|
let mut root = Element::parse(self.body().clone().reader())?;
|
||||||
|
let element = root
|
||||||
|
.get_mut_child("TagSet")
|
||||||
|
.ok_or(Error::XmlError("<TagSet> tag not found".to_string()))?;
|
||||||
|
while let Some(v) = element.take_child("Tag") {
|
||||||
|
tags.insert(get_text(&v, "Key")?, get_text(&v, "Value")?);
|
||||||
|
}
|
||||||
|
Ok(tags)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,78 +14,30 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasEtagFromHeaders, HasObject, HasObjectSize, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the `append_object` API call.
|
/// Represents the response of the `append_object` API call.
|
||||||
/// This struct contains metadata and information about the object being appended.
|
/// This struct contains metadata and information about the object being appended.
|
||||||
///
|
#[derive(Clone, Debug)]
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket containing the object.
|
|
||||||
/// * `object` - Key (path) identifying the object within the bucket.
|
|
||||||
/// * `etag` - Entity tag representing a specific version of the object.
|
|
||||||
/// * `version_id` - Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
/// * `object_size` - Value of the `x-amz-object-size` header.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct AppendObjectResponse {
|
pub struct AppendObjectResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the object.
|
|
||||||
pub etag: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
|
|
||||||
/// Value of the `x-amz-object-size` header.
|
|
||||||
pub object_size: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(AppendObjectResponse);
|
||||||
impl FromS3Response for AppendObjectResponse {
|
impl_has_s3fields!(AppendObjectResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let etag: String = match headers.get("etag") {
|
impl HasBucket for AppendObjectResponse {}
|
||||||
Some(v) => v.to_str()?.to_string().trim_matches('"').to_string(),
|
impl HasObject for AppendObjectResponse {}
|
||||||
_ => String::new(),
|
impl HasRegion for AppendObjectResponse {}
|
||||||
};
|
impl HasVersion for AppendObjectResponse {}
|
||||||
let version_id: Option<String> = match headers.get("x-amz-version-id") {
|
impl HasEtagFromHeaders for AppendObjectResponse {}
|
||||||
Some(v) => Some(v.to_str()?.to_string()),
|
impl HasObjectSize for AppendObjectResponse {}
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
let object_size: u64 = match headers.get("x-amz-object-size") {
|
|
||||||
Some(v) => v.to_str()?.parse::<u64>()?,
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
region: req.inner_region,
|
|
||||||
etag,
|
|
||||||
version_id,
|
|
||||||
object_size,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,59 +13,57 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [bucket_exists()](crate::s3::client::Client::bucket_exists) API call.
|
/// Represents the response of the [bucket_exists()](crate::s3::client::Client::bucket_exists) API call.
|
||||||
/// This struct contains metadata and information about the existence of a bucket.
|
/// This struct contains metadata and information about the existence of a bucket.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides. If the bucket does not exist, this will be an empty string.
|
|
||||||
/// * `bucket` - The name of the bucket being checked.
|
|
||||||
/// * `exists` - A boolean indicating whether the bucket exists or not.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BucketExistsResponse {
|
pub struct BucketExistsResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
pub(crate) exists: bool,
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// The name of the bucket being checked.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Whether the bucket exists or not.
|
|
||||||
pub exists: bool,
|
|
||||||
}
|
}
|
||||||
|
impl_has_s3fields!(BucketExistsResponse);
|
||||||
|
|
||||||
|
impl HasBucket for BucketExistsResponse {}
|
||||||
|
impl HasRegion for BucketExistsResponse {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for BucketExistsResponse {
|
impl FromS3Response for BucketExistsResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => Ok(Self {
|
Ok(mut resp) => Ok(Self {
|
||||||
headers: mem::take(r.headers_mut()),
|
request,
|
||||||
region: req.inner_region,
|
headers: mem::take(resp.headers_mut()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
body: resp.bytes().await?,
|
||||||
exists: true,
|
exists: true,
|
||||||
}),
|
}),
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucket => {
|
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucket => Ok(Self {
|
||||||
Ok(Self {
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: String::new(), // NOTE the bucket does not exist and the region is not provided
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
exists: false,
|
||||||
exists: false,
|
}),
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BucketExistsResponse {
|
||||||
|
/// Returns `true` if the bucket exists, `false` otherwise.
|
||||||
|
pub fn exists(&self) -> bool {
|
||||||
|
self.exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -14,186 +14,43 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasEtagFromBody, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{get_text, take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use bytes::{Buf, Bytes};
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
|
||||||
|
/// Base response struct that contains common functionality for S3 operations
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct S3Response2 {
|
||||||
|
pub(crate) request: S3Request,
|
||||||
|
pub(crate) headers: HeaderMap,
|
||||||
|
pub(crate) body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_s3response!(S3Response2);
|
||||||
|
impl_has_s3fields!(S3Response2);
|
||||||
|
|
||||||
|
impl HasBucket for S3Response2 {}
|
||||||
|
impl HasObject for S3Response2 {}
|
||||||
|
impl HasRegion for S3Response2 {}
|
||||||
|
impl HasVersion for S3Response2 {}
|
||||||
|
impl HasEtagFromBody for S3Response2 {}
|
||||||
|
|
||||||
/// Represents the response of the `upload_part_copy` API call.
|
/// Represents the response of the `upload_part_copy` API call.
|
||||||
/// This struct contains metadata and information about the part being copied during a multipart upload.
|
/// This struct contains metadata and information about the part being copied during a multipart upload.
|
||||||
///
|
pub type UploadPartCopyResponse = S3Response2;
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket containing the object.
|
|
||||||
/// * `object` - Key (path) identifying the object within the bucket.
|
|
||||||
/// * `etag` - Entity tag representing a specific version of the object.
|
|
||||||
/// * `version_id` - Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UploadPartCopyResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
/// Internal response type for copy operations
|
||||||
pub region: String,
|
pub type CopyObjectInternalResponse = S3Response2;
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the object.
|
|
||||||
pub etag: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl FromS3Response for UploadPartCopyResponse {
|
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let etag: String = {
|
|
||||||
let body: Bytes = resp.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
get_text(&root, "ETag")?.trim_matches('"').to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let version_id: Option<String> = headers
|
|
||||||
.get("x-amz-version-id")
|
|
||||||
.and_then(|v| v.to_str().ok().map(String::from));
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
etag,
|
|
||||||
version_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct CopyObjectInternalResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
pub region: String,
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
pub object: String,
|
|
||||||
pub etag: String,
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl FromS3Response for CopyObjectInternalResponse {
|
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let bucket = req
|
|
||||||
.bucket
|
|
||||||
.ok_or_else(|| Error::InvalidBucketName("no bucket specified".into()))?;
|
|
||||||
let object = req
|
|
||||||
.object
|
|
||||||
.ok_or_else(|| Error::InvalidObjectName("no object specified".into()))?;
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let etag: String = {
|
|
||||||
let body: Bytes = resp.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
get_text(&root, "ETag")?.trim_matches('"').to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let version_id: Option<String> = headers
|
|
||||||
.get("x-amz-version-id")
|
|
||||||
.and_then(|v| v.to_str().ok().map(String::from));
|
|
||||||
|
|
||||||
Ok(CopyObjectInternalResponse {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket,
|
|
||||||
object,
|
|
||||||
etag,
|
|
||||||
version_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the response of the `copy_object` API call.
|
/// Represents the response of the `copy_object` API call.
|
||||||
/// This struct contains metadata and information about the object being copied.
|
/// This struct contains metadata and information about the object being copied.
|
||||||
///
|
pub type CopyObjectResponse = S3Response2;
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket containing the object.
|
|
||||||
/// * `object` - Key (path) identifying the object within the bucket.
|
|
||||||
/// * `etag` - Entity tag representing a specific version of the object.
|
|
||||||
/// * `version_id` - Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct CopyObjectResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the object.
|
|
||||||
pub etag: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the response of the `[compose_object()](crate::s3::client::Client::compose_object) API call.
|
/// Represents the response of the `[compose_object()](crate::s3::client::Client::compose_object) API call.
|
||||||
/// This struct contains metadata and information about the composed object.
|
/// This struct contains metadata and information about the composed object.
|
||||||
///
|
pub type ComposeObjectResponse = S3Response2;
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `bucket` - Name of the bucket containing the composed object.
|
|
||||||
/// * `object` - Key (path) identifying the composed object within the bucket.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `etag` - Entity tag representing a specific version of the composed object.
|
|
||||||
/// * `version_id` - Version ID of the composed object, if versioning is enabled.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ComposeObjectResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the composed object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the composed object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the composed object.
|
|
||||||
pub etag: String,
|
|
||||||
|
|
||||||
/// Version ID of the composed object, if versioning is enabled.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,10 +13,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -25,31 +27,36 @@ use std::mem;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CreateBucketResponse {
|
pub struct CreateBucketResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(CreateBucketResponse);
|
||||||
|
|
||||||
|
impl HasBucket for CreateBucketResponse {}
|
||||||
|
impl HasRegion for CreateBucketResponse {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for CreateBucketResponse {
|
impl FromS3Response for CreateBucketResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut req = req;
|
let mut resp: reqwest::Response = response?;
|
||||||
let bucket: String = take_bucket(req.bucket)?;
|
|
||||||
req.client.add_bucket_region(&bucket, &req.inner_region);
|
let mut request = request;
|
||||||
let mut resp = resp?;
|
let bucket: &str = request
|
||||||
|
.bucket
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_else(|| Error::InvalidBucketName("no bucket specified".into()))?;
|
||||||
|
let region: &str = &request.inner_region;
|
||||||
|
request.client.add_bucket_region(bucket, region);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers: mem::take(resp.headers_mut()),
|
headers: mem::take(resp.headers_mut()),
|
||||||
region: req.inner_region,
|
body: resp.bytes().await?,
|
||||||
bucket,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,10 +13,11 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use bytes::Bytes;
|
||||||
use async_trait::async_trait;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -25,31 +26,34 @@ use std::mem;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketResponse {
|
pub struct DeleteBucketResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
pub(crate) request: S3Request,
|
||||||
pub headers: HeaderMap,
|
pub(crate) headers: HeaderMap,
|
||||||
|
pub(crate) body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
impl_has_s3fields!(DeleteBucketResponse);
|
||||||
|
|
||||||
#[async_trait]
|
impl HasBucket for DeleteBucketResponse {}
|
||||||
|
impl HasRegion for DeleteBucketResponse {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
impl FromS3Response for DeleteBucketResponse {
|
impl FromS3Response for DeleteBucketResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut req = req;
|
let mut resp: reqwest::Response = response?;
|
||||||
let bucket: String = take_bucket(req.bucket)?;
|
|
||||||
req.client.remove_bucket_region(&bucket);
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
|
let mut request = request;
|
||||||
|
let bucket: &str = request
|
||||||
|
.bucket
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_else(|| Error::InvalidBucketName("no bucket specified".into()))?;
|
||||||
|
|
||||||
|
request.client.remove_bucket_region(bucket);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers: mem::take(resp.headers_mut()),
|
headers: mem::take(resp.headers_mut()),
|
||||||
region: req.inner_region,
|
body: resp.bytes().await?,
|
||||||
bucket,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,44 +14,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [delete_bucket_encryption()](crate::s3::client::Client::delete_bucket_encryption) API call.
|
/// Represents the response of the [delete_bucket_encryption()](crate::s3::client::Client::delete_bucket_encryption) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose encryption configuration was removed.
|
/// This struct contains metadata and information about the bucket whose encryption configuration was removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the encryption configuration was removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketEncryptionResponse {
|
pub struct DeleteBucketEncryptionResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Encryption configuration was removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteBucketEncryptionResponse);
|
||||||
impl FromS3Response for DeleteBucketEncryptionResponse {
|
impl_has_s3fields!(DeleteBucketEncryptionResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteBucketEncryptionResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteBucketEncryptionResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,44 +14,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [delete_bucket_lifecycle()](crate::s3::client::Client::delete_bucket_lifecycle) API call.
|
/// Represents the response of the [delete_bucket_lifecycle()](crate::s3::client::Client::delete_bucket_lifecycle) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose lifecycle configuration was removed.
|
/// This struct contains metadata and information about the bucket whose lifecycle configuration was removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the Bucket Lifecycle configuration was removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketLifecycleResponse {
|
pub struct DeleteBucketLifecycleResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Bucket Lifecycle configuration was removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteBucketLifecycleResponse);
|
||||||
impl FromS3Response for DeleteBucketLifecycleResponse {
|
impl_has_s3fields!(DeleteBucketLifecycleResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteBucketLifecycleResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteBucketLifecycleResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,44 +14,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [delete_bucket_notification()](crate::s3::client::Client::delete_bucket_notification) API call.
|
/// Represents the response of the [delete_bucket_notification()](crate::s3::client::Client::delete_bucket_notification) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose notifications were removed.
|
/// This struct contains metadata and information about the bucket whose notifications were removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the Bucket Notifications were removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketNotificationResponse {
|
pub struct DeleteBucketNotificationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Bucket Notifications were removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteBucketNotificationResponse);
|
||||||
impl FromS3Response for DeleteBucketNotificationResponse {
|
impl_has_s3fields!(DeleteBucketNotificationResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteBucketNotificationResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteBucketNotificationResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,49 +13,45 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [delete_bucket_policy()](crate::s3::client::Client::delete_bucket_policy) API call.
|
/// Represents the response of the [delete_bucket_policy()](crate::s3::client::Client::delete_bucket_policy) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose policy was removed.
|
/// This struct contains metadata and information about the bucket whose policy was removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the Bucket Policy was removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketPolicyResponse {
|
pub struct DeleteBucketPolicyResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Bucket Policy was removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(DeleteBucketPolicyResponse);
|
||||||
|
|
||||||
|
impl HasBucket for DeleteBucketPolicyResponse {}
|
||||||
|
impl HasRegion for DeleteBucketPolicyResponse {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for DeleteBucketPolicyResponse {
|
impl FromS3Response for DeleteBucketPolicyResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => Ok(Self {
|
Ok(mut resp) => Ok(Self {
|
||||||
headers: mem::take(r.headers_mut()),
|
request,
|
||||||
region: req.inner_region,
|
headers: mem::take(resp.headers_mut()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
body: resp.bytes().await?,
|
||||||
}),
|
}),
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucketPolicy => Ok(Self {
|
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucketPolicy => Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
}),
|
}),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,52 +13,48 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the `[delete_bucket_replication()](crate::s3::client::Client::delete_bucket_replication) API call.
|
/// Represents the response of the `[delete_bucket_replication()](crate::s3::client::Client::delete_bucket_replication) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose replication configuration was removed.
|
/// This struct contains metadata and information about the bucket whose replication configuration was removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the Replication configuration was removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketReplicationResponse {
|
pub struct DeleteBucketReplicationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Replication configuration was removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(DeleteBucketReplicationResponse);
|
||||||
|
|
||||||
|
impl HasBucket for DeleteBucketReplicationResponse {}
|
||||||
|
impl HasRegion for DeleteBucketReplicationResponse {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for DeleteBucketReplicationResponse {
|
impl FromS3Response for DeleteBucketReplicationResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => Ok(Self {
|
Ok(mut resp) => Ok(Self {
|
||||||
headers: mem::take(r.headers_mut()),
|
request,
|
||||||
region: req.inner_region,
|
headers: mem::take(resp.headers_mut()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
body: resp.bytes().await?,
|
||||||
}),
|
}),
|
||||||
Err(Error::S3Error(e))
|
Err(Error::S3Error(e))
|
||||||
if e.code == ErrorCode::ReplicationConfigurationNotFoundError =>
|
if e.code == ErrorCode::ReplicationConfigurationNotFoundError =>
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
|
|||||||
@ -14,44 +14,24 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Represents the response of the [delete_bucket_tagging()](crate::s3::client::Client::delete_bucket_tagging) API call.
|
/// Represents the response of the [delete_bucket_tagging()](crate::s3::client::Client::delete_bucket_tagging) API call.
|
||||||
/// This struct contains metadata and information about the bucket whose tags were removed.
|
/// This struct contains metadata and information about the bucket whose tags were removed.
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `headers` - HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
/// * `region` - The AWS region where the bucket resides.
|
|
||||||
/// * `bucket` - Name of the bucket from which the tags were removed.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteBucketTaggingResponse {
|
pub struct DeleteBucketTaggingResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the tags were removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteBucketTaggingResponse);
|
||||||
impl FromS3Response for DeleteBucketTaggingResponse {
|
impl_has_s3fields!(DeleteBucketTaggingResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteBucketTaggingResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteBucketTaggingResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,58 +13,32 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use crate::s3::error::Error;
|
||||||
use bytes::Buf;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasIsDeleteMarker, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
|
use crate::s3::utils::{get_default_text, get_option_text, get_text};
|
||||||
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
|
|
||||||
use crate::s3::{
|
#[derive(Clone, Debug)]
|
||||||
error::Error,
|
|
||||||
types::{FromS3Response, S3Request},
|
|
||||||
utils::{get_default_text, get_option_text, get_text},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DeleteObjectResponse {
|
pub struct DeleteObjectResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// Value of the `x-amz-delete-marker` header.
|
|
||||||
/// Indicates whether the specified object version that was permanently deleted was (true) or
|
|
||||||
/// was not (false) a delete marker before deletion. In a simple DELETE, this header indicates
|
|
||||||
/// whether (true) or not (false) the current version of the object is a delete marker.
|
|
||||||
pub is_delete_marker: bool,
|
|
||||||
|
|
||||||
/// Value of the `x-amz-version-id` header.
|
|
||||||
/// If a delete marker was created, this field will contain the version_id of the delete marker.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteObjectResponse);
|
||||||
impl FromS3Response for DeleteObjectResponse {
|
impl_has_s3fields!(DeleteObjectResponse);
|
||||||
async fn from_s3response(
|
|
||||||
_req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
let is_delete_marker = headers
|
|
||||||
.get("x-amz-delete-marker")
|
|
||||||
.map(|v| v == "true")
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
let version_id: Option<String> = headers
|
impl HasBucket for DeleteObjectResponse {}
|
||||||
.get("x-amz-version-id")
|
impl HasRegion for DeleteObjectResponse {}
|
||||||
.and_then(|v| v.to_str().ok().map(String::from));
|
impl HasVersion for DeleteObjectResponse {}
|
||||||
|
impl HasIsDeleteMarker for DeleteObjectResponse {}
|
||||||
Ok(DeleteObjectResponse {
|
|
||||||
headers,
|
|
||||||
is_delete_marker,
|
|
||||||
version_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error info returned by the S3 API when an object could not be deleted.
|
/// Error info returned by the S3 API when an object could not be deleted.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -84,18 +58,6 @@ pub struct DeletedObject {
|
|||||||
pub delete_marker_version_id: Option<String>,
|
pub delete_marker_version_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response of
|
|
||||||
/// [delete_objects()](crate::s3::client::Client::delete_objects)
|
|
||||||
/// S3 API. It is also returned by the
|
|
||||||
/// [remove_objects()](crate::s3::client::Client::delete_objects_streaming) API in the
|
|
||||||
/// form of a stream.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct DeleteObjectsResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
pub result: Vec<DeleteResult>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of deleting an object.
|
/// Result of deleting an object.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DeleteResult {
|
pub enum DeleteResult {
|
||||||
@ -116,24 +78,30 @@ impl DeleteResult {
|
|||||||
pub fn is_deleted(&self) -> bool {
|
pub fn is_deleted(&self) -> bool {
|
||||||
matches!(self, DeleteResult::Deleted(_))
|
matches!(self, DeleteResult::Deleted(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_error(&self) -> bool {
|
pub fn is_error(&self) -> bool {
|
||||||
matches!(self, DeleteResult::Error(_))
|
matches!(self, DeleteResult::Error(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
/// Response of
|
||||||
impl FromS3Response for DeleteObjectsResponse {
|
/// [delete_objects()](crate::s3::client::Client::delete_objects)
|
||||||
async fn from_s3response(
|
/// S3 API. It is also returned by the
|
||||||
_req: S3Request,
|
/// [remove_objects()](crate::s3::client::Client::delete_objects_streaming) API in the
|
||||||
resp: Result<reqwest::Response, Error>,
|
/// form of a stream.
|
||||||
) -> Result<Self, Error> {
|
#[derive(Clone, Debug)]
|
||||||
let resp = resp?;
|
pub struct DeleteObjectsResponse {
|
||||||
let headers = resp.headers().clone();
|
request: S3Request,
|
||||||
|
pub(crate) headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
let body = resp.bytes().await?;
|
impl_from_s3response!(DeleteObjectsResponse);
|
||||||
|
impl_has_s3fields!(DeleteObjectsResponse);
|
||||||
|
|
||||||
let root = Element::parse(body.reader())?;
|
impl DeleteObjectsResponse {
|
||||||
|
/// Returns the bucket name for which the delete operation was performed.
|
||||||
|
pub fn result(&self) -> Result<Vec<DeleteResult>, Error> {
|
||||||
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
let result = root
|
let result = root
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
@ -158,7 +126,6 @@ impl FromS3Response for DeleteObjectsResponse {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<DeleteResult>, Error>>()?;
|
.collect::<Result<Vec<DeleteResult>, Error>>()?;
|
||||||
|
Ok(result)
|
||||||
Ok(Self { headers, result })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,9 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -29,28 +30,13 @@ use std::mem;
|
|||||||
/// For more information, refer to the [AWS S3 DeleteObjectLockConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectLockConfiguration.html).
|
/// For more information, refer to the [AWS S3 DeleteObjectLockConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectLockConfiguration.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteObjectLockConfigResponse {
|
pub struct DeleteObjectLockConfigResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket from which the Object Lock configuration was removed.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteObjectLockConfigResponse);
|
||||||
impl FromS3Response for DeleteObjectLockConfigResponse {
|
impl_has_s3fields!(DeleteObjectLockConfigResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteObjectLockConfigResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteObjectLockConfigResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,10 +14,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::MultimapExt;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -30,38 +32,15 @@ use std::mem;
|
|||||||
/// For more information, refer to the [AWS S3 DeleteObjectTagging API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html).
|
/// For more information, refer to the [AWS S3 DeleteObjectTagging API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DeleteObjectTaggingResponse {
|
pub struct DeleteObjectTaggingResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (name) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// The version ID of the object from which the tags were removed.
|
|
||||||
///
|
|
||||||
/// If versioning is not enabled on the bucket, this field may be `None`.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(DeleteObjectTaggingResponse);
|
||||||
impl FromS3Response for DeleteObjectTaggingResponse {
|
impl_has_s3fields!(DeleteObjectTaggingResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for DeleteObjectTaggingResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for DeleteObjectTaggingResponse {}
|
||||||
region: req.inner_region,
|
impl HasObject for DeleteObjectTaggingResponse {}
|
||||||
bucket: take_bucket(req.bucket)?,
|
impl HasVersion for DeleteObjectTaggingResponse {}
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -13,11 +13,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request, SseConfig};
|
use crate::s3::types::{FromS3Response, S3Request, SseConfig};
|
||||||
use crate::s3::utils::{get_option_text, get_text, take_bucket};
|
use crate::s3::utils::{get_option_text, get_text};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -32,64 +34,63 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketEncryption API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html).
|
/// For more information, refer to the [AWS S3 GetBucketEncryption API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketEncryptionResponse {
|
pub struct GetBucketEncryptionResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
impl_has_s3fields!(GetBucketEncryptionResponse);
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose encryption configuration is retrieved.
|
impl HasBucket for GetBucketEncryptionResponse {}
|
||||||
pub bucket: String,
|
impl HasRegion for GetBucketEncryptionResponse {}
|
||||||
|
|
||||||
/// The default server-side encryption configuration of the bucket.
|
impl GetBucketEncryptionResponse {
|
||||||
|
/// Returns the default server-side encryption configuration of the bucket.
|
||||||
///
|
///
|
||||||
/// This includes the encryption algorithm and, if applicable, the AWS KMS key ID used for encrypting objects.
|
/// This includes the encryption algorithm and, if applicable, the AWS KMS key ID used for encrypting objects.
|
||||||
///
|
/// If the bucket has no default encryption configuration, this method returns a default `SseConfig` with empty fields.
|
||||||
/// If the bucket has no default encryption configuration, the `get_bucket_encryption` API call may return an error
|
pub fn config(&self) -> Result<SseConfig, Error> {
|
||||||
/// with the code `ServerSideEncryptionConfigurationNotFoundError`. It's advisable to handle this case appropriately in your application.
|
if self.body.is_empty() {
|
||||||
pub config: SseConfig,
|
return Ok(SseConfig::default());
|
||||||
|
}
|
||||||
|
let mut root = Element::parse(self.body.clone().reader())?; // clone of Bytes is inexpensive
|
||||||
|
|
||||||
|
let rule = root
|
||||||
|
.get_mut_child("Rule")
|
||||||
|
.ok_or(Error::XmlError("<Rule> tag not found".into()))?;
|
||||||
|
|
||||||
|
let sse_by_default = rule
|
||||||
|
.get_mut_child("ApplyServerSideEncryptionByDefault")
|
||||||
|
.ok_or(Error::XmlError(
|
||||||
|
"<ApplyServerSideEncryptionByDefault> tag not found".into(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(SseConfig {
|
||||||
|
sse_algorithm: get_text(sse_by_default, "SSEAlgorithm")?,
|
||||||
|
kms_master_key_id: get_option_text(sse_by_default, "KMSMasterKeyID"),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for GetBucketEncryptionResponse {
|
impl FromS3Response for GetBucketEncryptionResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => {
|
Ok(mut resp) => Ok(Self {
|
||||||
let headers: HeaderMap = mem::take(r.headers_mut());
|
request,
|
||||||
let body = r.bytes().await?;
|
headers: mem::take(resp.headers_mut()),
|
||||||
let mut root = Element::parse(body.reader())?;
|
body: resp.bytes().await?,
|
||||||
|
}),
|
||||||
let rule = root
|
|
||||||
.get_mut_child("Rule")
|
|
||||||
.ok_or(Error::XmlError("<Rule> tag not found".into()))?;
|
|
||||||
|
|
||||||
let sse_by_default = rule
|
|
||||||
.get_mut_child("ApplyServerSideEncryptionByDefault")
|
|
||||||
.ok_or(Error::XmlError(
|
|
||||||
"<ApplyServerSideEncryptionByDefault> tag not found".into(),
|
|
||||||
))?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config: SseConfig {
|
|
||||||
sse_algorithm: get_text(sse_by_default, "SSEAlgorithm")?,
|
|
||||||
kms_master_key_id: get_option_text(sse_by_default, "KMSMasterKeyID"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(Error::S3Error(e))
|
Err(Error::S3Error(e))
|
||||||
if e.code == ErrorCode::ServerSideEncryptionConfigurationNotFoundError =>
|
if e.code == ErrorCode::ServerSideEncryptionConfigurationNotFoundError =>
|
||||||
{
|
{
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config: Default::default(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::lifecycle_config::LifecycleConfig;
|
use crate::s3::lifecycle_config::LifecycleConfig;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{UtcTime, take_bucket};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::{Buf, Bytes};
|
||||||
use bytes::Buf;
|
|
||||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -33,56 +33,36 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketLifecycleConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html).
|
/// For more information, refer to the [AWS S3 GetBucketLifecycleConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketLifecycleResponse {
|
pub struct GetBucketLifecycleResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose lifecycle configuration is retrieved.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// The lifecycle configuration of the bucket.
|
|
||||||
///
|
|
||||||
/// This includes a set of rules that define actions applied to objects, such as transitioning
|
|
||||||
/// them to different storage classes, expiring them, or aborting incomplete multipart uploads.
|
|
||||||
///
|
|
||||||
/// If the bucket has no lifecycle configuration, this field may contain an empty configuration.
|
|
||||||
pub config: LifecycleConfig,
|
|
||||||
|
|
||||||
/// Optional value of `X-Minio-LifecycleConfig-UpdatedAt` header, indicating the last update
|
|
||||||
/// time of the lifecycle configuration.
|
|
||||||
pub updated_at: Option<UtcTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetBucketLifecycleResponse);
|
||||||
impl FromS3Response for GetBucketLifecycleResponse {
|
impl_has_s3fields!(GetBucketLifecycleResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
impl HasBucket for GetBucketLifecycleResponse {}
|
||||||
resp: Result<reqwest::Response, Error>,
|
impl HasRegion for GetBucketLifecycleResponse {}
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
impl GetBucketLifecycleResponse {
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
/// Returns the lifecycle configuration of the bucket.
|
||||||
let config: LifecycleConfig = {
|
///
|
||||||
let body = resp.bytes().await?;
|
/// This configuration includes rules for managing the lifecycle of objects in the bucket,
|
||||||
let root = Element::parse(body.reader())?;
|
/// such as transitioning them to different storage classes or expiring them after a specified period.
|
||||||
LifecycleConfig::from_xml(&root)?
|
pub fn config(&self) -> Result<LifecycleConfig, Error> {
|
||||||
};
|
LifecycleConfig::from_xml(&Element::parse(self.body.clone().reader())?)
|
||||||
let updated_at: Option<DateTime<Utc>> = headers
|
}
|
||||||
|
|
||||||
|
/// Returns the last update time of the lifecycle configuration
|
||||||
|
/// (`X-Minio-LifecycleConfig-UpdatedAt`), if available.
|
||||||
|
pub fn updated_at(&self) -> Option<DateTime<Utc>> {
|
||||||
|
self.headers
|
||||||
.get("x-minio-lifecycleconfig-updatedat")
|
.get("x-minio-lifecycleconfig-updatedat")
|
||||||
.and_then(|v| v.to_str().ok())
|
.and_then(|v| v.to_str().ok())
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
NaiveDateTime::parse_from_str(v, "%Y%m%dT%H%M%SZ")
|
NaiveDateTime::parse_from_str(v, "%Y%m%dT%H%M%SZ")
|
||||||
.ok()
|
.ok()
|
||||||
.map(|naive| DateTime::from_naive_utc_and_offset(naive, Utc))
|
.map(|naive| DateTime::from_naive_utc_and_offset(naive, Utc))
|
||||||
});
|
})
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config,
|
|
||||||
updated_at,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, NotificationConfig, S3Request};
|
use crate::s3::types::{FromS3Response, NotificationConfig, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::{Buf, Bytes};
|
||||||
use bytes::Buf;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -31,42 +31,23 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketNotificationConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html).
|
/// For more information, refer to the [AWS S3 GetBucketNotificationConfiguration API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketNotificationResponse {
|
pub struct GetBucketNotificationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose notification configuration is retrieved.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// The notification configuration of the bucket.
|
|
||||||
///
|
|
||||||
/// This includes the event types and the destinations (e.g., SNS topics, SQS queues, Lambda functions)
|
|
||||||
/// configured to receive notifications for those events.
|
|
||||||
///
|
|
||||||
/// If the bucket has no notification configuration, this field may contain an empty configuration.
|
|
||||||
pub config: NotificationConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetBucketNotificationResponse);
|
||||||
impl FromS3Response for GetBucketNotificationResponse {
|
impl_has_s3fields!(GetBucketNotificationResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetBucketNotificationResponse {}
|
||||||
let body = resp.bytes().await?;
|
impl HasRegion for GetBucketNotificationResponse {}
|
||||||
let mut root = Element::parse(body.reader())?;
|
|
||||||
let config = NotificationConfig::from_xml(&mut root)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl GetBucketNotificationResponse {
|
||||||
headers,
|
/// Returns the notification configuration of the bucket.
|
||||||
region: req.inner_region,
|
///
|
||||||
bucket: take_bucket(req.bucket)?,
|
/// This configuration includes the event types and the destinations (e.g., SNS topics, SQS queues, Lambda functions)
|
||||||
config,
|
/// configured to receive notifications for those events.
|
||||||
})
|
pub fn config(&self) -> Result<NotificationConfig, Error> {
|
||||||
|
NotificationConfig::from_xml(&mut Element::parse(self.body.clone().reader())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,10 +13,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -29,45 +31,44 @@ use std::mem;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketPolicy API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicy.html).
|
/// For more information, refer to the [AWS S3 GetBucketPolicy API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicy.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketPolicyResponse {
|
pub struct GetBucketPolicyResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
impl_has_s3fields!(GetBucketPolicyResponse);
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose policy is retrieved.
|
impl HasBucket for GetBucketPolicyResponse {}
|
||||||
pub bucket: String,
|
impl HasRegion for GetBucketPolicyResponse {}
|
||||||
|
|
||||||
/// The bucket policy as a JSON-formatted string.
|
impl GetBucketPolicyResponse {
|
||||||
|
/// Returns the bucket policy as a JSON-formatted string.
|
||||||
///
|
///
|
||||||
/// This policy defines access permissions for the bucket. It specifies who can access the bucket,
|
/// This method retrieves the policy associated with the bucket, which defines permissions
|
||||||
/// what actions they can perform, and under what conditions.
|
/// for accessing the bucket and its contents.
|
||||||
///
|
pub fn config(&self) -> Result<&str, Error> {
|
||||||
/// For example, a policy might grant read-only access to anonymous users or restrict access to specific IP addresses.
|
std::str::from_utf8(&self.body).map_err(|e| {
|
||||||
///
|
Error::Utf8Error(format!("Failed to parse bucket policy as UTF-8: {}", e).into())
|
||||||
/// Note: If the bucket has no policy, the `get_bucket_policy` API call may return an error
|
})
|
||||||
/// with the code `NoSuchBucketPolicy`. It's advisable to handle this case appropriately in your application.
|
}
|
||||||
pub config: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for GetBucketPolicyResponse {
|
impl FromS3Response for GetBucketPolicyResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => Ok(Self {
|
Ok(mut resp) => Ok(Self {
|
||||||
headers: mem::take(r.headers_mut()),
|
request,
|
||||||
region: req.inner_region,
|
headers: mem::take(resp.headers_mut()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
body: resp.bytes().await?,
|
||||||
config: r.text().await?,
|
|
||||||
}),
|
}),
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucketPolicy => Ok(Self {
|
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchBucketPolicy => Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::from_static("{}".as_ref()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config: String::from("{}"),
|
|
||||||
}),
|
}),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, ReplicationConfig, S3Request};
|
use crate::s3::types::{FromS3Response, ReplicationConfig, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::{Buf, Bytes};
|
||||||
use bytes::Buf;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -30,42 +30,26 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketReplication API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html).
|
/// For more information, refer to the [AWS S3 GetBucketReplication API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketReplicationResponse {
|
pub struct GetBucketReplicationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
impl_from_s3response!(GetBucketReplicationResponse);
|
||||||
pub region: String,
|
impl_has_s3fields!(GetBucketReplicationResponse);
|
||||||
|
|
||||||
/// Name of the bucket whose replication configuration is retrieved.
|
impl HasBucket for GetBucketReplicationResponse {}
|
||||||
pub bucket: String,
|
impl HasRegion for GetBucketReplicationResponse {}
|
||||||
|
|
||||||
/// The replication configuration of the bucket.
|
impl GetBucketReplicationResponse {
|
||||||
|
/// Returns the replication configuration of the bucket.
|
||||||
///
|
///
|
||||||
/// This includes the IAM role that Amazon S3 assumes to replicate objects on your behalf,
|
/// This includes the IAM role that Amazon S3 assumes to replicate objects on your behalf,
|
||||||
/// and one or more replication rules that specify the conditions under which objects are replicated.
|
/// and one or more replication rules that specify the conditions under which objects are replicated.
|
||||||
///
|
///
|
||||||
/// For more details on replication configuration elements, see the [AWS S3 Replication Configuration documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication-add-config.html).
|
/// For more details on replication configuration elements, see the [AWS S3 Replication Configuration documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication-add-config.html).
|
||||||
pub config: ReplicationConfig,
|
pub fn config(&self) -> Result<ReplicationConfig, Error> {
|
||||||
}
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
ReplicationConfig::from_xml(&root)
|
||||||
#[async_trait]
|
|
||||||
impl FromS3Response for GetBucketReplicationResponse {
|
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
let body = resp.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
let config = ReplicationConfig::from_xml(&root)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,15 +13,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields, HasTagging};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{get_text, take_bucket};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bytes::Buf;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
|
||||||
|
|
||||||
/// Response from the [`get_bucket_tagging`](crate::s3::client::Client::get_bucket_tagging) API call,
|
/// Response from the [`get_bucket_tagging`](crate::s3::client::Client::get_bucket_tagging) API call,
|
||||||
/// providing the set of tags associated with an S3 bucket.
|
/// providing the set of tags associated with an S3 bucket.
|
||||||
@ -32,57 +31,33 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketTagging API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html).
|
/// For more information, refer to the [AWS S3 GetBucketTagging API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketTaggingResponse {
|
pub struct GetBucketTaggingResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose tags are retrieved.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// A collection of tags assigned to the bucket.
|
|
||||||
///
|
|
||||||
/// Each tag is a key-value pair represented as a `HashMap<String, String>`.
|
|
||||||
/// If the bucket has no tags, this map will be empty.
|
|
||||||
///
|
|
||||||
/// Note: If the bucket has no tags, the `get_bucket_tags` API call may return an error
|
|
||||||
/// with the code `NoSuchTagSet`. It's advisable to handle this case appropriately in your application.
|
|
||||||
pub tags: HashMap<String, String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(GetBucketTaggingResponse);
|
||||||
|
|
||||||
|
impl HasBucket for GetBucketTaggingResponse {}
|
||||||
|
impl HasRegion for GetBucketTaggingResponse {}
|
||||||
|
impl HasTagging for GetBucketTaggingResponse {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for GetBucketTaggingResponse {
|
impl FromS3Response for GetBucketTaggingResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => {
|
Ok(mut resp) => Ok(Self {
|
||||||
let headers: HeaderMap = mem::take(r.headers_mut());
|
request,
|
||||||
let body = r.bytes().await?;
|
headers: mem::take(resp.headers_mut()),
|
||||||
let mut root = Element::parse(body.reader())?;
|
body: resp.bytes().await?,
|
||||||
|
}),
|
||||||
let element = root
|
|
||||||
.get_mut_child("TagSet")
|
|
||||||
.ok_or(Error::XmlError("<TagSet> tag not found".to_string()))?;
|
|
||||||
let mut tags = HashMap::new();
|
|
||||||
while let Some(v) = element.take_child("Tag") {
|
|
||||||
tags.insert(get_text(&v, "Key")?, get_text(&v, "Value")?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
tags,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchTagSet => Ok(Self {
|
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchTagSet => Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
tags: HashMap::new(),
|
|
||||||
}),
|
}),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,10 +15,11 @@
|
|||||||
|
|
||||||
use crate::s3::builders::VersioningStatus;
|
use crate::s3::builders::VersioningStatus;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{get_option_text, take_bucket};
|
use crate::s3::utils::get_option_text;
|
||||||
use async_trait::async_trait;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -32,59 +33,40 @@ use xmltree::Element;
|
|||||||
/// For more information, refer to the [AWS S3 GetBucketVersioning API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html).
|
/// For more information, refer to the [AWS S3 GetBucketVersioning API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetBucketVersioningResponse {
|
pub struct GetBucketVersioningResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket whose versioning configuration is retrieved.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// The versioning status of the bucket.
|
|
||||||
///
|
|
||||||
/// - `Some(VersioningStatus::Enabled)`: Versioning is enabled.
|
|
||||||
/// - `Some(VersioningStatus::Suspended)`: Versioning is suspended.
|
|
||||||
/// - `None`: Versioning has never been configured for this bucket.
|
|
||||||
pub status: Option<VersioningStatus>,
|
|
||||||
|
|
||||||
/// Indicates whether MFA delete is enabled for the bucket.
|
|
||||||
///
|
|
||||||
/// - `Some(true)`: MFA delete is enabled.
|
|
||||||
/// - `Some(false)`: MFA delete is disabled.
|
|
||||||
/// - `None`: MFA delete has never been configured for this bucket.
|
|
||||||
///
|
|
||||||
/// Note: MFA delete adds an extra layer of security by requiring additional authentication
|
|
||||||
/// for certain operations. For more details, see the [AWS S3 MFA Delete documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiFactorAuthenticationDelete.html).
|
|
||||||
pub mfa_delete: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetBucketVersioningResponse);
|
||||||
impl FromS3Response for GetBucketVersioningResponse {
|
impl_has_s3fields!(GetBucketVersioningResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetBucketVersioningResponse {}
|
||||||
|
impl HasRegion for GetBucketVersioningResponse {}
|
||||||
|
|
||||||
let body = resp.bytes().await?;
|
impl GetBucketVersioningResponse {
|
||||||
let root = Element::parse(body.reader())?;
|
/// Returns the versioning status of the bucket.
|
||||||
let status: Option<VersioningStatus> =
|
///
|
||||||
get_option_text(&root, "Status").map(|v| match v.as_str() {
|
/// This method retrieves the current versioning status, which can be:
|
||||||
"Enabled" => VersioningStatus::Enabled,
|
/// - `Some(VersioningStatus::Enabled)` if versioning is enabled.
|
||||||
_ => VersioningStatus::Suspended, // Default case
|
/// - `Some(VersioningStatus::Suspended)` if versioning is suspended.
|
||||||
});
|
/// - `None` if versioning has never been configured for this bucket.
|
||||||
let mfa_delete: Option<bool> =
|
pub fn status(&self) -> Result<Option<VersioningStatus>, Error> {
|
||||||
get_option_text(&root, "MFADelete").map(|v| v.eq_ignore_ascii_case("Enabled"));
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
Ok(get_option_text(&root, "Status").map(|v| match v.as_str() {
|
||||||
|
"Enabled" => VersioningStatus::Enabled,
|
||||||
|
_ => VersioningStatus::Suspended, // Default case
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
/// Returns whether MFA delete is enabled for the bucket.
|
||||||
headers,
|
///
|
||||||
region: req.inner_region,
|
/// This method retrieves the MFA delete setting, which can be:
|
||||||
bucket: take_bucket(req.bucket)?,
|
/// - `Some(true)` if MFA delete is enabled.
|
||||||
status,
|
/// - `Some(false)` if MFA delete is disabled.
|
||||||
mfa_delete,
|
/// - `None` if MFA delete has never been configured for this bucket.
|
||||||
})
|
pub fn mfa_delete(&self) -> Result<Option<bool>, Error> {
|
||||||
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
Ok(get_option_text(&root, "MFADelete").map(|v| v.eq_ignore_ascii_case("Enabled")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,75 +13,64 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
use crate::impl_has_s3fields;
|
||||||
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasEtagFromHeaders, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::{
|
use crate::s3::{
|
||||||
builders::ObjectContent,
|
builders::ObjectContent,
|
||||||
error::Error,
|
error::Error,
|
||||||
types::{FromS3Response, S3Request},
|
types::{FromS3Response, S3Request},
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use bytes::Bytes;
|
||||||
use futures_util::TryStreamExt;
|
use futures_util::TryStreamExt;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
pub struct GetObjectResponse {
|
pub struct GetObjectResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes, // Note: not used
|
||||||
|
resp: reqwest::Response,
|
||||||
|
}
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
impl_has_s3fields!(GetObjectResponse);
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
impl HasBucket for GetObjectResponse {}
|
||||||
pub bucket: String,
|
impl HasRegion for GetObjectResponse {}
|
||||||
|
impl HasObject for GetObjectResponse {}
|
||||||
|
impl HasVersion for GetObjectResponse {}
|
||||||
|
impl HasEtagFromHeaders for GetObjectResponse {}
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
impl GetObjectResponse {
|
||||||
pub object: String,
|
/// Returns the content of the object as a (streaming) byte buffer. Note: consumes the response.
|
||||||
|
pub fn content(self) -> Result<ObjectContent, Error> {
|
||||||
|
let content_length: u64 = self.object_size()?;
|
||||||
|
let body = self.resp.bytes_stream().map_err(std::io::Error::other);
|
||||||
|
Ok(ObjectContent::new_from_stream(body, Some(content_length)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the object.
|
/// Returns the content size (in Bytes) of the object.
|
||||||
pub etag: Option<String>,
|
pub fn object_size(&self) -> Result<u64, Error> {
|
||||||
|
self.resp
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
.content_length()
|
||||||
pub version_id: Option<String>,
|
.ok_or(Error::ContentLengthUnknown)
|
||||||
|
}
|
||||||
/// The content of the object as a stream or byte buffer.
|
|
||||||
pub content: ObjectContent,
|
|
||||||
|
|
||||||
/// Size of the object in bytes.
|
|
||||||
pub object_size: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for GetObjectResponse {
|
impl FromS3Response for GetObjectResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut resp = resp?;
|
let mut resp = response?;
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let etag: Option<String> = headers
|
|
||||||
.get("etag")
|
|
||||||
.and_then(|v| v.to_str().ok())
|
|
||||||
.map(|s| s.trim_matches('"').to_string());
|
|
||||||
|
|
||||||
let version_id: Option<String> = headers
|
|
||||||
.get("x-amz-version-id")
|
|
||||||
.and_then(|v| v.to_str().ok().map(String::from));
|
|
||||||
|
|
||||||
let content_length: u64 = resp.content_length().ok_or(Error::ContentLengthUnknown)?;
|
|
||||||
let body = resp.bytes_stream().map_err(std::io::Error::other);
|
|
||||||
let content = ObjectContent::new_from_stream(body, Some(content_length));
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
headers,
|
request,
|
||||||
region: req.inner_region,
|
headers: mem::take(resp.headers_mut()),
|
||||||
bucket: take_bucket(req.bucket)?,
|
body: Bytes::new(),
|
||||||
object: take_object(req.object)?,
|
resp,
|
||||||
version_id,
|
|
||||||
content,
|
|
||||||
object_size: content_length,
|
|
||||||
etag,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::MultimapExt;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{get_default_text, take_bucket, take_object};
|
use crate::s3::utils::get_default_text;
|
||||||
use async_trait::async_trait;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -28,57 +30,28 @@ use xmltree::Element;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetObjectLegalHoldResponse {
|
pub struct GetObjectLegalHoldResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
|
|
||||||
/// Indicates whether the object legal hold is enabled.
|
|
||||||
pub enabled: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetObjectLegalHoldResponse);
|
||||||
impl FromS3Response for GetObjectLegalHoldResponse {
|
impl_has_s3fields!(GetObjectLegalHoldResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
match resp {
|
|
||||||
Ok(mut r) => {
|
|
||||||
let headers: HeaderMap = mem::take(r.headers_mut());
|
|
||||||
let body = r.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for GetObjectLegalHoldResponse {}
|
||||||
headers,
|
impl HasRegion for GetObjectLegalHoldResponse {}
|
||||||
region: req.inner_region,
|
impl HasObject for GetObjectLegalHoldResponse {}
|
||||||
bucket: take_bucket(req.bucket)?,
|
impl HasVersion for GetObjectLegalHoldResponse {}
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
impl GetObjectLegalHoldResponse {
|
||||||
enabled: get_default_text(&root, "Status") == "ON",
|
/// Returns the legal hold status of the object.
|
||||||
})
|
///
|
||||||
}
|
/// This method retrieves whether the legal hold is enabled for the specified object.
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchObjectLockConfiguration => {
|
pub fn enabled(&self) -> Result<bool, Error> {
|
||||||
Ok(Self {
|
if self.body.is_empty() {
|
||||||
headers: e.headers,
|
return Ok(false); // No legal hold configuration present due to NoSuchObjectLockConfiguration
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
enabled: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
}
|
||||||
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
Ok(get_default_text(&root, "Status") == "ON")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasObject, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, ObjectLockConfig, S3Request};
|
use crate::s3::types::{FromS3Response, ObjectLockConfig, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::{Buf, Bytes};
|
||||||
use bytes::Buf;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -29,36 +29,24 @@ use xmltree::Element;
|
|||||||
/// helping to enforce write-once-read-many (WORM) protection.
|
/// helping to enforce write-once-read-many (WORM) protection.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetObjectLockConfigResponse {
|
pub struct GetObjectLockConfigResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket for which the Object Lock configuration is retrieved.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// The Object Lock configuration of the bucket, including retention settings and legal hold status.
|
|
||||||
pub config: ObjectLockConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetObjectLockConfigResponse);
|
||||||
impl FromS3Response for GetObjectLockConfigResponse {
|
impl_has_s3fields!(GetObjectLockConfigResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetObjectLockConfigResponse {}
|
||||||
let body = resp.bytes().await?;
|
impl HasRegion for GetObjectLockConfigResponse {}
|
||||||
let root = Element::parse(body.reader())?;
|
impl HasObject for GetObjectLockConfigResponse {}
|
||||||
|
|
||||||
Ok(Self {
|
impl GetObjectLockConfigResponse {
|
||||||
headers,
|
/// Returns the Object Lock configuration of the bucket.
|
||||||
region: req.inner_region,
|
///
|
||||||
bucket: take_bucket(req.bucket)?,
|
/// This method retrieves the Object Lock settings, which include retention mode and period,
|
||||||
config: ObjectLockConfig::from_xml(&root)?,
|
/// as well as legal hold status for the bucket.
|
||||||
})
|
pub fn config(&self) -> Result<ObjectLockConfig, Error> {
|
||||||
|
ObjectLockConfig::from_xml(&Element::parse(self.body.clone().reader())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,47 +14,33 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasObject, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
pub struct GetObjectPromptResponse {
|
pub struct GetObjectPromptResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// The prompt response for the object.
|
|
||||||
pub prompt_response: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetObjectPromptResponse);
|
||||||
impl FromS3Response for GetObjectPromptResponse {
|
impl_has_s3fields!(GetObjectPromptResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetObjectPromptResponse {}
|
||||||
let body = resp.bytes().await?;
|
impl HasRegion for GetObjectPromptResponse {}
|
||||||
let prompt_response: String = String::from_utf8(body.to_vec())?;
|
impl HasObject for GetObjectPromptResponse {}
|
||||||
|
|
||||||
Ok(Self {
|
impl GetObjectPromptResponse {
|
||||||
headers,
|
/// Returns the prompt response for the object.
|
||||||
region: req.inner_region,
|
///
|
||||||
bucket: take_bucket(req.bucket)?,
|
/// This method retrieves the content of the object as a UTF-8 encoded string.
|
||||||
object: take_object(req.object)?,
|
pub fn prompt_response(&self) -> Result<&str, Error> {
|
||||||
prompt_response,
|
std::str::from_utf8(&self.body).map_err(|e| {
|
||||||
|
Error::Utf8Error(format!("Failed to parse prompt_response as UTF-8: {}", e).into())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::{Error, ErrorCode};
|
use crate::s3::error::{Error, ErrorCode};
|
||||||
use crate::s3::multimap::MultimapExt;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, RetentionMode, S3Request};
|
use crate::s3::types::{FromS3Response, RetentionMode, S3Request};
|
||||||
use crate::s3::utils::{UtcTime, from_iso8601utc, get_option_text, take_bucket, take_object};
|
use crate::s3::utils::{UtcTime, from_iso8601utc, get_option_text};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -26,67 +29,65 @@ use xmltree::Element;
|
|||||||
/// Response of [get_object_retention()](crate::s3::client::Client::get_object_retention) API
|
/// Response of [get_object_retention()](crate::s3::client::Client::get_object_retention) API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetObjectRetentionResponse {
|
pub struct GetObjectRetentionResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
impl_has_s3fields!(GetObjectRetentionResponse);
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
impl HasBucket for GetObjectRetentionResponse {}
|
||||||
pub bucket: String,
|
impl HasRegion for GetObjectRetentionResponse {}
|
||||||
|
impl HasObject for GetObjectRetentionResponse {}
|
||||||
|
impl HasVersion for GetObjectRetentionResponse {}
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
impl GetObjectRetentionResponse {
|
||||||
pub object: String,
|
/// Returns the retention mode of the object.
|
||||||
|
///
|
||||||
|
/// This method retrieves the retention mode, which can be either `Governance` or `Compliance`.
|
||||||
|
pub fn retention_mode(&self) -> Result<Option<RetentionMode>, Error> {
|
||||||
|
if self.body.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
Ok(match get_option_text(&root, "Mode") {
|
||||||
|
Some(v) => Some(RetentionMode::parse(&v)?),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
/// Returns the date until which the object is retained.
|
||||||
pub version_id: Option<String>,
|
///
|
||||||
|
/// This method retrieves the retention date, which indicates when the object will no longer be retained.
|
||||||
/// The retention mode of the object.
|
pub fn retain_until_date(&self) -> Result<Option<UtcTime>, Error> {
|
||||||
pub retention_mode: Option<RetentionMode>,
|
if self.body.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
/// The date until which the object is retained.
|
}
|
||||||
pub retain_until_date: Option<UtcTime>,
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
Ok(match get_option_text(&root, "RetainUntilDate") {
|
||||||
|
Some(v) => Some(from_iso8601utc(&v)?),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for GetObjectRetentionResponse {
|
impl FromS3Response for GetObjectRetentionResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match resp {
|
match response {
|
||||||
Ok(mut r) => {
|
Ok(mut resp) => Ok(Self {
|
||||||
let headers = mem::take(r.headers_mut());
|
request,
|
||||||
let body = r.bytes().await?;
|
headers: mem::take(resp.headers_mut()),
|
||||||
let root = Element::parse(body.reader())?;
|
body: resp.bytes().await?,
|
||||||
let retention_mode = match get_option_text(&root, "Mode") {
|
}),
|
||||||
Some(v) => Some(RetentionMode::parse(&v)?),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let retain_until_date = match get_option_text(&root, "RetainUntilDate") {
|
|
||||||
Some(v) => Some(from_iso8601utc(&v)?),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
retention_mode,
|
|
||||||
retain_until_date,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchObjectLockConfiguration => {
|
Err(Error::S3Error(e)) if e.code == ErrorCode::NoSuchObjectLockConfiguration => {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers: e.headers,
|
headers: e.headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
retention_mode: None,
|
|
||||||
retain_until_date: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
|
|||||||
@ -14,67 +14,30 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::MultimapExt;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasObject, HasRegion, HasS3Fields, HasTagging, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{get_text, take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use bytes::Buf;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
|
||||||
|
|
||||||
/// Response of
|
/// Response of
|
||||||
/// [get_object_tags()](crate::s3::client::Client::get_object_tagging)
|
/// [get_object_tags()](crate::s3::client::Client::get_object_tagging)
|
||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetObjectTaggingResponse {
|
pub struct GetObjectTaggingResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
|
|
||||||
/// Tags associated with the object.
|
|
||||||
pub tags: HashMap<String, String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetObjectTaggingResponse);
|
||||||
impl FromS3Response for GetObjectTaggingResponse {
|
impl_has_s3fields!(GetObjectTaggingResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetObjectTaggingResponse {}
|
||||||
|
impl HasRegion for GetObjectTaggingResponse {}
|
||||||
let body = resp.bytes().await?;
|
impl HasObject for GetObjectTaggingResponse {}
|
||||||
let mut root = Element::parse(body.reader())?;
|
impl HasVersion for GetObjectTaggingResponse {}
|
||||||
let element = root
|
impl HasTagging for GetObjectTaggingResponse {}
|
||||||
.get_mut_child("TagSet")
|
|
||||||
.ok_or(Error::XmlError("<TagSet> tag not found".to_string()))?;
|
|
||||||
let mut tags = HashMap::new();
|
|
||||||
while let Some(v) = element.take_child("Tag") {
|
|
||||||
tags.insert(get_text(&v, "Key")?, get_text(&v, "Value")?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
tags,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
use crate::s3::client::DEFAULT_REGION;
|
use crate::s3::client::DEFAULT_REGION;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::{Buf, Bytes};
|
||||||
use bytes::Buf;
|
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -28,44 +28,28 @@ use xmltree::Element;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GetRegionResponse {
|
pub struct GetRegionResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// The region response for the bucket.
|
|
||||||
pub region_response: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(GetRegionResponse);
|
||||||
impl FromS3Response for GetRegionResponse {
|
impl_has_s3fields!(GetRegionResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for GetRegionResponse {}
|
||||||
let region_response: String = {
|
impl HasRegion for GetRegionResponse {}
|
||||||
let body = resp.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
|
|
||||||
let mut location = root.get_text().unwrap_or_default().to_string();
|
impl GetRegionResponse {
|
||||||
if location.is_empty() {
|
/// Returns the region response for the bucket.
|
||||||
location = String::from(DEFAULT_REGION);
|
///
|
||||||
}
|
/// This method retrieves the region where the bucket is located.
|
||||||
location
|
pub fn region_response(&self) -> Result<String, Error> {
|
||||||
};
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
|
||||||
Ok(Self {
|
let mut location = root.get_text().unwrap_or_default().to_string();
|
||||||
headers,
|
if location.is_empty() {
|
||||||
region: req.inner_region,
|
location = String::from(DEFAULT_REGION);
|
||||||
bucket: take_bucket(req.bucket)?,
|
}
|
||||||
region_response,
|
Ok(location)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,11 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::HasS3Fields;
|
||||||
use crate::s3::types::{Bucket, FromS3Response, S3Request};
|
use crate::s3::types::{Bucket, FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{from_iso8601utc, get_text};
|
use crate::s3::utils::{from_iso8601utc, get_text};
|
||||||
use async_trait::async_trait;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -25,24 +26,18 @@ use xmltree::Element;
|
|||||||
/// Response of [list_buckets()](crate::s3::client::Client::list_buckets) API
|
/// Response of [list_buckets()](crate::s3::client::Client::list_buckets) API
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ListBucketsResponse {
|
pub struct ListBucketsResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// the list of buckets that are present in the account.
|
|
||||||
pub buckets: Vec<Bucket>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(ListBucketsResponse);
|
||||||
impl FromS3Response for ListBucketsResponse {
|
impl_has_s3fields!(ListBucketsResponse);
|
||||||
async fn from_s3response(
|
|
||||||
_req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let body = resp.bytes().await?;
|
impl ListBucketsResponse {
|
||||||
let mut root = Element::parse(body.reader())?;
|
/// Returns the list of buckets in the account.
|
||||||
|
pub fn buckets(&self) -> Result<Vec<Bucket>, Error> {
|
||||||
|
let mut root = Element::parse(self.body().clone().reader())?;
|
||||||
let buckets_xml = root
|
let buckets_xml = root
|
||||||
.get_mut_child("Buckets")
|
.get_mut_child("Buckets")
|
||||||
.ok_or(Error::XmlError("<Buckets> tag not found".into()))?;
|
.ok_or(Error::XmlError("<Buckets> tag not found".into()))?;
|
||||||
@ -55,7 +50,6 @@ impl FromS3Response for ListBucketsResponse {
|
|||||||
creation_date: from_iso8601utc(&get_text(&bucket, "CreationDate")?)?,
|
creation_date: from_iso8601utc(&get_text(&bucket, "CreationDate")?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Ok(buckets)
|
||||||
Ok(Self { headers, buckets })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,12 +12,8 @@
|
|||||||
|
|
||||||
//! Response types for ListObjects APIs
|
//! Response types for ListObjects APIs
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use crate::impl_has_s3fields;
|
||||||
use bytes::Buf;
|
use crate::s3::response::a_response_traits::HasS3Fields;
|
||||||
use reqwest::header::HeaderMap;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use crate::s3::{
|
use crate::s3::{
|
||||||
error::Error,
|
error::Error,
|
||||||
types::{FromS3Response, ListEntry, S3Request},
|
types::{FromS3Response, ListEntry, S3Request},
|
||||||
@ -26,6 +22,11 @@ use crate::s3::{
|
|||||||
xml::{Element, MergeXmlElements},
|
xml::{Element, MergeXmlElements},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use bytes::{Buf, Bytes};
|
||||||
|
use reqwest::header::HeaderMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
fn url_decode(
|
fn url_decode(
|
||||||
encoding_type: &Option<String>,
|
encoding_type: &Option<String>,
|
||||||
@ -188,8 +189,10 @@ fn parse_list_objects_common_prefixes(
|
|||||||
/// Response of [list_objects_v1()](crate::s3::client::Client::list_objects_v1) S3 API
|
/// Response of [list_objects_v1()](crate::s3::client::Client::list_objects_v1) S3 API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ListObjectsV1Response {
|
pub struct ListObjectsV1Response {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub encoding_type: Option<String>,
|
pub encoding_type: Option<String>,
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
@ -201,18 +204,20 @@ pub struct ListObjectsV1Response {
|
|||||||
pub next_marker: Option<String>,
|
pub next_marker: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(ListObjectsV1Response);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for ListObjectsV1Response {
|
impl FromS3Response for ListObjectsV1Response {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
_req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut resp = resp?;
|
let mut resp = response?;
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
let headers: HeaderMap = mem::take(resp.headers_mut());
|
||||||
let body = resp.bytes().await?;
|
let body = resp.bytes().await?;
|
||||||
let xmltree_root = xmltree::Element::parse(body.reader())?;
|
|
||||||
let root = Element::from(&xmltree_root);
|
|
||||||
|
|
||||||
|
let xmltree_root = xmltree::Element::parse(body.clone().reader())?;
|
||||||
|
let root = Element::from(&xmltree_root);
|
||||||
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
||||||
parse_common_list_objects_response(&root)?;
|
parse_common_list_objects_response(&root)?;
|
||||||
let marker = url_decode(&encoding_type, root.get_child_text("Marker"))?;
|
let marker = url_decode(&encoding_type, root.get_child_text("Marker"))?;
|
||||||
@ -224,8 +229,11 @@ impl FromS3Response for ListObjectsV1Response {
|
|||||||
}
|
}
|
||||||
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
||||||
|
|
||||||
Ok(ListObjectsV1Response {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers,
|
headers,
|
||||||
|
body,
|
||||||
|
|
||||||
name,
|
name,
|
||||||
encoding_type,
|
encoding_type,
|
||||||
prefix,
|
prefix,
|
||||||
@ -242,8 +250,10 @@ impl FromS3Response for ListObjectsV1Response {
|
|||||||
/// Response of [list_objects_v2()](crate::s3::client::Client::list_objects_v2) S3 API
|
/// Response of [list_objects_v2()](crate::s3::client::Client::list_objects_v2) S3 API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ListObjectsV2Response {
|
pub struct ListObjectsV2Response {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub encoding_type: Option<String>,
|
pub encoding_type: Option<String>,
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
@ -257,19 +267,20 @@ pub struct ListObjectsV2Response {
|
|||||||
pub next_continuation_token: Option<String>,
|
pub next_continuation_token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(ListObjectsV2Response);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for ListObjectsV2Response {
|
impl FromS3Response for ListObjectsV2Response {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
_req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut resp = resp?;
|
let mut resp = response?;
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
let headers: HeaderMap = mem::take(resp.headers_mut());
|
||||||
|
|
||||||
let body = resp.bytes().await?;
|
let body = resp.bytes().await?;
|
||||||
let xmltree_root = xmltree::Element::parse(body.reader())?;
|
|
||||||
let root = Element::from(&xmltree_root);
|
|
||||||
|
|
||||||
|
let xmltree_root = xmltree::Element::parse(body.clone().reader())?;
|
||||||
|
let root = Element::from(&xmltree_root);
|
||||||
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
||||||
parse_common_list_objects_response(&root)?;
|
parse_common_list_objects_response(&root)?;
|
||||||
let key_count = root
|
let key_count = root
|
||||||
@ -283,8 +294,11 @@ impl FromS3Response for ListObjectsV2Response {
|
|||||||
parse_list_objects_contents(&mut contents, &root, "Contents", &encoding_type, false)?;
|
parse_list_objects_contents(&mut contents, &root, "Contents", &encoding_type, false)?;
|
||||||
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
||||||
|
|
||||||
Ok(ListObjectsV2Response {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers,
|
headers,
|
||||||
|
body,
|
||||||
|
|
||||||
name,
|
name,
|
||||||
encoding_type,
|
encoding_type,
|
||||||
prefix,
|
prefix,
|
||||||
@ -303,8 +317,10 @@ impl FromS3Response for ListObjectsV2Response {
|
|||||||
/// Response of [list_object_versions()](crate::s3::client::Client::list_object_versions) S3 API
|
/// Response of [list_object_versions()](crate::s3::client::Client::list_object_versions) S3 API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ListObjectVersionsResponse {
|
pub struct ListObjectVersionsResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub encoding_type: Option<String>,
|
pub encoding_type: Option<String>,
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
@ -318,18 +334,20 @@ pub struct ListObjectVersionsResponse {
|
|||||||
pub next_version_id_marker: Option<String>,
|
pub next_version_id_marker: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(ListObjectVersionsResponse);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromS3Response for ListObjectVersionsResponse {
|
impl FromS3Response for ListObjectVersionsResponse {
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
_req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let resp = resp?;
|
let mut resp = response?;
|
||||||
let headers = resp.headers().clone();
|
let headers: HeaderMap = mem::take(resp.headers_mut());
|
||||||
let body = resp.bytes().await?;
|
let body = resp.bytes().await?;
|
||||||
let xmltree_root = xmltree::Element::parse(body.reader())?;
|
|
||||||
let root = Element::from(&xmltree_root);
|
|
||||||
|
|
||||||
|
let xmltree_root = xmltree::Element::parse(body.clone().reader())?;
|
||||||
|
let root = Element::from(&xmltree_root);
|
||||||
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
let (name, encoding_type, prefix, delimiter, is_truncated, max_keys) =
|
||||||
parse_common_list_objects_response(&root)?;
|
parse_common_list_objects_response(&root)?;
|
||||||
let key_marker = url_decode(&encoding_type, root.get_child_text("KeyMarker"))?;
|
let key_marker = url_decode(&encoding_type, root.get_child_text("KeyMarker"))?;
|
||||||
@ -340,8 +358,11 @@ impl FromS3Response for ListObjectVersionsResponse {
|
|||||||
parse_list_objects_contents(&mut contents, &root, "Version", &encoding_type, true)?;
|
parse_list_objects_contents(&mut contents, &root, "Version", &encoding_type, true)?;
|
||||||
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
parse_list_objects_common_prefixes(&mut contents, &root, &encoding_type)?;
|
||||||
|
|
||||||
Ok(ListObjectVersionsResponse {
|
Ok(Self {
|
||||||
|
request,
|
||||||
headers,
|
headers,
|
||||||
|
body,
|
||||||
|
|
||||||
name,
|
name,
|
||||||
encoding_type,
|
encoding_type,
|
||||||
prefix,
|
prefix,
|
||||||
@ -360,8 +381,10 @@ impl FromS3Response for ListObjectVersionsResponse {
|
|||||||
/// Response of [list_objects()](crate::s3::client::Client::list_objects) API
|
/// Response of [list_objects()](crate::s3::client::Client::list_objects) API
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct ListObjectsResponse {
|
pub struct ListObjectsResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub encoding_type: Option<String>,
|
pub encoding_type: Option<String>,
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
@ -387,10 +410,15 @@ pub struct ListObjectsResponse {
|
|||||||
pub next_version_id_marker: Option<String>,
|
pub next_version_id_marker: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(ListObjectsResponse);
|
||||||
|
|
||||||
impl From<ListObjectVersionsResponse> for ListObjectsResponse {
|
impl From<ListObjectVersionsResponse> for ListObjectsResponse {
|
||||||
fn from(value: ListObjectVersionsResponse) -> Self {
|
fn from(value: ListObjectVersionsResponse) -> Self {
|
||||||
ListObjectsResponse {
|
Self {
|
||||||
|
request: value.request,
|
||||||
headers: value.headers,
|
headers: value.headers,
|
||||||
|
body: value.body,
|
||||||
|
|
||||||
name: value.name,
|
name: value.name,
|
||||||
encoding_type: value.encoding_type,
|
encoding_type: value.encoding_type,
|
||||||
prefix: value.prefix,
|
prefix: value.prefix,
|
||||||
@ -409,8 +437,11 @@ impl From<ListObjectVersionsResponse> for ListObjectsResponse {
|
|||||||
|
|
||||||
impl From<ListObjectsV2Response> for ListObjectsResponse {
|
impl From<ListObjectsV2Response> for ListObjectsResponse {
|
||||||
fn from(value: ListObjectsV2Response) -> Self {
|
fn from(value: ListObjectsV2Response) -> Self {
|
||||||
ListObjectsResponse {
|
Self {
|
||||||
|
request: value.request,
|
||||||
headers: value.headers,
|
headers: value.headers,
|
||||||
|
body: value.body,
|
||||||
|
|
||||||
name: value.name,
|
name: value.name,
|
||||||
encoding_type: value.encoding_type,
|
encoding_type: value.encoding_type,
|
||||||
prefix: value.prefix,
|
prefix: value.prefix,
|
||||||
@ -430,7 +461,10 @@ impl From<ListObjectsV2Response> for ListObjectsResponse {
|
|||||||
impl From<ListObjectsV1Response> for ListObjectsResponse {
|
impl From<ListObjectsV1Response> for ListObjectsResponse {
|
||||||
fn from(value: ListObjectsV1Response) -> Self {
|
fn from(value: ListObjectsV1Response) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
request: value.request,
|
||||||
headers: value.headers,
|
headers: value.headers,
|
||||||
|
body: value.body,
|
||||||
|
|
||||||
name: value.name,
|
name: value.name,
|
||||||
encoding_type: value.encoding_type,
|
encoding_type: value.encoding_type,
|
||||||
prefix: value.prefix,
|
prefix: value.prefix,
|
||||||
|
|||||||
@ -13,28 +13,31 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use crate::impl_has_s3fields;
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, NotificationRecords, S3Request};
|
use crate::s3::types::{FromS3Response, NotificationRecords, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use async_std::stream::Stream;
|
||||||
use futures_util::{Stream, StreamExt, TryStreamExt};
|
use bytes::Bytes;
|
||||||
|
use futures_util::{StreamExt, TryStreamExt};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of
|
/// Response of
|
||||||
/// [listen _bucket_notification()](crate::s3::client::Client::listen_bucket_notification)
|
/// [listen_bucket_notification()](crate::s3::client::Client::listen_bucket_notification)
|
||||||
/// API
|
/// API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ListenBucketNotificationResponse {
|
pub struct ListenBucketNotificationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes, // Note: not used
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_has_s3fields!(ListenBucketNotificationResponse);
|
||||||
|
|
||||||
|
impl HasBucket for ListenBucketNotificationResponse {}
|
||||||
|
impl HasRegion for ListenBucketNotificationResponse {}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl FromS3Response
|
impl FromS3Response
|
||||||
for (
|
for (
|
||||||
@ -43,14 +46,13 @@ impl FromS3Response
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
async fn from_s3response(
|
async fn from_s3response(
|
||||||
req: S3Request,
|
request: S3Request,
|
||||||
resp: Result<reqwest::Response, Error>,
|
response: Result<reqwest::Response, Error>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut resp = resp?;
|
let mut resp = response?;
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
// A simple stateful decoder that buffers bytes and yields complete lines
|
let headers: HeaderMap = mem::take(resp.headers_mut());
|
||||||
let byte_stream = resp.bytes_stream(); // This is a futures::Stream<Item = Result<Bytes, reqwest::Error>>
|
let byte_stream = resp.bytes_stream();
|
||||||
|
|
||||||
let line_stream = Box::pin(async_stream::try_stream! {
|
let line_stream = Box::pin(async_stream::try_stream! {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
@ -94,9 +96,9 @@ impl FromS3Response
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
ListenBucketNotificationResponse {
|
ListenBucketNotificationResponse {
|
||||||
|
request,
|
||||||
headers,
|
headers,
|
||||||
region: req.inner_region,
|
body: Bytes::new(),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
},
|
},
|
||||||
Box::new(line_stream),
|
Box::new(line_stream),
|
||||||
))
|
))
|
||||||
|
|||||||
@ -14,10 +14,11 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request, SseConfig};
|
use crate::s3::types::{FromS3Response, S3Request, SseConfig};
|
||||||
use crate::s3::utils::{get_option_text, get_text, take_bucket};
|
use crate::s3::utils::{get_option_text, get_text};
|
||||||
use async_trait::async_trait;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use bytes::Buf;
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
@ -27,30 +28,21 @@ use xmltree::Element;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketEncryptionResponse {
|
pub struct PutBucketEncryptionResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Server-side encryption configuration.
|
|
||||||
pub config: SseConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketEncryptionResponse);
|
||||||
impl FromS3Response for PutBucketEncryptionResponse {
|
impl_has_s3fields!(PutBucketEncryptionResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
impl HasBucket for PutBucketEncryptionResponse {}
|
||||||
let body = resp.bytes().await?;
|
impl HasRegion for PutBucketEncryptionResponse {}
|
||||||
let mut root = Element::parse(body.reader())?;
|
|
||||||
|
impl PutBucketEncryptionResponse {
|
||||||
|
/// Returns the server-side encryption configuration.
|
||||||
|
pub fn config(&self) -> Result<SseConfig, Error> {
|
||||||
|
let mut root = Element::parse(self.body().clone().reader())?;
|
||||||
|
|
||||||
let rule = root
|
let rule = root
|
||||||
.get_mut_child("Rule")
|
.get_mut_child("Rule")
|
||||||
@ -62,14 +54,9 @@ impl FromS3Response for PutBucketEncryptionResponse {
|
|||||||
"<ApplyServerSideEncryptionByDefault> tag not found",
|
"<ApplyServerSideEncryptionByDefault> tag not found",
|
||||||
)))?;
|
)))?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(SseConfig {
|
||||||
headers,
|
sse_algorithm: get_text(sse_by_default, "SSEAlgorithm")?,
|
||||||
region: req.inner_region,
|
kms_master_key_id: get_option_text(sse_by_default, "KMSMasterKeyID"),
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
config: SseConfig {
|
|
||||||
sse_algorithm: get_text(sse_by_default, "SSEAlgorithm")?,
|
|
||||||
kms_master_key_id: get_option_text(sse_by_default, "KMSMasterKeyID"),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,37 +14,23 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of [put_bucket_lifecycle()](crate::s3::client::Client::put_bucket_lifecycle) API
|
/// Response of [put_bucket_lifecycle()](crate::s3::client::Client::put_bucket_lifecycle) API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketLifecycleResponse {
|
pub struct PutBucketLifecycleResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketLifecycleResponse);
|
||||||
impl FromS3Response for PutBucketLifecycleResponse {
|
impl_has_s3fields!(PutBucketLifecycleResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketLifecycleResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketLifecycleResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,37 +14,23 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of [put_bucket_notification()](crate::s3::client::Client::put_bucket_notification) API
|
/// Response of [put_bucket_notification()](crate::s3::client::Client::put_bucket_notification) API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketNotificationResponse {
|
pub struct PutBucketNotificationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketNotificationResponse);
|
||||||
impl FromS3Response for PutBucketNotificationResponse {
|
impl_has_s3fields!(PutBucketNotificationResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketNotificationResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketNotificationResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,37 +14,23 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of [put_bucket_policy()](crate::s3::client::Client::put_bucket_policy) API
|
/// Response of [put_bucket_policy()](crate::s3::client::Client::put_bucket_policy) API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketPolicyResponse {
|
pub struct PutBucketPolicyResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketPolicyResponse);
|
||||||
impl FromS3Response for PutBucketPolicyResponse {
|
impl_has_s3fields!(PutBucketPolicyResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketPolicyResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketPolicyResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,37 +14,23 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of [put_bucket_replication()](crate::s3::client::Client::put_bucket_replication) API
|
/// Response of [put_bucket_replication()](crate::s3::client::Client::put_bucket_replication) API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketReplicationResponse {
|
pub struct PutBucketReplicationResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketReplicationResponse);
|
||||||
impl FromS3Response for PutBucketReplicationResponse {
|
impl_has_s3fields!(PutBucketReplicationResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketReplicationResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketReplicationResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,9 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -25,28 +26,13 @@ use std::mem;
|
|||||||
/// API
|
/// API
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketTaggingResponse {
|
pub struct PutBucketTaggingResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketTaggingResponse);
|
||||||
impl FromS3Response for PutBucketTaggingResponse {
|
impl_has_s3fields!(PutBucketTaggingResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketTaggingResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketTaggingResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,37 +14,23 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
|
use crate::s3::response::a_response_traits::{HasBucket, HasRegion, HasS3Fields};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::take_bucket;
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// Response of [put_bucket_versioning()](crate::s3::client::Client::put_bucket_versioning) API
|
/// Response of [put_bucket_versioning()](crate::s3::client::Client::put_bucket_versioning) API
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutBucketVersioningResponse {
|
pub struct PutBucketVersioningResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutBucketVersioningResponse);
|
||||||
impl FromS3Response for PutBucketVersioningResponse {
|
impl_has_s3fields!(PutBucketVersioningResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutBucketVersioningResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutBucketVersioningResponse {}
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
|
||||||
// Copyright 2023 MinIO, Inc.
|
// Copyright 2025 MinIO, Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,126 +13,112 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use crate::s3::error::Error;
|
||||||
use bytes::Buf;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasEtagFromHeaders, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
|
use crate::s3::utils::get_text;
|
||||||
|
use crate::{impl_from_s3response, impl_from_s3response_with_size, impl_has_s3fields};
|
||||||
|
use bytes::{Buf, Bytes};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use xmltree::Element;
|
use xmltree::Element;
|
||||||
|
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
// region
|
||||||
use crate::s3::{
|
|
||||||
error::Error,
|
/// Base response struct that contains common functionality for S3 operations
|
||||||
types::{FromS3Response, S3Request},
|
#[derive(Clone, Debug)]
|
||||||
utils::get_text,
|
pub struct S3Response1 {
|
||||||
};
|
pub(crate) request: S3Request,
|
||||||
|
pub(crate) headers: HeaderMap,
|
||||||
|
pub(crate) body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_s3response!(S3Response1);
|
||||||
|
impl_has_s3fields!(S3Response1);
|
||||||
|
|
||||||
|
impl HasBucket for S3Response1 {}
|
||||||
|
impl HasObject for S3Response1 {}
|
||||||
|
impl HasRegion for S3Response1 {}
|
||||||
|
impl HasVersion for S3Response1 {}
|
||||||
|
impl HasEtagFromHeaders for S3Response1 {}
|
||||||
|
|
||||||
|
/// Extended response struct for operations that need additional data like object size
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct S3Response1WithSize {
|
||||||
|
request: S3Request,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
|
||||||
|
/// Additional object size information
|
||||||
|
pub(crate) object_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_s3response_with_size!(S3Response1WithSize);
|
||||||
|
impl_has_s3fields!(S3Response1WithSize);
|
||||||
|
|
||||||
|
impl HasBucket for S3Response1WithSize {}
|
||||||
|
impl HasObject for S3Response1WithSize {}
|
||||||
|
impl HasRegion for S3Response1WithSize {}
|
||||||
|
impl HasVersion for S3Response1WithSize {}
|
||||||
|
impl HasEtagFromHeaders for S3Response1WithSize {}
|
||||||
|
|
||||||
|
impl S3Response1WithSize {
|
||||||
|
pub fn new(response: S3Response1, object_size: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
request: response.request,
|
||||||
|
headers: response.headers,
|
||||||
|
body: response.body,
|
||||||
|
object_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the object size for the response
|
||||||
|
pub fn object_size(&self) -> u64 {
|
||||||
|
self.object_size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extended response struct for multipart operations that need upload_id
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct S3MultipartResponse {
|
||||||
|
request: S3Request,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_s3response!(S3MultipartResponse);
|
||||||
|
impl_has_s3fields!(S3MultipartResponse);
|
||||||
|
|
||||||
|
impl HasBucket for S3MultipartResponse {}
|
||||||
|
impl HasObject for S3MultipartResponse {}
|
||||||
|
impl HasRegion for S3MultipartResponse {}
|
||||||
|
impl HasVersion for S3MultipartResponse {}
|
||||||
|
impl HasEtagFromHeaders for S3MultipartResponse {}
|
||||||
|
|
||||||
|
impl S3MultipartResponse {
|
||||||
|
/// Returns the upload ID for the multipart upload, while consuming the response.
|
||||||
|
pub async fn upload_id(&self) -> Result<String, Error> {
|
||||||
|
let root = Element::parse(self.body.clone().reader())?;
|
||||||
|
get_text(&root, "UploadId").map_err(|e| Error::InvalidUploadId(e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Response of [put_object_api()](crate::s3::client::Client::put_object) API
|
/// Response of [put_object_api()](crate::s3::client::Client::put_object) API
|
||||||
#[derive(Debug, Clone)]
|
pub type PutObjectResponse = S3Response1;
|
||||||
pub struct PutObjectResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
pub bucket: String,
|
|
||||||
pub object: String,
|
|
||||||
pub region: String,
|
|
||||||
pub etag: String,
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl FromS3Response for PutObjectResponse {
|
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
|
|
||||||
let etag: String = headers
|
|
||||||
.get("etag")
|
|
||||||
.and_then(|v| v.to_str().ok()) // Convert to &str safely
|
|
||||||
.map(|s| s.trim_matches('"').to_string()) // Trim and convert to String
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let version_id: Option<String> = headers
|
|
||||||
.get("x-amz-version-id")
|
|
||||||
.and_then(|v| v.to_str().ok().map(String::from));
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
region: req.inner_region,
|
|
||||||
etag,
|
|
||||||
version_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Response of [create_multipart_upload()](crate::s3::client::Client::create_multipart_upload) API
|
/// Response of [create_multipart_upload()](crate::s3::client::Client::create_multipart_upload) API
|
||||||
#[derive(Debug, Clone)]
|
pub type CreateMultipartUploadResponse = S3MultipartResponse;
|
||||||
pub struct CreateMultipartUploadResponse {
|
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
pub region: String,
|
|
||||||
pub bucket: String,
|
|
||||||
pub object: String,
|
|
||||||
pub upload_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl FromS3Response for CreateMultipartUploadResponse {
|
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
let headers: HeaderMap = mem::take(resp.headers_mut());
|
|
||||||
let body = resp.bytes().await?;
|
|
||||||
let root = Element::parse(body.reader())?;
|
|
||||||
let upload_id: String =
|
|
||||||
get_text(&root, "UploadId").map_err(|e| Error::InvalidUploadId(e.to_string()))?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
headers,
|
|
||||||
region: req.inner_region,
|
|
||||||
bucket: take_bucket(req.bucket)?,
|
|
||||||
object: take_object(req.object)?,
|
|
||||||
upload_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Response of [abort_multipart_upload()](crate::s3::client::Client::abort_multipart_upload) API
|
/// Response of [abort_multipart_upload()](crate::s3::client::Client::abort_multipart_upload) API
|
||||||
pub type AbortMultipartUploadResponse = CreateMultipartUploadResponse;
|
pub type AbortMultipartUploadResponse = S3MultipartResponse;
|
||||||
|
|
||||||
/// Response of [complete_multipart_upload()](crate::s3::client::Client::complete_multipart_upload) API
|
/// Response of [complete_multipart_upload()](crate::s3::client::Client::complete_multipart_upload) API
|
||||||
pub type CompleteMultipartUploadResponse = PutObjectResponse;
|
pub type CompleteMultipartUploadResponse = S3Response1;
|
||||||
|
|
||||||
/// Response of [upload_part()](crate::s3::client::Client::upload_part) API
|
/// Response of [upload_part()](crate::s3::client::Client::upload_part) API
|
||||||
pub type UploadPartResponse = PutObjectResponse;
|
pub type UploadPartResponse = S3Response1;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
/// Response for put_object operations that include object size information
|
||||||
pub struct PutObjectContentResponse {
|
pub type PutObjectContentResponse = S3Response1WithSize;
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
|
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (path) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// Size of the object in bytes.
|
|
||||||
pub object_size: u64,
|
|
||||||
|
|
||||||
/// Entity tag representing a specific version of the object.
|
|
||||||
pub etag: String,
|
|
||||||
|
|
||||||
/// Version ID of the object, if versioning is enabled. Value of the `x-amz-version-id` header.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,10 +14,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::s3::error::Error;
|
use crate::s3::error::Error;
|
||||||
use crate::s3::multimap::MultimapExt;
|
use crate::s3::response::a_response_traits::{
|
||||||
|
HasBucket, HasObject, HasRegion, HasS3Fields, HasVersion,
|
||||||
|
};
|
||||||
use crate::s3::types::{FromS3Response, S3Request};
|
use crate::s3::types::{FromS3Response, S3Request};
|
||||||
use crate::s3::utils::{take_bucket, take_object};
|
use crate::{impl_from_s3response, impl_has_s3fields};
|
||||||
use async_trait::async_trait;
|
use bytes::Bytes;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -30,38 +32,15 @@ use std::mem;
|
|||||||
/// For more information, refer to the [AWS S3 PutObjectLegalHold API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLegalHold.html).
|
/// For more information, refer to the [AWS S3 PutObjectLegalHold API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLegalHold.html).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PutObjectLegalHoldResponse {
|
pub struct PutObjectLegalHoldResponse {
|
||||||
/// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc.
|
request: S3Request,
|
||||||
pub headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
|
body: Bytes,
|
||||||
/// The AWS region where the bucket resides.
|
|
||||||
pub region: String,
|
|
||||||
|
|
||||||
/// Name of the bucket containing the object.
|
|
||||||
pub bucket: String,
|
|
||||||
|
|
||||||
/// Key (name) identifying the object within the bucket.
|
|
||||||
pub object: String,
|
|
||||||
|
|
||||||
/// The version ID of the object from which the legal hold was removed.
|
|
||||||
///
|
|
||||||
/// If versioning is not enabled on the bucket, this field may be `None`.
|
|
||||||
pub version_id: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl_from_s3response!(PutObjectLegalHoldResponse);
|
||||||
impl FromS3Response for PutObjectLegalHoldResponse {
|
impl_has_s3fields!(PutObjectLegalHoldResponse);
|
||||||
async fn from_s3response(
|
|
||||||
req: S3Request,
|
|
||||||
resp: Result<reqwest::Response, Error>,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut resp = resp?;
|
|
||||||
|
|
||||||
Ok(Self {
|
impl HasBucket for PutObjectLegalHoldResponse {}
|
||||||
headers: mem::take(resp.headers_mut()),
|
impl HasRegion for PutObjectLegalHoldResponse {}
|
||||||
region: req.inner_region,
|
impl HasObject for PutObjectLegalHoldResponse {}
|
||||||
bucket: take_bucket(req.bucket)?,
|
impl HasVersion for PutObjectLegalHoldResponse {}
|
||||||
object: take_object(req.object)?,
|
|
||||||
version_id: req.query_params.take_version(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user