diff --git a/bitswap/src/behaviour.rs b/bitswap/src/behaviour.rs index a3719d35a..7d80f920e 100644 --- a/bitswap/src/behaviour.rs +++ b/bitswap/src/behaviour.rs @@ -26,6 +26,7 @@ use std::{ }, }; +/// Event used to communicate with the swarm or the higher level behaviour. #[derive(Clone, Debug, Eq, PartialEq)] pub enum BitswapEvent { ReceivedBlock(PeerId, Block), @@ -33,6 +34,7 @@ pub enum BitswapEvent { ReceivedCancel(PeerId, Cid), } +/// Bitswap statistics. #[derive(Debug, Default)] pub struct Stats { pub sent_blocks: AtomicU64, diff --git a/bitswap/src/block.rs b/bitswap/src/block.rs index 40cbaa9d2..1c1860033 100644 --- a/bitswap/src/block.rs +++ b/bitswap/src/block.rs @@ -1,8 +1,14 @@ use cid::Cid; +/// An Ipfs block consisting of a [`Cid`] and the bytes of the block. +/// +/// Note: At the moment the equality is based on [`Cid`] equality, which is based on the triple +/// `(cid::Version, cid::Codec, multihash)`. #[derive(Clone, Debug)] pub struct Block { + /// The content identifier for this block pub cid: Cid, + /// The data of this block pub data: Box<[u8]>, } @@ -11,6 +17,7 @@ impl PartialEq for Block { self.cid.hash() == other.cid.hash() } } + impl Eq for Block {} impl Block { diff --git a/http/README.md b/http/README.md index 2d89b817a..95875e76f 100644 --- a/http/README.md +++ b/http/README.md @@ -1,14 +1,18 @@ # ipfs-http crate -HTTP api on top of ipfs crate. The end binary has some rudimentary ipfs CLI +HTTP api on top of `ipfs` crate. The end binary has some rudimentary ipfs CLI functionality but mostly in the aim of testing the `rust-ipfs` via: - * [ipfs-rust-conformance](https://github.com/rs-ipfs/ipfs-rust-conformance) + * [conformance](../conformance) * [interop](https://github.com/rs-ipfs/interop/) +The vision for this crate is to eventually provide warp filters and async +methods suitable to providing the Ipfs HTTP API in other applications as well +instead of having to write application specific debug and introspection APIs. + HTTP specs: - * https://docs.ipfs.io/reference/api/http/ + * https://docs.ipfs.io/reference/http/api/ Status: Pre-alpha, most of the functionality is missing or `501 Not Implemented`. See the repository level README for more information. diff --git a/http/src/config.rs b/http/src/config.rs index ec741dac0..24abe3461 100644 --- a/http/src/config.rs +++ b/http/src/config.rs @@ -1,4 +1,4 @@ -//! go-ipfs compatible configuration file handling or at least setup. +//! go-ipfs compatible configuration file handling and setup. use parity_multiaddr::Multiaddr; use serde::{Deserialize, Serialize}; diff --git a/http/src/lib.rs b/http/src/lib.rs index e0a9d02d7..456b0bcd5 100644 --- a/http/src/lib.rs +++ b/http/src/lib.rs @@ -1,3 +1,8 @@ +//! `ipfs-http` http API implementation. +//! +//! This crate is most useful as a binary used first and foremost for compatibility testing against +//! other ipfs implementations. + #[macro_use] extern crate tracing; diff --git a/http/src/v0.rs b/http/src/v0.rs index 43bc6aeea..c4f2a1354 100644 --- a/http/src/v0.rs +++ b/http/src/v0.rs @@ -1,3 +1,7 @@ +//! Implementation of `/api/v0` HTTP endpoints. +//! +//! See https://docs.ipfs.io/reference/http/api/ for more information. + use ipfs::{Ipfs, IpfsTypes}; use warp::{query, Filter}; diff --git a/src/dag.rs b/src/dag.rs index 0811599be..02a824d67 100644 --- a/src/dag.rs +++ b/src/dag.rs @@ -1,3 +1,5 @@ +//! `ipfs.dag` interface implementation around [`Ipfs`]. + use crate::error::Error; use crate::ipld::{decode_ipld, encode_ipld, Ipld}; use crate::path::{IpfsPath, SlashedPath}; @@ -854,7 +856,7 @@ mod tests { // FIXME: validate that go-ipfs still does this let equiv_paths = vec![ prefix.sub_path("0/0").unwrap(), - prefix.into_sub_path("0/./0").unwrap(), + prefix.sub_path("0/./0").unwrap(), ]; for p in equiv_paths { diff --git a/src/error.rs b/src/error.rs index 5539d59b3..68ba1045d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,17 @@ +//! Crate-wide errors. +//! +//! The error handling in `ipfs` is subject to change in the future. + +/// Just re-export anyhow for now. +/// +/// # Stability +/// +/// Very likely to change in the future. pub use anyhow::Error; +/// A try conversion failed. +/// +/// # Stability +/// +/// Very likely to change in the future. pub struct TryError; diff --git a/src/ipld/ipld_macro.rs b/src/ipld/ipld_macro.rs index 8cc3e324c..ae27fa86a 100644 --- a/src/ipld/ipld_macro.rs +++ b/src/ipld/ipld_macro.rs @@ -1,3 +1,5 @@ +/// Easy to use nested [`crate::ipld::Ipld`] creation with syntax similar to +/// [`serde_json::json`](https://docs.rs/serde_json/1.0/serde_json/macro.json.html) macro. #[macro_export(local_inner_macros)] macro_rules! make_ipld { // Hide distracting implementation details from the generated rustdoc. diff --git a/src/ipld/mod.rs b/src/ipld/mod.rs index b113055d2..00a452558 100644 --- a/src/ipld/mod.rs +++ b/src/ipld/mod.rs @@ -1,7 +1,9 @@ -// This code was adapted from https://github.com/ipfs-rust/rust-ipld, and most of -// its code is the same as at revision b2286c53c13f3eeec2a3766387f2926838e8e4c9; -// it used to be a direct dependency, but recent updates to cid and multihash crates -// made it incompatible with them. +//! IPLD dag-json, dag-cbor and some dag-pb functionality. +//! +//! This code was adapted from https://github.com/ipfs-rust/rust-ipld, and most of +//! its code is the same as at revision b2286c53c13f3eeec2a3766387f2926838e8e4c9; +//! it used to be a direct dependency, but recent updates to cid and multihash crates +//! made it incompatible with them. pub mod dag_cbor; pub mod dag_json; diff --git a/src/ipns/mod.rs b/src/ipns/mod.rs index 602cc39dc..23e270e60 100644 --- a/src/ipns/mod.rs +++ b/src/ipns/mod.rs @@ -1,3 +1,5 @@ +//! IPNS functionality around [`Ipfs`]. + use crate::error::Error; use crate::path::{IpfsPath, PathRoot}; use crate::repo::RepoTypes; @@ -5,6 +7,7 @@ use crate::Ipfs; mod dnslink; +/// IPNS facade around [`Ipns`]. #[derive(Clone, Debug)] pub struct Ipns { ipfs: Ipfs, diff --git a/src/lib.rs b/src/lib.rs index 8d2f4ee6c..39a25cbb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,20 @@ //! IPFS node implementation +//! +//! [Ipfs](https://ipfs.io) is a peer-to-peer system with content addressed functionality. The main +//! entry point for users of this crate is the [`Ipfs`] facade, which allows access to most of the +//! implemented functionality. +//! +//! This crate passes a lot of the [interface-ipfs-core] test suite; most of that functionality is +//! in `ipfs-http` crate. The crate has some interoperability with the [go-ipfs] and [js-ipfs] +//! implementations. +//! +//! `ipfs` is an early alpha level crate: APIs and their implementation are subject to change in +//! any upcoming release at least for now. The aim of the crate is to become a library-first +//! production ready implementation of an Ipfs node. +//! +//! [interface-ipfs-core]: https://www.npmjs.com/package/interface-ipfs-core +//! [go-ipfs]: https://github.com/ipfs/go-ipfs/ +//! [js-ipfs]: https://github.com/ipfs/js-ipfs/ //#![deny(missing_docs)] mod config; @@ -65,22 +81,19 @@ pub use self::{ path::IpfsPath, repo::{PinKind, PinMode, RepoTypes}, }; -pub use bitswap::{BitswapEvent, Block, Stats}; +pub use bitswap::Block; pub use cid::Cid; pub use libp2p::{ - core::{ - connection::ListenerId, multiaddr::Protocol, ConnectedPoint, Multiaddr, PeerId, PublicKey, - }, + core::{connection::ListenerId, multiaddr::Protocol, Multiaddr, PeerId, PublicKey}, identity::Keypair, kad::{record::Key, Quorum}, }; -/// All types can be changed at compile time by implementing -/// `IpfsTypes`. +/// Represents the configuration of the Ipfs node, its backing blockstore and datastore. pub trait IpfsTypes: RepoTypes {} impl IpfsTypes for T {} -/// Default IPFS types. +/// Default node configuration, currently with persistent block store and data store for pins. #[derive(Debug)] pub struct Types; impl RepoTypes for Types { @@ -88,7 +101,7 @@ impl RepoTypes for Types { type TDataStore = repo::fs::FsDataStore; } -/// Testing IPFS types +/// In-memory testing configuration used in tests. #[derive(Debug)] pub struct TestTypes; impl RepoTypes for TestTypes { @@ -96,27 +109,43 @@ impl RepoTypes for TestTypes { type TDataStore = repo::mem::MemDataStore; } -/// Ipfs options +/// Ipfs node options used to configure the node to be created with [`UninitializedIpfs`]. #[derive(Clone)] pub struct IpfsOptions { - /// The path of the ipfs repo. + /// The path of the ipfs repo (blockstore and datastore). + /// + /// This is always required but can be any path with in-memory backends. The filesystem backend + /// creates a directory structure alike but not compatible to other ipfs implementations. + /// + /// # Incompatiblity and interop warning + /// + /// It is **not** recommended to set this to IPFS_PATH without first at least backing up your + /// existing repository. pub ipfs_path: PathBuf, - /// The keypair used with libp2p. + + /// The keypair used with libp2p, the identity of the node. pub keypair: Keypair, - /// Nodes dialed during startup. + + /// Nodes used as bootstrap peers. pub bootstrap: Vec<(Multiaddr, PeerId)>, - /// Enables mdns for peer discovery when true. + + /// Enables mdns for peer discovery and announcement when true. pub mdns: bool, + /// Custom Kademlia protocol name. + /// + /// The name given here is passed to [`libp2p_kad::KademliaConfig::set_protocol_name`]. + /// + /// [`libp2p_kad::KademliaConfig::set_protocol_name`]: https://docs.rs/libp2p-kad/*/libp2p_kad/struct.KademliaConfig.html##method.set_protocol_name pub kad_protocol: Option, - /// Custom listening addresses. + /// Bound listening addresses; by default the node will not listen on any address. pub listening_addrs: Vec, } impl fmt::Debug for IpfsOptions { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { // needed since libp2p::identity::Keypair does not have a Debug impl, and the IpfsOptions - // is a struct with all public fields, so don't enforce users to use this wrapper. + // is a struct with all public fields, don't enforce users to use this wrapper. fmt.debug_struct("IpfsOptions") .field("ipfs_path", &self.ipfs_path) .field("bootstrap", &self.bootstrap) @@ -129,7 +158,9 @@ impl fmt::Debug for IpfsOptions { } impl IpfsOptions { - /// Creates an inmemory store backed node for tests + /// Creates an in-memory store backed configuration useful for any testing purposes. + /// + /// Also used from examples. pub fn inmemory_with_generated_keys() -> Self { Self { ipfs_path: env::temp_dir(), @@ -236,6 +267,13 @@ impl Default for IpfsOptions { } } +/// The facade for the Ipfs node. +/// +/// The facade has most of the functionality either directly as a method or the functionality can +/// be implemented using the provided methods. For more information, see examples or the HTTP +/// endpoint implementations in `ipfs-http`. +/// +/// The facade is created through [`UninitializedIpfs`] which is configured with [`IpfsOptions`]. #[derive(Debug)] pub struct Ipfs(Arc>); @@ -245,9 +283,9 @@ impl Clone for Ipfs { } } -/// Ipfs struct creates a new IPFS node and is the main entry point -/// for interacting with IPFS. +/// The internal shared implementation of [`Ipfs`]. #[derive(Debug)] +#[doc(hidden)] pub struct IpfsInner { pub span: Span, repo: Repo, @@ -315,7 +353,7 @@ enum IpfsEvent { Exit, } -/// Configured Ipfs instace or value which can be only initialized. +/// Configured Ipfs which can only be started. pub struct UninitializedIpfs { repo: Repo, span: Span, @@ -405,6 +443,7 @@ impl Deref for Ipfs { } impl Ipfs { + /// Return an [`IpldDag`] for DAG operations pub fn dag(&self) -> IpldDag { IpldDag::new(self.clone()) } @@ -529,21 +568,20 @@ impl Ipfs { .await } - /// Checks whether a given block is pinned. At the moment does not support incomplete recursive - /// pins. + /// Checks whether a given block is pinned. /// /// Returns true if the block is pinned, false if not. See Crash unsafety notes for the false /// response. /// /// # Crash unsafety /// - /// Cannot detect partially written recursive pins. Those can happen if `Ipfs::insert_pin(cid, - /// recursive: true)` is interrupted by a crash for example. + /// Cannot currently detect partially written recursive pins. Those can happen if + /// `Ipfs::insert_pin(cid, true)` is interrupted by a crash for example. /// /// Works correctly only under no-crash situations. Workaround for hitting a crash is to re-pin /// any existing recursive pins. /// - /// TODO: This operation could be provided as a `Ipfs::fix_pins()`. + // TODO: This operation could be provided as a `Ipfs::fix_pins()`. pub async fn is_pinned(&self, cid: &Cid) -> Result { let span = debug_span!(parent: &self.span, "is_pinned", cid = %cid); self.repo.is_pinned(cid).instrument(span).await @@ -551,6 +589,8 @@ impl Ipfs { /// Lists all pins, or the specific kind thereof. /// + /// # Crash unsafety + /// /// Does not currently recover from partial recursive pin insertions. pub async fn list_pins( &self, @@ -561,7 +601,9 @@ impl Ipfs { } /// Read specific pins. When `requirement` is `Some`, all pins are required to be of the given - /// `PinMode`. + /// [`PinMode`]. + /// + /// # Crash unsafety /// /// Does not currently recover from partial recursive pin insertions. pub async fn query_pins( @@ -576,7 +618,9 @@ impl Ipfs { .await } - /// Puts an ipld dag node into the ipfs repo. + /// Puts an ipld node into the ipfs repo using `dag-cbor` codec and Sha2_256 hash. + /// + /// Returns Cid version 1 for the document pub async fn put_dag(&self, ipld: Ipld) -> Result { self.dag() .put(ipld, Codec::DagCBOR) @@ -584,7 +628,9 @@ impl Ipfs { .await } - /// Gets an ipld dag node from the ipfs repo. + /// Gets an ipld node from the ipfs, fetching the block if necessary. + /// + /// See [`IpldDag::get`] for more information. pub async fn get_dag(&self, path: IpfsPath) -> Result { self.dag() .get(path) @@ -637,6 +683,12 @@ impl Ipfs { .await } + /// Connects to the peer at the given Multiaddress. + /// + /// Accepts only multiaddresses with the PeerId to authenticate the connection. + /// + /// Returns a future which will complete when the connection has been successfully made or + /// failed for whatever reason. pub async fn connect(&self, target: MultiaddrWithPeerId) -> Result<(), Error> { async move { let (tx, rx) = oneshot_channel(); @@ -656,6 +708,7 @@ impl Ipfs { .await } + /// Returns known peer addresses pub async fn addrs(&self) -> Result)>, Error> { async move { let (tx, rx) = oneshot_channel(); @@ -666,6 +719,7 @@ impl Ipfs { .await } + /// Returns local listening addresses pub async fn addrs_local(&self) -> Result, Error> { async move { let (tx, rx) = oneshot_channel(); @@ -676,6 +730,7 @@ impl Ipfs { .await } + /// Returns the connected peers pub async fn peers(&self) -> Result, Error> { async move { let (tx, rx) = oneshot_channel(); @@ -689,6 +744,10 @@ impl Ipfs { .await } + /// Disconnects a given peer. + /// + /// At the moment the peer is disconnected by temporarily banning the peer and unbanning it + /// right after. This should always disconnect all connections to the peer. pub async fn disconnect(&self, target: MultiaddrWithPeerId) -> Result<(), Error> { async move { let (tx, rx) = oneshot_channel(); @@ -730,7 +789,7 @@ impl Ipfs { /// Subscribes to a given topic. Can be done at most once without unsubscribing in the between. /// The subscription can be unsubscribed by dropping the stream or calling - /// [`pubsub_unsubscribe`]. + /// [`Ipfs::pubsub_unsubscribe`]. pub async fn pubsub_subscribe(&self, topic: String) -> Result { async move { let (tx, rx) = oneshot_channel(); @@ -763,6 +822,9 @@ impl Ipfs { .await } + /// Forcibly unsubscribes a previously made [`SubscriptionStream`], which could also be + /// unsubscribed by dropping the stream. + /// /// Returns true if unsubscription was successful pub async fn pubsub_unsubscribe(&self, topic: &str) -> Result { async move { @@ -811,6 +873,7 @@ impl Ipfs { .await } + /// Returns the known wantlist for the local node when the `peer` is `None` or the wantlist of the given `peer` pub async fn bitswap_wantlist( &self, peer: Option, @@ -829,10 +892,15 @@ impl Ipfs { .await } + /// Returns a list of local blocks + /// + /// This implementation is subject to change into a stream, which might only include the pinned + /// blocks. pub async fn refs_local(&self) -> Result, Error> { self.repo.list_blocks().instrument(self.span.clone()).await } + /// Returns the accumulated bitswap stats pub async fn bitswap_stats(&self) -> Result { async move { let (tx, rx) = oneshot_channel(); @@ -933,6 +1001,8 @@ impl Ipfs { } /// Performs a DHT lookup for providers of a value to the given key. + /// + /// Returns a list of peers found providing the Cid. pub async fn get_providers(&self, cid: Cid) -> Result, Error> { let kad_result = async move { let (tx, rx) = oneshot_channel(); @@ -1548,15 +1618,24 @@ impl Future for IpfsFuture { } } +/// Bitswap statistics #[derive(Clone, Debug, Eq, PartialEq)] pub struct BitswapStats { + /// The number of IPFS blocks sent to other peers pub blocks_sent: u64, + /// The number of bytes sent in IPFS blocks to other peers pub data_sent: u64, + /// The number of IPFS blocks received from other peers pub blocks_received: u64, + /// The number of bytes received in IPFS blocks from other peers pub data_received: u64, + /// Duplicate blocks received (the block had already been received previously) pub dup_blks_received: u64, + /// The number of bytes in duplicate blocks received pub dup_data_received: u64, + /// The current peers pub peers: Vec, + /// The wantlist of the local node pub wantlist: Vec<(Cid, bitswap::Priority)>, } @@ -1580,6 +1659,7 @@ impl From<(bitswap::Stats, Vec, Vec<(Cid, bitswap::Priority)>)> for Bits #[doc(hidden)] pub use node::Node; +/// Node module provides an easy to use interface used in `tests/`. mod node { use super::*; use std::convert::TryFrom; diff --git a/src/p2p/pubsub.rs b/src/p2p/pubsub.rs index 458c30cd6..3479b9d97 100644 --- a/src/p2p/pubsub.rs +++ b/src/p2p/pubsub.rs @@ -169,8 +169,10 @@ impl Pubsub { } } - /// Unsubscribes from a topic. - /// Returns true if an existing subscription was dropped + /// Unsubscribes from a topic. Unsubscription is usually done through dropping the + /// SubscriptionStream. + /// + /// Returns true if an existing subscription was dropped, false otherwise pub fn unsubscribe(&mut self, topic: impl Into) -> bool { let topic = Topic::new(topic); if self.streams.remove(&topic).is_some() { diff --git a/src/path.rs b/src/path.rs index 87da90d52..00f22c312 100644 --- a/src/path.rs +++ b/src/path.rs @@ -1,12 +1,35 @@ +//! [`IpfsPath`] related functionality for content addressed paths with links. + use crate::error::{Error, TryError}; -use crate::ipld::Ipld; use cid::Cid; use core::convert::{TryFrom, TryInto}; use libp2p::PeerId; use std::fmt; use std::str::FromStr; -use thiserror::Error; +/// Abstraction over Ipfs paths, which are used to target sub-trees or sub-documents on top of +/// content addressable ([`Cid`]) trees. The most common use case is to specify a file under an +/// unixfs tree from underneath a [`Cid`] forest. +/// +/// In addition to being based on content addressing, IpfsPaths provide adaptation from other Ipfs +/// (related) functionality which can be resolved to a [`Cid`] such as IPNS. IpfsPaths have similar +/// structure to and can start with a "protocol" as [Multiaddr], except the protocols are +/// different, and at the moment there can be at most one protocol. +/// +/// This implementation supports: +/// +/// - synonymous `/ipfs` and `/ipld` prefixes to point to a [`Cid`] +/// - `/ipns` to point to either: +/// - [`PeerId`] to signify an [IPNS] DHT record +/// - domain name to signify an [DNSLINK] reachable record +/// +/// See [`crate::Ipfs::resolve_ipns`] for the current IPNS resolving capabilities. +/// +/// `IpfsPath` is usually created through the [`FromStr`] or [`From`] conversions. +/// +/// [Multiaddr]: https://github.com/multiformats/multiaddr +/// [IPNS]: https://github.com/ipfs/specs/blob/master/IPNS.md +/// [DNSLINK]: https://dnslink.io/ // TODO: it might be useful to split this into CidPath and IpnsPath, then have Ipns resolve through // latter into CidPath (recursively) and have dag.rs support only CidPath. Keep IpfsPath as a // common abstraction which can be either. @@ -38,7 +61,6 @@ impl FromStr for IpfsPath { None => PathRoot::Dns(key.to_string()), }, _ => { - //todo!("empty: {:?}, root: {:?}, key: {:?}", empty, root_type, key); return Err(IpfsPathError::InvalidPath(string.to_owned()).into()); } } @@ -64,26 +86,19 @@ impl IpfsPath { &self.root } - pub fn set_root(&mut self, root: PathRoot) { - self.root = root; - } - - pub fn push_str(&mut self, string: &str) -> Result<(), Error> { + pub(crate) fn push_str(&mut self, string: &str) -> Result<(), Error> { self.path.push_path(string)?; Ok(()) } - pub fn sub_path(&self, string: &str) -> Result { + /// Returns a new [`IpfsPath`] with the given path segments appended, or an error, if a segment is + /// invalid. + pub fn sub_path(&self, segments: &str) -> Result { let mut path = self.to_owned(); - path.push_str(string)?; + path.push_str(segments)?; Ok(path) } - pub fn into_sub_path(mut self, string: &str) -> Result { - self.push_str(string)?; - Ok(self) - } - /// Returns an iterator over the path segments following the root pub fn iter(&self) -> impl Iterator { self.path.iter().map(|s| s.as_str()) @@ -148,7 +163,7 @@ impl SlashedPath { Ok(()) } else { self.push_split(path.split('/')) - .map_err(|_| IpfsPathError::InvalidPath(path.to_owned())) + .map_err(|_| IpfsPathError::SegmentContainsSlash(path.to_owned())) } } @@ -172,15 +187,18 @@ impl SlashedPath { Ok(()) } + /// Returns an iterator over the path segments pub fn iter(&self) -> impl Iterator { self.path.iter() } + /// Returns the number of segments pub fn len(&self) -> usize { // intentionally try to hide the fact that this is based on Vec right now self.path.len() } + /// Returns true if len is zero pub fn is_empty(&self) -> bool { self.len() == 0 } @@ -217,10 +235,14 @@ impl<'a> PartialEq<[&'a str]> for SlashedPath { } } +/// The "protocol" of [`IpfsPath`]. #[derive(Clone, PartialEq, Eq, Hash)] pub enum PathRoot { + /// [`Cid`] based path is the simplest path, and is stable. Ipld(Cid), + /// IPNS record based path which can point to different [`Cid`] based paths at different times. Ipns(PeerId), + /// DNSLINK based path which can point to different [`Cid`] based paths at different times. Dns(String), } @@ -237,41 +259,12 @@ impl fmt::Debug for PathRoot { } impl PathRoot { - pub fn is_ipld(&self) -> bool { - matches!(self, PathRoot::Ipld(_)) - } - - pub fn is_ipns(&self) -> bool { - matches!(self, PathRoot::Ipns(_)) - } - pub fn cid(&self) -> Option<&Cid> { match self { PathRoot::Ipld(cid) => Some(cid), _ => None, } } - - pub fn peer_id(&self) -> Option<&PeerId> { - match self { - PathRoot::Ipns(peer_id) => Some(peer_id), - _ => None, - } - } - - pub fn to_bytes(&self) -> Vec { - self.into() - } -} - -impl Into> for &PathRoot { - fn into(self) -> Vec { - match self { - PathRoot::Ipld(cid) => cid.to_bytes(), - PathRoot::Ipns(peer_id) => peer_id.as_bytes().to_vec(), - PathRoot::Dns(domain) => domain.as_bytes().to_vec(), - } - } } impl fmt::Display for PathRoot { @@ -319,14 +312,17 @@ impl TryInto for PathRoot { } } -#[derive(Debug, Error)] +/// The path mutation or parsing errors. +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum IpfsPathError { + /// The given path cannot be parsed as IpfsPath. #[error("Invalid path {0:?}")] InvalidPath(String), - #[error("Can't resolve {path:?}")] - ResolveError { ipld: Ipld, path: String }, - #[error("Expected ipld path but found ipns path.")] - ExpectedIpldPath, + + /// Path segment contains a slash, which is not allowed. + #[error("Invalid segment {0:?}")] + SegmentContainsSlash(String), } #[cfg(test)] diff --git a/src/refs.rs b/src/refs.rs index 19f811631..f7a8f6c01 100644 --- a/src/refs.rs +++ b/src/refs.rs @@ -1,3 +1,5 @@ +//! `refs` or the references of dag-pb and other supported IPLD formats functionality. + use crate::ipld::{decode_ipld, Ipld}; use crate::{Block, Ipfs, IpfsTypes}; use async_stream::stream; @@ -11,7 +13,7 @@ use std::fmt; /// Represents a single link in an IPLD tree encountered during a `refs` walk. #[derive(Clone, PartialEq, Eq)] pub struct Edge { - /// Source document which links to [`destination`] + /// Source document which links to [`Edge::destination`] pub source: Cid, /// The destination document pub destination: Cid, diff --git a/src/repo/fs.rs b/src/repo/fs.rs index 30e14d0ca..2a7f634d2 100644 --- a/src/repo/fs.rs +++ b/src/repo/fs.rs @@ -1,4 +1,7 @@ -//! Persistent fs backed repo +//! Persistent fs backed repo. +//! +//! Consists of [`FsDataStore`] and [`FsBlockStore`]. + use crate::error::Error; use async_trait::async_trait; use std::path::PathBuf; @@ -19,12 +22,12 @@ mod paths; use paths::{block_path, filestem_to_block_cid, filestem_to_pin_cid, pin_path}; /// FsDataStore which uses the filesystem as a lockable key-value store. Maintains a similar to -/// blockstore sharded two level storage. Direct have empty files, recursive pins record all of +/// [`FsBlockStore`] sharded two level storage. Direct have empty files, recursive pins record all of /// their indirect descendants. Pin files are separated by their file extensions. /// -/// When modifying, single write lock is used. +/// When modifying, single lock is used. /// -/// For the PinStore implementation, please see `fs/pinstore.rs`. +/// For the [`crate::repo::PinStore`] implementation see `fs/pinstore.rs`. #[derive(Debug)] pub struct FsDataStore { /// The base directory under which we have a sharded directory structure, and the individual diff --git a/src/repo/fs/blocks.rs b/src/repo/fs/blocks.rs index c6a7a7d1e..7ca3e2d9a 100644 --- a/src/repo/fs/blocks.rs +++ b/src/repo/fs/blocks.rs @@ -20,7 +20,7 @@ type ArcMutexMap = Arc>>; /// File system backed block store. /// -/// For information on path mangling, please see [`block_path`] and [`filestem_to_block_cid`]. +/// For information on path mangling, please see `block_path` and `filestem_to_block_cid`. #[derive(Debug)] pub struct FsBlockStore { /// The base directory under which we have a sharded directory structure, and the individual diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 0da24cfcb..ea7f28786 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -1,4 +1,4 @@ -//! IPFS repo +//! Storage implementation(s) backing the [`crate::Ipfs`]. use crate::error::Error; use crate::p2p::KadResult; use crate::path::IpfsPath; @@ -259,7 +259,7 @@ impl Repo { } /// Shutdowns the repo, cancelling any pending subscriptions; Likely going away after some - /// refactoring, see notes on [`Ipfs::exit_daemon`]. + /// refactoring, see notes on [`crate::Ipfs::exit_daemon`]. pub fn shutdown(&self) { self.subscriptions.shutdown(); } diff --git a/src/unixfs/mod.rs b/src/unixfs/mod.rs index bb950fcef..62ee020bf 100644 --- a/src/unixfs/mod.rs +++ b/src/unixfs/mod.rs @@ -1,3 +1,8 @@ +//! Adaptation for `ipfs-unixfs` crate functionality on top of [`crate::Ipfs`]. +//! +//! Adding files and directory structures is supported but not exposed via an API. See examples and +//! `ipfs-http`. + pub use ipfs_unixfs as ll; mod cat;