Skip to content

Commit 3651322

Browse files
authored
feat(services/tos): add volcengine TOS support (#7233)
Change-Id: I12a490356a0996c4ce4f56614da62ca0bd8849ea
1 parent 77e74d0 commit 3651322

File tree

9 files changed

+539
-0
lines changed

9 files changed

+539
-0
lines changed

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,8 @@ OPENDAL_CLOUDFLARE_KV_ROOT=/path/to/dir
199199
OPENDAL_CLOUDFLARE_KV_API_TOKEN=<api_token>
200200
OPENDAL_CLOUDFLARE_KV_ACCOUNT_ID=<account_id>
201201
OPENDAL_CLOUDFLARE_KV_NAMESPACE_ID=<namespace_id>
202+
# tos
203+
OPENDAL_TOS_BUCKET=<bucket>
204+
OPENDAL_TOS_ENDPOINT=<endpoint>
205+
OPENDAL_TOS_ACCESS_KEY_ID=<access_key_id>
206+
OPENDAL_TOS_ACCESS_KEY_SECRET=<access_key_secret>

core/Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ services-sqlite = ["dep:opendal-service-sqlite"]
182182
services-surrealdb = ["dep:opendal-service-surrealdb"]
183183
services-swift = ["dep:opendal-service-swift"]
184184
services-tikv = ["dep:opendal-service-tikv"]
185+
services-tos = ["dep:opendal-service-tos"]
185186
services-upyun = ["dep:opendal-service-upyun"]
186187
services-vercel-artifacts = ["dep:opendal-service-vercel-artifacts"]
187188
services-vercel-blob = ["dep:opendal-service-vercel-blob"]
@@ -289,6 +290,7 @@ opendal-service-sqlite = { path = "services/sqlite", version = "0.55.0", optiona
289290
opendal-service-surrealdb = { path = "services/surrealdb", version = "0.55.0", optional = true, default-features = false }
290291
opendal-service-swift = { path = "services/swift", version = "0.55.0", optional = true, default-features = false }
291292
opendal-service-tikv = { path = "services/tikv", version = "0.55.0", optional = true, default-features = false }
293+
opendal-service-tos = { path = "services/tos", version = "0.55.0", optional = true, default-features = false }
292294
opendal-service-upyun = { path = "services/upyun", version = "0.55.0", optional = true, default-features = false }
293295
opendal-service-vercel-artifacts = { path = "services/vercel-artifacts", version = "0.55.0", optional = true, default-features = false }
294296
opendal-service-vercel-blob = { path = "services/vercel-blob", version = "0.55.0", optional = true, default-features = false }

core/services/tos/Cargo.toml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
[package]
19+
description = "Volcengine TOS service implementation for Apache OpenDAL"
20+
name = "opendal-service-tos"
21+
22+
authors = { workspace = true }
23+
edition = { workspace = true }
24+
homepage = { workspace = true }
25+
license = { workspace = true }
26+
repository = { workspace = true }
27+
rust-version = { workspace = true }
28+
version = { workspace = true }
29+
30+
[package.metadata.docs.rs]
31+
all-features = true
32+
33+
[dependencies]
34+
opendal-core = { path = "../../core", version = "0.55.0", default-features = false }
35+
serde = { workspace = true, features = ["derive"] }
36+
serde_json = { workspace = true }

core/services/tos/src/backend.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use std::fmt::Debug;
19+
use std::sync::Arc;
20+
21+
use crate::TosConfig;
22+
use crate::core::TosCore;
23+
use opendal_core::raw::*;
24+
use opendal_core::{Builder, Capability, Result};
25+
26+
const TOS_SCHEME: &str = "tos";
27+
28+
/// Builder for Volcengine TOS service.
29+
#[derive(Default)]
30+
pub struct TosBuilder {
31+
pub(super) config: TosConfig,
32+
}
33+
34+
impl Debug for TosBuilder {
35+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36+
f.debug_struct("TosBuilder")
37+
.field("config", &self.config)
38+
.finish_non_exhaustive()
39+
}
40+
}
41+
42+
impl TosBuilder {
43+
/// Set root of this backend.
44+
///
45+
/// All operations will happen under this root.
46+
pub fn root(mut self, root: &str) -> Self {
47+
self.config.root = if root.is_empty() {
48+
None
49+
} else {
50+
Some(root.to_string())
51+
};
52+
self
53+
}
54+
55+
/// Set bucket name of this backend.
56+
pub fn bucket(mut self, bucket: &str) -> Self {
57+
self.config.bucket = bucket.to_string();
58+
self
59+
}
60+
61+
/// Set endpoint of this backend.
62+
///
63+
/// Endpoint must be full uri, e.g.
64+
/// - TOS: `https://tos-cn-beijing.volces.com`
65+
/// - TOS with region: `https://tos-{region}.volces.com`
66+
///
67+
/// If user inputs endpoint without scheme like "tos-cn-beijing.volces.com", we
68+
/// will prepend "https://" before it.
69+
pub fn endpoint(mut self, endpoint: &str) -> Self {
70+
if !endpoint.is_empty() {
71+
self.config.endpoint = Some(endpoint.trim_end_matches('/').to_string());
72+
}
73+
self
74+
}
75+
76+
/// Set region of this backend.
77+
///
78+
/// Region represent the signing region of this endpoint.
79+
///
80+
/// If region is not set, we will try to load it from environment.
81+
/// If still not set, default to `cn-beijing`.
82+
pub fn region(mut self, region: &str) -> Self {
83+
if !region.is_empty() {
84+
self.config.region = Some(region.to_string());
85+
}
86+
self
87+
}
88+
89+
/// Set access_key_id of this backend.
90+
///
91+
/// - If access_key_id is set, we will take user's input first.
92+
/// - If not, we will try to load it from environment.
93+
pub fn access_key_id(mut self, v: &str) -> Self {
94+
self.config.access_key_id = Some(v.to_string());
95+
self
96+
}
97+
98+
/// Set secret_access_key of this backend.
99+
///
100+
/// - If secret_access_key is set, we will take user's input first.
101+
/// - If not, we will try to load it from environment.
102+
pub fn secret_access_key(mut self, v: &str) -> Self {
103+
self.config.secret_access_key = Some(v.to_string());
104+
self
105+
}
106+
107+
/// Set security_token of this backend.
108+
pub fn security_token(mut self, v: &str) -> Self {
109+
self.config.security_token = Some(v.to_string());
110+
self
111+
}
112+
113+
/// Allow anonymous will allow opendal to send request without signing
114+
/// when credential is not loaded.
115+
pub fn allow_anonymous(mut self, allow: bool) -> Self {
116+
self.config.allow_anonymous = allow;
117+
self
118+
}
119+
120+
/// Set bucket versioning status for this backend.
121+
///
122+
/// If set to true, OpenDAL will support versioned operations like list with
123+
/// versions, read with version, etc.
124+
pub fn enable_versioning(mut self, enabled: bool) -> Self {
125+
self.config.enable_versioning = enabled;
126+
self
127+
}
128+
}
129+
130+
impl Builder for TosBuilder {
131+
type Config = TosConfig;
132+
133+
fn build(self) -> Result<impl Access> {
134+
let mut config = self.config;
135+
let region = config
136+
.region
137+
.clone()
138+
.unwrap_or_else(|| "cn-beijing".to_string());
139+
140+
if config.endpoint.is_none() {
141+
config.endpoint = Some(format!("https://tos-{}.volces.com", region));
142+
}
143+
144+
let endpoint = config.endpoint.clone().unwrap();
145+
let bucket = config.bucket.clone();
146+
let root = config.root.clone().unwrap_or_else(|| "/".to_string());
147+
148+
let info = {
149+
let am = AccessorInfo::default();
150+
am.set_scheme(TOS_SCHEME)
151+
.set_root(&root)
152+
.set_name(&bucket)
153+
.set_native_capability(Capability {
154+
read: false,
155+
156+
write: false,
157+
158+
delete: false,
159+
160+
list: false,
161+
162+
stat: false,
163+
164+
shared: false,
165+
166+
..Default::default()
167+
});
168+
169+
am.into()
170+
};
171+
172+
let core = TosCore {
173+
info,
174+
bucket,
175+
endpoint: endpoint.clone(),
176+
root,
177+
};
178+
179+
Ok(TosBackend {
180+
core: Arc::new(core),
181+
})
182+
}
183+
}
184+
185+
#[derive(Debug)]
186+
pub struct TosBackend {
187+
core: Arc<TosCore>,
188+
}
189+
190+
impl Access for TosBackend {
191+
type Reader = ();
192+
type Writer = ();
193+
type Lister = ();
194+
type Deleter = ();
195+
196+
fn info(&self) -> Arc<AccessorInfo> {
197+
self.core.info.clone()
198+
}
199+
}

0 commit comments

Comments
 (0)