Skip to content

Commit 0c69f67

Browse files
committed
Add simple example about how to request a blob without a store.
1 parent 8601cdd commit 0c69f67

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ walkdir = "2.5.0"
6262
[features]
6363
hide-proto-docs = []
6464
metrics = []
65-
default = ["hide-proto-docs"]
65+
default = ["hide-proto-docs", "examples"]
6666
examples = ["iroh/discovery-local-network"]
6767

6868
[[example]]

examples/common/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(dead_code)]
12
use anyhow::Result;
23
use iroh::SecretKey;
34
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

examples/get-blob.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/// Example how to request a blob from a remote node without using a store.
2+
mod common;
3+
use bao_tree::io::BaoContentItem;
4+
use clap::Parser;
5+
use common::setup_logging;
6+
use iroh::discovery::pkarr::PkarrResolver;
7+
use iroh_blobs::{get::request::GetBlobItem, ticket::BlobTicket, BlobFormat};
8+
use n0_future::StreamExt;
9+
use tokio::io::AsyncWriteExt;
10+
11+
#[derive(Debug, Parser)]
12+
#[command(version, about)]
13+
pub struct Cli {
14+
/// Ticket describing the content to fetch and the node to fetch it from
15+
///
16+
/// This example only supports raw blobs.
17+
ticket: BlobTicket,
18+
/// True to print data as it arrives, false to complete the download and then
19+
/// print the data. Defaults to true.
20+
///
21+
/// Note that setting progress to false can lead to an out-of-memory error
22+
/// for very large blobs.
23+
#[arg(long, default_value = "true")]
24+
progress: bool,
25+
}
26+
27+
#[tokio::main]
28+
async fn main() -> anyhow::Result<()> {
29+
setup_logging();
30+
let cli = Cli::parse();
31+
let ticket = cli.ticket;
32+
let endpoint = iroh::Endpoint::builder()
33+
.discovery(PkarrResolver::n0_dns())
34+
.bind()
35+
.await?;
36+
anyhow::ensure!(
37+
ticket.format() == BlobFormat::Raw,
38+
"This example only supports raw blobs."
39+
);
40+
let connection = endpoint
41+
.connect(ticket.node_addr().node_id, iroh_blobs::ALPN)
42+
.await?;
43+
let mut progress = iroh_blobs::get::request::get_blob(connection, ticket.hash());
44+
let stats = if cli.progress {
45+
loop {
46+
match progress.next().await {
47+
Some(GetBlobItem::Item(item)) => match item {
48+
BaoContentItem::Leaf(leaf) => {
49+
tokio::io::stdout().write_all(&leaf.data).await?;
50+
}
51+
BaoContentItem::Parent(parent) => {
52+
tracing::info!("Parent: {parent:?}");
53+
}
54+
},
55+
Some(GetBlobItem::Done(stats)) => {
56+
break stats;
57+
}
58+
Some(GetBlobItem::Error(err)) => {
59+
anyhow::bail!("Error while streaming blob: {err}");
60+
}
61+
None => {
62+
anyhow::bail!("Stream ended unexpectedly.");
63+
}
64+
}
65+
}
66+
} else {
67+
let (bytes, stats) = progress.bytes_and_stats().await?;
68+
tokio::io::stdout().write_all(&bytes).await?;
69+
stats
70+
};
71+
tracing::info!("Stream done with stats: {stats:?}");
72+
Ok(())
73+
}

0 commit comments

Comments
 (0)