tc_server/cluster/public/
dir.rs1use 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}