tc_server/cluster/public/
dir.rs

1use std::fmt;
2
3use log::debug;
4use safecast::TryCastInto;
5
6use tc_error::*;
7use tc_state::CacheBlock;
8use tc_transact::fs;
9use tc_transact::public::*;
10use tc_transact::Transaction;
11use tcgeneric::{PathSegment, TCPath};
12
13use crate::cluster::dir::{Dir, DirCreate, DirCreateItem, DirEntry, DirItem};
14use crate::cluster::{Cluster, Schema};
15use crate::{State, Txn};
16
17struct DirHandler<'a, T> {
18    dir: &'a Dir<T>,
19}
20
21impl<'a, T> Handler<'a, State> for DirHandler<'a, T>
22where
23    T: DirItem + fmt::Debug,
24    Dir<T>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema> + Route<State> + fmt::Debug,
25    DirEntry<T>: Clone,
26    Cluster<T>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema>,
27    Cluster<Dir<T>>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema> + Clone,
28{
29    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, Txn, State>>
30    where
31        'b: 'a,
32    {
33        Some(Box::new(|txn, key| {
34            Box::pin(async move {
35                if key.is_none() {
36                    let entries = self.dir.entries(*txn.id()).await?;
37                    let entries = entries
38                        .map(|(name, entry)| ((*name).clone(), State::from(entry.is_dir())))
39                        .collect();
40
41                    Ok(State::Map(entries))
42                } else {
43                    let name =
44                        key.try_cast_into(|v| TCError::unexpected(v, "a directory entry name"))?;
45
46                    let entry = self.dir.entry(*txn.id(), &name).await?;
47                    let entry = entry.ok_or_else(|| not_found!("dir entry {name}"))?;
48                    Ok(entry.is_dir().into())
49                }
50            })
51        }))
52    }
53
54    fn put<'b>(self: Box<Self>) -> Option<PutHandler<'a, 'b, Txn, State>>
55    where
56        'b: 'a,
57    {
58        Some(Box::new(|txn, key, value| {
59            Box::pin(async move {
60                let name: PathSegment =
61                    key.try_cast_into(|v| TCError::unexpected(v, "a directory name"))?;
62
63                if value.try_into()? {
64                    self.dir.create_dir(txn, name).await?;
65                } else {
66                    self.dir.create_item(txn, name).await?;
67                }
68
69                Ok(())
70            })
71        }))
72    }
73}
74
75impl<'a, T> From<&'a Dir<T>> for DirHandler<'a, T> {
76    fn from(dir: &'a Dir<T>) -> Self {
77        Self { dir }
78    }
79}
80
81impl<T> Route<State> for Dir<T>
82where
83    T: DirItem + fmt::Debug,
84    Dir<T>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema> + fmt::Debug,
85    DirEntry<T>: Clone,
86    Cluster<T>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema>,
87    Cluster<Dir<T>>: fs::Persist<CacheBlock, Txn = Txn, Schema = Schema> + Clone,
88{
89    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
90        if path.is_empty() {
91            Some(Box::new(DirHandler::from(self)))
92        } else {
93            debug!("request to {} routed to parent dir", TCPath::from(path));
94            None
95        }
96    }
97}