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 b8e778c48 feat(core): Implement write returns metadata for b2 (#5750)
b8e778c48 is described below

commit b8e778c488c835e3c45156f77e6c2ec0c6837beb
Author: hoslo <[email protected]>
AuthorDate: Thu Mar 13 20:47:38 2025 +0800

    feat(core): Implement write returns metadata for b2 (#5750)
---
 core/src/services/b2/backend.rs       |  3 +++
 core/src/services/b2/core.rs          |  9 ++++++++
 core/src/services/b2/writer.rs        | 39 +++++++++++++++++++++++++++++++++--
 core/src/types/capability.rs          |  2 ++
 core/tests/behavior/async_write.rs    |  9 ++++++++
 core/tests/behavior/blocking_write.rs |  6 ++++++
 6 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/core/src/services/b2/backend.rs b/core/src/services/b2/backend.rs
index 1796e60c4..9a7e86c08 100644
--- a/core/src/services/b2/backend.rs
+++ b/core/src/services/b2/backend.rs
@@ -212,6 +212,9 @@ impl Builder for B2Builder {
                             write_can_empty: true,
                             write_can_multi: true,
                             write_with_content_type: true,
+                            write_has_content_md5: true,
+                            write_has_content_length: true,
+                            write_has_content_type: true,
                             // The min multipart size of b2 is 5 MiB.
                             //
                             // ref: 
<https://www.backblaze.com/docs/cloud-storage-large-files>
diff --git a/core/src/services/b2/core.rs b/core/src/services/b2/core.rs
index 4ee2f1d84..2c2733b0e 100644
--- a/core/src/services/b2/core.rs
+++ b/core/src/services/b2/core.rs
@@ -622,6 +622,15 @@ pub struct ListFileNamesResponse {
     pub next_file_name: Option<String>,
 }
 
+/// Response of 
[b2-finish-large-file](https://www.backblaze.com/apidocs/b2-finish-large-file).
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct UploadResponse {
+    pub content_length: u64,
+    pub content_md5: Option<String>,
+    pub content_type: Option<String>,
+}
+
 #[derive(Debug, Clone, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct File {
diff --git a/core/src/services/b2/writer.rs b/core/src/services/b2/writer.rs
index 5512c24ad..8213642e3 100644
--- a/core/src/services/b2/writer.rs
+++ b/core/src/services/b2/writer.rs
@@ -23,6 +23,7 @@ use http::StatusCode;
 use super::core::B2Core;
 use super::core::StartLargeFileResponse;
 use super::core::UploadPartResponse;
+use super::core::UploadResponse;
 use super::error::parse_error;
 use crate::raw::*;
 use crate::*;
@@ -44,6 +45,22 @@ impl B2Writer {
             op,
         }
     }
+
+    pub fn parse_body_into_meta(path: &str, resp: UploadResponse) -> Metadata {
+        let mut meta = Metadata::new(EntryMode::from_path(path));
+
+        if let Some(md5) = resp.content_md5 {
+            meta.set_content_md5(&md5);
+        }
+
+        if let Some(content_type) = resp.content_type {
+            meta.set_content_type(&content_type);
+        }
+
+        meta.set_content_length(resp.content_length);
+
+        meta
+    }
 }
 
 impl oio::MultipartWrite for B2Writer {
@@ -56,7 +73,16 @@ impl oio::MultipartWrite for B2Writer {
         let status = resp.status();
 
         match status {
-            StatusCode::OK => Ok(Metadata::default()),
+            StatusCode::OK => {
+                let bs = resp.into_body();
+
+                let result: UploadResponse =
+                    
serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
+
+                let meta = Self::parse_body_into_meta(&self.path, result);
+
+                Ok(meta)
+            }
             _ => Err(parse_error(resp)),
         }
     }
@@ -138,7 +164,16 @@ impl oio::MultipartWrite for B2Writer {
         let status = resp.status();
 
         match status {
-            StatusCode::OK => Ok(Metadata::default()),
+            StatusCode::OK => {
+                let bs = resp.into_body();
+
+                let result: UploadResponse =
+                    
serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
+
+                let meta = Self::parse_body_into_meta(&self.path, result);
+
+                Ok(meta)
+            }
             _ => Err(parse_error(resp)),
         }
     }
diff --git a/core/src/types/capability.rs b/core/src/types/capability.rs
index 10ef127b9..e14f8b8f2 100644
--- a/core/src/types/capability.rs
+++ b/core/src/types/capability.rs
@@ -168,6 +168,8 @@ pub struct Capability {
     pub write_has_version: bool,
     /// Indicates whether content MD5 checksum is available in write response
     pub write_has_content_md5: bool,
+    /// Indicates whether content type information is available in write 
response
+    pub write_has_content_type: bool,
 
     /// Indicates if directory creation is supported.
     pub create_dir: bool,
diff --git a/core/tests/behavior/async_write.rs 
b/core/tests/behavior/async_write.rs
index 867dc8833..73ff292e8 100644
--- a/core/tests/behavior/async_write.rs
+++ b/core/tests/behavior/async_write.rs
@@ -276,6 +276,9 @@ pub async fn test_write_returns_metadata(op: Operator) -> 
Result<()> {
     if cap.write_has_content_md5 {
         assert_eq!(stat_meta.content_md5(), meta.content_md5());
     }
+    if cap.write_has_content_type {
+        assert_eq!(stat_meta.content_type(), meta.content_type());
+    }
 
     Ok(())
 }
@@ -605,6 +608,9 @@ pub async fn test_writer_return_metadata(op: Operator) -> 
Result<()> {
     if cap.write_has_content_md5 {
         assert_eq!(stat_meta.content_md5(), meta.content_md5());
     }
+    if cap.write_has_content_type {
+        assert_eq!(stat_meta.content_type(), meta.content_type());
+    }
 
     Ok(())
 }
@@ -674,6 +680,9 @@ pub async fn test_write_with_append_returns_metadata(op: 
Operator) -> Result<()>
     if cap.write_has_content_md5 {
         assert_eq!(stat_meta.content_md5(), meta.content_md5());
     }
+    if cap.write_has_content_type {
+        assert_eq!(stat_meta.content_type(), meta.content_type());
+    }
 
     Ok(())
 }
diff --git a/core/tests/behavior/blocking_write.rs 
b/core/tests/behavior/blocking_write.rs
index 6d1bd9372..c1dbd9c05 100644
--- a/core/tests/behavior/blocking_write.rs
+++ b/core/tests/behavior/blocking_write.rs
@@ -112,6 +112,9 @@ pub fn test_blocking_write_returns_metadata(op: 
BlockingOperator) -> Result<()>
     if cap.write_has_content_md5 {
         assert_eq!(meta.content_md5(), stat_meta.content_md5());
     }
+    if cap.write_has_content_type {
+        assert_eq!(meta.content_type(), stat_meta.content_type());
+    }
 
     Ok(())
 }
@@ -172,6 +175,9 @@ pub fn test_blocking_write_with_append_returns_metadata(op: 
BlockingOperator) ->
     if cap.write_has_content_md5 {
         assert_eq!(meta.content_md5(), stat_meta.content_md5());
     }
+    if cap.write_has_content_type {
+        assert_eq!(meta.content_type(), stat_meta.content_type());
+    }
 
     Ok(())
 }

Reply via email to