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/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 5dfc3c29f refactor(services/azblob): add AzblobConfig (#3553)
5dfc3c29f is described below

commit 5dfc3c29fb3975d9ab5377412698b82aa23836c4
Author: Au <[email protected]>
AuthorDate: Sat Nov 11 15:24:10 2023 +0800

    refactor(services/azblob): add AzblobConfig (#3553)
    
    * refactor(services/azblob): add AzblobConfig
    
    * docs: add comments to Azblob Config
    
    * feat(services/azblob): impl from_map based on AzblobConfig
---
 core/src/services/azblob/backend.rs | 188 ++++++++++++++++++++++--------------
 core/src/services/azblob/mod.rs     |   1 +
 core/src/services/mod.rs            |   2 +
 3 files changed, 116 insertions(+), 75 deletions(-)

diff --git a/core/src/services/azblob/backend.rs 
b/core/src/services/azblob/backend.rs
index 6d6f5612d..acd29e74d 100644
--- a/core/src/services/azblob/backend.rs
+++ b/core/src/services/azblob/backend.rs
@@ -29,6 +29,7 @@ use log::debug;
 use reqsign::AzureStorageConfig;
 use reqsign::AzureStorageLoader;
 use reqsign::AzureStorageSigner;
+use serde::Deserialize;
 use sha2::Digest;
 use sha2::Sha256;
 
@@ -53,25 +54,49 @@ const KNOWN_AZBLOB_ENDPOINT_SUFFIX: &[&str] = &[
 
 const AZBLOB_BATCH_LIMIT: usize = 256;
 /// Azure Storage Blob services support.
-#[doc = include_str!("docs.md")]
-#[derive(Default, Clone)]
-pub struct AzblobBuilder {
-    root: Option<String>,
-    container: String,
-    endpoint: Option<String>,
-    account_name: Option<String>,
-    account_key: Option<String>,
-    encryption_key: Option<String>,
-    encryption_key_sha256: Option<String>,
-    encryption_algorithm: Option<String>,
-    sas_token: Option<String>,
-    http_client: Option<HttpClient>,
-    batch_max_operations: Option<usize>,
+#[derive(Default, Deserialize, Clone)]
+pub struct AzblobConfig {
+    /// The root of Azblob service backend.
+    ///
+    /// All operations will happen under this root.
+    pub root: Option<String>,
+
+    /// The container name of Azblob service backend.
+    pub container: String,
+
+    /// The endpoint of Azblob service backend.
+    ///
+    /// Endpoint must be full uri, e.g.
+    ///
+    /// - Azblob: `https://accountname.blob.core.windows.net`
+    /// - Azurite: `http://127.0.0.1:10000/devstoreaccount1`
+    pub endpoint: Option<String>,
+
+    /// The account name of Azblob service backend.
+    pub account_name: Option<String>,
+
+    /// The account key of Azblob service backend.
+    pub account_key: Option<String>,
+
+    /// The encryption key of Azblob service backend.
+    pub encryption_key: Option<String>,
+
+    /// The encryption key sha256 of Azblob service backend.
+    pub encryption_key_sha256: Option<String>,
+
+    /// The encryption algorithm of Azblob service backend.
+    pub encryption_algorithm: Option<String>,
+
+    /// The sas token of Azblob service backend.
+    pub sas_token: Option<String>,
+
+    /// The maximum batch operations of Azblob service backend.
+    pub batch_max_operations: Option<usize>,
 }
 
-impl Debug for AzblobBuilder {
+impl Debug for AzblobConfig {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        let mut ds = f.debug_struct("Builder");
+        let mut ds = f.debug_struct("AzblobConfig");
 
         ds.field("root", &self.root);
         ds.field("container", &self.container);
@@ -91,13 +116,30 @@ impl Debug for AzblobBuilder {
     }
 }
 
+#[doc = include_str!("docs.md")]
+#[derive(Default, Clone)]
+pub struct AzblobBuilder {
+    config: AzblobConfig,
+    http_client: Option<HttpClient>,
+}
+
+impl Debug for AzblobBuilder {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let mut ds = f.debug_struct("Builder");
+
+        ds.field("config", &self.config);
+
+        ds.finish()
+    }
+}
+
 impl AzblobBuilder {
     /// Set root of this backend.
     ///
     /// All operations will happen under this root.
     pub fn root(&mut self, root: &str) -> &mut Self {
         if !root.is_empty() {
-            self.root = Some(root.to_string())
+            self.config.root = Some(root.to_string())
         }
 
         self
@@ -105,12 +147,12 @@ impl AzblobBuilder {
 
     /// Set container name of this backend.
     pub fn container(&mut self, container: &str) -> &mut Self {
-        self.container = container.to_string();
+        self.config.container = container.to_string();
 
         self
     }
 
-    /// Set endpoint of this backend.
+    /// Set endpoint of this backend
     ///
     /// Endpoint must be full uri, e.g.
     ///
@@ -119,7 +161,7 @@ impl AzblobBuilder {
     pub fn endpoint(&mut self, endpoint: &str) -> &mut Self {
         if !endpoint.is_empty() {
             // Trim trailing `/` so that we can accept `http://127.0.0.1:9000/`
-            self.endpoint = Some(endpoint.trim_end_matches('/').to_string());
+            self.config.endpoint = 
Some(endpoint.trim_end_matches('/').to_string());
         }
 
         self
@@ -131,7 +173,7 @@ impl AzblobBuilder {
     /// - If not, we will try to load it from environment.
     pub fn account_name(&mut self, account_name: &str) -> &mut Self {
         if !account_name.is_empty() {
-            self.account_name = Some(account_name.to_string());
+            self.config.account_name = Some(account_name.to_string());
         }
 
         self
@@ -143,7 +185,7 @@ impl AzblobBuilder {
     /// - If not, we will try to load it from environment.
     pub fn account_key(&mut self, account_key: &str) -> &mut Self {
         if !account_key.is_empty() {
-            self.account_key = Some(account_key.to_string());
+            self.config.account_key = Some(account_key.to_string());
         }
 
         self
@@ -163,7 +205,7 @@ impl AzblobBuilder {
     /// Please use `server_side_encryption_with_*` helpers if even possible.
     pub fn encryption_key(&mut self, v: &str) -> &mut Self {
         if !v.is_empty() {
-            self.encryption_key = Some(v.to_string());
+            self.config.encryption_key = Some(v.to_string());
         }
 
         self
@@ -183,7 +225,7 @@ impl AzblobBuilder {
     /// Please use `server_side_encryption_with_*` helpers if even possible.
     pub fn encryption_key_sha256(&mut self, v: &str) -> &mut Self {
         if !v.is_empty() {
-            self.encryption_key_sha256 = Some(v.to_string());
+            self.config.encryption_key_sha256 = Some(v.to_string());
         }
 
         self
@@ -203,7 +245,7 @@ impl AzblobBuilder {
     /// Please use `server_side_encryption_with_*` helpers if even possible.
     pub fn encryption_algorithm(&mut self, v: &str) -> &mut Self {
         if !v.is_empty() {
-            self.encryption_algorithm = Some(v.to_string());
+            self.config.encryption_algorithm = Some(v.to_string());
         }
 
         self
@@ -224,9 +266,10 @@ impl AzblobBuilder {
     /// for more info.
     pub fn server_side_encryption_with_customer_key(&mut self, key: &[u8]) -> 
&mut Self {
         // Only AES256 is supported for now
-        self.encryption_algorithm = Some("AES256".to_string());
-        self.encryption_key = Some(BASE64_STANDARD.encode(key));
-        self.encryption_key_sha256 = 
Some(BASE64_STANDARD.encode(Sha256::digest(key).as_slice()));
+        self.config.encryption_algorithm = Some("AES256".to_string());
+        self.config.encryption_key = Some(BASE64_STANDARD.encode(key));
+        self.config.encryption_key_sha256 =
+            Some(BASE64_STANDARD.encode(Sha256::digest(key).as_slice()));
         self
     }
 
@@ -239,7 +282,7 @@ impl AzblobBuilder {
     /// for more info.
     pub fn sas_token(&mut self, sas_token: &str) -> &mut Self {
         if !sas_token.is_empty() {
-            self.sas_token = Some(sas_token.to_string());
+            self.config.sas_token = Some(sas_token.to_string());
         }
 
         self
@@ -258,7 +301,7 @@ impl AzblobBuilder {
 
     /// Set maximum batch operations of this backend.
     pub fn batch_max_operations(&mut self, batch_max_operations: usize) -> 
&mut Self {
-        self.batch_max_operations = Some(batch_max_operations);
+        self.config.batch_max_operations = Some(batch_max_operations);
 
         self
     }
@@ -331,6 +374,7 @@ impl AzblobBuilder {
         } else if let Some(v) = conn_map.get("EndpointSuffix") {
             let protocol = 
conn_map.get("DefaultEndpointsProtocol").unwrap_or(&"https");
             let account_name = builder
+                .config
                 .account_name
                 .as_ref()
                 .ok_or_else(|| {
@@ -353,41 +397,31 @@ impl Builder for AzblobBuilder {
     type Accessor = AzblobBackend;
 
     fn from_map(map: HashMap<String, String>) -> Self {
-        let mut builder = AzblobBuilder::default();
+        let config = AzblobConfig::deserialize(ConfigDeserializer::new(map))
+            .expect("config deserialize must succeed");
 
-        map.get("root").map(|v| builder.root(v));
-        map.get("container").map(|v| builder.container(v));
-        map.get("endpoint").map(|v| builder.endpoint(v));
-        map.get("account_name").map(|v| builder.account_name(v));
-        map.get("account_key").map(|v| builder.account_key(v));
-        map.get("encryption_key").map(|v| builder.encryption_key(v));
-        map.get("encryption_key_sha256")
-            .map(|v| builder.encryption_key_sha256(v));
-        map.get("encryption_algorithm")
-            .map(|v| builder.encryption_algorithm(v));
-        map.get("sas_token").map(|v| builder.sas_token(v));
-        map.get("batch_max_operations")
-            .map(|v| 
builder.batch_max_operations(v.parse::<usize>().unwrap()));
-
-        builder
+        AzblobBuilder {
+            config,
+            http_client: None,
+        }
     }
 
     fn build(&mut self) -> Result<Self::Accessor> {
         debug!("backend build started: {:?}", &self);
 
-        let root = normalize_root(&self.root.take().unwrap_or_default());
+        let root = 
normalize_root(&self.config.root.take().unwrap_or_default());
         debug!("backend use root {}", root);
 
         // Handle endpoint, region and container name.
-        let container = match self.container.is_empty() {
-            false => Ok(&self.container),
+        let container = match self.config.container.is_empty() {
+            false => Ok(&self.config.container),
             true => Err(Error::new(ErrorKind::ConfigInvalid, "container is 
empty")
                 .with_operation("Builder::build")
                 .with_context("service", Scheme::Azblob)),
         }?;
         debug!("backend use container {}", &container);
 
-        let endpoint = match &self.endpoint {
+        let endpoint = match &self.config.endpoint {
             Some(endpoint) => Ok(endpoint.clone()),
             None => Err(Error::new(ErrorKind::ConfigInvalid, "endpoint is 
empty")
                 .with_operation("Builder::build")
@@ -406,30 +440,31 @@ impl Builder for AzblobBuilder {
 
         let config_loader = AzureStorageConfig {
             account_name: self
+                .config
                 .account_name
                 .clone()
                 .or_else(|| 
infer_storage_name_from_endpoint(endpoint.as_str())),
-            account_key: self.account_key.clone(),
-            sas_token: self.sas_token.clone(),
+            account_key: self.config.account_key.clone(),
+            sas_token: self.config.sas_token.clone(),
             ..Default::default()
         };
 
         let encryption_key =
-            match &self.encryption_key {
+            match &self.config.encryption_key {
                 None => None,
                 Some(v) => Some(build_header_value(v).map_err(|err| {
                     err.with_context("key", 
"server_side_encryption_customer_key")
                 })?),
             };
 
-        let encryption_key_sha256 = match &self.encryption_key_sha256 {
+        let encryption_key_sha256 = match &self.config.encryption_key_sha256 {
             None => None,
             Some(v) => Some(build_header_value(v).map_err(|err| {
                 err.with_context("key", 
"server_side_encryption_customer_key_sha256")
             })?),
         };
 
-        let encryption_algorithm = match &self.encryption_algorithm {
+        let encryption_algorithm = match &self.config.encryption_algorithm {
             None => None,
             Some(v) => {
                 if v == "AES256" {
@@ -449,7 +484,10 @@ impl Builder for AzblobBuilder {
 
         let signer = AzureStorageSigner::new();
 
-        let batch_max_operations = 
self.batch_max_operations.unwrap_or(AZBLOB_BATCH_LIMIT);
+        let batch_max_operations = self
+            .config
+            .batch_max_operations
+            .unwrap_or(AZBLOB_BATCH_LIMIT);
 
         debug!("backend build finished: {:?}", &self);
         Ok(AzblobBackend {
@@ -459,14 +497,14 @@ impl Builder for AzblobBuilder {
                 encryption_key,
                 encryption_key_sha256,
                 encryption_algorithm,
-                container: self.container.clone(),
+                container: self.config.container.clone(),
 
                 client,
                 loader: cred_loader,
                 signer,
                 batch_max_operations,
             }),
-            has_sas_token: self.sas_token.is_some(),
+            has_sas_token: self.config.sas_token.is_some(),
         })
     }
 }
@@ -793,7 +831,7 @@ mod tests {
         assert_eq!(azblob.core.container, "container".to_string());
 
         assert_eq!(
-            azblob_builder.account_key.unwrap(),
+            azblob_builder.config.account_key.unwrap(),
             "account-key".to_string()
         );
     }
@@ -814,7 +852,7 @@ mod tests {
 
         assert_eq!(azblob.core.container, "container".to_string());
 
-        assert_eq!(azblob_builder.account_key, None);
+        assert_eq!(azblob_builder.config.account_key, None);
     }
 
     #[test]
@@ -837,11 +875,11 @@ mod tests {
         assert_eq!(azblob.core.container, "container".to_string());
 
         assert_eq!(
-            azblob_builder.account_key.unwrap(),
+            azblob_builder.config.account_key.unwrap(),
             "account-key".to_string()
         );
 
-        assert_eq!(azblob_builder.sas_token.unwrap(), "sas".to_string());
+        assert_eq!(azblob_builder.config.sas_token.unwrap(), 
"sas".to_string());
     }
 
     #[test]
@@ -858,11 +896,11 @@ TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;
         .expect("from connection string must succeed");
 
         assert_eq!(
-            builder.endpoint.unwrap(),
+            builder.config.endpoint.unwrap(),
             "http://127.0.0.1:10000/devstoreaccount1";
         );
-        assert_eq!(builder.account_name.unwrap(), "devstoreaccount1");
-        assert_eq!(builder.account_key.unwrap(), 
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");
+        assert_eq!(builder.config.account_name.unwrap(), "devstoreaccount1");
+        assert_eq!(builder.config.account_key.unwrap(), 
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");
 
         let builder = AzblobBuilder::from_connection_string(
             r#"
@@ -875,11 +913,11 @@ EndpointSuffix=core.chinacloudapi.cn;
         .expect("from connection string must succeed");
 
         assert_eq!(
-            builder.endpoint.unwrap(),
+            builder.config.endpoint.unwrap(),
             "https://storagesample.blob.core.chinacloudapi.cn";
         );
-        assert_eq!(builder.account_name.unwrap(), "storagesample");
-        assert_eq!(builder.account_key.unwrap(), "account-key")
+        assert_eq!(builder.config.account_name.unwrap(), "storagesample");
+        assert_eq!(builder.config.account_key.unwrap(), "account-key")
     }
 
     #[test]
@@ -896,12 +934,12 @@ 
SharedAccessSignature=sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:0
         .expect("from connection string must succeed");
 
         assert_eq!(
-            builder.endpoint.unwrap(),
+            builder.config.endpoint.unwrap(),
             "http://127.0.0.1:10000/devstoreaccount1";
         );
-        assert_eq!(builder.sas_token.unwrap(), 
"sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:00:14Z&st=2022-01-02T03:00:14Z&spr=https&sig=KEllk4N8f7rJfLjQCmikL2fRVt%2B%2Bl73UBkbgH%2FK3VGE%3D");
-        assert_eq!(builder.account_name, None);
-        assert_eq!(builder.account_key, None);
+        assert_eq!(builder.config.sas_token.unwrap(), 
"sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:00:14Z&st=2022-01-02T03:00:14Z&spr=https&sig=KEllk4N8f7rJfLjQCmikL2fRVt%2B%2Bl73UBkbgH%2FK3VGE%3D");
+        assert_eq!(builder.config.account_name, None);
+        assert_eq!(builder.config.account_key, None);
     }
 
     #[test]
@@ -917,8 +955,8 @@ 
SharedAccessSignature=sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:0
         .expect("from connection string must succeed");
 
         // SAS should be preferred over shared key
-        assert_eq!(builder.sas_token.unwrap(), 
"sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:00:14Z&st=2022-01-02T03:00:14Z&spr=https&sig=KEllk4N8f7rJfLjQCmikL2fRVt%2B%2Bl73UBkbgH%2FK3VGE%3D");
-        assert_eq!(builder.account_name, None);
-        assert_eq!(builder.account_key, None);
+        assert_eq!(builder.config.sas_token.unwrap(), 
"sv=2021-01-01&ss=b&srt=c&sp=rwdlaciytfx&se=2022-01-01T11:00:14Z&st=2022-01-02T03:00:14Z&spr=https&sig=KEllk4N8f7rJfLjQCmikL2fRVt%2B%2Bl73UBkbgH%2FK3VGE%3D");
+        assert_eq!(builder.config.account_name, None);
+        assert_eq!(builder.config.account_key, None);
     }
 }
diff --git a/core/src/services/azblob/mod.rs b/core/src/services/azblob/mod.rs
index 8170b176b..efc6e42f0 100644
--- a/core/src/services/azblob/mod.rs
+++ b/core/src/services/azblob/mod.rs
@@ -17,6 +17,7 @@
 
 mod backend;
 pub use backend::AzblobBuilder as Azblob;
+pub use backend::AzblobConfig;
 
 mod core;
 mod error;
diff --git a/core/src/services/mod.rs b/core/src/services/mod.rs
index d4298e9dc..8ed196f87 100644
--- a/core/src/services/mod.rs
+++ b/core/src/services/mod.rs
@@ -23,6 +23,8 @@
 mod azblob;
 #[cfg(feature = "services-azblob")]
 pub use azblob::Azblob;
+#[cfg(feature = "services-azblob")]
+pub use azblob::AzblobConfig;
 
 #[cfg(feature = "services-azdls")]
 mod azdls;

Reply via email to