From ff942cdca769dc37596d57da5ce64320c6874eb8 Mon Sep 17 00:00:00 2001 From: Henk-Jan Lebbink Date: Tue, 7 Jan 2025 12:57:50 +0100 Subject: [PATCH 1/3] Added object_prompt support --- Cargo.toml | 7 +- README.md | 14 +- examples/cat.png | Bin 0 -> 88702 bytes .../{file-uploader.rs => file_uploader.rs} | 36 +++- examples/object_prompt.rs | 90 ++++++++++ examples/{put-object.rs => put_object.rs} | 0 src/s3/builders.rs | 5 + src/s3/builders/get_object.rs | 18 +- src/s3/builders/object_prompt.rs | 156 ++++++++++++++++++ src/s3/builders/put_object.rs | 10 +- src/s3/builders/remove_objects.rs | 13 +- src/s3/client.rs | 1 + src/s3/client/object_prompt.rs | 27 +++ src/s3/response.rs | 4 +- src/s3/response/object_prompt.rs | 61 +++++++ src/s3/response/put_object.rs | 30 +++- src/s3/utils.rs | 19 ++- 17 files changed, 443 insertions(+), 48 deletions(-) create mode 100644 examples/cat.png rename examples/{file-uploader.rs => file_uploader.rs} (54%) create mode 100644 examples/object_prompt.rs rename examples/{put-object.rs => put_object.rs} (100%) create mode 100644 src/s3/builders/object_prompt.rs create mode 100644 src/s3/client/object_prompt.rs create mode 100644 src/s3/response/object_prompt.rs diff --git a/Cargo.toml b/Cargo.toml index d8c870d2..39a557b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ futures-util = "0.3.31" hex = "0.4.3" hmac = "0.12.1" home = "0.5.9" -http = "1.1.0" +http = "1.2.0" hyper = { version = "1.5.1", features = ["full"] } lazy_static = "1.5.0" log = "0.4.22" @@ -61,4 +61,7 @@ clap = { version = "4.5.23", features = ["derive"] } quickcheck = "1.0.3" [[example]] -name = "file-uploader" +name = "file_uploader" + +[[example]] +name = "object_prompt" diff --git a/README.md b/README.md index 0fe4a086..06cc8842 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,20 @@ MinIO Rust SDK is Simple Storage Service (aka S3) client to perform bucket and o For a complete list of APIs and examples, please take a look at the [MinIO Rust Client API Reference](https://minio-rs.min.io/) -## Example:: file-uploader.rs +## Examples -[Upload a file to MinIO](examples/file-uploader.rs) +Run the examples from the command line with: +`cargo run --example ` + +### file_uploader.rs + +* [Upload a file to MinIO](examples/file_uploader) +* [Upload a file to MinIO with CLI](examples/put_object) + +### object_prompt.rs + +* [Prompt a file on MinIO](examples/object_prompt) ## License This SDK is distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), see [LICENSE](https://github.com/minio/minio-rs/blob/master/LICENSE) for more information. diff --git a/examples/cat.png b/examples/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce7442e6f7f9ae79f402cf62d7e42901dfd8a96 GIT binary patch literal 88702 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%0A5X$OR`0cUS9`odAoU41220Qvg0BlFUw8te}Vc* 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 {NZ==maR!7&&l&XbpFwbb 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 Result<(), Box> { env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher let base_url = "https://play.min.io".parse::()?; - - info!("Trying to connect to MinIO at: `{:?}`", base_url); + log::info!("Trying to connect to MinIO at: `{:?}`", base_url); let static_provider = StaticProvider::new( "Q3AM3UQ867SPQQA43P2F", @@ -24,7 +37,7 @@ async fn main() -> Result<(), Box> { .provider(Some(Box::new(static_provider))) .build()?; - let bucket_name: &str = "asiatrip"; + let bucket_name: &str = "file-upload-rust-bucket"; // Check 'bucket_name' bucket exist or not. let exists: bool = client @@ -41,12 +54,17 @@ async fn main() -> Result<(), Box> { } // File we are going to upload to the bucket - let filename: &Path = Path::new("/tmp/asiaphotos.zip"); + let filename: &Path = Path::new("./examples/cat.png"); // Name of the object that will be stored in the bucket - let object_name: &str = "asiaphotos-2015.zip"; + let object_name: &str = "cat.png"; - info!("filename {}", &filename.to_str().unwrap()); + if filename.exists() { + log::info!("File '{}' exists.", &filename.to_str().unwrap()); + } else { + log::error!("File '{}' does not exist.", &filename.to_str().unwrap()); + return Ok(()); + } let content = ObjectContent::from(filename); client @@ -54,8 +72,8 @@ async fn main() -> Result<(), Box> { .send() .await?; - info!( - "file `{}` is successfully uploaded as object `{object_name}` to bucket `{bucket_name}`.", + log::info!( + "file '{}' is successfully uploaded as object '{object_name}' to bucket '{bucket_name}'.", filename.display() ); Ok(()) diff --git a/examples/object_prompt.rs b/examples/object_prompt.rs new file mode 100644 index 00000000..4210e042 --- /dev/null +++ b/examples/object_prompt.rs @@ -0,0 +1,90 @@ +// MinIO Rust Library for Amazon S3 Compatible Cloud Storage +// Copyright 2024 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use minio::s3::args::{BucketExistsArgs, MakeBucketArgs}; +use minio::s3::builders::{ObjectContent, ObjectPrompt}; +use minio::s3::client::ClientBuilder; +use minio::s3::creds::StaticProvider; +use minio::s3::http::BaseUrl; +use minio::s3::types::S3Api; +use std::path::Path; + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher + + let base_url = "https://play.min.io".parse::()?; + log::info!("Trying to connect to MinIO at: `{:?}`", base_url); + + let static_provider = StaticProvider::new( + "Q3AM3UQ867SPQQA43P2F", + "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", + None, + ); + + let client = ClientBuilder::new(base_url.clone()) + .provider(Some(Box::new(static_provider))) + .ignore_cert_check(Some(true)) + .build()?; + + let bucket_name: &str = "object-prompt-rust-bucket"; + + // Check 'bucket_name' bucket exist or not. + let exists: bool = client + .bucket_exists(&BucketExistsArgs::new(bucket_name).unwrap()) + .await + .unwrap(); + + // Make 'bucket_name' bucket if not exist. + if !exists { + client + .make_bucket(&MakeBucketArgs::new(bucket_name).unwrap()) + .await + .unwrap(); + } + + // File we are going to upload to the bucket + let filename: &Path = Path::new("./examples/cat.png"); + + // Name of the object that will be stored in the bucket + let object_name: &str = "cat.png"; + + if filename.exists() { + log::info!("File '{}' exists.", &filename.to_str().unwrap()); + } else { + log::error!("File '{}' does not exist.", &filename.to_str().unwrap()); + return Ok(()); + } + + let content = ObjectContent::from(filename); + client + .put_object_content(bucket_name, object_name, content) + .send() + .await?; + + log::info!( + "File '{}' is successfully uploaded as object '{object_name}' to bucket '{bucket_name}'.", + filename.display() + ); + + let op = ObjectPrompt::new(bucket_name, object_name, "what is it about?") + //.lambda_arn("arn:minio:s3-object-lambda::_:webhook") // this is the default value + .client(&client); + + let res = op.send().await?; + log::info!("Object prompt result: '{}'", res.prompt_response); + + Ok(()) +} diff --git a/examples/put-object.rs b/examples/put_object.rs similarity index 100% rename from examples/put-object.rs rename to examples/put_object.rs diff --git a/src/s3/builders.rs b/src/s3/builders.rs index d114a598..9df7c407 100644 --- a/src/s3/builders.rs +++ b/src/s3/builders.rs @@ -1,3 +1,6 @@ +// MinIO Rust Library for Amazon S3 Compatible Cloud Storage +// Copyright 2024 MinIO, Inc. +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -17,6 +20,7 @@ mod get_object; mod list_objects; mod listen_bucket_notification; mod object_content; +mod object_prompt; mod put_object; mod remove_objects; @@ -25,5 +29,6 @@ pub use get_object::*; pub use list_objects::*; pub use listen_bucket_notification::*; pub use object_content::*; +pub use object_prompt::*; pub use put_object::*; pub use remove_objects::*; diff --git a/src/s3/builders/get_object.rs b/src/s3/builders/get_object.rs index b8da5477..69f20306 100644 --- a/src/s3/builders/get_object.rs +++ b/src/s3/builders/get_object.rs @@ -178,8 +178,7 @@ impl ToS3Request for GetObject { "object name cannot be empty", ))); } - - let client = self.client.clone().ok_or(Error::NoClientProvided)?; + let client: &Client = self.client.as_ref().ok_or(Error::NoClientProvided)?; if self.ssec.is_some() && !client.is_secure() { return Err(Error::SseTlsRequired(None)); @@ -199,15 +198,12 @@ impl ToS3Request for GetObject { query_params.insert(String::from("versionId"), v.to_string()); } - let req = S3Request::new( - self.client.as_ref().ok_or(Error::NoClientProvided)?, - Method::GET, - ) - .region(self.region.as_deref()) - .bucket(Some(&self.bucket)) - .object(Some(&self.object)) - .query_params(query_params) - .headers(headers); + let req = S3Request::new(client, Method::GET) + .region(self.region.as_deref()) + .bucket(Some(&self.bucket)) + .object(Some(&self.object)) + .query_params(query_params) + .headers(headers); Ok(req) } diff --git a/src/s3/builders/object_prompt.rs b/src/s3/builders/object_prompt.rs new file mode 100644 index 00000000..45d85570 --- /dev/null +++ b/src/s3/builders/object_prompt.rs @@ -0,0 +1,156 @@ +// MinIO Rust Library for Amazon S3 Compatible Cloud Storage +// Copyright 2024 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::s3::builders::SegmentedBytes; +use crate::s3::sse::{Sse, SseCustomerKey}; +use crate::s3::utils::{check_bucket_name, merge, Multimap}; +use crate::s3::{ + client::Client, + error::Error, + response::ObjectPromptResponse, + types::{S3Api, S3Request, ToS3Request}, +}; +use bytes::Bytes; +use http::Method; +use serde_json::json; + +#[derive(Debug, Clone, Default)] +pub struct ObjectPrompt { + client: Option, + bucket: String, + object: String, + prompt: String, + lambda_arn: Option, + + version_id: Option, + region: Option, + ssec: Option, + extra_headers: Option, + extra_query_params: Option, +} + +// builder interface +impl ObjectPrompt { + pub fn new(bucket: &str, object: &str, prompt: &str) -> Self { + ObjectPrompt { + client: None, + bucket: bucket.to_string(), + object: object.to_string(), + prompt: prompt.to_string(), + ..Default::default() + } + } + + pub fn client(mut self, client: &Client) -> Self { + self.client = Some(client.clone()); + self + } + + pub fn lambda_arn(mut self, lambda_arn: &str) -> Self { + self.lambda_arn = Some(lambda_arn.to_string()); + self + } + + pub fn extra_headers(mut self, extra_headers: Option) -> Self { + self.extra_headers = extra_headers; + self + } + + pub fn extra_query_params(mut self, extra_query_params: Option) -> Self { + self.extra_query_params = extra_query_params; + self + } + + pub fn version_id(mut self, version_id: Option) -> Self { + self.version_id = version_id; + self + } + + pub fn region(mut self, region: Option) -> Self { + self.region = region; + self + } + + pub fn ssec(mut self, ssec: Option) -> Self { + self.ssec = ssec; + self + } +} + +// internal helpers +impl ObjectPrompt { + fn get_headers(&self) -> Multimap { + let mut headers = Multimap::new(); + if let Some(v) = &self.ssec { + merge(&mut headers, &v.headers()); + } + headers + } +} + +impl ToS3Request for ObjectPrompt { + fn to_s3request(&self) -> Result { + check_bucket_name(&self.bucket, true)?; + + if self.object.is_empty() { + return Err(Error::InvalidObjectName(String::from( + "object name cannot be empty", + ))); + } + let client: &Client = self.client.as_ref().ok_or(Error::NoClientProvided)?; + + if self.ssec.is_some() && !client.is_secure() { + return Err(Error::SseTlsRequired(None)); + } + + let mut headers = Multimap::new(); + if let Some(v) = &self.extra_headers { + merge(&mut headers, v); + } + merge(&mut headers, &self.get_headers()); + + let mut query_params = Multimap::new(); + if let Some(v) = &self.extra_query_params { + merge(&mut query_params, v); + } + if let Some(v) = &self.version_id { + query_params.insert(String::from("versionId"), v.to_string()); + } + query_params.insert( + String::from("lambdaArn"), + self.lambda_arn + .as_ref() + .map(ToString::to_string) + .unwrap_or_default(), + ); + + let prompt_body = json!({ "prompt": self.prompt }); + let body: SegmentedBytes = SegmentedBytes::from(Bytes::from(prompt_body.to_string())); + + let req = S3Request::new(client, Method::POST) + .region(self.region.as_deref()) + .bucket(Some(&self.bucket)) + .object(Some(&self.object)) + .query_params(query_params) + .headers(headers) + .body(Some(body)); + + Ok(req) + } +} + +impl S3Api for ObjectPrompt { + type S3Response = ObjectPromptResponse; +} diff --git a/src/s3/builders/put_object.rs b/src/s3/builders/put_object.rs index e6beecfb..3719340a 100644 --- a/src/s3/builders/put_object.rs +++ b/src/s3/builders/put_object.rs @@ -682,9 +682,9 @@ fn object_write_args_headers( Ok(map) } -// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3. -// -// It is a higher level API and handles multipart uploads transparently. +/// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3. +/// +/// It is a higher level API and handles multipart uploads transparently. pub struct PutObjectContent { client: Option, @@ -1048,8 +1048,8 @@ pub const MAX_PART_SIZE: u64 = 1024 * MIN_PART_SIZE; // 5 GiB pub const MAX_OBJECT_SIZE: u64 = 1024 * MAX_PART_SIZE; // 5 TiB pub const MAX_MULTIPART_COUNT: u16 = 10_000; -// Returns the size of each part to upload and the total number of parts. The -// number of parts is `None` when the object size is unknown. +/// Returns the size of each part to upload and the total number of parts. The +/// number of parts is `None` when the object size is unknown. fn calc_part_info(object_size: Size, part_size: Size) -> Result<(u64, Option), Error> { // Validate arguments against limits. if let Size::Known(v) = part_size { diff --git a/src/s3/builders/remove_objects.rs b/src/s3/builders/remove_objects.rs index 16943dd6..bb2b5407 100644 --- a/src/s3/builders/remove_objects.rs +++ b/src/s3/builders/remove_objects.rs @@ -126,10 +126,6 @@ impl RemoveObject { } } -impl S3Api for RemoveObject { - type S3Response = RemoveObjectResponse; -} - impl ToS3Request for RemoveObject { fn to_s3request(&self) -> Result { check_bucket_name(&self.bucket, true)?; @@ -160,6 +156,10 @@ impl ToS3Request for RemoveObject { } } +impl S3Api for RemoveObject { + type S3Response = RemoveObjectResponse; +} + #[derive(Debug, Clone)] pub struct RemoveObjectsApi { client: Option, @@ -302,7 +302,10 @@ impl From for DeleteObjects { } } -impl + Send + Sync + 'static> From for DeleteObjects { +impl From for DeleteObjects +where + I: Iterator + Send + Sync + 'static, +{ fn from(keys: I) -> Self { DeleteObjects::from_stream(stream_iter(keys)) } diff --git a/src/s3/client.rs b/src/s3/client.rs index 48350205..3590bc58 100644 --- a/src/s3/client.rs +++ b/src/s3/client.rs @@ -50,6 +50,7 @@ use xmltree::Element; mod get_object; mod list_objects; mod listen_bucket_notification; +mod object_prompt; mod put_object; mod remove_objects; diff --git a/src/s3/client/object_prompt.rs b/src/s3/client/object_prompt.rs new file mode 100644 index 00000000..3d62969a --- /dev/null +++ b/src/s3/client/object_prompt.rs @@ -0,0 +1,27 @@ +// MinIO Rust Library for Amazon S3 Compatible Cloud Storage +// Copyright 2024 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! S3 APIs for downloading objects. + +use crate::s3::builders::ObjectPrompt; + +use super::Client; + +impl Client { + /// Create a ObjectPrompt request builder. Prompt an object using natural language. + pub fn object_prompt(&self, bucket: &str, object: &str, prompt: &str) -> ObjectPrompt { + ObjectPrompt::new(bucket, object, prompt).client(self) + } +} diff --git a/src/s3/response.rs b/src/s3/response.rs index c1ec9842..96282185 100644 --- a/src/s3/response.rs +++ b/src/s3/response.rs @@ -35,6 +35,7 @@ mod buckets; mod get_object; pub(crate) mod list_objects; mod listen_bucket_notification; +mod object_prompt; mod put_object; mod remove_objects; @@ -42,6 +43,7 @@ pub use buckets::{GetBucketVersioningResponse, ListBucketsResponse}; pub use get_object::GetObjectResponse; pub use list_objects::ListObjectsResponse; pub use listen_bucket_notification::ListenBucketNotificationResponse; +pub use object_prompt::ObjectPromptResponse; pub use put_object::{ AbortMultipartUploadResponse2, CompleteMultipartUploadResponse2, CreateMultipartUploadResponse2, PutObjectContentResponse, PutObjectResponse, @@ -381,7 +383,7 @@ impl SelectObjectContentResponse { offset += 1; let b1 = self.data[offset] as u16; offset += 1; - length = (b0 << 8 | b1) as usize; + length = ((b0 << 8) | b1) as usize; let value = String::from_utf8(self.data[offset..offset + length].to_vec())?; offset += length; diff --git a/src/s3/response/object_prompt.rs b/src/s3/response/object_prompt.rs new file mode 100644 index 00000000..9abc1aca --- /dev/null +++ b/src/s3/response/object_prompt.rs @@ -0,0 +1,61 @@ +// MinIO Rust Library for Amazon S3 Compatible Cloud Storage +// Copyright 2024 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::s3::error::Error; +use crate::s3::types::{FromS3Response, S3Request}; +use async_trait::async_trait; + +pub struct ObjectPromptResponse { + pub headers: http::HeaderMap, + pub region: String, + pub bucket_name: String, + pub object_name: String, + pub prompt_response: String, +} + +#[async_trait] +impl FromS3Response for ObjectPromptResponse { + async fn from_s3response<'a>( + req: S3Request<'a>, + response: reqwest::Response, + ) -> Result { + let headers = response.headers().clone(); + let body = response.bytes().await?; + let prompt_response: String = String::from_utf8(body.to_vec())?; + let region: String = req.region.unwrap_or("").to_string(); // Keep this since it defaults to an empty string + + let bucket_name: String = req + .bucket + .ok_or_else(|| { + Error::InvalidBucketName(String::from("Missing bucket name in request")) + })? + .to_string(); + + let object_name: String = req + .object + .ok_or_else(|| { + Error::InvalidObjectName(String::from("Missing object name in request")) + })? + .to_string(); + + Ok(ObjectPromptResponse { + headers, + region, + bucket_name, + object_name, + prompt_response, + }) + } +} diff --git a/src/s3/response/put_object.rs b/src/s3/response/put_object.rs index e5cbae90..a5f69e35 100644 --- a/src/s3/response/put_object.rs +++ b/src/s3/response/put_object.rs @@ -74,16 +74,34 @@ impl FromS3Response for CreateMultipartUploadResponse2 { req: S3Request<'a>, response: reqwest::Response, ) -> Result { - let header_map = response.headers().clone(); + let headers = response.headers().clone(); let body = response.bytes().await?; let root = Element::parse(body.reader())?; + let region: String = req.region.unwrap_or("").to_string(); // Keep this since it defaults to an empty string + + let bucket_name: String = req + .bucket + .ok_or_else(|| { + Error::InvalidBucketName(String::from("Missing bucket name in request")) + })? + .to_string(); + + let object_name: String = req + .object + .ok_or_else(|| { + Error::InvalidObjectName(String::from("Missing object name in request")) + })? + .to_string(); + + let upload_id: String = get_text(&root, "UploadId")?; + Ok(CreateMultipartUploadResponse2 { - headers: header_map.clone(), - region: req.region.unwrap_or("").to_string(), - bucket_name: req.bucket.unwrap().to_string(), - object_name: req.object.unwrap().to_string(), - upload_id: get_text(&root, "UploadId")?, + headers, + region, + bucket_name, + object_name, + upload_id, }) } } diff --git a/src/s3/utils.rs b/src/s3/utils.rs index 9cf9716c..0e8e3bf7 100644 --- a/src/s3/utils.rs +++ b/src/s3/utils.rs @@ -335,7 +335,9 @@ pub fn match_region(value: &str) -> bool { /// Validates given bucket name pub fn check_bucket_name(bucket_name: &str, strict: bool) -> Result<(), Error> { - if bucket_name.trim().is_empty() { + let bucket_name: &str = bucket_name.trim(); + + if bucket_name.is_empty() { return Err(Error::InvalidBucketName(String::from( "bucket name cannot be empty", ))); @@ -368,20 +370,23 @@ pub fn check_bucket_name(bucket_name: &str, strict: bool) -> Result<(), Error> { } if bucket_name.contains("..") || bucket_name.contains(".-") || bucket_name.contains("-.") { - return Err(Error::InvalidBucketName(String::from( - "bucket name contains invalid successive characters '..', '.-' or '-.'", + return Err(Error::InvalidBucketName(format!( + "bucket name ('{}') contains invalid successive characters '..', '.-' or '-.'", + bucket_name ))); } if strict { if !VALID_BUCKET_NAME_STRICT_REGEX.is_match(bucket_name) { - return Err(Error::InvalidBucketName(String::from( - "bucket name does not follow S3 standards strictly", + return Err(Error::InvalidBucketName(format!( + "bucket name ('{}') does not follow S3 standards strictly", + bucket_name ))); } } else if !VALID_BUCKET_NAME_REGEX.is_match(bucket_name) { - return Err(Error::InvalidBucketName(String::from( - "bucket name does not follow S3 standards", + return Err(Error::InvalidBucketName(format!( + "bucket name ('{}') does not follow S3 standards", + bucket_name ))); } From c642843cd8304f42afc05aca3e911b1b685c2ade Mon Sep 17 00:00:00 2001 From: Jean Sainctavit Date: Tue, 19 Nov 2024 18:59:56 +0100 Subject: [PATCH 2/3] Fix ObjectContent::to_file() The ObjectContent::to_file() function was not working properly, as it could not write in a temporary file (created with tokio::fs::File::open(), which opens a file in read-only mode). To solve this issue, modified the way temporary files are opened to be able to write inside of it. --- src/s3/builders/object_content.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/s3/builders/object_content.rs b/src/s3/builders/object_content.rs index 2f6e19aa..0ba2f165 100644 --- a/src/s3/builders/object_content.rs +++ b/src/s3/builders/object_content.rs @@ -201,19 +201,21 @@ impl ObjectContent { .join(Path::new(tmp_file_name.as_os_str())); let mut total = 0; - { - let mut fp = fs::File::open(&tmp_file_path).await?; - let (mut r, _) = self.to_stream().await?; - while let Some(bytes) = r.next().await { - let bytes = bytes?; - if bytes.is_empty() { - break; - } - total += bytes.len() as u64; - fp.write_all(&bytes).await?; + let mut fp = fs::OpenOptions::new() + .write(true) + .create(true) + .open(&tmp_file_path) + .await?; + let (mut r, _) = self.to_stream().await?; + while let Some(bytes) = r.next().await { + let bytes = bytes?; + if bytes.is_empty() { + break; } - fp.flush().await?; + total += bytes.len() as u64; + fp.write_all(&bytes).await?; } + fp.flush().await?; fs::rename(&tmp_file_path, file_path).await?; Ok(total) } From b97b2f6673c1a701fc2bcda21eb1b4aa78b17660 Mon Sep 17 00:00:00 2001 From: Jean Sainctavit Date: Tue, 19 Nov 2024 19:00:09 +0100 Subject: [PATCH 3/3] Add an example to download a file This new example demonstrates how to download an object and store its content into a file. --- Cargo.toml | 4 ++ README.md | 4 ++ examples/file_downloader.rs | 75 +++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 examples/file_downloader.rs diff --git a/Cargo.toml b/Cargo.toml index 39a557b4..79725464 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,5 +63,9 @@ quickcheck = "1.0.3" [[example]] name = "file_uploader" +[[example]] +name = "file_downloader" + [[example]] name = "object_prompt" + diff --git a/README.md b/README.md index 06cc8842..f3eb3f0c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ Run the examples from the command line with: * [Upload a file to MinIO](examples/file_uploader) * [Upload a file to MinIO with CLI](examples/put_object) +### file_downloader.rs + +* [Download af file from MinIO](examples/file_downloader.rs) + ### object_prompt.rs * [Prompt a file on MinIO](examples/object_prompt) diff --git a/examples/file_downloader.rs b/examples/file_downloader.rs new file mode 100644 index 00000000..3bc22455 --- /dev/null +++ b/examples/file_downloader.rs @@ -0,0 +1,75 @@ +use minio::s3::client::ClientBuilder; +use minio::s3::creds::StaticProvider; +use minio::s3::http::BaseUrl; +use minio::s3::types::S3Api; +use std::path::Path; +use minio::s3::args::{BucketExistsArgs, MakeBucketArgs}; +use minio::s3::builders::ObjectContent; + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher + + let base_url = "https://play.min.io".parse::()?; + log::info!("Trying to connect to MinIO at: `{:?}`", base_url); + + let static_provider = StaticProvider::new( + "Q3AM3UQ867SPQQA43P2F", + "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", + None, + ); + + let client = ClientBuilder::new(base_url.clone()) + .provider(Some(Box::new(static_provider))) + .build()?; + + let bucket_name: &str = "file-download-rust-bucket"; + let object_name: &str = "cat.png"; + + // File we are going to upload to the bucket + let filename: &Path = Path::new("./examples/cat.png"); + let download_path: &str = &format!("/tmp/downloads/{object_name}"); + + // Check 'bucket_name' bucket exist or not. + let exists: bool = client + .bucket_exists(&BucketExistsArgs::new(bucket_name).unwrap()) + .await + .unwrap(); + + // Make 'bucket_name' bucket if not exist. + if !exists { + client + .make_bucket(&MakeBucketArgs::new(bucket_name).unwrap()) + .await + .unwrap(); + } + + if filename.exists() { + log::info!("File '{}' exists.", &filename.to_str().unwrap()); + } else { + log::error!("File '{}' does not exist.", &filename.to_str().unwrap()); + return Ok(()); + } + + let content = ObjectContent::from(filename); + client + .put_object_content(bucket_name, object_name, content) + .send() + .await?; + + log::info!( + "file '{}' is successfully uploaded as object '{object_name}' to bucket '{bucket_name}'.", + filename.display() + ); + + let get_object = client.get_object(bucket_name, object_name).send().await?; + + get_object + .content + .to_file(&Path::new(download_path)) + .await?; + + log::info!("Object '{object_name}' is successfully downloaded to file '{download_path}'."); + + Ok(()) +}