opendal_service_alluxio/
backend.rs1use std::fmt::Debug;
19use std::sync::Arc;
20
21use log::debug;
22
23use super::ALLUXIO_SCHEME;
24use super::config::AlluxioConfig;
25use super::core::AlluxioCore;
26use super::deleter::AlluxioDeleter;
27use super::lister::AlluxioLister;
28use super::reader::*;
29use super::writer::AlluxioWriter;
30use super::writer::AlluxioWriters;
31use opendal_core::raw::*;
32use opendal_core::*;
33
34#[doc = include_str!("docs.md")]
36#[derive(Default)]
37pub struct AlluxioBuilder {
38 pub(super) config: AlluxioConfig,
39}
40
41impl Debug for AlluxioBuilder {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("AlluxioBuilder")
44 .field("config", &self.config)
45 .finish_non_exhaustive()
46 }
47}
48
49impl AlluxioBuilder {
50 pub fn root(mut self, root: &str) -> Self {
54 self.config.root = if root.is_empty() {
55 None
56 } else {
57 Some(root.to_string())
58 };
59
60 self
61 }
62
63 pub fn endpoint(mut self, endpoint: &str) -> Self {
67 if !endpoint.is_empty() {
68 self.config.endpoint = Some(endpoint.trim_end_matches('/').to_string())
70 }
71
72 self
73 }
74}
75
76impl Builder for AlluxioBuilder {
77 type Config = AlluxioConfig;
78
79 fn build(self) -> Result<impl Service> {
81 debug!("backend build started: {:?}", self);
82
83 let root = normalize_root(&self.config.root.clone().unwrap_or_default());
84 debug!("backend use root {}", root);
85
86 let endpoint = match &self.config.endpoint {
87 Some(endpoint) => Ok(endpoint.clone()),
88 None => Err(Error::new(ErrorKind::ConfigInvalid, "endpoint is empty")
89 .with_operation("Builder::build")
90 .with_context("service", ALLUXIO_SCHEME)),
91 }?;
92 debug!("backend use endpoint {}", endpoint);
93
94 Ok(AlluxioBackend {
95 core: Arc::new(AlluxioCore {
96 info: ServiceInfo::new(ALLUXIO_SCHEME, &root, ""),
97 capability: Capability {
98 stat: true,
99
100 read: false,
105
106 write: true,
107 write_can_multi: true,
108
109 create_dir: true,
110 delete: true,
111
112 list: true,
113
114 shared: true,
115
116 ..Default::default()
117 },
118 root,
119 endpoint,
120 }),
121 })
122 }
123}
124
125#[derive(Debug, Clone)]
126pub struct AlluxioBackend {
127 pub(crate) core: Arc<AlluxioCore>,
128}
129
130impl Service for AlluxioBackend {
131 type Reader = oio::StreamReader<AlluxioReader>;
132 type Writer = AlluxioWriters;
133 type Lister = oio::PageLister<AlluxioLister>;
134 type Deleter = oio::OneShotDeleter<AlluxioDeleter>;
135 type Copier = ();
136 type Composer = ();
137
138 fn info(&self) -> ServiceInfo {
139 self.core.info.clone()
140 }
141
142 fn capability(&self) -> Capability {
143 self.core.capability
144 }
145
146 async fn create_dir(
147 &self,
148 ctx: &OperationContext,
149 path: &str,
150 _: OpCreateDir,
151 ) -> Result<RpCreateDir> {
152 self.core.create_dir(ctx, path).await?;
153 Ok(RpCreateDir::default())
154 }
155
156 async fn stat(&self, ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
157 let file_info = self.core.get_status(ctx, path).await?;
158
159 Ok(RpStat::new(file_info.try_into()?))
160 }
161 fn read(&self, ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
162 let output: oio::StreamReader<AlluxioReader> = {
163 Ok(oio::StreamReader::new(AlluxioReader::new(
164 self.clone(),
165 ctx.clone(),
166 path,
167 args,
168 )))
169 }?;
170
171 Ok(output)
172 }
173
174 fn write(&self, ctx: &OperationContext, path: &str, args: OpWrite) -> Result<Self::Writer> {
175 let output: AlluxioWriters = {
176 let w = AlluxioWriter::new(
177 self.core.clone(),
178 ctx.clone(),
179 args.clone(),
180 path.to_string(),
181 );
182
183 Ok(w)
184 }?;
185
186 Ok(output)
187 }
188
189 fn delete(&self, ctx: &OperationContext) -> Result<Self::Deleter> {
190 let output: oio::OneShotDeleter<AlluxioDeleter> = {
191 Ok(oio::OneShotDeleter::new(AlluxioDeleter::new(
192 self.core.clone(),
193 ctx.clone(),
194 )))
195 }?;
196
197 Ok(output)
198 }
199
200 fn list(&self, ctx: &OperationContext, path: &str, _args: OpList) -> Result<Self::Lister> {
201 let output: oio::PageLister<AlluxioLister> = {
202 let l = AlluxioLister::new(self.core.clone(), ctx.clone(), path);
203 Ok(oio::PageLister::new(l))
204 }?;
205
206 Ok(output)
207 }
208
209 fn copy(
210 &self,
211 _ctx: &OperationContext,
212 _from: &str,
213 _to: &str,
214 _args: OpCopy,
215 ) -> Result<Self::Copier> {
216 Err(Error::new(
217 ErrorKind::Unsupported,
218 "operation is not supported",
219 ))
220 }
221
222 async fn rename(
223 &self,
224 ctx: &OperationContext,
225 from: &str,
226 to: &str,
227 _: OpRename,
228 ) -> Result<RpRename> {
229 self.core.rename(ctx, from, to).await?;
230
231 Ok(RpRename::default())
232 }
233
234 async fn presign(
235 &self,
236 _ctx: &OperationContext,
237 _path: &str,
238 _args: OpPresign,
239 ) -> Result<RpPresign> {
240 Err(Error::new(
241 ErrorKind::Unsupported,
242 "operation is not supported",
243 ))
244 }
245}
246
247#[cfg(test)]
248mod test {
249 use std::collections::HashMap;
250
251 use super::*;
252
253 #[test]
254 fn test_builder_from_map() {
255 let mut map = HashMap::new();
256 map.insert("root".to_string(), "/".to_string());
257 map.insert("endpoint".to_string(), "http://127.0.0.1:39999".to_string());
258
259 let builder = AlluxioConfig::from_iter(map).unwrap();
260
261 assert_eq!(builder.root, Some("/".to_string()));
262 assert_eq!(builder.endpoint, Some("http://127.0.0.1:39999".to_string()));
263 }
264
265 #[test]
266 fn test_builder_build() {
267 let builder = AlluxioBuilder::default()
268 .root("/root")
269 .endpoint("http://127.0.0.1:39999")
270 .build();
271
272 assert!(builder.is_ok());
273 }
274}