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 0f30f3297 fix(core)!: chainsafe services has been sunset (#5744)
0f30f3297 is described below
commit 0f30f3297bcbefc994ad1f52daab6a1237ee6c8c
Author: yihong <[email protected]>
AuthorDate: Tue Mar 11 20:59:29 2025 +0800
fix(core)!: chainsafe services has been sunset (#5744)
fix: drop chainsafe services support
Signed-off-by: yihong0618 <[email protected]>
---
.env.example | 4 -
.../chainsafe/chainsafe/disable_action.yml | 30 ---
README.md | 3 +-
bindings/java/Cargo.toml | 2 -
.../java/org/apache/opendal/ServiceConfig.java | 41 ----
bindings/nodejs/Cargo.toml | 2 -
bindings/python/Cargo.toml | 2 -
bindings/python/python/opendal/__base.pyi | 11 -
core/Cargo.toml | 1 -
core/README.md | 3 +-
core/src/services/chainsafe/backend.rs | 271 ---------------------
core/src/services/chainsafe/config.rs | 50 ----
core/src/services/chainsafe/core.rs | 246 -------------------
core/src/services/chainsafe/delete.rs | 48 ----
core/src/services/chainsafe/docs.md | 48 ----
core/src/services/chainsafe/error.rs | 103 --------
core/src/services/chainsafe/lister.rs | 76 ------
core/src/services/chainsafe/mod.rs | 35 ---
core/src/services/chainsafe/writer.rs | 56 -----
core/src/services/mod.rs | 3 -
core/src/types/operator/builder.rs | 2 -
core/src/types/scheme.rs | 4 -
22 files changed, 2 insertions(+), 1039 deletions(-)
diff --git a/.env.example b/.env.example
index 814ab27a3..4c3143d36 100644
--- a/.env.example
+++ b/.env.example
@@ -174,10 +174,6 @@ OPENDAL_UPYUN_ROOT=/path/to/dir
OPENDAL_UPYUN_BUCKET=<bucket>
OPENDAL_UPYUN_OPERATOR=<operator>
OPENDAL_UPYUN_PASSWORD=<password>
-# chainsafe
-OPENDAL_CHAINSAFE_ROOT=/path/to/dir
-OPENDAL_CHAINSAFE_BUCKET_ID=<bucket_id>
-OPENDAL_CHAINSAFE_API_KEY=<api_key>
# pcloud
OPENDAL_PCLOUD_ROOT=/path/to/dir
OPENDAL_PCLOUD_ENDPOINT=<endpoint>
diff --git a/.github/services/chainsafe/chainsafe/disable_action.yml
b/.github/services/chainsafe/chainsafe/disable_action.yml
deleted file mode 100644
index 09920e8cb..000000000
--- a/.github/services/chainsafe/chainsafe/disable_action.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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.
-
-name: chainsafe
-description: 'Behavior test for Chainsafe.'
-
-runs:
- using: "composite"
- steps:
- - name: Setup
- uses: 1password/load-secrets-action@v1
- with:
- export-env: true
- env:
- OPENDAL_CHAINSAFE_BUCKET_ID: op://services/chainsafe/bucket_id
- OPENDAL_CHAINSAFE_API_KEY: op://services/chainsafe/api_key
diff --git a/README.md b/README.md
index 605e4abc1..797c65ce7 100644
--- a/README.md
+++ b/README.md
@@ -155,7 +155,7 @@ OpenDAL's development is guided by its vision of **One
Layer, All Storage** and
| ------------------------------ |
----------------------------------------------------------------------------------------------------------------------------------------
|
| Standard Storage Protocols | ftp http [sftp] [webdav]
|
| Object Storage Services | [azblob] [cos] [gcs] [obs] [oss] [s3] <br>
[b2] [openstack_swift] [upyun] [vercel_blob]
|
-| File Storage Services | fs [alluxio] [azdls] [azfile] [chainsafe]
[compfs] <br> [dbfs] [gridfs] [hdfs] [hdfs_native] [ipfs] [webhdfs]
|
+| File Storage Services | fs [alluxio] [azdls] [azfile] [compfs] <br>
[dbfs] [gridfs] [hdfs] [hdfs_native] [ipfs] [webhdfs]
|
| Consumer Cloud Storage Service | [aliyun_drive] [gdrive] [onedrive]
[dropbox] [icloud] [koofr] <br> [pcloud] [seafile] [yandex_disk]
|
| Key-Value Storage Services | [cacache] [cloudflare_kv] [dashmap] memory
[etcd] <br> [foundationdb] [persy] [redis] [rocksdb] [sled] <br> [redb] [tikv]
[atomicserver] |
| Database Storage Services | [d1] [mongodb] [mysql] [postgresql]
[sqlite] [surrealdb]
|
@@ -179,7 +179,6 @@ OpenDAL's development is guided by its vision of **One
Layer, All Storage** and
[alluxio]: https://docs.alluxio.io/os/user/stable/en/api/REST-API.html
[azdls]: https://azure.microsoft.com/en-us/products/storage/data-lake-storage/
[azfile]:
https://learn.microsoft.com/en-us/rest/api/storageservices/file-service-rest-api
-[chainsafe]: https://storage.chainsafe.io/
[compfs]: https://github.com/compio-rs/compio/
[dbfs]: https://docs.databricks.com/en/dbfs/index.html
[gridfs]: https://www.mongodb.com/docs/manual/core/gridfs/
diff --git a/bindings/java/Cargo.toml b/bindings/java/Cargo.toml
index 0f2d6b7ce..e534e2bc3 100644
--- a/bindings/java/Cargo.toml
+++ b/bindings/java/Cargo.toml
@@ -52,7 +52,6 @@ services-all = [
"default",
"services-aliyun-drive",
"services-cacache",
- "services-chainsafe",
"services-dashmap",
"services-dropbox",
"services-etcd",
@@ -96,7 +95,6 @@ services-all = [
services-aliyun-drive = ["opendal/services-aliyun-drive"]
services-azblob = ["opendal/services-azblob"]
services-azdls = ["opendal/services-azdls"]
-services-chainsafe = ["opendal/services-chainsafe"]
services-cos = ["opendal/services-cos"]
services-fs = ["opendal/services-fs"]
services-gcs = ["opendal/services-gcs"]
diff --git a/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java
b/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java
index e1f092105..88db85433 100644
--- a/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java
+++ b/bindings/java/src/main/java/org/apache/opendal/ServiceConfig.java
@@ -508,47 +508,6 @@ public interface ServiceConfig {
}
}
- /**
- * Configuration for service chainsafe.
- */
- @Builder
- @Data
- @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
- class Chainsafe implements ServiceConfig {
- /**
- * <p>bucket_id of this backend.</p>
- * <p>required.</p>
- */
- public final @NonNull String bucketId;
- /**
- * <p>root of this backend.</p>
- * <p>All operations will happen under this root.</p>
- */
- public final String root;
- /**
- * <p>api_key of this backend.</p>
- */
- public final String apiKey;
-
- @Override
- public String scheme() {
- return "chainsafe";
- }
-
- @Override
- public Map<String, String> configMap() {
- final HashMap<String, String> map = new HashMap<>();
- map.put("bucket_id", bucketId);
- if (root != null) {
- map.put("root", root);
- }
- if (apiKey != null) {
- map.put("api_key", apiKey);
- }
- return map;
- }
- }
-
/**
* Configuration for service cloudflare_kv.
*/
diff --git a/bindings/nodejs/Cargo.toml b/bindings/nodejs/Cargo.toml
index 0b0482dfb..439488f51 100644
--- a/bindings/nodejs/Cargo.toml
+++ b/bindings/nodejs/Cargo.toml
@@ -50,7 +50,6 @@ services-all = [
"services-alluxio",
"services-azfile",
"services-cacache",
- "services-chainsafe",
"services-dashmap",
"services-dropbox",
# FIXME this service need protoc
@@ -94,7 +93,6 @@ services-all = [
services-aliyun-drive = ["opendal/services-aliyun-drive"]
services-azblob = ["opendal/services-azblob"]
services-azdls = ["opendal/services-azdls"]
-services-chainsafe = ["opendal/services-chainsafe"]
services-cos = ["opendal/services-cos"]
services-fs = ["opendal/services-fs"]
services-gcs = ["opendal/services-gcs"]
diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml
index 3d73acf50..54dd455c5 100644
--- a/bindings/python/Cargo.toml
+++ b/bindings/python/Cargo.toml
@@ -53,7 +53,6 @@ services-all = [
"services-aliyun-drive",
"services-azfile",
"services-cacache",
- "services-chainsafe",
"services-dashmap",
"services-dropbox",
# FIXME this service need protoc
@@ -97,7 +96,6 @@ services-all = [
services-aliyun-drive = ["opendal/services-aliyun-drive"]
services-azblob = ["opendal/services-azblob"]
services-azdls = ["opendal/services-azdls"]
-services-chainsafe = ["opendal/services-chainsafe"]
services-cos = ["opendal/services-cos"]
services-fs = ["opendal/services-fs"]
services-gcs = ["opendal/services-gcs"]
diff --git a/bindings/python/python/opendal/__base.pyi
b/bindings/python/python/opendal/__base.pyi
index 5bce6711c..b5f3b2562 100644
--- a/bindings/python/python/opendal/__base.pyi
+++ b/bindings/python/python/opendal/__base.pyi
@@ -148,17 +148,6 @@ class _Base:
datadir: str = ...,
) -> None: ...
- @overload
- def __init__(
- self,
- scheme: Literal["chainsafe"],
- /,
- *,
- bucket_id: str,
- root: str = ...,
- api_key: str = ...,
- ) -> None: ...
-
@overload
def __init__(
self,
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 08bcfd571..fe60c1ac0 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -126,7 +126,6 @@ services-azfile = [
]
services-b2 = []
services-cacache = ["dep:cacache"]
-services-chainsafe = []
services-cloudflare-kv = []
services-compfs = ["dep:compio"]
services-cos = [
diff --git a/core/README.md b/core/README.md
index 876bca50b..0b4ed24d6 100644
--- a/core/README.md
+++ b/core/README.md
@@ -30,7 +30,7 @@ OpenDAL supports the following storage
[services](https://docs.rs/opendal/latest
|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
| Standard Storage Protocols | ftp http [sftp] [webdav]
|
| Object Storage Services | [azblob] [cos] [gcs] [obs] [oss] [s3] <br>
[b2] [openstack_swift] [upyun] [vercel_blob]
|
-| File Storage Services | fs [alluxio] [azdls] [azfile] [chainsafe]
[compfs] <br> [dbfs] [gridfs] [hdfs] [hdfs_native] [ipfs] [webhdfs]
|
+| File Storage Services | fs [alluxio] [azdls] [azfile] [compfs] <br>
[dbfs] [gridfs] [hdfs] [hdfs_native] [ipfs] [webhdfs]
|
| Consumer Cloud Storage Service | [aliyun_drive] [gdrive] [onedrive]
[dropbox] [icloud] [koofr] <br> [pcloud] [seafile] [yandex_disk]
|
| Key-Value Storage Services | [cacache] [cloudflare_kv] [dashmap] memory
[etcd] <br> [foundationdb] [persy] [redis] [rocksdb] [sled] <br> [redb] [tikv]
[atomicserver] |
| Database Storage Services | [d1] [mongodb] [mysql] [postgresql]
[sqlite] [surrealdb]
|
@@ -54,7 +54,6 @@ OpenDAL supports the following storage
[services](https://docs.rs/opendal/latest
[alluxio]: https://docs.alluxio.io/os/user/stable/en/api/REST-API.html
[azdls]: https://azure.microsoft.com/en-us/products/storage/data-lake-storage/
[azfile]:
https://learn.microsoft.com/en-us/rest/api/storageservices/file-service-rest-api
-[chainsafe]: https://storage.chainsafe.io/
[compfs]: https://github.com/compio-rs/compio/
[dbfs]: https://docs.databricks.com/en/dbfs/index.html
[gridfs]: https://www.mongodb.com/docs/manual/core/gridfs/
diff --git a/core/src/services/chainsafe/backend.rs
b/core/src/services/chainsafe/backend.rs
deleted file mode 100644
index 89903598a..000000000
--- a/core/src/services/chainsafe/backend.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-// 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 std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
-
-use bytes::Buf;
-use http::Response;
-use http::StatusCode;
-use log::debug;
-
-use super::core::parse_info;
-use super::core::ChainsafeCore;
-use super::core::ObjectInfoResponse;
-use super::delete::ChainsafeDeleter;
-use super::error::parse_error;
-use super::lister::ChainsafeLister;
-use super::writer::ChainsafeWriter;
-use super::writer::ChainsafeWriters;
-use crate::raw::*;
-use crate::services::ChainsafeConfig;
-use crate::*;
-
-impl Configurator for ChainsafeConfig {
- type Builder = ChainsafeBuilder;
- fn into_builder(self) -> Self::Builder {
- ChainsafeBuilder {
- config: self,
- http_client: None,
- }
- }
-}
-
-/// [chainsafe](https://storage.chainsafe.io/) services support.
-#[doc = include_str!("docs.md")]
-#[derive(Default)]
-pub struct ChainsafeBuilder {
- config: ChainsafeConfig,
-
- http_client: Option<HttpClient>,
-}
-
-impl Debug for ChainsafeBuilder {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- let mut d = f.debug_struct("ChainsafeBuilder");
-
- d.field("config", &self.config);
- d.finish_non_exhaustive()
- }
-}
-
-impl ChainsafeBuilder {
- /// Set root of this backend.
- ///
- /// All operations will happen under this root.
- pub fn root(mut self, root: &str) -> Self {
- self.config.root = if root.is_empty() {
- None
- } else {
- Some(root.to_string())
- };
-
- self
- }
-
- /// api_key of this backend.
- ///
- /// required.
- pub fn api_key(mut self, api_key: &str) -> Self {
- self.config.api_key = if api_key.is_empty() {
- None
- } else {
- Some(api_key.to_string())
- };
-
- self
- }
-
- /// Set bucket_id name of this backend.
- pub fn bucket_id(mut self, bucket_id: &str) -> Self {
- self.config.bucket_id = bucket_id.to_string();
-
- self
- }
-
- /// Specify the http client that used by this service.
- ///
- /// # Notes
- ///
- /// This API is part of OpenDAL's Raw API. `HttpClient` could be changed
- /// during minor updates.
- pub fn http_client(mut self, client: HttpClient) -> Self {
- self.http_client = Some(client);
- self
- }
-}
-
-impl Builder for ChainsafeBuilder {
- const SCHEME: Scheme = Scheme::Chainsafe;
- type Config = ChainsafeConfig;
-
- /// Builds the backend and returns the result of ChainsafeBackend.
- fn build(self) -> Result<impl Access> {
- debug!("backend build started: {:?}", &self);
-
- let root =
normalize_root(&self.config.root.clone().unwrap_or_default());
- debug!("backend use root {}", &root);
-
- // Handle bucket_id.
- if self.config.bucket_id.is_empty() {
- return Err(Error::new(ErrorKind::ConfigInvalid, "bucket_id is
empty")
- .with_operation("Builder::build")
- .with_context("service", Scheme::Chainsafe));
- }
-
- debug!("backend use bucket_id {}", &self.config.bucket_id);
-
- let api_key = match &self.config.api_key {
- Some(api_key) => Ok(api_key.clone()),
- None => Err(Error::new(ErrorKind::ConfigInvalid, "api_key is
empty")
- .with_operation("Builder::build")
- .with_context("service", Scheme::Chainsafe)),
- }?;
-
- let client = if let Some(client) = self.http_client {
- client
- } else {
- HttpClient::new().map_err(|err| {
- err.with_operation("Builder::build")
- .with_context("service", Scheme::Chainsafe)
- })?
- };
-
- Ok(ChainsafeBackend {
- core: Arc::new(ChainsafeCore {
- info: {
- let am = AccessorInfo::default();
- am.set_scheme(Scheme::Chainsafe)
- .set_root(&root)
- .set_native_capability(Capability {
- stat: true,
- stat_has_content_length: true,
- stat_has_content_type: true,
-
- read: true,
-
- create_dir: true,
- write: true,
- write_can_empty: true,
-
- delete: true,
-
- list: true,
- list_has_content_length: true,
- list_has_content_type: true,
-
- shared: true,
-
- ..Default::default()
- });
-
- am.into()
- },
- root,
- api_key,
- bucket_id: self.config.bucket_id.clone(),
- client,
- }),
- })
- }
-}
-
-/// Backend for Chainsafe services.
-#[derive(Debug, Clone)]
-pub struct ChainsafeBackend {
- core: Arc<ChainsafeCore>,
-}
-
-impl Access for ChainsafeBackend {
- type Reader = HttpBody;
- type Writer = ChainsafeWriters;
- type Lister = oio::PageLister<ChainsafeLister>;
- type Deleter = oio::OneShotDeleter<ChainsafeDeleter>;
- type BlockingReader = ();
- type BlockingWriter = ();
- type BlockingLister = ();
- type BlockingDeleter = ();
-
- fn info(&self) -> Arc<AccessorInfo> {
- self.core.info.clone()
- }
-
- async fn create_dir(&self, path: &str, _: OpCreateDir) ->
Result<RpCreateDir> {
- let resp = self.core.create_dir(path).await?;
-
- let status = resp.status();
-
- match status {
- StatusCode::OK => Ok(RpCreateDir::default()),
- // Allow 409 when creating a existing dir
- StatusCode::CONFLICT => Ok(RpCreateDir::default()),
- _ => Err(parse_error(resp)),
- }
- }
-
- async fn stat(&self, path: &str, _args: OpStat) -> Result<RpStat> {
- let resp = self.core.object_info(path).await?;
-
- let status = resp.status();
-
- match status {
- StatusCode::OK => {
- let bs = resp.into_body();
-
- let output: ObjectInfoResponse =
-
serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
- Ok(RpStat::new(parse_info(output.content)))
- }
- _ => Err(parse_error(resp)),
- }
- }
-
- async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead,
Self::Reader)> {
- let resp = self.core.download_object(path, args.range()).await?;
-
- let status = resp.status();
- match status {
- StatusCode::OK | StatusCode::PARTIAL_CONTENT => Ok((RpRead::new(),
resp.into_body())),
- _ => {
- let (part, mut body) = resp.into_parts();
- let buf = body.to_buffer().await?;
- Err(parse_error(Response::from_parts(part, buf)))
- }
- }
- }
-
- async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite,
Self::Writer)> {
- let writer = ChainsafeWriter::new(self.core.clone(), args,
path.to_string());
-
- let w = oio::OneShotWriter::new(writer);
-
- Ok((RpWrite::default(), w))
- }
-
- async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
- Ok((
- RpDelete::default(),
- oio::OneShotDeleter::new(ChainsafeDeleter::new(self.core.clone())),
- ))
- }
-
- async fn list(&self, path: &str, _args: OpList) -> Result<(RpList,
Self::Lister)> {
- let l = ChainsafeLister::new(self.core.clone(), path);
- Ok((RpList::default(), oio::PageLister::new(l)))
- }
-}
diff --git a/core/src/services/chainsafe/config.rs
b/core/src/services/chainsafe/config.rs
deleted file mode 100644
index dc73c94f6..000000000
--- a/core/src/services/chainsafe/config.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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 std::fmt::Debug;
-use std::fmt::Formatter;
-
-use serde::Deserialize;
-use serde::Serialize;
-
-/// Config for Chainsafe services support.
-#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
-#[serde(default)]
-#[non_exhaustive]
-pub struct ChainsafeConfig {
- /// root of this backend.
- ///
- /// All operations will happen under this root.
- pub root: Option<String>,
- /// api_key of this backend.
- pub api_key: Option<String>,
- /// bucket_id of this backend.
- ///
- /// required.
- pub bucket_id: String,
-}
-
-impl Debug for ChainsafeConfig {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- let mut d = f.debug_struct("ChainsafeConfig");
-
- d.field("root", &self.root)
- .field("bucket_id", &self.bucket_id);
-
- d.finish_non_exhaustive()
- }
-}
diff --git a/core/src/services/chainsafe/core.rs
b/core/src/services/chainsafe/core.rs
deleted file mode 100644
index a6b69872f..000000000
--- a/core/src/services/chainsafe/core.rs
+++ /dev/null
@@ -1,246 +0,0 @@
-// 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 bytes::Bytes;
-use http::header;
-use http::Request;
-use http::Response;
-use serde::Deserialize;
-use serde_json::json;
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
-
-use crate::raw::*;
-use crate::*;
-
-/// Core of [chainsafe](https://storage.chainsafe.io/) services support.
-#[derive(Clone)]
-pub struct ChainsafeCore {
- pub info: Arc<AccessorInfo>,
- /// The root of this core.
- pub root: String,
- /// The api_key of this core.
- pub api_key: String,
- /// The bucket id of this backend.
- pub bucket_id: String,
-
- pub client: HttpClient,
-}
-
-impl Debug for ChainsafeCore {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("Backend")
- .field("root", &self.root)
- .field("bucket_id", &self.bucket_id)
- .finish_non_exhaustive()
- }
-}
-
-impl ChainsafeCore {
- #[inline]
- pub async fn send(&self, req: Request<Buffer>) -> Result<Response<Buffer>>
{
- self.client.send(req).await
- }
-}
-
-impl ChainsafeCore {
- pub async fn download_object(
- &self,
- path: &str,
- range: BytesRange,
- ) -> Result<Response<HttpBody>> {
- let path = build_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/download",
- self.bucket_id
- );
-
- let req_body = &json!({
- "path": path,
- });
- let body = Buffer::from(Bytes::from(req_body.to_string()));
-
- let req = Request::post(url)
- .header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- )
- .header(header::RANGE, range.to_header())
- .header(header::CONTENT_TYPE, "application/json")
- .body(body)
- .map_err(new_request_build_error)?;
-
- self.client.fetch(req).await
- }
-
- pub async fn object_info(&self, path: &str) -> Result<Response<Buffer>> {
- let path = build_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/file",
- self.bucket_id
- );
-
- let req_body = &json!({
- "path": path,
- });
-
- let body = Buffer::from(Bytes::from(req_body.to_string()));
-
- let req = Request::post(url)
- .header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- )
- .header(header::CONTENT_TYPE, "application/json")
- .body(body)
- .map_err(new_request_build_error)?;
-
- self.send(req).await
- }
-
- pub async fn delete_object(&self, path: &str) -> Result<Response<Buffer>> {
- let path = build_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/rm",
- self.bucket_id
- );
-
- let req_body = &json!({
- "paths": vec![path],
- });
-
- let body = Buffer::from(Bytes::from(req_body.to_string()));
-
- let req = Request::post(url)
- .header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- )
- .header(header::CONTENT_TYPE, "application/json")
- .body(body)
- .map_err(new_request_build_error)?;
-
- self.send(req).await
- }
-
- pub async fn upload_object(&self, path: &str, bs: Buffer) ->
Result<Response<Buffer>> {
- let path = build_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/upload",
- self.bucket_id
- );
-
- let file_part = FormDataPart::new("file").content(bs);
-
- let multipart = Multipart::new()
- .part(file_part)
- .part(FormDataPart::new("path").content(path));
-
- let req = Request::post(url).header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- );
-
- let req = multipart.apply(req)?;
-
- self.send(req).await
- }
-
- pub async fn list_objects(&self, path: &str) -> Result<Response<Buffer>> {
- let path = build_rooted_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/ls",
- self.bucket_id
- );
-
- let req_body = &json!({
- "path": path,
- });
-
- let body = Buffer::from(Bytes::from(req_body.to_string()));
-
- let req = Request::post(url)
- .header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- )
- .header(header::CONTENT_TYPE, "application/json")
- .body(body)
- .map_err(new_request_build_error)?;
-
- self.send(req).await
- }
-
- pub async fn create_dir(&self, path: &str) -> Result<Response<Buffer>> {
- let path = build_abs_path(&self.root, path);
-
- let url = format!(
- "https://api.chainsafe.io/api/v1/bucket/{}/mkdir",
- self.bucket_id
- );
-
- let req_body = &json!({
- "path": path,
- });
-
- let body = Buffer::from(Bytes::from(req_body.to_string()));
-
- let req = Request::post(url)
- .header(
- header::AUTHORIZATION,
- format_authorization_by_bearer(&self.api_key)?,
- )
- .header(header::CONTENT_TYPE, "application/json")
- .body(body)
- .map_err(new_request_build_error)?;
-
- self.send(req).await
- }
-}
-
-#[derive(Debug, Deserialize)]
-pub struct Info {
- pub name: String,
- pub content_type: String,
- pub size: u64,
-}
-
-#[derive(Deserialize)]
-pub struct ObjectInfoResponse {
- pub content: Info,
-}
-
-pub(super) fn parse_info(info: Info) -> Metadata {
- let mode = if info.content_type == "application/chainsafe-files-directory"
{
- EntryMode::DIR
- } else {
- EntryMode::FILE
- };
-
- let mut md = Metadata::new(mode);
-
- md.set_content_length(info.size)
- .set_content_type(&info.content_type);
-
- md
-}
diff --git a/core/src/services/chainsafe/delete.rs
b/core/src/services/chainsafe/delete.rs
deleted file mode 100644
index 436d2b348..000000000
--- a/core/src/services/chainsafe/delete.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 super::core::*;
-use super::error::parse_error;
-use crate::raw::*;
-use crate::*;
-use http::StatusCode;
-use std::sync::Arc;
-
-pub struct ChainsafeDeleter {
- core: Arc<ChainsafeCore>,
-}
-
-impl ChainsafeDeleter {
- pub fn new(core: Arc<ChainsafeCore>) -> Self {
- Self { core }
- }
-}
-
-impl oio::OneShotDelete for ChainsafeDeleter {
- async fn delete_once(&self, path: String, _: OpDelete) -> Result<()> {
- let resp = self.core.delete_object(&path).await?;
-
- let status = resp.status();
-
- match status {
- StatusCode::OK => Ok(()),
- // Allow 404 when deleting a non-existing object
- StatusCode::NOT_FOUND => Ok(()),
- _ => Err(parse_error(resp)),
- }
- }
-}
diff --git a/core/src/services/chainsafe/docs.md
b/core/src/services/chainsafe/docs.md
deleted file mode 100644
index 64d9b3ee8..000000000
--- a/core/src/services/chainsafe/docs.md
+++ /dev/null
@@ -1,48 +0,0 @@
-## Capabilities
-
-This service can be used to:
-
-- [x] stat
-- [x] read
-- [x] write
-- [x] create_dir
-- [x] delete
-- [ ] copy
-- [ ] rename
-- [x] list
-- [ ] presign
-- [ ] blocking
-
-## Configuration
-
-- `root`: Set the work directory for backend
-- `bucket_id` Chainsafe bucket_id
-- `api_key` Chainsafe api_key
-
-You can refer to [`ChainsafeBuilder`]'s docs for more information
-
-## Example
-
-### Via Builder
-
-```rust,no_run
-use anyhow::Result;
-use opendal::services::Chainsafe;
-use opendal::Operator;
-
-#[tokio::main]
-async fn main() -> Result<()> {
- // create backend builder
- let mut builder = Chainsafe::default()
- // set the storage root for OpenDAL
- .root("/")
- // set the bucket_id for OpenDAL
- .bucket_id("opendal")
- // set the api_key for OpenDAL
- .api_key("xxxxxxxxxxxxx");
-
- let op: Operator = Operator::new(builder)?.finish();
-
- Ok(())
-}
-```
diff --git a/core/src/services/chainsafe/error.rs
b/core/src/services/chainsafe/error.rs
deleted file mode 100644
index 87f78e40c..000000000
--- a/core/src/services/chainsafe/error.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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 bytes::Buf;
-use http::Response;
-use serde::Deserialize;
-
-use crate::raw::*;
-use crate::*;
-
-#[derive(Default, Debug, Deserialize)]
-#[allow(dead_code)]
-struct ChainsafeError {
- error: ChainsafeSubError,
-}
-
-#[derive(Default, Debug, Deserialize)]
-#[allow(dead_code)]
-struct ChainsafeSubError {
- code: i64,
- message: String,
-}
-
-/// Parse error response into Error.
-pub(super) fn parse_error(resp: Response<Buffer>) -> Error {
- let (parts, body) = resp.into_parts();
- let bs = body.to_bytes();
-
- let (kind, retryable) = match parts.status.as_u16() {
- 401 | 403 => (ErrorKind::PermissionDenied, false),
- 404 => (ErrorKind::NotFound, false),
- 304 | 412 => (ErrorKind::ConditionNotMatch, false),
- // https://github.com/apache/opendal/issues/4146
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/423
- // We should retry it when we get 423 error.
- 423 => (ErrorKind::RateLimited, true),
- // Service like Upyun could return 499 error with a message like:
- // Client Disconnect, we should retry it.
- 499 => (ErrorKind::Unexpected, true),
- 500 | 502 | 503 | 504 => (ErrorKind::Unexpected, true),
- _ => (ErrorKind::Unexpected, false),
- };
-
- let (message, _chainsafe_err) =
- serde_json::from_reader::<_, ChainsafeError>(bs.clone().reader())
- .map(|chainsafe_err| (format!("{chainsafe_err:?}"),
Some(chainsafe_err)))
- .unwrap_or_else(|_| (String::from_utf8_lossy(&bs).into_owned(),
None));
-
- let mut err = Error::new(kind, message);
-
- err = with_error_response_context(err, parts);
-
- if retryable {
- err = err.set_temporary();
- }
-
- err
-}
-
-#[cfg(test)]
-mod test {
- use http::StatusCode;
-
- use super::*;
-
- #[test]
- fn test_parse_error() {
- let err_res = vec![(
- r#"{
- "error": {
- "code": 404,
- "message": "path:test4, file doesn't exist"
- }
- }"#,
- ErrorKind::NotFound,
- StatusCode::NOT_FOUND,
- )];
-
- for res in err_res {
- let bs = bytes::Bytes::from(res.0);
- let body = Buffer::from(bs);
- let resp = Response::builder().status(res.2).body(body).unwrap();
-
- let err = parse_error(resp);
-
- assert_eq!(err.kind(), res.1);
- }
- }
-}
diff --git a/core/src/services/chainsafe/lister.rs
b/core/src/services/chainsafe/lister.rs
deleted file mode 100644
index 9d6e82275..000000000
--- a/core/src/services/chainsafe/lister.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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 std::sync::Arc;
-
-use bytes::Buf;
-use http::StatusCode;
-
-use super::core::parse_info;
-use super::core::ChainsafeCore;
-use super::core::Info;
-use super::error::parse_error;
-use crate::raw::oio::Entry;
-use crate::raw::*;
-use crate::*;
-
-pub struct ChainsafeLister {
- core: Arc<ChainsafeCore>,
- path: String,
-}
-
-impl ChainsafeLister {
- pub fn new(core: Arc<ChainsafeCore>, path: &str) -> Self {
- Self {
- core,
-
- path: path.to_string(),
- }
- }
-}
-
-impl oio::PageList for ChainsafeLister {
- async fn next_page(&self, ctx: &mut oio::PageContext) -> Result<()> {
- let resp = self.core.list_objects(&self.path).await?;
-
- match resp.status() {
- StatusCode::OK => {
- let bs = resp.into_body();
-
- let output: Vec<Info> =
-
serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
-
- for info in output {
- let mut path = build_abs_path(&normalize_root(&self.path),
&info.name);
-
- let md = parse_info(info);
-
- if md.mode() == EntryMode::DIR {
- path = format!("{}/", path);
- }
-
- ctx.entries.push_back(Entry::new(&path, md));
- }
-
- ctx.done = true;
-
- Ok(())
- }
- _ => Err(parse_error(resp)),
- }
- }
-}
diff --git a/core/src/services/chainsafe/mod.rs
b/core/src/services/chainsafe/mod.rs
deleted file mode 100644
index fa455cb38..000000000
--- a/core/src/services/chainsafe/mod.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#[cfg(feature = "services-chainsafe")]
-mod core;
-#[cfg(feature = "services-chainsafe")]
-mod delete;
-#[cfg(feature = "services-chainsafe")]
-mod error;
-#[cfg(feature = "services-chainsafe")]
-mod lister;
-#[cfg(feature = "services-chainsafe")]
-mod writer;
-
-#[cfg(feature = "services-chainsafe")]
-mod backend;
-#[cfg(feature = "services-chainsafe")]
-pub use backend::ChainsafeBuilder as Chainsafe;
-
-mod config;
-pub use config::ChainsafeConfig;
diff --git a/core/src/services/chainsafe/writer.rs
b/core/src/services/chainsafe/writer.rs
deleted file mode 100644
index e1b8181b7..000000000
--- a/core/src/services/chainsafe/writer.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 std::sync::Arc;
-
-use http::StatusCode;
-
-use super::core::ChainsafeCore;
-use super::error::parse_error;
-use crate::raw::*;
-use crate::*;
-
-pub type ChainsafeWriters = oio::OneShotWriter<ChainsafeWriter>;
-
-pub struct ChainsafeWriter {
- core: Arc<ChainsafeCore>,
- _op: OpWrite,
- path: String,
-}
-
-impl ChainsafeWriter {
- pub fn new(core: Arc<ChainsafeCore>, op: OpWrite, path: String) -> Self {
- ChainsafeWriter {
- core,
- _op: op,
- path,
- }
- }
-}
-
-impl oio::OneShotWrite for ChainsafeWriter {
- async fn write_once(&self, bs: Buffer) -> Result<Metadata> {
- let resp = self.core.upload_object(&self.path, bs).await?;
-
- let status = resp.status();
-
- match status {
- StatusCode::OK => Ok(Metadata::default()),
- _ => Err(parse_error(resp)),
- }
- }
-}
diff --git a/core/src/services/mod.rs b/core/src/services/mod.rs
index c9a98ea4f..a4ee5ff42 100644
--- a/core/src/services/mod.rs
+++ b/core/src/services/mod.rs
@@ -43,9 +43,6 @@ pub use b2::*;
mod cacache;
pub use self::cacache::*;
-mod chainsafe;
-pub use chainsafe::*;
-
mod cloudflare_kv;
pub use self::cloudflare_kv::*;
diff --git a/core/src/types/operator/builder.rs
b/core/src/types/operator/builder.rs
index f739b5fbf..8ebd03228 100644
--- a/core/src/types/operator/builder.rs
+++ b/core/src/types/operator/builder.rs
@@ -182,8 +182,6 @@ impl Operator {
Scheme::YandexDisk =>
Self::from_iter::<services::YandexDisk>(iter)?.finish(),
#[cfg(feature = "services-pcloud")]
Scheme::Pcloud =>
Self::from_iter::<services::Pcloud>(iter)?.finish(),
- #[cfg(feature = "services-chainsafe")]
- Scheme::Chainsafe =>
Self::from_iter::<services::Chainsafe>(iter)?.finish(),
#[cfg(feature = "services-azblob")]
Scheme::Azblob =>
Self::from_iter::<services::Azblob>(iter)?.finish(),
#[cfg(feature = "services-azdls")]
diff --git a/core/src/types/scheme.rs b/core/src/types/scheme.rs
index dfa22d8b6..e120edb4a 100644
--- a/core/src/types/scheme.rs
+++ b/core/src/types/scheme.rs
@@ -56,8 +56,6 @@ pub enum Scheme {
Pcloud,
/// [Koofr][crate::services::Koofr]: Koofr Services.
Koofr,
- /// [Chainsafe][crate::services::Chainsafe]: Chainsafe Services.
- Chainsafe,
/// [cacache][crate::services::Cacache]: cacache backend support.
Cacache,
/// [cloudflare-kv][crate::services::CloudflareKv]: Cloudflare KV services.
@@ -343,7 +341,6 @@ impl FromStr for Scheme {
// And abfs is widely used in hadoop ecosystem, keep it for easy
to use.
"azdls" | "azdfs" | "abfs" => Ok(Scheme::Azdls),
"b2" => Ok(Scheme::B2),
- "chainsafe" => Ok(Scheme::Chainsafe),
"cacache" => Ok(Scheme::Cacache),
"compfs" => Ok(Scheme::Compfs),
"cloudflare_kv" => Ok(Scheme::CloudflareKv),
@@ -414,7 +411,6 @@ impl From<Scheme> for &'static str {
Scheme::Azblob => "azblob",
Scheme::Azdls => "azdls",
Scheme::B2 => "b2",
- Scheme::Chainsafe => "chainsafe",
Scheme::Cacache => "cacache",
Scheme::CloudflareKv => "cloudflare_kv",
Scheme::Cos => "cos",