1use dynamic::{MsgPack, MsgUnpack};
2use rand::random_range;
3use scc::HashMap;
4use smol_str::SmolStr;
5
6use anyhow::{Result, anyhow};
7
8use super::sync_await;
9use crate::directory;
10use crate::node::Node;
11use redis::AsyncCommands;
12use redis::Commands;
13use std::sync::Arc;
14
15use rslock::LockManager;
16
17pub enum Mount<T> {
18 Memory(Arc<HashMap<SmolStr, Node<T>>>),
19 Redis { client: redis::Client, rl: LockManager },
20}
21
22impl<T: std::fmt::Debug + MsgPack + MsgUnpack + Default + Send> Mount<T> {
23 pub fn memory() -> Self {
24 Self::Memory(Arc::new(HashMap::new()))
25 }
26
27 pub fn redis(url: &str) -> Result<Self> {
28 let client = redis::Client::open(url)?;
29 let mut conn = client.get_connection()?;
30 directory::rebuild_once(&mut conn)?;
31 let rl = LockManager::new(vec![url]);
32 Ok(Self::Redis { client, rl })
33 }
34
35 pub fn add(&self, name: &str, value: T) -> bool {
36 match self {
37 Self::Memory(m) => {
38 m.upsert_sync(name.into(), Node::Object(value));
39 true
40 }
41 Self::Redis { client, rl: _ } => {
42 let mut buf = Vec::new();
43 value.encode(&mut buf);
44 let Ok(mut conn) = client.get_connection() else {
45 return false;
46 };
47 conn.set::<&str, Vec<u8>, ()>(name, buf).is_ok() && directory::add_path(&mut conn, name).is_ok()
48 }
49 }
50 }
51
52 pub fn contains(&self, name: &str) -> bool {
53 match self {
54 Self::Memory(m) => m.contains_sync(name),
55 Self::Redis { client, rl: _ } => client.get_connection().and_then(|mut conn| conn.exists::<&str, bool>(name)).unwrap_or(false),
56 }
57 }
58
59 pub fn get_mut<R: Send + 'static, F: FnMut(&mut T) -> R>(&self, name: &str, mut f: F) -> Result<R>
60 where
61 F: Send + 'static,
62 {
63 match self {
64 Self::Memory(m) => m
65 .update_sync(name, |_, v| match v {
66 Node::Object(v) => Some(f(v)),
67 _ => None,
68 })
69 .flatten()
70 .ok_or(anyhow!("{} 不存在", name)),
71 Self::Redis { client, rl } => {
72 let name = String::from(name);
73 let rl = rl.clone();
74 let client = client.clone();
75 sync_await!(async move {
76 loop {
77 let time_out = random_range(0..1000); if let Ok(lock) = rl.lock(name.as_str(), std::time::Duration::from_millis(time_out)).await {
79 let mut conn = client.get_multiplexed_async_connection().await?;
80 let mut buf: Vec<u8> = conn.get(name.as_str()).await?;
81 let (mut v, _) = T::decode(buf.as_slice())?;
82 let r = f(&mut v);
83 buf.clear();
84 v.encode(&mut buf);
85 conn.set::<&str, Vec<u8>, ()>(name.as_str(), buf).await?;
86 rl.unlock(&lock).await;
87 break Ok(r);
88 }
89 }
90 })
91 }
92 }
93 }
94
95 pub fn get<R, F: FnOnce(&T) -> R>(&self, name: &str, f: F) -> Result<R> {
96 match self {
97 Self::Memory(m) => m
98 .read_sync(name, |_, v| match v {
99 Node::Object(v) => Some(f(v)),
100 _ => None,
101 })
102 .flatten()
103 .ok_or(anyhow!("{} 不存在", name)),
104 Self::Redis { client, rl: _ } => {
105 let mut conn = client.get_connection()?;
106 let buf: Vec<u8> = conn.get(name)?;
107 let (v, _) = T::decode(buf.as_slice())?;
108 Ok(f(&v))
109 }
110 }
111 }
112
113 pub fn get_key_mut<'a, R: Send + 'static, F: FnOnce(&mut T) -> R>(&'a self, name: &'a str, key: &'a str, f: F) -> Result<R>
114 where
115 F: Send + 'static,
116 {
117 match self {
118 Self::Memory(m) => m
119 .update_sync(name, |_, v| match v {
120 Node::Map(m) => m.update_sync(key, |_, v| f(v)),
121 _ => None,
122 })
123 .flatten()
124 .ok_or(anyhow!("{} 不存在", name)),
125 Self::Redis { client, rl } => {
126 let name = String::from(name);
127 let key = String::from(key);
128 let rl = rl.clone();
129 let client = client.clone();
130 sync_await!(async move {
131 loop {
132 let time_out = random_range(0..1000); let lock_name = format!("{}::{}", name, key); if let Ok(lock) = rl.lock(lock_name.as_str(), std::time::Duration::from_millis(time_out)).await {
135 let mut conn = client.get_multiplexed_async_connection().await?;
136 let mut buf: Vec<u8> = conn.hget(name.as_str(), key.as_str()).await?;
137 let (mut v, _) = T::decode(buf.as_slice())?;
138 let r = f(&mut v);
139 buf.clear();
140 v.encode(&mut buf);
141 conn.hset::<&str, &str, Vec<u8>, ()>(name.as_str(), key.as_str(), buf).await?;
142 rl.unlock(&lock).await;
143 break Ok(r);
144 }
145 }
146 })
147 }
148 }
149 }
150
151 pub fn dir(&self, name: &str) -> Result<Vec<SmolStr>> {
152 let prefix = if name.is_empty() || name.ends_with('/') { name.to_string() } else { format!("{name}/") };
153 if let Self::Redis { client, rl: _ } = self {
154 let mut conn = client.get_connection()?;
155 return Ok(Self::dir_entries_from_children(&prefix, directory::children(&mut conn, name)?));
156 }
157
158 let raw = self.dir_raw(&prefix)?;
159 Ok(Self::dir_entries_from_raw(&prefix, raw))
160 }
161
162 fn dir_entries_from_children(prefix: &str, children: Vec<SmolStr>) -> Vec<SmolStr> {
163 children.into_iter().map(|child| if prefix.is_empty() { child } else { format!("{prefix}{child}").into() }).collect()
164 }
165
166 fn dir_entries_from_raw(prefix: &str, raw: Vec<SmolStr>) -> Vec<SmolStr> {
167 let mut seen = std::collections::HashSet::new();
168 let mut names = Vec::new();
169 for key in raw {
170 let Some(rest) = key.strip_prefix(&prefix) else {
171 continue;
172 };
173 let end = rest.find('/').unwrap_or(rest.len());
174 let entry = &rest[..end];
175 if !entry.is_empty() && seen.insert(entry.to_string()) {
176 names.push(format!("{prefix}{entry}").into());
177 }
178 }
179 names
180 }
181
182 pub fn dir_raw(&self, name: &str) -> Result<Vec<SmolStr>> {
183 let mut names = Vec::new();
184 match self {
185 Self::Memory(m) => {
186 m.iter_sync(|key, _| {
187 if key.starts_with(name) {
188 names.push(key.clone())
189 }
190 true
191 });
192 }
193 Self::Redis { client, rl: _ } => {
194 let mut conn = client.get_connection()?;
195 let prefix = if name.is_empty() || name.ends_with('/') { name.to_string() } else { format!("{name}/") };
196 names.append(&mut Self::dir_entries_from_children(&prefix, directory::children(&mut conn, name)?));
197 }
198 }
199 Ok(names)
200 }
201
202 pub fn len(&self, name: &str) -> Result<usize> {
203 match self {
204 Self::Memory(m) => m.read_sync(name, |_, v| v.len()).ok_or(anyhow!("{} 不是列表", name)),
205 Self::Redis { client, rl: _ } => {
206 let mut conn = client.get_connection()?;
207 let ty: String = conn.key_type(name)?;
208 match ty.as_str() {
209 "list" => Ok(conn.llen(name)?),
210 "hash" => Ok(conn.hlen(name)?),
211 _ => Ok(1),
212 }
213 }
214 }
215 }
216
217 pub fn remove(&self, name: &str) -> Result<T> {
218 match self {
219 Self::Memory(m) => m.remove_sync(name).and_then(|(_, v)| v.into_object()).ok_or(anyhow!("{} 不存在", name)),
220 Self::Redis { client, rl: _ } => {
221 let mut conn = client.get_connection()?;
222 let buf: Vec<u8> = conn.get(name)?;
223 let (v, _) = T::decode(buf.as_slice())?;
224 let removed: usize = conn.del(name)?;
225 if removed != 0 {
226 directory::remove_path(&mut conn, name)?;
227 }
228 Ok(v)
229 }
230 }
231 }
232
233 pub fn add_list(&self, name: &str) {
234 match self {
235 Self::Memory(m) => {
236 m.upsert_sync(name.into(), Node::<T>::list());
237 } Self::Redis { client: _, rl: _ } => {}
239 }
240 }
241
242 pub fn add_map(&self, name: &str) {
243 match self {
244 Self::Memory(m) => {
245 m.upsert_sync(name.into(), Node::<T>::map());
246 } Self::Redis { client: _, rl: _ } => {}
248 }
249 }
250
251 pub fn push(&self, name: &str, value: T) -> Result<usize> {
252 match self {
253 Self::Memory(m) => m.update_sync(name, |_, v| v.push(value)).flatten().ok_or(anyhow!("push {} 失败", name)),
254 Self::Redis { client, rl: _ } => {
255 let mut conn = client.get_connection()?;
256 let mut buf = Vec::new();
257 value.encode(&mut buf);
258 let len = conn.rpush(name, buf)?;
259 directory::add_path(&mut conn, name)?;
260 Ok(len)
261 }
262 }
263 }
264
265 pub fn get_idx<R, F: FnOnce(&T) -> R>(&self, name: &str, idx: usize, f: F) -> Result<R> {
266 match self {
267 Self::Memory(m) => m.read_sync(name, |_, v| v.get_idx(idx, f)).flatten().ok_or(anyhow!("get_idx {} 失败", name)),
268 Self::Redis { client, rl: _ } => {
269 let mut conn = client.get_connection()?;
270 let buf: Vec<u8> = conn.lindex(name, idx as isize)?;
271 let (v, _) = T::decode(buf.as_slice())?;
272 Ok(f(&v))
273 }
274 }
275 }
276
277 pub fn get_idx_mut<R, F: FnMut(&mut T) -> R>(&self, name: &str, idx: usize, mut f: F) -> Result<R> {
278 match self {
279 Self::Memory(m) => m.update_sync(name, |_, v| v.get_idx_mut(idx, f)).flatten().ok_or(anyhow!("get_idx {} 失败", name)),
280 Self::Redis { client, rl: _ } => {
281 let mut conn = client.get_connection()?;
282 let buf: Vec<u8> = conn.lindex(name, idx as isize)?;
283 let (mut v, _) = T::decode(buf.as_slice())?;
284 Ok(f(&mut v))
285 }
286 }
287 }
288
289 pub fn remove_idx(&self, name: &str, idx: usize) -> Result<T> {
290 match self {
291 Self::Memory(m) => m.update_sync(name, |_, v| v.remove_idx(idx)).flatten().ok_or(anyhow!("remove_idx {} 失败", name)),
292 Self::Redis { client, rl: _ } => {
293 let mut conn = client.get_connection()?;
294 let buf: Vec<u8> = conn.lindex(name, idx as isize)?;
295 let v = T::decode(buf.as_slice()).map(|(v, _)| v).unwrap_or(T::default());
296 let _: () = conn.lset(name, idx as isize, Vec::new())?;
297 Ok(v)
298 }
299 }
300 }
301
302 pub fn insert(&self, name: &str, key: &str, value: T) -> Option<T> {
303 match self {
304 Self::Memory(m) => m.update_sync(name, |_, v| v.insert(key.into(), value)).flatten(),
305 Self::Redis { client, rl: _ } => {
306 if let Ok(mut conn) = client.get_connection() {
307 let mut buf = Vec::new();
308 value.encode(&mut buf);
309 if conn.hset::<&str, &str, Vec<u8>, ()>(name, key, buf).is_ok() {
310 let _ = directory::add_path(&mut conn, name);
311 }
312 }
313 None
314 }
315 }
316 }
317
318 pub fn get_key<R, F: FnOnce(&T) -> R>(&self, name: &str, key: &str, f: F) -> Result<R> {
319 match self {
320 Self::Memory(m) => m.read_sync(name, |_, v| v.get_key(key, f)).flatten().ok_or(anyhow!("get_key {} 失败", name)),
321 Self::Redis { client, rl: _ } => {
322 let mut conn = client.get_connection()?;
323 let buf: Vec<u8> = conn.hget(name, key)?;
324 let (v, _) = T::decode(buf.as_slice())?;
325 Ok(f(&v))
326 }
327 }
328 }
329
330 pub fn keys(&self, name: &str) -> Result<Vec<SmolStr>> {
331 match self {
332 Self::Memory(m) => m.read_sync(name, |_, v| v.keys()).flatten().ok_or(anyhow!("get_key {} 失败", name)),
333 Self::Redis { client, rl: _ } => {
334 let mut conn = client.get_connection()?;
335 let keys: Vec<String> = conn.hkeys(name).unwrap_or(Vec::new());
336 Ok(keys.into_iter().map(|k| k.into()).collect())
337 }
338 }
339 }
340
341 pub fn remove_key(&self, name: &str, key: &str) -> Result<T> {
342 match self {
343 Self::Memory(m) => m.update_sync(name, |_, v| v.remove_key(key)).flatten().ok_or(anyhow!("remove_key {} 失败", name)),
344 Self::Redis { client, rl: _ } => {
345 let mut conn = client.get_connection()?;
346 let buf: Vec<u8> = conn.hget(name, key)?;
347 let v = T::decode(buf.as_slice())?.0;
348 let _: usize = conn.hdel(name, key)?;
349 if !conn.exists::<_, bool>(name)? {
350 directory::remove_path(&mut conn, name)?;
351 }
352 Ok(v)
353 }
354 }
355 }
356}
357
358use std::sync::RwLock;
359
360#[derive(Debug)]
361pub struct Root<T> {
362 mounts: Arc<RwLock<Vec<(SmolStr, Mount<T>)>>>,
363}
364
365impl<T: std::fmt::Debug> std::fmt::Debug for Mount<T> {
366 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
367 match self {
368 Self::Memory(_) => write!(f, "Mount::Memory"),
369 Self::Redis { client: _, rl: _ } => write!(f, "Mount::Redis"),
370 }
371 }
372}
373
374impl<T> Clone for Mount<T> {
375 fn clone(&self) -> Self {
376 match self {
377 Self::Memory(m) => Self::Memory(m.clone()),
378 Self::Redis { client, rl } => Self::Redis { client: client.clone(), rl: rl.clone() },
379 }
380 }
381}
382
383impl<T: std::fmt::Debug + MsgPack + MsgUnpack + Default + Send> Root<T> {
384 pub fn new() -> Self {
385 Self { mounts: Arc::new(RwLock::new(vec![("local".into(), Mount::<T>::memory())])) }
386 }
387
388 pub fn mount_memory(&self, name: &str) -> bool {
389 let mounts = self.mounts.write();
390 match mounts {
391 Ok(mut mounts) => {
392 if mounts.iter().any(|(n, _)| n == name) {
393 return false;
394 }
395 mounts.push((name.into(), Mount::<T>::memory()));
396 true
397 }
398 Err(_) => false,
399 }
400 }
401
402 pub fn mount_redis(&self, name: &str, url: &str) -> Result<bool> {
403 let mounts = self.mounts.write();
404 match mounts {
405 Ok(mut mounts) => {
406 if mounts.iter().any(|(n, _)| n == name) {
407 return Ok(false);
408 }
409 mounts.push((name.into(), Mount::<T>::redis(url)?));
410 Ok(true)
411 }
412 Err(e) => Err(anyhow!("无法获取写锁: {}", e)),
413 }
414 }
415
416 pub fn get_mount<'a>(&self, name: &'a str) -> Result<(Mount<T>, &'a str)> {
417 let (mount, name) = name.split_once('/').ok_or(anyhow!("{} 没有 root 路径", name))?;
418 let mounts = self.mounts.read().map_err(|e| anyhow!("无法获取读锁: {}", e))?;
419 let m = mounts.iter().find_map(|m| if m.0 == mount { Some(m.1.clone()) } else { None }).ok_or(anyhow!("没有找到 {}", name))?;
420 Ok((m, name))
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use super::*;
427 use dynamic::Dynamic;
428
429 #[test]
430 fn dir_returns_only_immediate_children() {
431 let root = Root::<Dynamic>::new();
432 let (mount, name) = root.get_mount("local/test/dir/a").unwrap();
433 assert!(mount.add(name, 1.into()));
434 let (mount, name) = root.get_mount("local/test/dir/sub/item").unwrap();
435 assert!(mount.add(name, 2.into()));
436 let (mount, name) = root.get_mount("local/test/dir2/x").unwrap();
437 assert!(mount.add(name, 3.into()));
438
439 let (mount, name) = root.get_mount("local/test/dir").unwrap();
440 let mut entries = mount.dir(name).unwrap();
441 entries.sort();
442
443 assert_eq!(entries, vec![SmolStr::new("test/dir/a"), SmolStr::new("test/dir/sub")]);
444 }
445
446 #[test]
447 fn dir_accepts_trailing_slash() {
448 let root = Root::<Dynamic>::new();
449 let (mount, name) = root.get_mount("local/test/slash/a").unwrap();
450 assert!(mount.add(name, 1.into()));
451
452 let (mount, name) = root.get_mount("local/test/slash/").unwrap();
453 assert_eq!(mount.dir(name).unwrap(), vec![SmolStr::new("test/slash/a")]);
454 }
455}