opendal_service_mini_moka/
backend.rs1use std::sync::Arc;
19
20use log::debug;
21use opendal_core::raw::*;
22use opendal_core::*;
23
24use super::MINI_MOKA_SCHEME;
25use super::config::MiniMokaConfig;
26use super::core::*;
27use super::deleter::MiniMokaDeleter;
28use super::lister::MiniMokaLister;
29use super::reader::*;
30use super::writer::MiniMokaWriter;
31
32#[doc = include_str!("docs.md")]
34#[derive(Debug, Default)]
35pub struct MiniMokaBuilder {
36 pub(super) config: MiniMokaConfig,
37}
38
39impl MiniMokaBuilder {
40 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn max_capacity(mut self, v: u64) -> Self {
49 if v != 0 {
50 self.config.max_capacity = Some(v);
51 }
52 self
53 }
54
55 pub fn time_to_live(mut self, v: Duration) -> Self {
59 if !v.is_zero() {
60 self.config.time_to_live = Some(format!("{}s", v.as_secs()));
61 }
62 self
63 }
64
65 pub fn time_to_idle(mut self, v: Duration) -> Self {
69 if !v.is_zero() {
70 self.config.time_to_idle = Some(format!("{}s", v.as_secs()));
71 }
72 self
73 }
74
75 pub fn root(mut self, path: &str) -> Self {
77 self.config.root = if path.is_empty() {
78 None
79 } else {
80 Some(path.to_string())
81 };
82
83 self
84 }
85}
86
87impl Builder for MiniMokaBuilder {
88 type Config = MiniMokaConfig;
89
90 fn build(self) -> Result<impl Service> {
91 debug!("backend build started: {:?}", self);
92
93 let mut builder: mini_moka::sync::CacheBuilder<String, MiniMokaValue, _> =
94 mini_moka::sync::Cache::builder();
95
96 builder = builder.weigher(|k, v| (k.len() + v.content.len()) as u32);
98
99 if let Some(v) = self.config.max_capacity {
100 builder = builder.max_capacity(v);
101 }
102 if let Some(value) = self.config.time_to_live.as_deref() {
103 let duration = signed_to_duration(value)?;
104 builder = builder.time_to_live(duration);
105 }
106 if let Some(value) = self.config.time_to_idle.as_deref() {
107 let duration = signed_to_duration(value)?;
108 builder = builder.time_to_idle(duration);
109 }
110
111 let cache = builder.build();
112
113 let root = normalize_root(self.config.root.as_deref().unwrap_or("/"));
114
115 let core = Arc::new(MiniMokaCore { cache });
116
117 debug!("backend build finished: {root}");
118 Ok(MiniMokaBackend::new(core, root))
119 }
120}
121
122#[derive(Debug, Clone)]
123pub(crate) struct MiniMokaBackend {
124 pub(crate) core: Arc<MiniMokaCore>,
125 pub(crate) root: String,
126 capability: Capability,
127}
128
129impl MiniMokaBackend {
130 fn new(core: Arc<MiniMokaCore>, root: String) -> Self {
131 let capability = Capability {
132 stat: true,
133 read: true,
134 write: true,
135 write_can_empty: true,
136 delete: true,
137 list: true,
138
139 ..Default::default()
140 };
141
142 Self {
143 core,
144 root,
145 capability,
146 }
147 }
148}
149
150impl Service for MiniMokaBackend {
151 type Reader = oio::StreamReader<MiniMokaReader>;
152 type Writer = MiniMokaWriter;
153 type Lister = oio::HierarchyLister<MiniMokaLister>;
154 type Deleter = oio::OneShotDeleter<MiniMokaDeleter>;
155 type Copier = ();
156 type Composer = ();
157
158 fn info(&self) -> ServiceInfo {
159 ServiceInfo::new(MINI_MOKA_SCHEME, &self.root, "")
160 }
161
162 fn capability(&self) -> Capability {
163 self.capability
164 }
165
166 async fn create_dir(
167 &self,
168 _ctx: &OperationContext,
169 _path: &str,
170 _args: OpCreateDir,
171 ) -> Result<RpCreateDir> {
172 Err(Error::new(
173 ErrorKind::Unsupported,
174 "operation is not supported",
175 ))
176 }
177
178 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
179 let p = build_abs_path(&self.root, path);
180
181 match self.core.get(&p) {
183 Some(value) => {
184 let mut metadata = value.metadata.clone().into_builder();
185 if p.ends_with('/') {
186 metadata.set_dir();
187 } else {
188 metadata.set_file(value.metadata.content_length());
189 }
190 Ok(RpStat::new(metadata.build()))
191 }
192 None => {
193 if p.ends_with('/') {
194 let is_prefix = self
195 .core
196 .cache
197 .iter()
198 .any(|entry| entry.key().starts_with(&p) && entry.key() != &p);
199
200 if is_prefix {
201 let mut metadata = MetadataBuilder::unknown();
202 metadata.set_dir();
203 return Ok(RpStat::new(metadata.build()));
204 }
205 }
206
207 Err(Error::new(ErrorKind::NotFound, "path not found"))
208 }
209 }
210 }
211 fn read(&self, _ctx: &OperationContext, path: &str, op: OpRead) -> Result<Self::Reader> {
212 let output: oio::StreamReader<MiniMokaReader> = {
213 Ok(oio::StreamReader::new(MiniMokaReader::new(
214 self.clone(),
215 path,
216 op,
217 )))
218 }?;
219
220 Ok(output)
221 }
222
223 fn write(&self, _ctx: &OperationContext, path: &str, op: OpWrite) -> Result<Self::Writer> {
224 let output: MiniMokaWriter = {
225 let p = build_abs_path(&self.root, path);
226 let writer = MiniMokaWriter::new(self.core.clone(), p, op);
227 Ok(writer)
228 }?;
229
230 Ok(output)
231 }
232
233 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
234 let output: oio::OneShotDeleter<MiniMokaDeleter> = {
235 let deleter = oio::OneShotDeleter::new(MiniMokaDeleter::new(
236 self.core.clone(),
237 self.root.clone(),
238 ));
239 Ok(deleter)
240 }?;
241
242 Ok(output)
243 }
244
245 fn list(&self, _ctx: &OperationContext, path: &str, op: OpList) -> Result<Self::Lister> {
246 let output: oio::HierarchyLister<MiniMokaLister> = {
247 let p = build_abs_path(&self.root, path);
248
249 let mini_moka_lister = MiniMokaLister::new(self.core.clone(), self.root.clone(), p);
250 let lister = oio::HierarchyLister::new(mini_moka_lister, path, op.recursive());
251
252 Ok(lister)
253 }?;
254
255 Ok(output)
256 }
257
258 fn copy(
259 &self,
260 _ctx: &OperationContext,
261 _from: &str,
262 _to: &str,
263 _args: OpCopy,
264 ) -> Result<Self::Copier> {
265 Err(Error::new(
266 ErrorKind::Unsupported,
267 "operation is not supported",
268 ))
269 }
270
271 async fn rename(
272 &self,
273 _ctx: &OperationContext,
274 _from: &str,
275 _to: &str,
276 _args: OpRename,
277 ) -> Result<RpRename> {
278 Err(Error::new(
279 ErrorKind::Unsupported,
280 "operation is not supported",
281 ))
282 }
283
284 async fn presign(
285 &self,
286 _ctx: &OperationContext,
287 _path: &str,
288 _args: OpPresign,
289 ) -> Result<RpPresign> {
290 Err(Error::new(
291 ErrorKind::Unsupported,
292 "operation is not supported",
293 ))
294 }
295}