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
157 fn info(&self) -> ServiceInfo {
158 ServiceInfo::new(MINI_MOKA_SCHEME, &self.root, "")
159 }
160
161 fn capability(&self) -> Capability {
162 self.capability
163 }
164
165 async fn create_dir(
166 &self,
167 _ctx: &OperationContext,
168 _path: &str,
169 _args: OpCreateDir,
170 ) -> Result<RpCreateDir> {
171 Err(Error::new(
172 ErrorKind::Unsupported,
173 "operation is not supported",
174 ))
175 }
176
177 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
178 let p = build_abs_path(&self.root, path);
179
180 match self.core.get(&p) {
182 Some(value) => {
183 let mut metadata = value.metadata.clone();
184 if p.ends_with('/') {
185 metadata.set_mode(EntryMode::DIR);
186 } else {
187 metadata.set_mode(EntryMode::FILE);
188 }
189 Ok(RpStat::new(metadata))
190 }
191 None => {
192 if p.ends_with('/') {
193 let is_prefix = self
194 .core
195 .cache
196 .iter()
197 .any(|entry| entry.key().starts_with(&p) && entry.key() != &p);
198
199 if is_prefix {
200 let mut metadata = Metadata::default();
201 metadata.set_mode(EntryMode::DIR);
202 return Ok(RpStat::new(metadata));
203 }
204 }
205
206 Err(Error::new(ErrorKind::NotFound, "path not found"))
207 }
208 }
209 }
210 fn read(&self, _ctx: &OperationContext, path: &str, op: OpRead) -> Result<Self::Reader> {
211 let output: oio::StreamReader<MiniMokaReader> = {
212 Ok(oio::StreamReader::new(MiniMokaReader::new(
213 self.clone(),
214 path,
215 op,
216 )))
217 }?;
218
219 Ok(output)
220 }
221
222 fn write(&self, _ctx: &OperationContext, path: &str, op: OpWrite) -> Result<Self::Writer> {
223 let output: MiniMokaWriter = {
224 let p = build_abs_path(&self.root, path);
225 let writer = MiniMokaWriter::new(self.core.clone(), p, op);
226 Ok(writer)
227 }?;
228
229 Ok(output)
230 }
231
232 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
233 let output: oio::OneShotDeleter<MiniMokaDeleter> = {
234 let deleter = oio::OneShotDeleter::new(MiniMokaDeleter::new(
235 self.core.clone(),
236 self.root.clone(),
237 ));
238 Ok(deleter)
239 }?;
240
241 Ok(output)
242 }
243
244 fn list(&self, _ctx: &OperationContext, path: &str, op: OpList) -> Result<Self::Lister> {
245 let output: oio::HierarchyLister<MiniMokaLister> = {
246 let p = build_abs_path(&self.root, path);
247
248 let mini_moka_lister = MiniMokaLister::new(self.core.clone(), self.root.clone(), p);
249 let lister = oio::HierarchyLister::new(mini_moka_lister, path, op.recursive());
250
251 Ok(lister)
252 }?;
253
254 Ok(output)
255 }
256
257 fn copy(
258 &self,
259 _ctx: &OperationContext,
260 _from: &str,
261 _to: &str,
262 _args: OpCopy,
263 _opts: OpCopier,
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}