mirror of
https://github.com/minio/minio-rs.git
synced 2025-12-06 15:26:51 +08:00
Added object_prompt support (#109)
This commit is contained in:
parent
8facff7bad
commit
0438f044ff
@ -36,7 +36,7 @@ futures-util = "0.3.31"
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
hmac = "0.12.1"
|
hmac = "0.12.1"
|
||||||
home = "0.5.9"
|
home = "0.5.9"
|
||||||
http = "1.1.0"
|
http = "1.2.0"
|
||||||
hyper = { version = "1.5.1", features = ["full"] }
|
hyper = { version = "1.5.1", features = ["full"] }
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
@ -61,4 +61,7 @@ clap = { version = "4.5.23", features = ["derive"] }
|
|||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "file-uploader"
|
name = "file_uploader"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "object_prompt"
|
||||||
|
|||||||
14
README.md
14
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/)
|
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 <example_name>`
|
||||||
|
|
||||||
|
### 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
|
## 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.
|
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.
|
||||||
|
|||||||
BIN
examples/cat.png
Normal file
BIN
examples/cat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@ -1,4 +1,18 @@
|
|||||||
use log::info;
|
// 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::args::{BucketExistsArgs, MakeBucketArgs};
|
||||||
use minio::s3::builders::ObjectContent;
|
use minio::s3::builders::ObjectContent;
|
||||||
use minio::s3::client::ClientBuilder;
|
use minio::s3::client::ClientBuilder;
|
||||||
@ -11,8 +25,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher
|
env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher
|
||||||
|
|
||||||
let base_url = "https://play.min.io".parse::<BaseUrl>()?;
|
let base_url = "https://play.min.io".parse::<BaseUrl>()?;
|
||||||
|
log::info!("Trying to connect to MinIO at: `{:?}`", base_url);
|
||||||
info!("Trying to connect to MinIO at: `{:?}`", base_url);
|
|
||||||
|
|
||||||
let static_provider = StaticProvider::new(
|
let static_provider = StaticProvider::new(
|
||||||
"Q3AM3UQ867SPQQA43P2F",
|
"Q3AM3UQ867SPQQA43P2F",
|
||||||
@ -24,7 +37,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.provider(Some(Box::new(static_provider)))
|
.provider(Some(Box::new(static_provider)))
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
let bucket_name: &str = "asiatrip";
|
let bucket_name: &str = "file-upload-rust-bucket";
|
||||||
|
|
||||||
// Check 'bucket_name' bucket exist or not.
|
// Check 'bucket_name' bucket exist or not.
|
||||||
let exists: bool = client
|
let exists: bool = client
|
||||||
@ -41,12 +54,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// File we are going to upload to the bucket
|
// 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
|
// 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);
|
let content = ObjectContent::from(filename);
|
||||||
client
|
client
|
||||||
@ -54,8 +72,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
info!(
|
log::info!(
|
||||||
"file `{}` is successfully uploaded as object `{object_name}` to bucket `{bucket_name}`.",
|
"file '{}' is successfully uploaded as object '{object_name}' to bucket '{bucket_name}'.",
|
||||||
filename.display()
|
filename.display()
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
90
examples/object_prompt.rs
Normal file
90
examples/object_prompt.rs
Normal file
@ -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<dyn std::error::Error + Send + Sync>> {
|
||||||
|
env_logger::init(); // Note: set environment variable RUST_LOG="INFO" to log info and higher
|
||||||
|
|
||||||
|
let base_url = "https://play.min.io".parse::<BaseUrl>()?;
|
||||||
|
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(())
|
||||||
|
}
|
||||||
@ -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");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
@ -17,6 +20,7 @@ mod get_object;
|
|||||||
mod list_objects;
|
mod list_objects;
|
||||||
mod listen_bucket_notification;
|
mod listen_bucket_notification;
|
||||||
mod object_content;
|
mod object_content;
|
||||||
|
mod object_prompt;
|
||||||
mod put_object;
|
mod put_object;
|
||||||
mod remove_objects;
|
mod remove_objects;
|
||||||
|
|
||||||
@ -25,5 +29,6 @@ pub use get_object::*;
|
|||||||
pub use list_objects::*;
|
pub use list_objects::*;
|
||||||
pub use listen_bucket_notification::*;
|
pub use listen_bucket_notification::*;
|
||||||
pub use object_content::*;
|
pub use object_content::*;
|
||||||
|
pub use object_prompt::*;
|
||||||
pub use put_object::*;
|
pub use put_object::*;
|
||||||
pub use remove_objects::*;
|
pub use remove_objects::*;
|
||||||
|
|||||||
@ -178,8 +178,7 @@ impl ToS3Request for GetObject {
|
|||||||
"object name cannot be empty",
|
"object name cannot be empty",
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
let client: &Client = self.client.as_ref().ok_or(Error::NoClientProvided)?;
|
||||||
let client = self.client.clone().ok_or(Error::NoClientProvided)?;
|
|
||||||
|
|
||||||
if self.ssec.is_some() && !client.is_secure() {
|
if self.ssec.is_some() && !client.is_secure() {
|
||||||
return Err(Error::SseTlsRequired(None));
|
return Err(Error::SseTlsRequired(None));
|
||||||
@ -199,15 +198,12 @@ impl ToS3Request for GetObject {
|
|||||||
query_params.insert(String::from("versionId"), v.to_string());
|
query_params.insert(String::from("versionId"), v.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let req = S3Request::new(
|
let req = S3Request::new(client, Method::GET)
|
||||||
self.client.as_ref().ok_or(Error::NoClientProvided)?,
|
.region(self.region.as_deref())
|
||||||
Method::GET,
|
.bucket(Some(&self.bucket))
|
||||||
)
|
.object(Some(&self.object))
|
||||||
.region(self.region.as_deref())
|
.query_params(query_params)
|
||||||
.bucket(Some(&self.bucket))
|
.headers(headers);
|
||||||
.object(Some(&self.object))
|
|
||||||
.query_params(query_params)
|
|
||||||
.headers(headers);
|
|
||||||
|
|
||||||
Ok(req)
|
Ok(req)
|
||||||
}
|
}
|
||||||
|
|||||||
156
src/s3/builders/object_prompt.rs
Normal file
156
src/s3/builders/object_prompt.rs
Normal file
@ -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<Client>,
|
||||||
|
bucket: String,
|
||||||
|
object: String,
|
||||||
|
prompt: String,
|
||||||
|
lambda_arn: Option<String>,
|
||||||
|
|
||||||
|
version_id: Option<String>,
|
||||||
|
region: Option<String>,
|
||||||
|
ssec: Option<SseCustomerKey>,
|
||||||
|
extra_headers: Option<Multimap>,
|
||||||
|
extra_query_params: Option<Multimap>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<Multimap>) -> Self {
|
||||||
|
self.extra_headers = extra_headers;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extra_query_params(mut self, extra_query_params: Option<Multimap>) -> Self {
|
||||||
|
self.extra_query_params = extra_query_params;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version_id(mut self, version_id: Option<String>) -> Self {
|
||||||
|
self.version_id = version_id;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn region(mut self, region: Option<String>) -> Self {
|
||||||
|
self.region = region;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ssec(mut self, ssec: Option<SseCustomerKey>) -> 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<S3Request, Error> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
@ -682,9 +682,9 @@ fn object_write_args_headers(
|
|||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3.
|
/// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3.
|
||||||
//
|
///
|
||||||
// It is a higher level API and handles multipart uploads transparently.
|
/// It is a higher level API and handles multipart uploads transparently.
|
||||||
pub struct PutObjectContent {
|
pub struct PutObjectContent {
|
||||||
client: Option<Client>,
|
client: Option<Client>,
|
||||||
|
|
||||||
@ -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_OBJECT_SIZE: u64 = 1024 * MAX_PART_SIZE; // 5 TiB
|
||||||
pub const MAX_MULTIPART_COUNT: u16 = 10_000;
|
pub const MAX_MULTIPART_COUNT: u16 = 10_000;
|
||||||
|
|
||||||
// Returns the size of each part to upload and the total number of parts. The
|
/// 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.
|
/// number of parts is `None` when the object size is unknown.
|
||||||
fn calc_part_info(object_size: Size, part_size: Size) -> Result<(u64, Option<u16>), Error> {
|
fn calc_part_info(object_size: Size, part_size: Size) -> Result<(u64, Option<u16>), Error> {
|
||||||
// Validate arguments against limits.
|
// Validate arguments against limits.
|
||||||
if let Size::Known(v) = part_size {
|
if let Size::Known(v) = part_size {
|
||||||
|
|||||||
@ -126,10 +126,6 @@ impl RemoveObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl S3Api for RemoveObject {
|
|
||||||
type S3Response = RemoveObjectResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToS3Request for RemoveObject {
|
impl ToS3Request for RemoveObject {
|
||||||
fn to_s3request(&self) -> Result<S3Request, Error> {
|
fn to_s3request(&self) -> Result<S3Request, Error> {
|
||||||
check_bucket_name(&self.bucket, true)?;
|
check_bucket_name(&self.bucket, true)?;
|
||||||
@ -160,6 +156,10 @@ impl ToS3Request for RemoveObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl S3Api for RemoveObject {
|
||||||
|
type S3Response = RemoveObjectResponse;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RemoveObjectsApi {
|
pub struct RemoveObjectsApi {
|
||||||
client: Option<ClientCore>,
|
client: Option<ClientCore>,
|
||||||
@ -302,7 +302,10 @@ impl From<ObjectToDelete> for DeleteObjects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Iterator<Item = ObjectToDelete> + Send + Sync + 'static> From<I> for DeleteObjects {
|
impl<I> From<I> for DeleteObjects
|
||||||
|
where
|
||||||
|
I: Iterator<Item = ObjectToDelete> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn from(keys: I) -> Self {
|
fn from(keys: I) -> Self {
|
||||||
DeleteObjects::from_stream(stream_iter(keys))
|
DeleteObjects::from_stream(stream_iter(keys))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,7 @@ use xmltree::Element;
|
|||||||
mod get_object;
|
mod get_object;
|
||||||
mod list_objects;
|
mod list_objects;
|
||||||
mod listen_bucket_notification;
|
mod listen_bucket_notification;
|
||||||
|
mod object_prompt;
|
||||||
mod put_object;
|
mod put_object;
|
||||||
mod remove_objects;
|
mod remove_objects;
|
||||||
|
|
||||||
|
|||||||
27
src/s3/client/object_prompt.rs
Normal file
27
src/s3/client/object_prompt.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,6 +35,7 @@ mod buckets;
|
|||||||
mod get_object;
|
mod get_object;
|
||||||
pub(crate) mod list_objects;
|
pub(crate) mod list_objects;
|
||||||
mod listen_bucket_notification;
|
mod listen_bucket_notification;
|
||||||
|
mod object_prompt;
|
||||||
mod put_object;
|
mod put_object;
|
||||||
mod remove_objects;
|
mod remove_objects;
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ pub use buckets::{GetBucketVersioningResponse, ListBucketsResponse};
|
|||||||
pub use get_object::GetObjectResponse;
|
pub use get_object::GetObjectResponse;
|
||||||
pub use list_objects::ListObjectsResponse;
|
pub use list_objects::ListObjectsResponse;
|
||||||
pub use listen_bucket_notification::ListenBucketNotificationResponse;
|
pub use listen_bucket_notification::ListenBucketNotificationResponse;
|
||||||
|
pub use object_prompt::ObjectPromptResponse;
|
||||||
pub use put_object::{
|
pub use put_object::{
|
||||||
AbortMultipartUploadResponse2, CompleteMultipartUploadResponse2,
|
AbortMultipartUploadResponse2, CompleteMultipartUploadResponse2,
|
||||||
CreateMultipartUploadResponse2, PutObjectContentResponse, PutObjectResponse,
|
CreateMultipartUploadResponse2, PutObjectContentResponse, PutObjectResponse,
|
||||||
@ -381,7 +383,7 @@ impl SelectObjectContentResponse {
|
|||||||
offset += 1;
|
offset += 1;
|
||||||
let b1 = self.data[offset] as u16;
|
let b1 = self.data[offset] as u16;
|
||||||
offset += 1;
|
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())?;
|
let value = String::from_utf8(self.data[offset..offset + length].to_vec())?;
|
||||||
offset += length;
|
offset += length;
|
||||||
|
|||||||
61
src/s3/response/object_prompt.rs
Normal file
61
src/s3/response/object_prompt.rs
Normal file
@ -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<Self, Error> {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -74,16 +74,34 @@ impl FromS3Response for CreateMultipartUploadResponse2 {
|
|||||||
req: S3Request<'a>,
|
req: S3Request<'a>,
|
||||||
response: reqwest::Response,
|
response: reqwest::Response,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let header_map = response.headers().clone();
|
let headers = response.headers().clone();
|
||||||
let body = response.bytes().await?;
|
let body = response.bytes().await?;
|
||||||
let root = Element::parse(body.reader())?;
|
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 {
|
Ok(CreateMultipartUploadResponse2 {
|
||||||
headers: header_map.clone(),
|
headers,
|
||||||
region: req.region.unwrap_or("").to_string(),
|
region,
|
||||||
bucket_name: req.bucket.unwrap().to_string(),
|
bucket_name,
|
||||||
object_name: req.object.unwrap().to_string(),
|
object_name,
|
||||||
upload_id: get_text(&root, "UploadId")?,
|
upload_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -335,7 +335,9 @@ pub fn match_region(value: &str) -> bool {
|
|||||||
|
|
||||||
/// Validates given bucket name
|
/// Validates given bucket name
|
||||||
pub fn check_bucket_name(bucket_name: &str, strict: bool) -> Result<(), Error> {
|
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(
|
return Err(Error::InvalidBucketName(String::from(
|
||||||
"bucket name cannot be empty",
|
"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("-.") {
|
if bucket_name.contains("..") || bucket_name.contains(".-") || bucket_name.contains("-.") {
|
||||||
return Err(Error::InvalidBucketName(String::from(
|
return Err(Error::InvalidBucketName(format!(
|
||||||
"bucket name contains invalid successive characters '..', '.-' or '-.'",
|
"bucket name ('{}') contains invalid successive characters '..', '.-' or '-.'",
|
||||||
|
bucket_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if strict {
|
if strict {
|
||||||
if !VALID_BUCKET_NAME_STRICT_REGEX.is_match(bucket_name) {
|
if !VALID_BUCKET_NAME_STRICT_REGEX.is_match(bucket_name) {
|
||||||
return Err(Error::InvalidBucketName(String::from(
|
return Err(Error::InvalidBucketName(format!(
|
||||||
"bucket name does not follow S3 standards strictly",
|
"bucket name ('{}') does not follow S3 standards strictly",
|
||||||
|
bucket_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
} else if !VALID_BUCKET_NAME_REGEX.is_match(bucket_name) {
|
} else if !VALID_BUCKET_NAME_REGEX.is_match(bucket_name) {
|
||||||
return Err(Error::InvalidBucketName(String::from(
|
return Err(Error::InvalidBucketName(format!(
|
||||||
"bucket name does not follow S3 standards",
|
"bucket name ('{}') does not follow S3 standards",
|
||||||
|
bucket_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user