diff --git a/Cargo.toml b/Cargo.toml index 1f6a93b..b607653 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "minio" -version = "0.2.0" +version = "0.3.0" edition = "2024" authors = ["MinIO Dev Team "] description = "MinIO SDK for Amazon S3 compatible object storage access" @@ -11,7 +11,7 @@ keywords = ["object-storage", "minio", "s3"] categories = ["api-bindings", "web-programming::http-client"] [dependencies.reqwest] -version = "0.12.9" +version = "0.12.18" default-features = false features = ["stream"] @@ -28,11 +28,11 @@ async-trait = "0.1.88" base64 = "0.22.1" byteorder = "1.5.0" bytes = "1.10.1" -chrono = "0.4.40" -crc = "3.2.1" +chrono = "0.4.41" +crc = "3.3.0" dashmap = "6.1.0" derivative = "2.2.0" -env_logger = "0.11.7" +env_logger = "0.11.8" futures-util = "0.3.31" hex = "0.4.3" hmac = { version = "0.12.1", optional = true } @@ -40,7 +40,7 @@ hyper = { version = "1.6.0", features = ["full"] } lazy_static = "1.5.0" log = "0.4.27" md5 = "0.7.0" -multimap = "0.10.0" +multimap = "0.10.1" percent-encoding = "2.3.1" rand = { version = "0.8.5", features = ["small_rng"] } regex = "1.11.1" @@ -48,9 +48,9 @@ ring = { version = "0.17.14", optional = true, default-features = false, feature serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" sha2 = { version = "0.10.8", optional = true } -tokio = { version = "1.44.2", features = ["full"] } +tokio = { version = "1.45.1", features = ["full"] } tokio-stream = "0.1.17" -tokio-util = { version = "0.7.14", features = ["io"] } +tokio-util = { version = "0.7.15", features = ["io"] } urlencoding = "2.1.3" xmltree = "0.11.0" futures = "0.3.31" @@ -59,9 +59,9 @@ http = "1.3.1" [dev-dependencies] minio_common = { path = "./common" } async-std = { version = "1.13.1", features = ["attributes", "tokio1"] } -clap = { version = "4.5.35", features = ["derive"] } +clap = { version = "4.5.39", features = ["derive"] } quickcheck = "1.0.3" -criterion = "0.5.1" +criterion = "0.6.0" [lib] name = "minio" diff --git a/README.md b/README.md index 7ba3f9c..21fce30 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -# MinIO Rust SDK for Amazon S3 Compatible Cloud Storage [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io) [![Sourcegraph](https://sourcegraph.com/github.com/minio/minio-rs/-/badge.svg)](https://sourcegraph.com/github.com/minio/minio-rs?badge) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/minio/minio-rs/blob/master/LICENSE) +# MinIO Rust SDK for Amazon S3 Compatible Cloud Storage + +[![CI](https://github.com/minio/minio-rs/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/minio/minio-rs/actions/workflows/rust.yml) +[![docs.rs](https://docs.rs/minio/badge.svg)](https://docs.rs/minio/latest/minio/) +[![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io) +[![Sourcegraph](https://sourcegraph.com/github.com/minio/minio-rs/-/badge.svg)](https://sourcegraph.com/github.com/minio/minio-rs?badge) +[![crates.io](https://img.shields.io/crates/v/minio)](https://crates.io/crates/minio) +[![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/minio/minio-rs/blob/master/LICENSE) The MinIO Rust SDK is a Simple Storage Service (aka S3) client for performing bucket and object operations to any Amazon S3 compatible object storage service. It provides a strongly-typed, async-first interface to the MinIO and Amazon S3-compatible object storage APIs. diff --git a/src/lib.rs b/src/lib.rs index 39e92c7..84ff667 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,10 +17,10 @@ //! //! This crate provides a strongly-typed, async-first interface to the MinIO and Amazon S3-compatible object storage APIs. //! -//! Each supported S3 operation has a corresponding request builder (e.g., [`BucketExists`], [`PutObject`], [`UploadPartCopy`]), +//! Each supported S3 operation has a corresponding request builder (e.g., [`s3::builders::BucketExists`], [`s3::builders::PutObject`], [`s3::builders::UploadPartCopy`]), //! which allows users to configure request parameters using a fluent builder pattern. //! -//! All request builders implement the [`S3Api`] trait, which provides the async [`send`](crate::s3::types::S3Api::send) method +//! All request builders implement the [`s3::types::S3Api`] trait, which provides the async [`send`](crate::s3::types::S3Api::send) method //! to execute the request and return a typed response. //! //! ## Basic Usage @@ -51,9 +51,9 @@ //! - Transparent error handling via `Result` //! //! ## Design -//! - Each API method on the [`Client`] returns a builder struct -//! - Builders implement [`ToS3Request`] for request conversion and [`S3Api`] for execution -//! - Responses implement [`FromS3Response`] for consistent deserialization +//! - Each API method on the [`s3::client::Client`] returns a builder struct +//! - Builders implement [`s3::types::ToS3Request`] for request conversion and [`s3::types::S3Api`] for execution +//! - Responses implement [`s3::types::FromS3Response`] for consistent deserialization #![allow(clippy::result_large_err)] #![allow(clippy::too_many_arguments)] diff --git a/src/s3/builders/append_object.rs b/src/s3/builders/append_object.rs index 2096794..cebbc13 100644 --- a/src/s3/builders/append_object.rs +++ b/src/s3/builders/append_object.rs @@ -174,6 +174,7 @@ impl AppendObjectContent { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/bucket_common.rs b/src/s3/builders/bucket_common.rs index 50f9c41..95af12d 100644 --- a/src/s3/builders/bucket_common.rs +++ b/src/s3/builders/bucket_common.rs @@ -18,6 +18,9 @@ use std::marker::PhantomData; use crate::s3::client::Client; use crate::s3::multimap::Multimap; +/// Common parameters for bucket operations +/// +/// See [Amazon S3 Buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) for more information. #[derive(Clone, Debug, Default)] pub struct BucketCommon { pub(crate) client: Client, @@ -39,16 +42,19 @@ impl BucketCommon { } } + /// Sets extra headers for the request pub fn extra_headers(mut self, extra_headers: Option) -> Self { self.extra_headers = extra_headers; self } + /// Sets extra query parameters for the request pub fn extra_query_params(mut self, extra_query_params: Option) -> Self { self.extra_query_params = extra_query_params; self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/bucket_exists.rs b/src/s3/builders/bucket_exists.rs index 27e070d..d15732f 100644 --- a/src/s3/builders/bucket_exists.rs +++ b/src/s3/builders/bucket_exists.rs @@ -21,8 +21,12 @@ use crate::s3::utils::check_bucket_name; use http::Method; /// This struct constructs the parameters required for the [`Client::bucket_exists`](crate::s3::client::Client::bucket_exists) method. +/// +/// See [Amazon S3: Working with Buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) +/// for more information about checking if a bucket exists. pub type BucketExists = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct BucketExistsPhantomData; diff --git a/src/s3/builders/copy_object.rs b/src/s3/builders/copy_object.rs index 4896e37..e2cec60 100644 --- a/src/s3/builders/copy_object.rs +++ b/src/s3/builders/copy_object.rs @@ -70,6 +70,7 @@ impl UploadPartCopy { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -165,6 +166,7 @@ impl CopyObjectInternal { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -326,7 +328,9 @@ impl ToS3Request for CopyObjectInternal { } } -/// Argument builder for [copy_object()](Client::copy_object) API +/// Argument builder for [`CopyObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) S3 API operation. +/// +/// This struct constructs the parameters required for the [`Client::copy_object`](crate::s3::client::Client::copy_object) method. #[derive(Clone, Debug, Default)] pub struct CopyObject { client: Client, @@ -368,6 +372,7 @@ impl CopyObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -572,6 +577,7 @@ impl ComposeObjectInternal { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -804,6 +810,10 @@ impl ComposeObjectInternal { } } +/// Argument builder for [`CopyObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) S3 API operation. +/// +/// See [Amazon S3 Multipart Upload](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html) +/// This struct constructs the parameters required for the [`Client::copy_object`](crate::s3::client::Client::copy_object) method. #[derive(Clone, Debug, Default)] pub struct ComposeObject { client: Client, @@ -843,6 +853,7 @@ impl ComposeObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/create_bucket.rs b/src/s3/builders/create_bucket.rs index a6b0125..ee76a91 100644 --- a/src/s3/builders/create_bucket.rs +++ b/src/s3/builders/create_bucket.rs @@ -57,6 +57,7 @@ impl CreateBucket { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/delete_bucket.rs b/src/s3/builders/delete_bucket.rs index 21e9986..d5b48c6 100644 --- a/src/s3/builders/delete_bucket.rs +++ b/src/s3/builders/delete_bucket.rs @@ -20,11 +20,13 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::utils::check_bucket_name; use http::Method; -/// Argument builder for the [`GetBucketEncryption`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html) S3 API operation. +/// Argument builder for the [`DeleteBucket`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html) S3 API operation. /// /// This struct constructs the parameters required for the [`Client::delete_bucket`](crate::s3::client::Client::delete_bucket) method. +/// See [Amazon S3: Deleting Buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html) for more information. pub type DeleteBucket = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketPhantomData; diff --git a/src/s3/builders/delete_bucket_encryption.rs b/src/s3/builders/delete_bucket_encryption.rs index 5dc921b..4a64153 100644 --- a/src/s3/builders/delete_bucket_encryption.rs +++ b/src/s3/builders/delete_bucket_encryption.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_bucket_encryption`](crate::s3::client::Client::delete_bucket_encryption) method. pub type DeleteBucketEncryption = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketEncryptionPhantomData; diff --git a/src/s3/builders/delete_bucket_lifecycle.rs b/src/s3/builders/delete_bucket_lifecycle.rs index c8eb148..da851b6 100644 --- a/src/s3/builders/delete_bucket_lifecycle.rs +++ b/src/s3/builders/delete_bucket_lifecycle.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_bucket_lifecycle`](crate::s3::client::Client::delete_bucket_lifecycle) method. pub type DeleteBucketLifecycle = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketLifecyclePhantomData; diff --git a/src/s3/builders/delete_bucket_notification.rs b/src/s3/builders/delete_bucket_notification.rs index ddfcef4..2151b1c 100644 --- a/src/s3/builders/delete_bucket_notification.rs +++ b/src/s3/builders/delete_bucket_notification.rs @@ -22,9 +22,14 @@ use crate::s3::utils::{check_bucket_name, insert}; use bytes::Bytes; use http::Method; +/// Argument builder for the [`DeleteBucketNotification`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotificationConfiguration.html) S3 API operation. +/// Note: on Amazon S3, a bucket notification is deleted by setting its configuration to empty. +/// /// This struct constructs the parameters required for the [`Client::delete_bucket_notification`](crate::s3::client::Client::delete_bucket_notification) method. +/// See [Amazon S3: Managing Bucket Notifications](https://docs.aws.amazon.com/AmazonS3/latest/userguide/NotificationHowTo.html) for more information. pub type DeleteBucketNotification = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketNotificationPhantomData; diff --git a/src/s3/builders/delete_bucket_policy.rs b/src/s3/builders/delete_bucket_policy.rs index 3a400fb..7491070 100644 --- a/src/s3/builders/delete_bucket_policy.rs +++ b/src/s3/builders/delete_bucket_policy.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_bucket_policy`](crate::s3::client::Client::delete_bucket_policy) method. pub type DeleteBucketPolicy = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketPolicyPhantomData; diff --git a/src/s3/builders/delete_bucket_replication.rs b/src/s3/builders/delete_bucket_replication.rs index ae9a5e6..59a3849 100644 --- a/src/s3/builders/delete_bucket_replication.rs +++ b/src/s3/builders/delete_bucket_replication.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_bucket_replication`](crate::s3::client::Client::delete_bucket_replication) method. pub type DeleteBucketReplication = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketReplicationPhantomData; diff --git a/src/s3/builders/delete_bucket_tagging.rs b/src/s3/builders/delete_bucket_tagging.rs index cc375bb..81fa066 100644 --- a/src/s3/builders/delete_bucket_tagging.rs +++ b/src/s3/builders/delete_bucket_tagging.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_bucket_tags`](crate::s3::client::Client::delete_bucket_tagging) method. pub type DeleteBucketTagging = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteBucketTaggingPhantomData; diff --git a/src/s3/builders/delete_object_lock_config.rs b/src/s3/builders/delete_object_lock_config.rs index ad47022..077145f 100644 --- a/src/s3/builders/delete_object_lock_config.rs +++ b/src/s3/builders/delete_object_lock_config.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::delete_object_lock_config`](crate::s3::client::Client::delete_object_lock_config) method. pub type DeleteObjectLockConfig = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct DeleteObjectLockConfigPhantomData; diff --git a/src/s3/builders/delete_object_tagging.rs b/src/s3/builders/delete_object_tagging.rs index e6f39ef..1fe0471 100644 --- a/src/s3/builders/delete_object_tagging.rs +++ b/src/s3/builders/delete_object_tagging.rs @@ -57,6 +57,7 @@ impl DeleteObjectTagging { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/delete_objects.rs b/src/s3/builders/delete_objects.rs index 027084f..434595b 100644 --- a/src/s3/builders/delete_objects.rs +++ b/src/s3/builders/delete_objects.rs @@ -31,7 +31,7 @@ use crate::s3::utils::{check_object_name, insert}; use crate::s3::{ Client, error::Error, - response::{RemoveObjectResponse, RemoveObjectsResponse}, + response::{DeleteObjectResponse, DeleteObjectsResponse}, types::{S3Api, S3Request, ToS3Request, ToStream}, utils::{check_bucket_name, md5sum_hash}, }; @@ -101,10 +101,13 @@ impl From for ObjectToDelete { // endregion: object-to-delete -// region: remove-object +// region: delete-object +/// Argument builder for the [`RemoveObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html) S3 API operation. +/// +/// This struct constructs the parameters required for the [`Client::remove_object`](crate::s3::client::Client::delete_object) method. #[derive(Debug, Clone, Default)] -pub struct RemoveObject { +pub struct DeleteObject { client: Client, extra_headers: Option, @@ -116,7 +119,7 @@ pub struct RemoveObject { bypass_governance_mode: bool, } -impl RemoveObject { +impl DeleteObject { pub fn new(client: Client, bucket: String, object: impl Into) -> Self { Self { client, @@ -141,17 +144,18 @@ impl RemoveObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self } } -impl S3Api for RemoveObject { - type S3Response = RemoveObjectResponse; +impl S3Api for DeleteObject { + type S3Response = DeleteObjectResponse; } -impl ToS3Request for RemoveObject { +impl ToS3Request for DeleteObject { fn to_s3request(self) -> Result { check_bucket_name(&self.bucket, true)?; check_object_name(&self.object.key)?; @@ -159,20 +163,25 @@ impl ToS3Request for RemoveObject { let mut query_params: Multimap = self.extra_query_params.unwrap_or_default(); query_params.add_version(self.object.version_id); + let mut headers: Multimap = self.extra_headers.unwrap_or_default(); + if self.bypass_governance_mode { + headers.add("x-amz-bypass-governance-retention", "true"); + } + Ok(S3Request::new(self.client, Method::DELETE) .region(self.region) .bucket(Some(self.bucket)) .object(Some(self.object.key)) .query_params(query_params) - .headers(self.extra_headers.unwrap_or_default())) + .headers(headers)) } } -// endregion: remove-object +// endregion: delete-object -// region: remove-object-api +// region: delete-objects #[derive(Debug, Clone, Default)] -pub struct RemoveObjectsApi { +pub struct DeleteObjects { client: Client, bucket: String, @@ -186,10 +195,9 @@ pub struct RemoveObjectsApi { region: Option, } -impl RemoveObjectsApi { - #[inline] +impl DeleteObjects { pub fn new(client: Client, bucket: String, objects: Vec) -> Self { - RemoveObjectsApi { + DeleteObjects { client, bucket, objects, @@ -220,17 +228,18 @@ impl RemoveObjectsApi { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self } } -impl S3Api for RemoveObjectsApi { - type S3Response = RemoveObjectsResponse; +impl S3Api for DeleteObjects { + type S3Response = DeleteObjectsResponse; } -impl ToS3Request for RemoveObjectsApi { +impl ToS3Request for DeleteObjects { fn to_s3request(self) -> Result { check_bucket_name(&self.bucket, true)?; @@ -271,30 +280,27 @@ impl ToS3Request for RemoveObjectsApi { } } -// endregion: remove-object-api +// endregion: delete-objects -// region: delete-objects +// region: object-stream -/// Argument builder for the [`DeleteObjects`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) S3 API operation. -/// -/// This struct constructs the parameters required for the [`Client::delete`](crate::s3::client::Client::get_bucket_encryption) method. -pub struct DeleteObjects { +pub struct ObjectsStream { items: Pin + Send + Sync>>, } -impl DeleteObjects { +impl ObjectsStream { pub fn from_stream(s: impl Stream + Send + Sync + 'static) -> Self { Self { items: Box::pin(s) } } } -impl From for DeleteObjects { +impl From for ObjectsStream { fn from(delete_object: ObjectToDelete) -> Self { Self::from_stream(stream_iter(std::iter::once(delete_object))) } } -impl From for DeleteObjects +impl From for ObjectsStream where I: Iterator + Send + Sync + 'static, { @@ -303,15 +309,19 @@ where } } -// endregion: delete-objects +// endregion: object-stream -// region: remove-objects +// region: delete-objects-streaming -pub struct RemoveObjects { +/// Argument builder for the [`DeleteObjectsStreaming`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) S3 API operation. +/// Note that this API is not part of the official S3 API, but is a MinIO extension for streaming deletion of multiple objects. +/// +/// This struct constructs the parameters required for the [`Client::`](crate::s3::client::Client::get_bucket_encryption) method. +pub struct DeleteObjectsStreaming { client: Client, bucket: String, - objects: DeleteObjects, + objects: ObjectsStream, bypass_governance_mode: bool, verbose_mode: bool, @@ -321,8 +331,8 @@ pub struct RemoveObjects { region: Option, } -impl RemoveObjects { - pub fn new(client: Client, bucket: String, objects: impl Into) -> Self { +impl DeleteObjectsStreaming { + pub fn new(client: Client, bucket: String, objects: impl Into) -> Self { Self { client, bucket, @@ -360,12 +370,13 @@ impl RemoveObjects { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self } - async fn next_request(&mut self) -> Result, Error> { + async fn next_request(&mut self) -> Result, Error> { let mut objects = Vec::new(); while let Some(object) = self.objects.items.next().await { objects.push(object); @@ -378,7 +389,7 @@ impl RemoveObjects { } Ok(Some( - RemoveObjectsApi::new(self.client.clone(), self.bucket.clone(), objects) + DeleteObjects::new(self.client.clone(), self.bucket.clone(), objects) .bypass_governance_mode(self.bypass_governance_mode) .verbose_mode(self.verbose_mode) .extra_headers(self.extra_headers.clone()) @@ -389,8 +400,8 @@ impl RemoveObjects { } #[async_trait] -impl ToStream for RemoveObjects { - type Item = RemoveObjectsResponse; +impl ToStream for DeleteObjectsStreaming { + type Item = DeleteObjectsResponse; async fn to_stream( mut self, @@ -411,4 +422,4 @@ impl ToStream for RemoveObjects { } } -// endregion: remove-objects +// endregion: delete-objects-streaming diff --git a/src/s3/builders/get_bucket_encryption.rs b/src/s3/builders/get_bucket_encryption.rs index 199bffa..44ef149 100644 --- a/src/s3/builders/get_bucket_encryption.rs +++ b/src/s3/builders/get_bucket_encryption.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_bucket_encryption`](crate::s3::client::Client::get_bucket_encryption) method. pub type GetBucketEncryption = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct GetBucketEncryptionPhantomData; diff --git a/src/s3/builders/get_bucket_notification.rs b/src/s3/builders/get_bucket_notification.rs index 4ba959d..f77a3da 100644 --- a/src/s3/builders/get_bucket_notification.rs +++ b/src/s3/builders/get_bucket_notification.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_bucket_notification`](crate::s3::client::Client::get_bucket_notification) method. pub type GetBucketNotification = BucketCommon; +#[doc(hidden)] #[derive(Default, Debug)] pub struct GetBucketNotificationPhantomData; diff --git a/src/s3/builders/get_bucket_policy.rs b/src/s3/builders/get_bucket_policy.rs index 0185fb9..f5f2323 100644 --- a/src/s3/builders/get_bucket_policy.rs +++ b/src/s3/builders/get_bucket_policy.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_bucket_policy`](crate::s3::client::Client::get_bucket_policy) method. pub type GetBucketPolicy = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct GetBucketPolicyPhantomData; diff --git a/src/s3/builders/get_bucket_replication.rs b/src/s3/builders/get_bucket_replication.rs index 551b594..97834d6 100644 --- a/src/s3/builders/get_bucket_replication.rs +++ b/src/s3/builders/get_bucket_replication.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_bucket_replication`](crate::s3::client::Client::get_bucket_replication) method. pub type GetBucketReplication = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct GetBucketReplicationPhantomData; diff --git a/src/s3/builders/get_bucket_tagging.rs b/src/s3/builders/get_bucket_tagging.rs index 3fb513a..49eb663 100644 --- a/src/s3/builders/get_bucket_tagging.rs +++ b/src/s3/builders/get_bucket_tagging.rs @@ -56,6 +56,7 @@ impl GetBucketTagging { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/get_bucket_versioning.rs b/src/s3/builders/get_bucket_versioning.rs index 1e771b1..54b8087 100644 --- a/src/s3/builders/get_bucket_versioning.rs +++ b/src/s3/builders/get_bucket_versioning.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_bucket_versioning`](crate::s3::client::Client::get_bucket_versioning) method. pub type GetBucketVersioning = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct GetBucketVersioningPhantomData; diff --git a/src/s3/builders/get_object.rs b/src/s3/builders/get_object.rs index 32a6375..a64e22a 100644 --- a/src/s3/builders/get_object.rs +++ b/src/s3/builders/get_object.rs @@ -85,6 +85,7 @@ impl GetObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/get_object_lock_config.rs b/src/s3/builders/get_object_lock_config.rs index 3095cf6..1d98cd8 100644 --- a/src/s3/builders/get_object_lock_config.rs +++ b/src/s3/builders/get_object_lock_config.rs @@ -25,6 +25,7 @@ use http::Method; /// This struct constructs the parameters required for the [`Client::get_object_lock_config`](crate::s3::client::Client::get_object_lock_config) method. pub type GetObjectLockConfig = BucketCommon; +#[doc(hidden)] #[derive(Clone, Debug, Default)] pub struct GetObjectLockConfigPhantomData; diff --git a/src/s3/builders/get_object_prompt.rs b/src/s3/builders/get_object_prompt.rs index 79ee312..5a1bf4e 100644 --- a/src/s3/builders/get_object_prompt.rs +++ b/src/s3/builders/get_object_prompt.rs @@ -27,6 +27,9 @@ use bytes::Bytes; use http::Method; use serde_json::json; +/// Argument builder for the `GetObjectPrompt` operation. +/// +/// This struct constructs the parameters required for the [`Client::get_object_prompt`](crate::s3::client::Client::get_object_prompt) method. #[derive(Debug, Clone, Default)] pub struct GetObjectPrompt { client: Client, @@ -74,6 +77,7 @@ impl GetObjectPrompt { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/get_object_retention.rs b/src/s3/builders/get_object_retention.rs index f2c7b37..c6df748 100644 --- a/src/s3/builders/get_object_retention.rs +++ b/src/s3/builders/get_object_retention.rs @@ -57,6 +57,7 @@ impl GetObjectRetention { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/get_object_tagging.rs b/src/s3/builders/get_object_tagging.rs index d283524..f866d77 100644 --- a/src/s3/builders/get_object_tagging.rs +++ b/src/s3/builders/get_object_tagging.rs @@ -21,7 +21,9 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use http::Method; -/// Argument builder for [get_object_tags()](crate::s3::client::Client::get_object_tagging) API +/// Argument builder for the [`GetObjectTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html) S3 API operation. +/// +/// This struct constructs the parameters required for the [`Client::get_object_tagging`](crate::s3::client::Client::get_object_tagging) method. #[derive(Clone, Debug, Default)] pub struct GetObjectTagging { client: Client, @@ -55,6 +57,7 @@ impl GetObjectTagging { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/get_presigned_object_url.rs b/src/s3/builders/get_presigned_object_url.rs index 7978a5b..a600934 100644 --- a/src/s3/builders/get_presigned_object_url.rs +++ b/src/s3/builders/get_presigned_object_url.rs @@ -14,7 +14,6 @@ // limitations under the License. use crate::s3::Client; -use crate::s3::client::DEFAULT_EXPIRY_SECONDS; use crate::s3::creds::Credentials; use crate::s3::error::Error; use crate::s3::multimap::{Multimap, MultimapExt}; @@ -23,6 +22,9 @@ use crate::s3::signer::presign_v4; use crate::s3::utils::{UtcTime, check_bucket_name, check_object_name, utc_now}; use http::Method; +/// The default expiry time in seconds for a [`GetPresignedObjectUrl`]. +pub const DEFAULT_EXPIRY_SECONDS: u32 = 604_800; // 7 days + /// This struct constructs the parameters required for the [`Client::get_presigned_object_url`](crate::s3::client::Client::get_presigned_object_url) method. #[derive(Clone, Debug, Default)] pub struct GetPresignedObjectUrl { @@ -35,6 +37,7 @@ pub struct GetPresignedObjectUrl { object: String, version_id: Option, method: Method, + expiry_seconds: Option, request_time: Option, } @@ -51,8 +54,21 @@ impl GetPresignedObjectUrl { } } + /// Sets the expiry time for the presigned URL, defaulting to 7 days if not specified. + pub fn expiry_seconds(mut self, seconds: u32) -> Self { + self.expiry_seconds = Some(seconds); + self + } + + /// Sets the request time for the presigned URL, defaulting to the current time if not specified. + pub fn request_time(mut self, time: UtcTime) -> Self { + self.request_time = Some(time); + self + } + + /// Sends the request to generate a presigned URL for an S3 object. pub async fn send(self) -> Result { - // NOTE: this send function is async to be comparable with other functions... + // NOTE: this send function is async and because of that, not comparable with other send functions... check_bucket_name(&self.bucket, true)?; check_object_name(&self.object)?; diff --git a/src/s3/builders/get_region.rs b/src/s3/builders/get_region.rs index b7589cb..96e373d 100644 --- a/src/s3/builders/get_region.rs +++ b/src/s3/builders/get_region.rs @@ -22,6 +22,8 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::utils::{check_bucket_name, insert}; use http::Method; +/// Argument builder for the [`GetRegion`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html) S3 API operation. +/// /// This struct constructs the parameters required for the [`Client::get_region`](crate::s3::client::Client::get_region) method. #[derive(Clone, Debug, Default)] pub struct GetRegion { @@ -52,6 +54,7 @@ impl GetRegion { } } +#[doc(hidden)] #[derive(Default, Debug)] pub struct GetRegionPhantomData; diff --git a/src/s3/builders/list_objects.rs b/src/s3/builders/list_objects.rs index e93267a..3542fe3 100644 --- a/src/s3/builders/list_objects.rs +++ b/src/s3/builders/list_objects.rs @@ -469,6 +469,7 @@ impl ListObjects { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/listen_bucket_notification.rs b/src/s3/builders/listen_bucket_notification.rs index 5ba7647..117d3d9 100644 --- a/src/s3/builders/listen_bucket_notification.rs +++ b/src/s3/builders/listen_bucket_notification.rs @@ -61,6 +61,7 @@ impl ListenBucketNotification { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_encryption.rs b/src/s3/builders/put_bucket_encryption.rs index 0390853..982f5a5 100644 --- a/src/s3/builders/put_bucket_encryption.rs +++ b/src/s3/builders/put_bucket_encryption.rs @@ -23,7 +23,9 @@ use crate::s3::utils::{check_bucket_name, insert}; use bytes::Bytes; use http::Method; -/// Argument builder for [put_bucket_encryption()](crate::s3::client::Client::put_bucket_encryption) API +/// Argument builder for the [`PutBucketEncryption`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html) S3 API operation. +/// +/// This struct constructs the parameters required for the [`Client::put_bucket_encryption`](crate::s3::client::Client::put_bucket_encryption) method. #[derive(Clone, Debug, Default)] pub struct PutBucketEncryption { client: Client, @@ -55,11 +57,13 @@ impl PutBucketEncryption { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self } + /// Sets the server-side encryption configuration for the bucket. pub fn sse_config(mut self, config: SseConfig) -> Self { self.config = config; self diff --git a/src/s3/builders/put_bucket_lifecycle.rs b/src/s3/builders/put_bucket_lifecycle.rs index 8ba124c..8caa934 100644 --- a/src/s3/builders/put_bucket_lifecycle.rs +++ b/src/s3/builders/put_bucket_lifecycle.rs @@ -58,6 +58,7 @@ impl PutBucketLifecycle { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_notification.rs b/src/s3/builders/put_bucket_notification.rs index 3654175..1458778 100644 --- a/src/s3/builders/put_bucket_notification.rs +++ b/src/s3/builders/put_bucket_notification.rs @@ -57,6 +57,7 @@ impl PutBucketNotification { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_policy.rs b/src/s3/builders/put_bucket_policy.rs index c047abe..7f0695e 100644 --- a/src/s3/builders/put_bucket_policy.rs +++ b/src/s3/builders/put_bucket_policy.rs @@ -57,6 +57,7 @@ impl PutBucketPolicy { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_replication.rs b/src/s3/builders/put_bucket_replication.rs index 0ba0bda..ce737eb 100644 --- a/src/s3/builders/put_bucket_replication.rs +++ b/src/s3/builders/put_bucket_replication.rs @@ -57,6 +57,7 @@ impl PutBucketReplication { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_tagging.rs b/src/s3/builders/put_bucket_tagging.rs index 00d8849..9eafba8 100644 --- a/src/s3/builders/put_bucket_tagging.rs +++ b/src/s3/builders/put_bucket_tagging.rs @@ -58,6 +58,7 @@ impl PutBucketTagging { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_bucket_versioning.rs b/src/s3/builders/put_bucket_versioning.rs index 83376b0..b4ac168 100644 --- a/src/s3/builders/put_bucket_versioning.rs +++ b/src/s3/builders/put_bucket_versioning.rs @@ -104,6 +104,7 @@ impl PutBucketVersioning { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_object.rs b/src/s3/builders/put_object.rs index 8a51d7c..ede2ee4 100644 --- a/src/s3/builders/put_object.rs +++ b/src/s3/builders/put_object.rs @@ -76,6 +76,7 @@ impl CreateMultipartUpload { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -181,6 +182,7 @@ impl AbortMultipartUpload { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -261,6 +263,7 @@ impl CompleteMultipartUpload { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -373,6 +376,7 @@ impl UploadPart { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -481,6 +485,7 @@ impl PutObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.0.region = region; self @@ -581,6 +586,7 @@ impl PutObjectContent { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_object_lock_config.rs b/src/s3/builders/put_object_lock_config.rs index 4b80116..d823258 100644 --- a/src/s3/builders/put_object_lock_config.rs +++ b/src/s3/builders/put_object_lock_config.rs @@ -57,6 +57,7 @@ impl PutObjectLockConfig { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_object_retention.rs b/src/s3/builders/put_object_retention.rs index 434fd54..f24e733 100644 --- a/src/s3/builders/put_object_retention.rs +++ b/src/s3/builders/put_object_retention.rs @@ -64,6 +64,7 @@ impl PutObjectRetention { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/put_object_tagging.rs b/src/s3/builders/put_object_tagging.rs index 2c9aec4..83fae15 100644 --- a/src/s3/builders/put_object_tagging.rs +++ b/src/s3/builders/put_object_tagging.rs @@ -24,7 +24,9 @@ use bytes::Bytes; use http::Method; use std::collections::HashMap; -/// Argument builder for [put_object_tagging()](crate::s3::client::Client::put_object_tagging) API +/// Argument builder for the [`PutObjectTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html) S3 API operation. +/// +/// This struct constructs the parameters required for the [`Client::put_object_tagging`](crate::s3::client::Client::put_object_tagging) method. #[derive(Clone, Debug, Default)] pub struct PutObjectTagging { client: Client, @@ -59,6 +61,7 @@ impl PutObjectTagging { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/select_object_content.rs b/src/s3/builders/select_object_content.rs index 90f8111..d94f539 100644 --- a/src/s3/builders/select_object_content.rs +++ b/src/s3/builders/select_object_content.rs @@ -63,6 +63,7 @@ impl SelectObjectContent { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/builders/stat_object.rs b/src/s3/builders/stat_object.rs index fde1834..da33950 100644 --- a/src/s3/builders/stat_object.rs +++ b/src/s3/builders/stat_object.rs @@ -27,6 +27,9 @@ use crate::s3::{ utils::{UtcTime, check_bucket_name, to_http_header_value}, }; +/// Argument builder for the [`StatObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) S3 API operation. +/// Retrieves all of the metadata from an object without returning the object itself. +/// /// This struct constructs the parameters required for the [`Client::stat_object`](crate::s3::client::Client::stat_object) method. #[derive(Debug, Clone, Default)] pub struct StatObject { @@ -84,6 +87,7 @@ impl StatObject { self } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self diff --git a/src/s3/client.rs b/src/s3/client.rs index aa09ba9..a1f3801 100644 --- a/src/s3/client.rs +++ b/src/s3/client.rs @@ -90,12 +90,34 @@ mod stat_object; use super::types::S3Api; +/// The default AWS region to be used if no other region is specified. pub const DEFAULT_REGION: &str = "us-east-1"; + +/// Minimum allowed size (in bytes) for a multipart upload part (except the last). +/// +/// Used in multipart uploads to ensure each part (except the final one) +/// meets the required minimum size for transfer or storage. pub const MIN_PART_SIZE: u64 = 5_242_880; // 5 MiB + +/// Maximum allowed size (in bytes) for a single multipart upload part. +/// +/// In multipart uploads, no part can exceed this size limit. +/// This constraint ensures compatibility with services that enforce +/// a 5 GiB maximum per part. pub const MAX_PART_SIZE: u64 = 5_368_709_120; // 5 GiB + +/// Maximum allowed size (in bytes) for a single object upload. +/// +/// This is the upper limit for the total size of an object stored using +/// multipart uploads. It applies to the combined size of all parts, +/// ensuring the object does not exceed 5 TiB. pub const MAX_OBJECT_SIZE: u64 = 5_497_558_138_880; // 5 TiB + +/// Maximum number of parts allowed in a multipart upload. +/// +/// Multipart uploads are limited to a total of 10,000 parts. If the object +/// exceeds this count, each part must be larger to remain within the limit. pub const MAX_MULTIPART_COUNT: u16 = 10_000; -pub const DEFAULT_EXPIRY_SECONDS: u32 = 604_800; // 7 days /// Client Builder manufactures a Client using given parameters. #[derive(Debug, Default)] diff --git a/src/s3/client/append_object.rs b/src/s3/client/append_object.rs index 9189811..be6eb59 100644 --- a/src/s3/client/append_object.rs +++ b/src/s3/client/append_object.rs @@ -52,10 +52,10 @@ impl Client { /// println!("size of the final object is {} bytes", resp.object_size); /// } /// ``` - pub fn append_object>( + pub fn append_object, S2: Into>( &self, - bucket: S, - object: S, + bucket: S1, + object: S2, data: SegmentedBytes, offset_bytes: u64, ) -> AppendObject { @@ -100,10 +100,10 @@ impl Client { /// println!("size of the final object is {} bytes", resp.object_size); /// } /// ``` - pub fn append_object_content, C: Into>( + pub fn append_object_content, S2: Into, C: Into>( &self, - bucket: S, - object: S, + bucket: S1, + object: S2, content: C, ) -> AppendObjectContent { AppendObjectContent::new(self.clone(), bucket.into(), object.into(), content) diff --git a/src/s3/client/bucket_exists.rs b/src/s3/client/bucket_exists.rs index f8d64da..9de6174 100644 --- a/src/s3/client/bucket_exists.rs +++ b/src/s3/client/bucket_exists.rs @@ -13,13 +13,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::BucketExists; impl Client { - /// Creates a [`BucketExists`] request builder. + /// Creates a [`BucketExists`] request builder to check if a bucket exists in S3. /// /// To execute the request, call [`BucketExists::send()`](crate::s3::types::S3Api::send), /// which returns a [`Result`] containing a [`BucketExistsResponse`](crate::s3::response::BucketExistsResponse). diff --git a/src/s3/client/copy_object.rs b/src/s3/client/copy_object.rs index 4a2203a..771f847 100644 --- a/src/s3/client/copy_object.rs +++ b/src/s3/client/copy_object.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::{ ComposeObject, ComposeObjectInternal, ComposeSource, CopyObject, CopyObjectInternal, @@ -66,8 +64,8 @@ impl Client { CopyObjectInternal::new(self.clone(), bucket.into(), object.into()) } - /// copy object is a high-order API that calls [stat_object](Client::stat_object) and based on the results calls - /// either [compose_object](Client::compose_object) or [`copy_object_internal`](Client::copy_object_internal) to copy the object. + /// copy object is a higher-level API that calls [stat_object](Client::stat_object) and based on the results calls + /// [compose_object](Client::compose_object) to copy the object. pub fn copy_object, S2: Into>( &self, bucket: S1, @@ -76,6 +74,8 @@ impl Client { CopyObject::new(self.clone(), bucket.into(), object.into()) } + /// Create a ComposeObjectInternal request builder. This is a higher-level API that + /// performs a multipart object compose. pub(crate) fn compose_object_internal, S2: Into>( &self, bucket: S1, @@ -84,7 +84,7 @@ impl Client { ComposeObjectInternal::new(self.clone(), bucket.into(), object.into()) } - /// compose object is high-order API that calls [`compose_object_internal`](Client::compose_object_internal) and if that call fails, + /// compose object is higher-level API that calls an internal compose object, and if that call fails, /// it calls ['abort_multipart_upload`](Client::abort_multipart_upload). pub fn compose_object, S2: Into>( &self, diff --git a/src/s3/client/create_bucket.rs b/src/s3/client/create_bucket.rs index 2961d2b..0a74f37 100644 --- a/src/s3/client/create_bucket.rs +++ b/src/s3/client/create_bucket.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::CreateBucket; diff --git a/src/s3/client/delete_bucket.rs b/src/s3/client/delete_bucket.rs index 42efaaf..f3a5611 100644 --- a/src/s3/client/delete_bucket.rs +++ b/src/s3/client/delete_bucket.rs @@ -13,14 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; -use crate::s3::builders::{DeleteBucket, ObjectToDelete, RemoveObject}; +use crate::s3::builders::{DeleteBucket, DeleteObject, ObjectToDelete}; use crate::s3::error::{Error, ErrorCode}; use crate::s3::response::DeleteResult; use crate::s3::response::{ - DeleteBucketResponse, PutObjectLegalHoldResponse, RemoveObjectResponse, RemoveObjectsResponse, + DeleteBucketResponse, DeleteObjectResponse, DeleteObjectsResponse, PutObjectLegalHoldResponse, }; use crate::s3::types::{S3Api, ToStream}; use futures::StreamExt; @@ -62,14 +60,14 @@ impl Client { while let Some(items) = stream.next().await { let mut resp = self - .remove_objects( + .delete_objects_streaming( &bucket, items?.contents.into_iter().map(ObjectToDelete::from), ) .to_stream() .await; while let Some(item) = resp.next().await { - let _resp: RemoveObjectsResponse = item?; + let _resp: DeleteObjectsResponse = item?; } } } else { @@ -81,7 +79,7 @@ impl Client { while let Some(items) = stream.next().await { let mut resp = self - .remove_objects( + .delete_objects_streaming( &bucket, items?.contents.into_iter().map(ObjectToDelete::from), ) @@ -90,7 +88,7 @@ impl Client { .await; while let Some(item) = resp.next().await { - let resp: RemoveObjectsResponse = item?; + let resp: DeleteObjectsResponse = item?; for obj in resp.result.into_iter() { match obj { DeleteResult::Deleted(_) => {} @@ -102,7 +100,7 @@ impl Client { .send() .await?; - let _resp: RemoveObjectResponse = RemoveObject::new( + let _resp: DeleteObjectResponse = DeleteObject::new( self.clone(), bucket.clone(), ObjectToDelete::from(v), diff --git a/src/s3/client/delete_bucket_encryption.rs b/src/s3/client/delete_bucket_encryption.rs index 68afd7a..44c0615 100644 --- a/src/s3/client/delete_bucket_encryption.rs +++ b/src/s3/client/delete_bucket_encryption.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketEncryption; diff --git a/src/s3/client/delete_bucket_lifecycle.rs b/src/s3/client/delete_bucket_lifecycle.rs index 2386c70..9a3bcb0 100644 --- a/src/s3/client/delete_bucket_lifecycle.rs +++ b/src/s3/client/delete_bucket_lifecycle.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketLifecycle; diff --git a/src/s3/client/delete_bucket_notification.rs b/src/s3/client/delete_bucket_notification.rs index 24995b0..cf3fa87 100644 --- a/src/s3/client/delete_bucket_notification.rs +++ b/src/s3/client/delete_bucket_notification.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketNotification; diff --git a/src/s3/client/delete_bucket_policy.rs b/src/s3/client/delete_bucket_policy.rs index 3e743ae..bd587d5 100644 --- a/src/s3/client/delete_bucket_policy.rs +++ b/src/s3/client/delete_bucket_policy.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketPolicy; diff --git a/src/s3/client/delete_bucket_replication.rs b/src/s3/client/delete_bucket_replication.rs index 0658059..5d17d5d 100644 --- a/src/s3/client/delete_bucket_replication.rs +++ b/src/s3/client/delete_bucket_replication.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketReplication; diff --git a/src/s3/client/delete_bucket_tagging.rs b/src/s3/client/delete_bucket_tagging.rs index ad22e0b..4f0a33c 100644 --- a/src/s3/client/delete_bucket_tagging.rs +++ b/src/s3/client/delete_bucket_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteBucketTagging; diff --git a/src/s3/client/delete_object_lock_config.rs b/src/s3/client/delete_object_lock_config.rs index 56192fb..af1c028 100644 --- a/src/s3/client/delete_object_lock_config.rs +++ b/src/s3/client/delete_object_lock_config.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteObjectLockConfig; diff --git a/src/s3/client/delete_object_tagging.rs b/src/s3/client/delete_object_tagging.rs index 91dcdaf..990a2d3 100644 --- a/src/s3/client/delete_object_tagging.rs +++ b/src/s3/client/delete_object_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::DeleteObjectTagging; diff --git a/src/s3/client/delete_objects.rs b/src/s3/client/delete_objects.rs index 3fdc35d..2951616 100644 --- a/src/s3/client/delete_objects.rs +++ b/src/s3/client/delete_objects.rs @@ -13,61 +13,65 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! APIs to remove objects. - -use crate::s3::builders::RemoveObjectsApi; use crate::s3::{ - builders::{DeleteObjects, ObjectToDelete, RemoveObject, RemoveObjects}, + builders::{ + DeleteObject, DeleteObjects, DeleteObjectsStreaming, ObjectToDelete, ObjectsStream, + }, client::Client, }; impl Client { - /// Creates a [`RemoveObject`] request builder. + /// Creates a [`DeleteObject`] request builder to delete a single object from an S3 bucket. /// - /// To execute the request, call [`RemoveObject::send()`](crate::s3::types::S3Api::send), - /// which returns a [`Result`] containing a [`RemoveObjectResponse`](crate::s3::response::RemoveObjectResponse). + /// To execute the request, call [`DeleteObject::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`DeleteObjectResponse`](crate::s3::response::DeleteObjectResponse). /// /// # Example /// /// ```no_run /// use minio::s3::Client; - /// use minio::s3::response::RemoveObjectResponse; + /// use minio::s3::response::DeleteObjectResponse; /// use minio::s3::builders::ObjectToDelete; /// use minio::s3::types::S3Api; /// /// #[tokio::main] /// async fn main() { /// let client: Client = Default::default(); // configure your client here - /// let resp: RemoveObjectResponse = client - /// .remove_object("bucket-name", ObjectToDelete::from("object-name")) + /// let resp: DeleteObjectResponse = client + /// .delete_object("bucket-name", ObjectToDelete::from("object-name")) /// .send().await.unwrap(); /// println!("the object is deleted. The delete marker has version '{:?}'", resp.version_id); /// } /// ``` - pub fn remove_object, D: Into>( + pub fn delete_object, D: Into>( &self, bucket: S, object: D, - ) -> RemoveObject { - RemoveObject::new(self.clone(), bucket.into(), object) + ) -> DeleteObject { + DeleteObject::new(self.clone(), bucket.into(), object) } - pub fn remove_objects, D: Into>( - &self, - bucket: S, - objects: D, - ) -> RemoveObjects { - RemoveObjects::new(self.clone(), bucket.into(), objects) - } - - /// Creates a builder to execute - /// [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) - /// S3 API + /// Creates a [`DeleteObjects`] request builder to delete multiple objects from an S3 bucket. + /// + /// To execute the request, call [`DeleteObjects::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`DeleteObjectsResponse`](crate::s3::response::DeleteObjectsResponse). pub fn delete_objects, D: Into>( &self, bucket: S, object: Vec, - ) -> RemoveObjectsApi { - RemoveObjectsApi::new(self.clone(), bucket.into(), object) + ) -> DeleteObjects { + DeleteObjects::new(self.clone(), bucket.into(), object) + } + + /// Creates a [`DeleteObjectsStreaming`] request builder to delete a stream of objects from an S3 bucket. + /// + /// to execute the request, call [`DeleteObjectsStreaming::to_stream()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`DeleteObjectsResponse`](crate::s3::response::DeleteObjectsResponse). + pub fn delete_objects_streaming, D: Into>( + &self, + bucket: S, + objects: D, + ) -> DeleteObjectsStreaming { + DeleteObjectsStreaming::new(self.clone(), bucket.into(), objects) } } diff --git a/src/s3/client/get_bucket_encryption.rs b/src/s3/client/get_bucket_encryption.rs index a39d931..5efd9e7 100644 --- a/src/s3/client/get_bucket_encryption.rs +++ b/src/s3/client/get_bucket_encryption.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketEncryption; diff --git a/src/s3/client/get_bucket_lifecycle.rs b/src/s3/client/get_bucket_lifecycle.rs index 9325853..6362287 100644 --- a/src/s3/client/get_bucket_lifecycle.rs +++ b/src/s3/client/get_bucket_lifecycle.rs @@ -13,14 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketLifecycle; impl Client { - /// Create a GetBucketLifecycle request builder. - /// /// Creates a [`GetBucketLifecycle`] request builder. /// /// To execute the request, call [`GetBucketLifecycle::send()`](crate::s3::types::S3Api::send), diff --git a/src/s3/client/get_bucket_notification.rs b/src/s3/client/get_bucket_notification.rs index e4befe8..8c1251b 100644 --- a/src/s3/client/get_bucket_notification.rs +++ b/src/s3/client/get_bucket_notification.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketNotification; diff --git a/src/s3/client/get_bucket_policy.rs b/src/s3/client/get_bucket_policy.rs index 3d605db..1bb91b1 100644 --- a/src/s3/client/get_bucket_policy.rs +++ b/src/s3/client/get_bucket_policy.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketPolicy; diff --git a/src/s3/client/get_bucket_replication.rs b/src/s3/client/get_bucket_replication.rs index cebedd9..28348ba 100644 --- a/src/s3/client/get_bucket_replication.rs +++ b/src/s3/client/get_bucket_replication.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketReplication; diff --git a/src/s3/client/get_bucket_tagging.rs b/src/s3/client/get_bucket_tagging.rs index 8071e72..c7211c6 100644 --- a/src/s3/client/get_bucket_tagging.rs +++ b/src/s3/client/get_bucket_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketTagging; diff --git a/src/s3/client/get_bucket_versioning.rs b/src/s3/client/get_bucket_versioning.rs index ed893dd..db95531 100644 --- a/src/s3/client/get_bucket_versioning.rs +++ b/src/s3/client/get_bucket_versioning.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetBucketVersioning; diff --git a/src/s3/client/get_object.rs b/src/s3/client/get_object.rs index 59209d4..ddd7089 100644 --- a/src/s3/client/get_object.rs +++ b/src/s3/client/get_object.rs @@ -13,17 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for downloading objects. - use super::Client; use crate::s3::builders::GetObject; impl Client { - /// Creates a [`GetObject`] request builder. - /// + /// Creates a [`GetObject`] request builder to download an object from a specified S3 bucket. + /// This allows retrieval of the full content and metadata for the object. + /// /// To execute the request, call [`GetObject::send()`](crate::s3::types::S3Api::send), /// which returns a [`Result`] containing a [`GetObjectResponse`](crate::s3::response::GetObjectResponse). /// + /// For more information, refer to the [AWS S3 GetObject API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html). + /// /// # Example /// /// ```no_run @@ -39,7 +40,7 @@ impl Client { /// .send().await.unwrap(); /// let content_bytes = resp.content.to_segmented_bytes().await.unwrap().to_bytes(); /// let content_str = String::from_utf8(content_bytes.to_vec()).unwrap(); - /// println!("retrieved content '{}'", content_str); + /// println!("retrieved content '{content_str}'"); /// } /// ``` pub fn get_object, S2: Into>( diff --git a/src/s3/client/get_object_legal_hold.rs b/src/s3/client/get_object_legal_hold.rs index 7693d3b..2c70219 100644 --- a/src/s3/client/get_object_legal_hold.rs +++ b/src/s3/client/get_object_legal_hold.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetObjectLegalHold; diff --git a/src/s3/client/get_object_lock_config.rs b/src/s3/client/get_object_lock_config.rs index d4e06f9..d65f383 100644 --- a/src/s3/client/get_object_lock_config.rs +++ b/src/s3/client/get_object_lock_config.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetObjectLockConfig; diff --git a/src/s3/client/get_object_prompt.rs b/src/s3/client/get_object_prompt.rs index 01a5ed1..dfdb4e5 100644 --- a/src/s3/client/get_object_prompt.rs +++ b/src/s3/client/get_object_prompt.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for downloading objects. - use crate::s3::builders::GetObjectPrompt; use super::Client; diff --git a/src/s3/client/get_object_retention.rs b/src/s3/client/get_object_retention.rs index 574e3d9..6111b70 100644 --- a/src/s3/client/get_object_retention.rs +++ b/src/s3/client/get_object_retention.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetObjectRetention; diff --git a/src/s3/client/get_object_tagging.rs b/src/s3/client/get_object_tagging.rs index 1332fad..0a06729 100644 --- a/src/s3/client/get_object_tagging.rs +++ b/src/s3/client/get_object_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::GetObjectTagging; diff --git a/src/s3/client/get_region.rs b/src/s3/client/get_region.rs index 9204158..21ac285 100644 --- a/src/s3/client/get_region.rs +++ b/src/s3/client/get_region.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for downloading objects. - use super::{Client, DEFAULT_REGION}; use crate::s3::builders::GetRegion; use crate::s3::error::Error; diff --git a/src/s3/client/list_buckets.rs b/src/s3/client/list_buckets.rs index fe0f4d8..ada5ad7 100644 --- a/src/s3/client/list_buckets.rs +++ b/src/s3/client/list_buckets.rs @@ -13,28 +13,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for listing objects. - use super::Client; use crate::s3::builders::ListBuckets; impl Client { - /// Creates a [`ListBuckets`] request builder. + /// Creates a [`ListBuckets`] request builder to retrieve the list of all buckets owned by the authenticated sender of the request. /// /// To execute the request, call [`ListBuckets::send()`](crate::s3::types::S3Api::send), /// which returns a [`Result`] containing a [`ListBucketsResponse`](crate::s3::response::ListBucketsResponse). /// + /// For more information, refer to the [AWS S3 ListBuckets API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html). + /// /// # Example /// /// ```no_run /// use minio::s3::Client; /// use minio::s3::response::ListBucketsResponse; /// use minio::s3::types::S3Api; - /// use std::sync::Arc; /// /// #[tokio::main] /// async fn main() { - /// let client: Client = Default::default(); // configure your client here + /// let client: Client = Default::default(); // configure your client here /// let resp: ListBucketsResponse = client /// .list_buckets() /// .send().await.unwrap(); diff --git a/src/s3/client/list_objects.rs b/src/s3/client/list_objects.rs index f9b6590..9e361d0 100644 --- a/src/s3/client/list_objects.rs +++ b/src/s3/client/list_objects.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for listing objects. - use super::Client; use crate::s3::builders::ListObjects; diff --git a/src/s3/client/put_bucket_encryption.rs b/src/s3/client/put_bucket_encryption.rs index 12c20bf..edfada0 100644 --- a/src/s3/client/put_bucket_encryption.rs +++ b/src/s3/client/put_bucket_encryption.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketEncryption; diff --git a/src/s3/client/put_bucket_lifecycle.rs b/src/s3/client/put_bucket_lifecycle.rs index 32fd457..19df3e8 100644 --- a/src/s3/client/put_bucket_lifecycle.rs +++ b/src/s3/client/put_bucket_lifecycle.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketLifecycle; diff --git a/src/s3/client/put_bucket_notification.rs b/src/s3/client/put_bucket_notification.rs index 4a57f92..fb67fd5 100644 --- a/src/s3/client/put_bucket_notification.rs +++ b/src/s3/client/put_bucket_notification.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketNotification; diff --git a/src/s3/client/put_bucket_policy.rs b/src/s3/client/put_bucket_policy.rs index ca3e404..3ff4799 100644 --- a/src/s3/client/put_bucket_policy.rs +++ b/src/s3/client/put_bucket_policy.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketPolicy; diff --git a/src/s3/client/put_bucket_replication.rs b/src/s3/client/put_bucket_replication.rs index 9e39e18..69737db 100644 --- a/src/s3/client/put_bucket_replication.rs +++ b/src/s3/client/put_bucket_replication.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketReplication; diff --git a/src/s3/client/put_bucket_tagging.rs b/src/s3/client/put_bucket_tagging.rs index 2d2ad21..97e1f4b 100644 --- a/src/s3/client/put_bucket_tagging.rs +++ b/src/s3/client/put_bucket_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketTagging; diff --git a/src/s3/client/put_bucket_versioning.rs b/src/s3/client/put_bucket_versioning.rs index 132a1ca..15fe27c 100644 --- a/src/s3/client/put_bucket_versioning.rs +++ b/src/s3/client/put_bucket_versioning.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutBucketVersioning; diff --git a/src/s3/client/put_object.rs b/src/s3/client/put_object.rs index 2efaee7..41afe2a 100644 --- a/src/s3/client/put_object.rs +++ b/src/s3/client/put_object.rs @@ -1,5 +1,5 @@ // 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"); // you may not use this file except in compliance with the License. @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for uploading objects. - use super::Client; use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::{ @@ -26,12 +24,16 @@ use crate::s3::{ }; impl Client { - /// Creates a [`PutObject`] request builder. This is a lower-level API that - /// performs a non-multipart object upload. + /// Creates a [`PutObject`] request builder to upload an object to a specified bucket in S3-compatible storage. + /// This method performs a simple, non-multipart upload of the provided content as an object. + /// + /// 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), /// 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). + /// /// # Example /// /// ```no_run @@ -58,7 +60,29 @@ impl Client { PutObject::new(self.clone(), bucket.into(), object.into(), data) } - /// Create a CreateMultipartUpload request builder. + /// Creates a [`CreateMultipartUpload`] request builder to initiate a new multipart upload for a specified object in a bucket. + /// This allows uploading large objects as a series of parts, which can be uploaded independently and in parallel. + /// + /// To execute the request, call [`CreateMultipartUpload::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`CreateMultipartUploadResponse`](crate::s3::response::CreateMultipartUploadResponse). + /// + /// For more information, refer to the [AWS S3 CreateMultipartUpload API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html). + /// + /// # Example + /// ```no_run + /// use minio::s3::Client; + /// use minio::s3::response::CreateMultipartUploadResponse; + /// use minio::s3::types::S3Api; + /// + /// #[tokio::main] + /// async fn main() { + /// let client: Client = Default::default(); + /// let resp: CreateMultipartUploadResponse = client + /// .create_multipart_upload("bucket-name", "large-object") + /// .send().await.unwrap(); + /// println!("Initiated multipart upload with UploadId '{}'", resp.upload_id); + /// } + /// ``` pub fn create_multipart_upload, S2: Into>( &self, bucket: S1, @@ -67,6 +91,29 @@ impl Client { CreateMultipartUpload::new(self.clone(), bucket.into(), object.into()) } + /// Creates an [`AbortMultipartUpload`] request builder to abort an ongoing multipart upload for an object. + /// This operation stops the multipart upload and discards all uploaded parts, freeing storage. + /// + /// To execute the request, call [`AbortMultipartUpload::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`AbortMultipartUploadResponse`](crate::s3::response::AbortMultipartUploadResponse). + /// + /// For more information, refer to the [AWS S3 AbortMultipartUpload API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html). + /// + /// # Example + /// ```no_run + /// use minio::s3::Client; + /// use minio::s3::response::AbortMultipartUploadResponse; + /// use minio::s3::types::S3Api; + /// + /// #[tokio::main] + /// async fn main() { + /// let client: Client = Default::default(); + /// let resp: AbortMultipartUploadResponse = client + /// .abort_multipart_upload("bucket-name", "object-name", "upload-id-123") + /// .send().await.unwrap(); + /// println!("Aborted multipart upload for '{}', upload id '{}'", "object-name", "upload-id-123"); + /// } + /// ``` pub fn abort_multipart_upload, S2: Into, S3: Into>( &self, bucket: S1, @@ -76,6 +123,31 @@ impl Client { AbortMultipartUpload::new(self.clone(), bucket.into(), object.into(), upload_id.into()) } + /// Creates a [`CompleteMultipartUpload`] request builder to complete a multipart upload by assembling previously uploaded parts into a single object. + /// This finalizes the upload and makes the object available in the bucket. + /// + /// To execute the request, call [`CompleteMultipartUpload::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`CompleteMultipartUploadResponse`](crate::s3::response::CompleteMultipartUploadResponse). + /// + /// For more information, refer to the [AWS S3 CompleteMultipartUpload API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html). + /// + /// # Example + /// ```no_run + /// use minio::s3::Client; + /// use minio::s3::response::CompleteMultipartUploadResponse; + /// use minio::s3::types::S3Api; + /// use minio::s3::types::PartInfo; + /// + /// #[tokio::main] + /// async fn main() { + /// let client: Client = Default::default(); + /// let parts: Vec = vec![]; // fill with your uploaded part info + /// let resp: CompleteMultipartUploadResponse = client + /// .complete_multipart_upload("bucket-name", "object-name", "upload-id-123", parts) + /// .send().await.unwrap(); + /// println!("Completed multipart upload for '{}'", resp.object); + /// } + /// ``` pub fn complete_multipart_upload, S2: Into, S3: Into>( &self, bucket: S1, @@ -92,6 +164,31 @@ impl Client { ) } + /// Creates an [`UploadPart`] request builder to upload a single part as part of a multipart upload. + /// Each part is uploaded independently, enabling parallel uploads for large objects. + /// + /// To execute the request, call [`UploadPart::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`UploadPartResponse`](crate::s3::response::UploadPartResponse). + /// + /// For more information, refer to the [AWS S3 UploadPart API documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html). + /// + /// # Example + /// ```no_run + /// use minio::s3::Client; + /// use minio::s3::response::UploadPartResponse; + /// use minio::s3::types::S3Api; + /// use minio::s3::segmented_bytes::SegmentedBytes; + /// + /// #[tokio::main] + /// async fn main() { + /// let client: Client = Default::default(); + /// let data = SegmentedBytes::from("Some part data".to_string()); + /// let resp: UploadPartResponse = client + /// .upload_part("bucket-name", "object-name", "upload-id", 1, data) + /// .send().await.unwrap(); + /// println!("Uploaded object: {}", resp.object); + /// } + /// ``` pub fn upload_part, S2: Into, S3: Into>( &self, bucket: S1, @@ -110,8 +207,30 @@ impl Client { ) } - /// Creates a PutObjectContent request builder to upload data to MinIO/S3. - /// The content is streamed, and this higher-level API handles multipart uploads transparently. + /// Creates a [`PutObjectContent`] request builder to upload data to MinIO/S3, automatically handling multipart uploads for large content. + /// This higher-level API efficiently streams and uploads content, splitting it into parts as needed. + /// + /// To execute the request, call [`PutObjectContent::send()`](crate::s3::types::S3Api::send), + /// which returns a [`Result`] containing a [`PutObjectContentResponse`](crate::s3::response::PutObjectContentResponse). + /// + /// For more information, see the [AWS S3 Multipart Upload Overview](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html). + /// + /// # Example + /// ```no_run + /// use minio::s3::Client; + /// use minio::s3::response::PutObjectContentResponse; + /// use minio::s3::types::S3Api; + /// + /// #[tokio::main] + /// async fn main() { + /// let client: Client = Default::default(); + /// let content = "Hello, world!".to_string(); + /// let resp: PutObjectContentResponse = client + /// .put_object_content("bucket", "object", content) + /// .send().await.unwrap(); + /// println!("Uploaded object '{}' with ETag '{}'", resp.object, resp.etag); + /// } + /// ``` pub fn put_object_content, S2: Into, C: Into>( &self, bucket: S1, diff --git a/src/s3/client/put_object_legal_hold.rs b/src/s3/client/put_object_legal_hold.rs index f7cc525..38a57dd 100644 --- a/src/s3/client/put_object_legal_hold.rs +++ b/src/s3/client/put_object_legal_hold.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutObjectLegalHold; diff --git a/src/s3/client/put_object_lock_config.rs b/src/s3/client/put_object_lock_config.rs index ad01616..5a2655a 100644 --- a/src/s3/client/put_object_lock_config.rs +++ b/src/s3/client/put_object_lock_config.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutObjectLockConfig; diff --git a/src/s3/client/put_object_retention.rs b/src/s3/client/put_object_retention.rs index 726c48a..635775b 100644 --- a/src/s3/client/put_object_retention.rs +++ b/src/s3/client/put_object_retention.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutObjectRetention; diff --git a/src/s3/client/put_object_tagging.rs b/src/s3/client/put_object_tagging.rs index b0429bf..543e463 100644 --- a/src/s3/client/put_object_tagging.rs +++ b/src/s3/client/put_object_tagging.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::PutObjectTagging; diff --git a/src/s3/client/select_object_content.rs b/src/s3/client/select_object_content.rs index 8632c84..6492ab1 100644 --- a/src/s3/client/select_object_content.rs +++ b/src/s3/client/select_object_content.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::SelectObjectContent; use crate::s3::types::SelectRequest; diff --git a/src/s3/client/stat_object.rs b/src/s3/client/stat_object.rs index cbc47b5..00cbbb2 100644 --- a/src/s3/client/stat_object.rs +++ b/src/s3/client/stat_object.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! S3 APIs for bucket objects. - use super::Client; use crate::s3::builders::StatObject; diff --git a/src/s3/response.rs b/src/s3/response.rs index dd259ba..793ef66 100644 --- a/src/s3/response.rs +++ b/src/s3/response.rs @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Responses for [minio::s3::client::Client](crate::s3::client::Client) APIs - mod append_object; mod bucket_exists; mod copy_object; @@ -26,6 +24,7 @@ mod delete_bucket_notification; mod delete_bucket_policy; mod delete_bucket_replication; mod delete_bucket_tagging; +mod delete_object; mod delete_object_lock_config; mod delete_object_tagging; mod get_bucket_encryption; @@ -58,7 +57,6 @@ mod put_object_legal_hold; mod put_object_lock_config; mod put_object_retention; mod put_object_tagging; -mod remove_objects; mod select_object_content; mod stat_object; @@ -73,6 +71,9 @@ pub use delete_bucket_notification::DeleteBucketNotificationResponse; pub use delete_bucket_policy::DeleteBucketPolicyResponse; pub use delete_bucket_replication::DeleteBucketReplicationResponse; pub use delete_bucket_tagging::DeleteBucketTaggingResponse; +pub use delete_object::{ + DeleteError, DeleteObjectResponse, DeleteObjectsResponse, DeleteResult, DeletedObject, +}; pub use delete_object_lock_config::DeleteObjectLockConfigResponse; pub use delete_object_tagging::DeleteObjectTaggingResponse; pub use get_bucket_encryption::GetBucketEncryptionResponse; @@ -108,8 +109,5 @@ pub use put_object_legal_hold::PutObjectLegalHoldResponse; pub use put_object_lock_config::PutObjectLockConfigResponse; pub use put_object_retention::PutObjectRetentionResponse; pub use put_object_tagging::PutObjectTaggingResponse; -pub use remove_objects::{ - DeleteError, DeleteResult, DeletedObject, RemoveObjectResponse, RemoveObjectsResponse, -}; pub use select_object_content::SelectObjectContentResponse; pub use stat_object::StatObjectResponse; diff --git a/src/s3/response/remove_objects.rs b/src/s3/response/delete_object.rs similarity index 87% rename from src/s3/response/remove_objects.rs rename to src/s3/response/delete_object.rs index 926333c..c75b56d 100644 --- a/src/s3/response/remove_objects.rs +++ b/src/s3/response/delete_object.rs @@ -1,5 +1,5 @@ // MinIO Rust Library for Amazon S3 Compatible Cloud Storage -// Copyright 2022-2024 MinIO, Inc. +// Copyright 2022-2025 MinIO, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Responses for RemoveObject APIs. - use async_trait::async_trait; use bytes::Buf; use http::HeaderMap; @@ -28,20 +26,23 @@ use crate::s3::{ }; #[derive(Debug, Clone)] -pub struct RemoveObjectResponse { +pub struct DeleteObjectResponse { /// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc. pub headers: HeaderMap, /// 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, - /// If a delete marker was created, this field will contain the version_id - /// of the delete marker. Value of the `x-amz-version-id` header. + /// 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, } #[async_trait] -impl FromS3Response for RemoveObjectResponse { +impl FromS3Response for DeleteObjectResponse { async fn from_s3response( _req: S3Request, resp: Result, @@ -57,7 +58,7 @@ impl FromS3Response for RemoveObjectResponse { .get("x-amz-version-id") .and_then(|v| v.to_str().ok().map(String::from)); - Ok(RemoveObjectResponse { + Ok(DeleteObjectResponse { headers, is_delete_marker, version_id, @@ -86,10 +87,10 @@ pub struct DeletedObject { /// Response of /// [delete_objects()](crate::s3::client::Client::delete_objects) /// S3 API. It is also returned by the -/// [remove_objects()](crate::s3::client::Client::remove_objects) API in the +/// [remove_objects()](crate::s3::client::Client::delete_objects_streaming) API in the /// form of a stream. #[derive(Clone, Debug)] -pub struct RemoveObjectsResponse { +pub struct DeleteObjectsResponse { /// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc. pub headers: HeaderMap, pub result: Vec, @@ -122,7 +123,7 @@ impl DeleteResult { } #[async_trait] -impl FromS3Response for RemoveObjectsResponse { +impl FromS3Response for DeleteObjectsResponse { async fn from_s3response( _req: S3Request, resp: Result, diff --git a/src/s3/response/put_object.rs b/src/s3/response/put_object.rs index d28d159..b2c9f6e 100644 --- a/src/s3/response/put_object.rs +++ b/src/s3/response/put_object.rs @@ -69,6 +69,7 @@ impl FromS3Response for PutObjectResponse { } } +/// Response of [create_multipart_upload()](crate::s3::client::Client::create_multipart_upload) API #[derive(Debug, Clone)] pub struct CreateMultipartUploadResponse { /// HTTP headers returned by the server, containing metadata such as `Content-Type`, `ETag`, etc. @@ -103,10 +104,13 @@ impl FromS3Response for CreateMultipartUploadResponse { } } +/// Response of [abort_multipart_upload()](crate::s3::client::Client::abort_multipart_upload) API pub type AbortMultipartUploadResponse = CreateMultipartUploadResponse; +/// Response of [complete_multipart_upload()](crate::s3::client::Client::complete_multipart_upload) API pub type CompleteMultipartUploadResponse = PutObjectResponse; +/// Response of [upload_part()](crate::s3::client::Client::upload_part) API pub type UploadPartResponse = PutObjectResponse; #[derive(Debug, Clone)] diff --git a/src/s3/types.rs b/src/s3/types.rs index bacab64..bf45fe0 100644 --- a/src/s3/types.rs +++ b/src/s3/types.rs @@ -56,6 +56,7 @@ impl S3Request { } } + /// Sets the region for the request pub fn region(mut self, region: Option) -> Self { self.region = region; self @@ -715,6 +716,7 @@ impl RequestParameters { self.0.get("principalId") } + /// Gets the region for the request pub fn region(&self) -> Option<&String> { self.0.get("region") } diff --git a/tests/test_append_object.rs b/tests/test_append_object.rs index 014e718..9dcebf3 100644 --- a/tests/test_append_object.rs +++ b/tests/test_append_object.rs @@ -546,7 +546,7 @@ async fn append_object_content_3() { assert_eq!(resp.size, sizes[idx] + initial_size); assert_eq!(resp.etag, etag); client - .remove_object(&test_bucket, &object_name) + .delete_object(&test_bucket, &object_name) .send() .await .unwrap(); diff --git a/tests/test_object_put.rs b/tests/test_object_put.rs index c826d26..924f65b 100644 --- a/tests/test_object_put.rs +++ b/tests/test_object_put.rs @@ -192,7 +192,7 @@ async fn put_object_content_2() { assert_eq!(resp.size, sizes[idx]); assert_eq!(resp.etag, etag); client - .remove_object(&test_bucket, &object_name) + .delete_object(&test_bucket, &object_name) .send() .await .unwrap(); diff --git a/tests/test_object_remove.rs b/tests/test_object_remove.rs index 72579f6..cc7c820 100644 --- a/tests/test_object_remove.rs +++ b/tests/test_object_remove.rs @@ -45,7 +45,7 @@ async fn remove_objects() { let mut resp = ctx .client - .remove_objects(&bucket_name, del_items.into_iter()) + .delete_objects_streaming(&bucket_name, del_items.into_iter()) .verbose_mode(true) .to_stream() .await; diff --git a/tests/test_put_object.rs b/tests/test_put_object.rs index e7a2cd1..298edaa 100644 --- a/tests/test_put_object.rs +++ b/tests/test_put_object.rs @@ -15,8 +15,9 @@ use http::header; use minio::s3::builders::ObjectContent; +use minio::s3::client; use minio::s3::error::{Error, ErrorCode}; -use minio::s3::response::{PutObjectContentResponse, RemoveObjectResponse, StatObjectResponse}; +use minio::s3::response::{DeleteObjectResponse, PutObjectContentResponse, StatObjectResponse}; use minio::s3::types::S3Api; use minio_common::rand_src::RandSrc; use minio_common::test_context::TestContext; @@ -54,9 +55,9 @@ async fn put_object() { assert_eq!(resp.object, object_name); assert_eq!(resp.size, size); - let resp: RemoveObjectResponse = ctx + let resp: DeleteObjectResponse = ctx .client - .remove_object(&bucket_name, &object_name) + .delete_object(&bucket_name, &object_name) .send() .await .unwrap(); @@ -83,9 +84,10 @@ async fn put_object_multipart() { let (bucket_name, _cleanup) = ctx.create_bucket_helper().await; let object_name = rand_object_name(); - let size: u64 = 16 + 5 * 1024 * 1024; + let size: u64 = 16 + client::MIN_PART_SIZE; - ctx.client + let resp: PutObjectContentResponse = ctx + .client .put_object_content( &bucket_name, &object_name, @@ -94,7 +96,11 @@ async fn put_object_multipart() { .send() .await .unwrap(); - let resp = ctx + assert_eq!(resp.bucket, bucket_name); + assert_eq!(resp.object, object_name); + assert_eq!(resp.object_size, size); + + let resp: StatObjectResponse = ctx .client .stat_object(&bucket_name, &object_name) .send() @@ -102,12 +108,15 @@ async fn put_object_multipart() { .unwrap(); assert_eq!(resp.bucket, bucket_name); assert_eq!(resp.object, object_name); - assert_eq!(resp.size as u64, size); - ctx.client - .remove_object(&bucket_name, &object_name) + assert_eq!(resp.size, size); + + let resp: DeleteObjectResponse = ctx + .client + .delete_object(&bucket_name, &object_name) .send() .await .unwrap(); + assert_eq!(resp.version_id, None); } #[tokio::test(flavor = "multi_thread", worker_threads = 10)] @@ -143,9 +152,9 @@ async fn put_object_content_1() { resp.headers.get(header::CONTENT_TYPE).unwrap(), "image/jpeg" ); - let resp: RemoveObjectResponse = ctx + let resp: DeleteObjectResponse = ctx .client - .remove_object(&bucket_name, &object_name) + .delete_object(&bucket_name, &object_name) .send() .await .unwrap(); @@ -185,7 +194,7 @@ async fn put_object_content_2() { assert_eq!(resp.size, *size); assert_eq!(resp.etag, etag); ctx.client - .remove_object(&bucket_name, &object_name) + .delete_object(&bucket_name, &object_name) .send() .await .unwrap(); @@ -239,7 +248,7 @@ async fn put_object_content_3() { assert_eq!(resp.size, sizes[idx]); assert_eq!(resp.etag, etag); client - .remove_object(&test_bucket, &object_name) + .delete_object(&test_bucket, &object_name) .send() .await .unwrap();