wnfs/lib.rs
1//! The crate implements the [Web Native File System](https://whitepaper.fission.codes/file-system/file-system-basics) (WNFS) version 2.
2//!
3//! The Web Native File System is a file system written for the web.
4//! It is versioned, logged, programmable, has strong-yet-flexible security, and is fully controlled by the end user.
5//! Service providers can validate writes without reading the contents of the file system, and minimal metadata is leaked.
6//!
7//! This implementation is based off of the [typescript implementation](https://github.com/fission-suite/webnative/tree/matheus23/wnfs2/src/fs) but designed with immutability in mind.
8//!
9//! Let's see an example of working with a public filesystem. We will use the in-memory block store provided by the library.
10//!
11//! ```rust
12//! use anyhow::Result;
13//! use chrono::Utc;
14//! use wnfs::{
15//! common::{MemoryBlockStore, Storable},
16//! public::PublicDirectory,
17//! };
18//!
19//! #[async_std::main]
20//! async fn main() -> Result<()> {
21//! // Create a new public directory.
22//! let dir = &mut PublicDirectory::new_rc(Utc::now());
23//!
24//! // Create an in-memory block store.
25//! let store = &MemoryBlockStore::new();
26//!
27//! // Add a /pictures/cats subdirectory.
28//! dir.mkdir(&["pictures".into(), "cats".into()], Utc::now(), store)
29//! .await?;
30//!
31//! // Store the the file tree in the in-memory block store.
32//! dir.store(store).await?;
33//!
34//! // List all files in /pictures directory.
35//! let result = dir.ls(&["pictures".into()], store).await?;
36//!
37//! println!("Files in /pictures: {:#?}", result);
38//!
39//! Ok(())
40//! }
41//! ```
42//!
43//! Here we create a root directory `dir` and subsequently add a `/pictures/cats` subdirectory to it. As mentioned earlier, system-level operations like time are passed in from the API. In this case, we use the `Utc::now()` function from the [chrono][chrono-crate] crate to get the current time.
44//!
45//! `PublicDirectory` gets wrapped in `Rc` here because it lets us pass it around without worrying about ownership and lifetimes. Making the Rc `&mut` futher allows us to relinquish ownership to the interior `PublicDirectory` and point to a new one when needed (essentially for every write). This immutable way of handling changes has cool benefits like tracking and rolling back changes. It also makes collaborative editing easier to implement and reason about. You can find more examples in the [`wnfs/examples/`][wnfs-examples] folder.
46//!
47//! That's the public filesystem, the private filesystem, on the other hand, is a bit more involved. The [Hash Array Mapped Trie (HAMT)][hamt-wiki] is where we store the private filesystem tree and some other information related to it. HAMT allows for effective storage and retrieval of encrypted and obfuscated filesystem trees and `PrivateForest` is basically a HAMT that can contain multiple file trees with hash for keys and CIDs for values.
48//!
49//! ```rust
50//! use anyhow::Result;
51//! use chrono::Utc;
52//! use rand_chacha::ChaCha12Rng;
53//! use rand_core::SeedableRng;
54//! use wnfs::{
55//! common::MemoryBlockStore,
56//! private::{
57//! PrivateDirectory,
58//! forest::{hamt::HamtForest, traits::PrivateForest},
59//! }
60//! };
61//!
62//! #[async_std::main]
63//! async fn main() -> Result<()> {
64//! // Create an in-memory block store.
65//! let store = &MemoryBlockStore::default();
66//!
67//! // A random number generator.
68//! let rng = &mut ChaCha12Rng::from_entropy();
69//!
70//! // Create a private forest.
71//! let forest = &mut HamtForest::new_trusted_rc(rng);
72//!
73//! // Create a new private directory.
74//! let dir = &mut PrivateDirectory::new_rc(&forest.empty_name(), Utc::now(), rng);
75//!
76//! // Add a file to /pictures/cats directory.
77//! dir.mkdir(
78//! &["pictures".into(), "cats".into()],
79//! true,
80//! Utc::now(),
81//! forest,
82//! store,
83//! rng,
84//! )
85//! .await?;
86//!
87//! // Add a file to /pictures/dogs/billie.jpg file.
88//! dir.write(
89//! &["pictures".into(), "dogs".into(), "billie.jpg".into()],
90//! true,
91//! Utc::now(),
92//! b"Hello! This is billie".to_vec(),
93//! forest,
94//! store,
95//! rng,
96//! )
97//! .await?;
98//!
99//! // List all files in /pictures directory.
100//! let result = dir.ls(&["pictures".into()], true, forest, store).await?;
101//!
102//! println!("Files in /pictures: {:#?}", result);
103//!
104//! Ok(())
105//! }
106//! ```
107//!
108//! This example introduces a few new concepts. The first is the `HamtForest` which is a HAMT that can contain multiple file trees and implements the `PrivateForest` interface needed for persisting private file systems.
109//!
110//! The second is the `Name` (returned from `forest.empty_name()`) and `NameAccumulator` that lets us identify nodes in the filesystem, and are suitable for offspring proving.
111//!
112//! Finally, we have the random number generator, `rng`, that the library uses for generating new keys and other random values needed for the protocol.
113//!
114//! Check the [`wnfs/examples/`](wnfs-examples) folder for more examples.
115//!
116//!
117//! [blockstore-trait]: https://github.com/wnfs-wg/rs-wnfs/blob/main/wnfs-common/src/blockstore.rs
118//! [hamt-wiki]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie
119//! [ipld-spec]: https://ipld.io/
120//! [wnfs-examples]: https://github.com/wnfs-wg/rs-wnfs/tree/main/wnfs/examples
121//! [wnfs-graph-demo]: https://calm-thin-barista.fission.app
122//! [wnfs-spec]: https://github.com/wnfs-wg/spec
123
124#![deny(unsafe_code)]
125
126pub mod error;
127pub mod private;
128pub mod public;
129#[doc(hidden)] // The API is in "prerelease" for now
130pub mod root_tree;
131pub mod traits;
132mod utils;
133
134pub mod rand_core {
135 //! Re-exports of rand-core lib.
136 pub use rand_core::CryptoRngCore;
137}
138pub mod common {
139 //! Re-exports of wnfs-common lib.
140 pub use wnfs_common::*;
141}
142pub mod hamt {
143 //! Re-exports of wnfs-hamt lib.
144 pub use wnfs_hamt::*;
145}
146pub mod nameaccumulator {
147 //! Re-exports of wnfs-nameaccumulator lib.
148 pub use wnfs_nameaccumulator::*;
149}
150
151//--------------------------------------------------------------------------------------------------
152// Constants
153//--------------------------------------------------------------------------------------------------
154
155/// The version of the WNFS data format that this library outputs
156pub const WNFS_VERSION: semver::Version = semver::Version::new(1, 0, 0);
157
158//--------------------------------------------------------------------------------------------------
159// Types
160//--------------------------------------------------------------------------------------------------
161
162/// The result of an basic get operation.
163pub(crate) enum SearchResult<T> {
164 Missing(T, usize),
165 NotADir(T, #[allow(unused)] usize),
166 Found(T),
167}
168
169//--------------------------------------------------------------------------------------------------
170// Functions
171//--------------------------------------------------------------------------------------------------
172
173/// Whether given WNFS data format version can be read by this library
174pub fn is_readable_wnfs_version(version: &semver::Version) -> bool {
175 get_wnfs_version_req().matches(version)
176}
177
178/// The WNFS data format version requirement for this version of the library
179pub fn get_wnfs_version_req() -> semver::VersionReq {
180 use semver::*;
181 VersionReq {
182 comparators: vec![Comparator {
183 op: Op::Exact,
184 major: WNFS_VERSION.major,
185 minor: Some(WNFS_VERSION.minor),
186 patch: None,
187 pre: Prerelease::EMPTY,
188 }],
189 }
190}