Skip to content

docs: Add module docs #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This crate is used together with [iroh](https://crates.io/crates/iroh). Connecti

- **Requester:** The side that asks for data. It is initiating requests to one or many providers.

A node can be a provider and a requester at the same time.

## Getting started

Expand All @@ -31,33 +32,33 @@ Iroh provides a [`Router`](https://docs.rs/iroh/latest/iroh/protocol/struct.Rout

Here is a basic example of how to set up `iroh-blobs` with `iroh`:

```rust
```rust,no_run
use iroh::{protocol::Router, Endpoint};
use iroh_blobs::{store::Store, net_protocol::Blobs};
use iroh_blobs::{store::mem::MemStore, BlobsProtocol};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
// create an iroh endpoint that includes the standard discovery mechanisms
// we've built at number0
let endpoint = Endpoint::builder().discovery_n0().bind().await?;

// create an in-memory blob store
// use `iroh_blobs::net_protocol::Blobs::persistent` to load or create a
// persistent blob store from a path
let blobs = Blobs::memory().build(&endpoint);

// turn on the "rpc" feature if you need to create blobs and tags clients
let blobs_client = blobs.client();
let tags_client = blobs_client.tags();
// create a protocol handler using an in-memory blob store.
let store = MemStore::new();
let blobs = BlobsProtocol::new(&store, endpoint.clone(), None);

// build the router
let router = Router::builder(endpoint)
.accept(iroh_blobs::ALPN, blobs.clone())
.spawn();

// do fun stuff with the blobs protocol!
let tag = blobs.add_slice(b"Hello world").await?;
println!("We are now serving {}", blobs.ticket(tag).await?);

// wait for control-c
tokio::signal::ctrl_c().await;

// clean shutdown of router and store
router.shutdown().await?;
drop(tags_client);
Ok(())
}
```
Expand All @@ -81,4 +82,4 @@ at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.
shall be dual licensed as above, without any additional terms or conditions.
4 changes: 2 additions & 2 deletions examples/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use iroh::{protocol::Router, Endpoint};
use iroh_blobs::{net_protocol::Blobs, store::mem::MemStore, ticket::BlobTicket};
use iroh_blobs::{store::mem::MemStore, ticket::BlobTicket, BlobsProtocol};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand All @@ -12,7 +12,7 @@ async fn main() -> anyhow::Result<()> {
// We initialize an in-memory backing store for iroh-blobs
let store = MemStore::new();
// Then we initialize a struct that can accept blobs requests over iroh connections
let blobs = Blobs::new(&store, endpoint.clone(), None);
let blobs = BlobsProtocol::new(&store, endpoint.clone(), None);

// Grab all passed in arguments, the first one is the binary itself, so we skip it.
let args: Vec<String> = std::env::args().skip(1).collect();
Expand Down
24 changes: 12 additions & 12 deletions src/api/blobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl Blobs {
.await
}

pub fn add_slice(&self, data: impl AsRef<[u8]>) -> AddProgress {
pub fn add_slice(&self, data: impl AsRef<[u8]>) -> AddProgress<'_> {
let options = ImportBytesRequest {
data: Bytes::copy_from_slice(data.as_ref()),
format: crate::BlobFormat::Raw,
Expand All @@ -136,7 +136,7 @@ impl Blobs {
self.add_bytes_impl(options)
}

pub fn add_bytes(&self, data: impl Into<bytes::Bytes>) -> AddProgress {
pub fn add_bytes(&self, data: impl Into<bytes::Bytes>) -> AddProgress<'_> {
let options = ImportBytesRequest {
data: data.into(),
format: crate::BlobFormat::Raw,
Expand All @@ -145,7 +145,7 @@ impl Blobs {
self.add_bytes_impl(options)
}

pub fn add_bytes_with_opts(&self, options: impl Into<AddBytesOptions>) -> AddProgress {
pub fn add_bytes_with_opts(&self, options: impl Into<AddBytesOptions>) -> AddProgress<'_> {
let options = options.into();
let request = ImportBytesRequest {
data: options.data,
Expand All @@ -155,7 +155,7 @@ impl Blobs {
self.add_bytes_impl(request)
}

fn add_bytes_impl(&self, options: ImportBytesRequest) -> AddProgress {
fn add_bytes_impl(&self, options: ImportBytesRequest) -> AddProgress<'_> {
trace!("{options:?}");
let this = self.clone();
let stream = Gen::new(|co| async move {
Expand All @@ -180,7 +180,7 @@ impl Blobs {
AddProgress::new(self, stream)
}

pub fn add_path_with_opts(&self, options: impl Into<AddPathOptions>) -> AddProgress {
pub fn add_path_with_opts(&self, options: impl Into<AddPathOptions>) -> AddProgress<'_> {
let options = options.into();
self.add_path_with_opts_impl(ImportPathRequest {
path: options.path,
Expand All @@ -190,7 +190,7 @@ impl Blobs {
})
}

fn add_path_with_opts_impl(&self, options: ImportPathRequest) -> AddProgress {
fn add_path_with_opts_impl(&self, options: ImportPathRequest) -> AddProgress<'_> {
trace!("{:?}", options);
let client = self.client.clone();
let stream = Gen::new(|co| async move {
Expand All @@ -215,7 +215,7 @@ impl Blobs {
AddProgress::new(self, stream)
}

pub fn add_path(&self, path: impl AsRef<Path>) -> AddProgress {
pub fn add_path(&self, path: impl AsRef<Path>) -> AddProgress<'_> {
self.add_path_with_opts(AddPathOptions {
path: path.as_ref().to_owned(),
mode: ImportMode::Copy,
Expand All @@ -226,7 +226,7 @@ impl Blobs {
pub async fn add_stream(
&self,
data: impl Stream<Item = io::Result<Bytes>> + Send + Sync + 'static,
) -> AddProgress {
) -> AddProgress<'_> {
let inner = ImportByteStreamRequest {
format: crate::BlobFormat::Raw,
scope: Scope::default(),
Expand Down Expand Up @@ -521,7 +521,7 @@ pub struct Batch<'a> {
}

impl<'a> Batch<'a> {
pub fn add_bytes(&self, data: impl Into<Bytes>) -> BatchAddProgress {
pub fn add_bytes(&self, data: impl Into<Bytes>) -> BatchAddProgress<'_> {
let options = ImportBytesRequest {
data: data.into(),
format: crate::BlobFormat::Raw,
Expand All @@ -530,7 +530,7 @@ impl<'a> Batch<'a> {
BatchAddProgress(self.blobs.add_bytes_impl(options))
}

pub fn add_bytes_with_opts(&self, options: impl Into<AddBytesOptions>) -> BatchAddProgress {
pub fn add_bytes_with_opts(&self, options: impl Into<AddBytesOptions>) -> BatchAddProgress<'_> {
let options = options.into();
BatchAddProgress(self.blobs.add_bytes_impl(ImportBytesRequest {
data: options.data,
Expand All @@ -539,7 +539,7 @@ impl<'a> Batch<'a> {
}))
}

pub fn add_slice(&self, data: impl AsRef<[u8]>) -> BatchAddProgress {
pub fn add_slice(&self, data: impl AsRef<[u8]>) -> BatchAddProgress<'_> {
let options = ImportBytesRequest {
data: Bytes::copy_from_slice(data.as_ref()),
format: crate::BlobFormat::Raw,
Expand All @@ -548,7 +548,7 @@ impl<'a> Batch<'a> {
BatchAddProgress(self.blobs.add_bytes_impl(options))
}

pub fn add_path_with_opts(&self, options: impl Into<AddPathOptions>) -> BatchAddProgress {
pub fn add_path_with_opts(&self, options: impl Into<AddPathOptions>) -> BatchAddProgress<'_> {
let options = options.into();
BatchAddProgress(self.blobs.add_path_with_opts_impl(ImportPathRequest {
path: options.path,
Expand Down
31 changes: 30 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
#![doc = include_str!("../README.md")]
//! # Module docs
//!
//! The crate is designed to be used from the [iroh] crate.
//!
//! It implements a [protocol] for streaming content-addressed data transfer using
//! [BLAKE3] verified streaming.
//!
//! It also provides a [store] module for storage of blobs and outboards,
//! as well as a [persistent](crate::store::fs) and a [memory](crate::store::mem)
//! store implementation.
//!
//! To implement a server, the [provider] module provides helpers for handling
//! connections and individual requests given a store.
//!
//! To perform get requests, the [get] module provides utilities to perform
//! requests and store the result in a store, as well as a low level state
//! machine for executing requests.
//!
//! The client API is available in the [api] module. You can get a client
//! either from one of the [store] implementations, or from the [BlobsProtocol]
//! via a
//!
//! The [downloader](api::downloader) module provides a component to download blobs from
//! multiple sources and store them in a store.
//!
//! [BLAKE3]: https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf
//! [iroh]: https://docs.rs/iroh
mod hash;
pub mod store;
pub use hash::{BlobFormat, Hash, HashAndFormat};
Expand All @@ -11,11 +39,12 @@ mod net_protocol;
pub use net_protocol::BlobsProtocol;
pub mod protocol;
pub mod provider;
pub mod test;
pub mod ticket;
pub mod util;

#[cfg(test)]
mod tests;

pub mod test;

pub use protocol::ALPN;
10 changes: 9 additions & 1 deletion src/net_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
//! # }
//! ```

use std::{fmt::Debug, future::Future, sync::Arc};
use std::{fmt::Debug, future::Future, ops::Deref, sync::Arc};

use iroh::{
endpoint::Connection,
Expand Down Expand Up @@ -66,6 +66,14 @@ pub struct BlobsProtocol {
pub(crate) inner: Arc<BlobsInner>,
}

impl Deref for BlobsProtocol {
type Target = Store;

fn deref(&self) -> &Self::Target {
&self.inner.store
}
Comment on lines +72 to +74
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm not a huge fan of derefs, but also 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm not a huge fan of derefs, but also 🤷

If we don't like derefs in public APIs, we would also have to remove the deref from MemStore and FsStore to the client API. But if we want to do this, it would have to be a separate PR since it would affect a lot of places.

}

impl BlobsProtocol {
pub fn new(store: &Store, endpoint: Endpoint, events: Option<mpsc::Sender<Event>>) -> Self {
Self {
Expand Down
Loading