1use std::fmt::Debug;
19use std::sync::Arc;
20
21use asyncband::once::OnceCell;
22
23use super::TIKV_SCHEME;
24use super::config::TikvConfig;
25use super::core::*;
26use super::deleter::TikvDeleter;
27use super::reader::*;
28use super::writer::TikvWriter;
29use opendal_core::raw::oio;
30use opendal_core::raw::*;
31use opendal_core::*;
32
33#[doc = include_str!("docs.md")]
35#[derive(Debug, Default)]
36pub struct TikvBuilder {
37 pub(super) config: TikvConfig,
38}
39
40impl TikvBuilder {
41 pub fn endpoints(mut self, endpoints: Vec<String>) -> Self {
43 if !endpoints.is_empty() {
44 self.config.endpoints = Some(endpoints)
45 }
46 self
47 }
48
49 pub fn insecure(mut self) -> Self {
51 self.config.insecure = true;
52 self
53 }
54
55 pub fn ca_path(mut self, ca_path: &str) -> Self {
57 if !ca_path.is_empty() {
58 self.config.ca_path = Some(ca_path.to_string())
59 }
60 self
61 }
62
63 pub fn cert_path(mut self, cert_path: &str) -> Self {
65 if !cert_path.is_empty() {
66 self.config.cert_path = Some(cert_path.to_string())
67 }
68 self
69 }
70
71 pub fn key_path(mut self, key_path: &str) -> Self {
73 if !key_path.is_empty() {
74 self.config.key_path = Some(key_path.to_string())
75 }
76 self
77 }
78}
79
80impl Builder for TikvBuilder {
81 type Config = TikvConfig;
82
83 fn build(self) -> Result<impl Service> {
84 let endpoints = self.config.endpoints.ok_or_else(|| {
85 Error::new(
86 ErrorKind::ConfigInvalid,
87 "endpoints is required but not set",
88 )
89 .with_context("service", TIKV_SCHEME)
90 })?;
91
92 if self.config.insecure
93 && (self.config.ca_path.is_some()
94 || self.config.key_path.is_some()
95 || self.config.cert_path.is_some())
96 {
97 Err(
98 Error::new(ErrorKind::ConfigInvalid, "invalid tls configuration")
99 .with_context("service", TIKV_SCHEME)
100 .with_context("endpoints", format!("{endpoints:?}")),
101 )?;
102 }
103
104 Ok(TikvBackend::new(TikvCore {
105 client: OnceCell::new(),
106 endpoints,
107 insecure: self.config.insecure,
108 ca_path: self.config.ca_path.clone(),
109 cert_path: self.config.cert_path.clone(),
110 key_path: self.config.key_path.clone(),
111 }))
112 }
113}
114
115#[derive(Clone, Debug)]
117pub struct TikvBackend {
118 pub(crate) core: Arc<TikvCore>,
119 pub(crate) root: String,
120 pub(crate) info: ServiceInfo,
121 pub(crate) capability: Capability,
122}
123
124impl TikvBackend {
125 fn new(core: TikvCore) -> Self {
126 let info = ServiceInfo::new(TIKV_SCHEME, "/", "TiKV");
127 let capability = Capability {
128 read: true,
129 stat: true,
130 write: true,
131 write_can_empty: true,
132 delete: true,
133 shared: true,
134 ..Default::default()
135 };
136
137 Self {
138 core: Arc::new(core),
139 root: "/".to_string(),
140 info,
141 capability,
142 }
143 }
144}
145
146impl Service for TikvBackend {
147 type Reader = oio::StreamReader<TikvReader>;
148 type Writer = TikvWriter;
149 type Lister = ();
150 type Deleter = oio::OneShotDeleter<TikvDeleter>;
151 type Copier = ();
152 type Composer = ();
153
154 fn info(&self) -> ServiceInfo {
155 self.info.clone()
156 }
157
158 fn capability(&self) -> Capability {
159 self.capability
160 }
161
162 async fn create_dir(
163 &self,
164 _ctx: &OperationContext,
165 _path: &str,
166 _args: OpCreateDir,
167 ) -> Result<RpCreateDir> {
168 Err(Error::new(
169 ErrorKind::Unsupported,
170 "operation is not supported",
171 ))
172 }
173
174 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
175 let p = build_abs_path(&self.root, path);
176
177 if p == build_abs_path(&self.root, "") {
178 Ok(RpStat::new(MetadataBuilder::dir().build()))
179 } else {
180 let bs = self.core.get(&p).await?;
181 match bs {
182 Some(bs) => Ok(RpStat::new({
183 let metadata = MetadataBuilder::file(bs.len() as u64);
184 metadata.build()
185 })),
186 None => Err(Error::new(ErrorKind::NotFound, "kv not found in tikv")),
187 }
188 }
189 }
190 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
191 let output: oio::StreamReader<TikvReader> = {
192 Ok(oio::StreamReader::new(TikvReader::new(
193 self.clone(),
194 path,
195 args,
196 )))
197 }?;
198
199 Ok(output)
200 }
201
202 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
203 let output: TikvWriter = {
204 let p = build_abs_path(&self.root, path);
205 Ok(TikvWriter::new(self.core.clone(), p))
206 }?;
207
208 Ok(output)
209 }
210
211 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
212 let output: oio::OneShotDeleter<TikvDeleter> = {
213 Ok(oio::OneShotDeleter::new(TikvDeleter::new(
214 self.core.clone(),
215 self.root.clone(),
216 )))
217 }?;
218
219 Ok(output)
220 }
221
222 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
223 Err(Error::new(
224 ErrorKind::Unsupported,
225 "operation is not supported",
226 ))
227 }
228
229 fn copy(
230 &self,
231 _ctx: &OperationContext,
232 _from: &str,
233 _to: &str,
234 _args: OpCopy,
235 ) -> Result<Self::Copier> {
236 Err(Error::new(
237 ErrorKind::Unsupported,
238 "operation is not supported",
239 ))
240 }
241
242 async fn rename(
243 &self,
244 _ctx: &OperationContext,
245 _from: &str,
246 _to: &str,
247 _args: OpRename,
248 ) -> Result<RpRename> {
249 Err(Error::new(
250 ErrorKind::Unsupported,
251 "operation is not supported",
252 ))
253 }
254
255 async fn presign(
256 &self,
257 _ctx: &OperationContext,
258 _path: &str,
259 _args: OpPresign,
260 ) -> Result<RpPresign> {
261 Err(Error::new(
262 ErrorKind::Unsupported,
263 "operation is not supported",
264 ))
265 }
266}