Skip to main content

root/
mount.rs

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); //等待随机时间
78                        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); //等待随机时间
133                        let lock_name = format!("{}::{}", name, key); //为这个 name 里面的 key 单独上锁
134                        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            } // 强制插入 肯定成功
238            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            } // 强制插入 肯定成功
247            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}