This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 523269117 feat(integrations/object_store): add AmazonS3Builder (#5456)
523269117 is described below

commit 523269117cb8b9933617d2e8dcfb5c020ca74835
Author: meteorgan <[email protected]>
AuthorDate: Wed Apr 23 13:25:55 2025 +0800

    feat(integrations/object_store): add AmazonS3Builder (#5456)
    
    feat(integrations/object_store): add new_amazon_s3 for OpendalStore
---
 core/src/types/scheme.rs                    |  2 +-
 integrations/object_store/Cargo.toml        |  3 +-
 integrations/object_store/examples/basic.rs | 41 +++++++--------
 integrations/object_store/src/amazon_s3.rs  | 78 +++++++++++++++++++++++++++++
 integrations/object_store/src/lib.rs        |  3 ++
 5 files changed, 100 insertions(+), 27 deletions(-)

diff --git a/core/src/types/scheme.rs b/core/src/types/scheme.rs
index e120edb4a..20efe9b93 100644
--- a/core/src/types/scheme.rs
+++ b/core/src/types/scheme.rs
@@ -161,7 +161,7 @@ pub enum Scheme {
     Lakefs,
     /// [NebulaGraph](crate::services::NebulaGraph): NebulaGraph Services
     NebulaGraph,
-    /// Custom that allow users to implement services outside of OpenDAL.
+    /// Custom that allow users to implement services outside OpenDAL.
     ///
     /// # NOTE
     ///
diff --git a/integrations/object_store/Cargo.toml 
b/integrations/object_store/Cargo.toml
index 63b5dcaa8..2e2ea1cd5 100644
--- a/integrations/object_store/Cargo.toml
+++ b/integrations/object_store/Cargo.toml
@@ -29,6 +29,7 @@ version = "0.51.1"
 
 [features]
 send_wrapper = ["dep:send_wrapper"]
+services-s3 = ["opendal/services-s3", "object_store/aws"]
 
 [[test]]
 harness = false
@@ -38,9 +39,7 @@ path = "tests/behavior/main.rs"
 [dependencies]
 async-trait = "0.1"
 bytes = "1"
-flagset = "0.4"
 futures = "0.3"
-futures-util = "0.3"
 object_store = "0.11"
 opendal = { version = "0.53.0", path = "../../core", default-features = false }
 pin-project = "1.1"
diff --git a/integrations/object_store/examples/basic.rs 
b/integrations/object_store/examples/basic.rs
index 0157d5e4a..eaf4a18e5 100644
--- a/integrations/object_store/examples/basic.rs
+++ b/integrations/object_store/examples/basic.rs
@@ -1,39 +1,32 @@
-use std::sync::Arc;
-
 use bytes::Bytes;
+#[cfg(feature = "services-s3")]
+use object_store::aws::AmazonS3Builder;
 use object_store::path::Path;
 use object_store::ObjectStore;
 use object_store_opendal::OpendalStore;
-use opendal::services::S3Config;
-use opendal::Operator;
 
+#[cfg(feature = "services-s3")]
 #[tokio::main]
 async fn main() {
-    let mut cfg = S3Config::default();
-    cfg.access_key_id = Some("my_access_key".to_string());
-    cfg.secret_access_key = Some("my_secret_key".to_string());
-    cfg.endpoint = Some("my_endpoint".to_string());
-    cfg.region = Some("my_region".to_string());
-    cfg.bucket = "my_bucket".to_string();
-
-    // Create a new operator
-    let operator = Operator::from_config(cfg).unwrap().finish();
-
-    // Create a new object store
-    let object_store = Arc::new(OpendalStore::new(operator));
+    let builder = AmazonS3Builder::default()
+        .with_bucket_name("my_bucket")
+        .with_region("my_region")
+        .with_endpoint("my_endpoint")
+        .with_access_key_id("my_access_key")
+        .with_secret_access_key("my_secret_access_key");
+    let s3_store = OpendalStore::new_amazon_s3(builder).unwrap();
 
     let path = Path::from("data/nested/test.txt");
     let bytes = Bytes::from_static(b"hello, world! I am nested.");
 
-    object_store.put(&path, bytes.clone().into()).await.unwrap();
+    s3_store.put(&path, bytes.clone().into()).await.unwrap();
 
-    let content = object_store
-        .get(&path)
-        .await
-        .unwrap()
-        .bytes()
-        .await
-        .unwrap();
+    let content = s3_store.get(&path).await.unwrap().bytes().await.unwrap();
 
     assert_eq!(content, bytes);
 }
+
+#[cfg(not(feature = "services-s3"))]
+fn main() {
+    println!("The 'services-s3' feature is not enabled.");
+}
diff --git a/integrations/object_store/src/amazon_s3.rs 
b/integrations/object_store/src/amazon_s3.rs
new file mode 100644
index 000000000..207c3c7e4
--- /dev/null
+++ b/integrations/object_store/src/amazon_s3.rs
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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::utils::format_object_store_error;
+use crate::OpendalStore;
+use object_store::aws::{AmazonS3Builder, AmazonS3ConfigKey};
+use opendal::services::S3;
+use opendal::Operator;
+
+impl OpendalStore {
+    /// Create OpendalStore from object_store Amazon S3 builder.
+    pub fn new_amazon_s3(builder: AmazonS3Builder) -> 
object_store::Result<OpendalStore> {
+        let mut s3 = S3::default();
+        if let Some(endpoint) = 
builder.get_config_value(&AmazonS3ConfigKey::Endpoint) {
+            s3 = s3.endpoint(endpoint.as_str());
+        }
+        if let Some(region) = 
builder.get_config_value(&AmazonS3ConfigKey::Region) {
+            s3 = s3.region(region.as_str());
+        }
+        if let Some(bucket_name) = 
builder.get_config_value(&AmazonS3ConfigKey::Bucket) {
+            s3 = s3.bucket(bucket_name.as_str());
+        }
+        if let Some(access_key_id) = 
builder.get_config_value(&AmazonS3ConfigKey::AccessKeyId) {
+            s3 = s3.access_key_id(access_key_id.as_str());
+        }
+        if let Some(secret_access_key) =
+            builder.get_config_value(&AmazonS3ConfigKey::SecretAccessKey)
+        {
+            s3 = s3.secret_access_key(secret_access_key.as_str());
+        }
+        if let Some(token) = 
builder.get_config_value(&AmazonS3ConfigKey::Token) {
+            s3 = s3.session_token(token.as_str());
+        }
+        if let Some(virtual_hosted_style_request) =
+            
builder.get_config_value(&AmazonS3ConfigKey::VirtualHostedStyleRequest)
+        {
+            let r = virtual_hosted_style_request
+                .parse::<bool>()
+                .map_err(|err| object_store::Error::Generic {
+                    store: "s3",
+                    source: Box::new(err),
+                })?;
+            if r {
+                s3 = s3.enable_virtual_host_style();
+            }
+        }
+        if let Some(skip_signature) = 
builder.get_config_value(&AmazonS3ConfigKey::SkipSignature) {
+            let r = skip_signature
+                .parse::<bool>()
+                .map_err(|err| object_store::Error::Generic {
+                    store: "s3",
+                    source: Box::new(err),
+                })?;
+            if r {
+                s3 = s3.allow_anonymous();
+            }
+        }
+
+        let op = Operator::new(s3)
+            .map_err(|err| format_object_store_error(err, ""))?
+            .finish();
+        Ok(OpendalStore::new(op))
+    }
+}
diff --git a/integrations/object_store/src/lib.rs 
b/integrations/object_store/src/lib.rs
index f9951b8ce..60a7126cd 100644
--- a/integrations/object_store/src/lib.rs
+++ b/integrations/object_store/src/lib.rs
@@ -65,6 +65,9 @@ pub use store::OpendalStore;
 
 mod utils;
 
+#[cfg(feature = "services-s3")]
+mod amazon_s3;
+
 // Make sure `send_wrapper` works as expected
 #[cfg(all(feature = "send_wrapper", test))]
 mod assert_send {

Reply via email to