1use std::fmt::Debug;
19use std::sync::Arc;
20
21use mea::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
153 fn info(&self) -> ServiceInfo {
154 self.info.clone()
155 }
156
157 fn capability(&self) -> Capability {
158 self.capability
159 }
160
161 async fn create_dir(
162 &self,
163 _ctx: &OperationContext,
164 _path: &str,
165 _args: OpCreateDir,
166 ) -> Result<RpCreateDir> {
167 Err(Error::new(
168 ErrorKind::Unsupported,
169 "operation is not supported",
170 ))
171 }
172
173 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
174 let p = build_abs_path(&self.root, path);
175
176 if p == build_abs_path(&self.root, "") {
177 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
178 } else {
179 let bs = self.core.get(&p).await?;
180 match bs {
181 Some(bs) => Ok(RpStat::new(
182 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
183 )),
184 None => Err(Error::new(ErrorKind::NotFound, "kv not found in tikv")),
185 }
186 }
187 }
188 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
189 let output: oio::StreamReader<TikvReader> = {
190 Ok(oio::StreamReader::new(TikvReader::new(
191 self.clone(),
192 path,
193 args,
194 )))
195 }?;
196
197 Ok(output)
198 }
199
200 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
201 let output: TikvWriter = {
202 let p = build_abs_path(&self.root, path);
203 Ok(TikvWriter::new(self.core.clone(), p))
204 }?;
205
206 Ok(output)
207 }
208
209 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
210 let output: oio::OneShotDeleter<TikvDeleter> = {
211 Ok(oio::OneShotDeleter::new(TikvDeleter::new(
212 self.core.clone(),
213 self.root.clone(),
214 )))
215 }?;
216
217 Ok(output)
218 }
219
220 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
221 Err(Error::new(
222 ErrorKind::Unsupported,
223 "operation is not supported",
224 ))
225 }
226
227 fn copy(
228 &self,
229 _ctx: &OperationContext,
230 _from: &str,
231 _to: &str,
232 _args: OpCopy,
233 _opts: OpCopier,
234 ) -> Result<Self::Copier> {
235 Err(Error::new(
236 ErrorKind::Unsupported,
237 "operation is not supported",
238 ))
239 }
240
241 async fn rename(
242 &self,
243 _ctx: &OperationContext,
244 _from: &str,
245 _to: &str,
246 _args: OpRename,
247 ) -> Result<RpRename> {
248 Err(Error::new(
249 ErrorKind::Unsupported,
250 "operation is not supported",
251 ))
252 }
253
254 async fn presign(
255 &self,
256 _ctx: &OperationContext,
257 _path: &str,
258 _args: OpPresign,
259 ) -> Result<RpPresign> {
260 Err(Error::new(
261 ErrorKind::Unsupported,
262 "operation is not supported",
263 ))
264 }
265}