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 adb1bc4d0 feat(service/gdrive): add gdrive copy (#3098)
adb1bc4d0 is described below
commit adb1bc4d059bc40569245f4c2ce4d133a08ecc9e
Author: Flash <[email protected]>
AuthorDate: Sun Sep 17 14:08:07 2023 +0800
feat(service/gdrive): add gdrive copy (#3098)
---
core/src/services/gdrive/backend.rs | 56 ++++++++++++++++++++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/core/src/services/gdrive/backend.rs
b/core/src/services/gdrive/backend.rs
index 66c181d2b..e7bc2a2bd 100644
--- a/core/src/services/gdrive/backend.rs
+++ b/core/src/services/gdrive/backend.rs
@@ -19,8 +19,11 @@ use std::fmt::Debug;
use std::sync::Arc;
use async_trait::async_trait;
+use bytes::Bytes;
use chrono::Utc;
+use http::Request;
use http::StatusCode;
+use serde_json::json;
use super::core::GdriveCore;
use super::error::parse_error;
@@ -67,6 +70,8 @@ impl Accessor for GdriveBackend {
delete: true,
+ copy: true,
+
..Default::default()
});
@@ -253,10 +258,59 @@ impl Accessor for GdriveBackend {
GdrivePager::new(path.into(), self.core.clone()),
))
}
+
+ async fn copy(&self, from: &str, to: &str, _args: OpCopy) ->
Result<RpCopy> {
+ let from_file_id = self.core.get_file_id_by_path(from).await?;
+
+ // split `to` into parent and name according to the last `/`
+ let mut to_path_items: Vec<&str> = to.split('/').filter(|&x|
!x.is_empty()).collect();
+
+ let to_name = if let Some(name) = to_path_items.pop() {
+ name
+ } else {
+ return Err(Error::new(ErrorKind::InvalidInput, "invalid 'to'
path"));
+ };
+
+ let to_parent = to_path_items.join("/") + "/";
+
+ if to_parent != "/" {
+ self.create_dir(&to_parent, OpCreateDir::new()).await?;
+ }
+
+ let to_parent_id =
self.core.get_file_id_by_path(to_parent.as_str()).await?;
+
+ // copy will overwrite `to`, delete it if exist
+ if self.core.get_file_id_by_path(to).await.is_ok() {
+ self.delete(to, OpDelete::new()).await?;
+ }
+
+ let url = format!(
+ "https://www.googleapis.com/drive/v3/files/{}/copy",
+ from_file_id
+ );
+
+ let request_body = &json!({
+ "name": to_name,
+ "parents": [to_parent_id],
+ });
+ let body = AsyncBody::Bytes(Bytes::from(request_body.to_string()));
+
+ let mut req = Request::post(&url)
+ .body(body)
+ .map_err(new_request_build_error)?;
+ self.core.sign(&mut req).await?;
+
+ let resp = self.core.client.send(req).await?;
+
+ match resp.status() {
+ StatusCode::OK => Ok(RpCopy::default()),
+ _ => Err(parse_error(resp).await?),
+ }
+ }
}
impl GdriveBackend {
- pub(crate) fn parse_metadata(&self, body: bytes::Bytes) ->
Result<Metadata> {
+ pub(crate) fn parse_metadata(&self, body: Bytes) -> Result<Metadata> {
let metadata =
serde_json::from_slice::<GdriveFile>(&body).map_err(new_json_deserialize_error)?;