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",


Reply via email to