snix_castore/directoryservice/
mod.rs

1use crate::composition::{Registry, ServiceBuilder};
2use crate::{B3Digest, Directory, Error};
3
4use auto_impl::auto_impl;
5use futures::stream::BoxStream;
6use tonic::async_trait;
7mod combinators;
8mod directory_graph;
9mod from_addr;
10mod grpc;
11mod memory;
12mod object_store;
13mod order_validator;
14mod redb;
15mod simple_putter;
16#[cfg(test)]
17pub mod tests;
18mod traverse;
19mod utils;
20
21pub use self::combinators::{Cache, CacheConfig};
22pub use self::directory_graph::{DirectoryGraph, ValidatedDirectoryGraph};
23pub use self::from_addr::from_addr;
24pub use self::grpc::{GRPCDirectoryService, GRPCDirectoryServiceConfig};
25pub use self::memory::{MemoryDirectoryService, MemoryDirectoryServiceConfig};
26pub use self::object_store::{ObjectStoreDirectoryService, ObjectStoreDirectoryServiceConfig};
27pub use self::order_validator::{LeavesToRootValidator, OrderValidator, RootToLeavesValidator};
28pub use self::redb::{RedbDirectoryService, RedbDirectoryServiceConfig};
29pub use self::simple_putter::SimplePutter;
30pub use self::traverse::descend_to;
31pub use self::utils::traverse_directory;
32
33#[cfg(feature = "cloud")]
34mod bigtable;
35
36#[cfg(feature = "cloud")]
37pub use self::bigtable::{BigtableDirectoryService, BigtableParameters};
38
39/// The base trait all Directory services need to implement.
40/// This is a simple get and put of [Directory], returning their
41/// digest.
42#[async_trait]
43#[auto_impl(&, &mut, Arc, Box)]
44pub trait DirectoryService: Send + Sync {
45    /// Looks up a single Directory message by its digest.
46    /// The returned Directory message *must* be valid.
47    /// In case the directory is not found, Ok(None) is returned.
48    ///
49    /// It is okay for certain implementations to only allow retrieval of
50    /// Directory digests that are at the "root", aka the last element that's
51    /// sent to a DirectoryPutter. This makes sense for implementations bundling
52    /// closures of directories together in batches.
53    async fn get(&self, digest: &B3Digest) -> Result<Option<Directory>, Error>;
54    /// Uploads a single Directory message, and returns the calculated
55    /// digest, or an error. An error *must* also be returned if the message is
56    /// not valid.
57    async fn put(&self, directory: Directory) -> Result<B3Digest, Error>;
58
59    /// Looks up a closure of [Directory].
60    /// Ideally this would be a `impl Stream<Item = Result<Directory, Error>>`,
61    /// and we'd be able to add a default implementation for it here, but
62    /// we can't have that yet.
63    ///
64    /// This returns a pinned, boxed stream. The pinning allows for it to be polled easily,
65    /// and the box allows different underlying stream implementations to be returned since
66    /// Rust doesn't support this as a generic in traits yet. This is the same thing that
67    /// [async_trait] generates, but for streams instead of futures.
68    ///
69    /// The individually returned Directory messages *must* be valid.
70    /// Directories are sent in an order from the root to the leaves, so that
71    /// the receiving side can validate each message to be a connected to the root
72    /// that has initially been requested.
73    ///
74    /// In case the directory can not be found, this should return an empty stream.
75    fn get_recursive(
76        &self,
77        root_directory_digest: &B3Digest,
78    ) -> BoxStream<'static, Result<Directory, Error>>;
79
80    /// Allows persisting a closure of [Directory], which is a graph of
81    /// connected Directory messages.
82    fn put_multiple_start(&self) -> Box<dyn DirectoryPutter + '_>;
83}
84
85/// Provides a handle to put a closure of connected [Directory] elements.
86///
87/// The consumer can periodically call [DirectoryPutter::put], starting from the
88/// leaves. Once the root is reached, [DirectoryPutter::close] can be called to
89/// retrieve the root digest (or an error).
90///
91/// DirectoryPutters might be created without a single [DirectoryPutter::put],
92/// and then dropped without calling [DirectoryPutter::close],
93/// for example when ingesting a path that ends up not pointing to a directory,
94/// but a single file or symlink.
95#[async_trait]
96pub trait DirectoryPutter: Send {
97    /// Put a individual [Directory] into the store.
98    /// Error semantics and behaviour is up to the specific implementation of
99    /// this trait.
100    /// Due to bursting, the returned error might refer to an object previously
101    /// sent via `put`.
102    async fn put(&mut self, directory: Directory) -> Result<(), Error>;
103
104    /// Close the stream, and wait for any errors.
105    /// If there's been any invalid Directory message uploaded, and error *must*
106    /// be returned.
107    async fn close(&mut self) -> Result<B3Digest, Error>;
108}
109
110/// Registers the builtin DirectoryService implementations with the registry
111pub(crate) fn register_directory_services(reg: &mut Registry) {
112    reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::ObjectStoreDirectoryServiceConfig>("objectstore");
113    reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::MemoryDirectoryServiceConfig>("memory");
114    reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::CacheConfig>("cache");
115    reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::GRPCDirectoryServiceConfig>("grpc");
116    reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::RedbDirectoryServiceConfig>("redb");
117    #[cfg(feature = "cloud")]
118    {
119        reg.register::<Box<dyn ServiceBuilder<Output = dyn DirectoryService>>, super::directoryservice::BigtableParameters>("bigtable");
120    }
121}