Skip to content

Commit d38e92b

Browse files
committed
Rework transfer example to use clap
since the others use it as well
1 parent 0c69f67 commit d38e92b

File tree

1 file changed

+86
-60
lines changed

1 file changed

+86
-60
lines changed

examples/transfer.rs

Lines changed: 86 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
11
use std::path::PathBuf;
22

3-
use iroh::{protocol::Router, Endpoint};
3+
use clap::Parser;
4+
use iroh::{discovery::pkarr::PkarrResolver, protocol::Router, Endpoint};
45
use iroh_blobs::{store::mem::MemStore, ticket::BlobTicket, BlobsProtocol};
6+
mod common;
7+
use common::setup_logging;
8+
#[derive(Debug, Parser)]
9+
#[command(version, about)]
10+
pub struct Cli {
11+
#[clap(subcommand)]
12+
command: Command,
13+
}
514

6-
#[tokio::main]
7-
async fn main() -> anyhow::Result<()> {
15+
#[derive(Parser, Debug)]
16+
pub enum Command {
17+
/// Send a file to the network
18+
Send {
19+
/// Path to the file to send
20+
file: PathBuf,
21+
},
22+
/// Receive a file from the network
23+
Receive {
24+
/// Ticket describing the content to fetch
25+
ticket: BlobTicket,
26+
/// Path to save the received file
27+
filename: PathBuf,
28+
},
29+
}
30+
31+
async fn send(filename: PathBuf) -> anyhow::Result<()> {
832
// Create an endpoint, it allows creating and accepting
933
// connections in the iroh p2p world
1034
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
@@ -14,80 +38,82 @@ async fn main() -> anyhow::Result<()> {
1438
// Then we initialize a struct that can accept blobs requests over iroh connections
1539
let blobs = BlobsProtocol::new(&store, endpoint.clone(), None);
1640

17-
// Grab all passed in arguments, the first one is the binary itself, so we skip it.
18-
let args: Vec<String> = std::env::args().skip(1).collect();
19-
// Convert to &str, so we can pattern-match easily:
20-
let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
41+
let abs_path = std::path::absolute(&filename)?;
42+
let tag = store.blobs().add_path(abs_path).await?;
43+
44+
let node_id = endpoint.node_id();
45+
let ticket = BlobTicket::new(node_id.into(), tag.hash, tag.format);
2146

22-
match arg_refs.as_slice() {
23-
["send", filename] => {
24-
let filename: PathBuf = filename.parse()?;
25-
let abs_path = std::path::absolute(&filename)?;
47+
println!("File hashed. Fetch this file by running:");
48+
println!(
49+
"cargo run --example transfer -- receive {ticket} {}",
50+
filename.display()
51+
);
2652

27-
println!("Hashing file.");
53+
// For sending files we build a router that accepts blobs connections & routes them
54+
// to the blobs protocol.
55+
let router = Router::builder(endpoint)
56+
.accept(iroh_blobs::ALPN, blobs)
57+
.spawn();
2858

29-
// When we import a blob, we get back a "tag" that refers to said blob in the store
30-
// and allows us to control when/if it gets garbage-collected
31-
let tag = store.blobs().add_path(abs_path).await?;
59+
tokio::signal::ctrl_c().await?;
3260

33-
let node_id = endpoint.node_id();
34-
let ticket = BlobTicket::new(node_id.into(), tag.hash, tag.format);
61+
// Gracefully shut down the node
62+
println!("Shutting down.");
63+
router.shutdown().await?;
64+
Ok(())
65+
}
3566

36-
println!("File hashed. Fetch this file by running:");
37-
println!(
38-
"cargo run --example transfer -- receive {ticket} {}",
39-
filename.display()
40-
);
67+
async fn receive(ticket: BlobTicket, filename: PathBuf) -> anyhow::Result<()> {
68+
// Create a store to download blobs into
69+
let store = MemStore::new();
4170

42-
// For sending files we build a router that accepts blobs connections & routes them
43-
// to the blobs protocol.
44-
let router = Router::builder(endpoint)
45-
.accept(iroh_blobs::ALPN, blobs)
46-
.spawn();
71+
// Create an endpoint, it allows creating and accepting
72+
// connections in the iroh p2p world.
73+
//
74+
// Since we just want to receive files, we don't need a stable node address
75+
// or to publish our discovery information.
76+
let endpoint = Endpoint::builder()
77+
.discovery(PkarrResolver::n0_dns())
78+
.bind()
79+
.await?;
4780

48-
tokio::signal::ctrl_c().await?;
81+
// For receiving files, we create a "downloader" that allows us to fetch files
82+
// from other nodes via iroh connections
83+
let downloader = store.downloader(&endpoint);
4984

50-
// Gracefully shut down the node
51-
println!("Shutting down.");
52-
router.shutdown().await?;
53-
}
54-
["receive", ticket, filename] => {
55-
let filename: PathBuf = filename.parse()?;
56-
let abs_path = std::path::absolute(filename)?;
57-
let ticket: BlobTicket = ticket.parse()?;
85+
println!("Starting download.");
5886

59-
// For receiving files, we create a "downloader" that allows us to fetch files
60-
// from other nodes via iroh connections
61-
let downloader = store.downloader(&endpoint);
87+
downloader
88+
.download(ticket.hash(), [ticket.node_addr().node_id])
89+
.await?;
6290

63-
println!("Starting download.");
91+
println!("Finished download.");
92+
println!("Copying to destination.");
6493

65-
downloader
66-
.download(ticket.hash(), Some(ticket.node_addr().node_id))
67-
.await?;
94+
store.export(ticket.hash(), filename).await?;
6895

69-
println!("Finished download.");
70-
println!("Copying to destination.");
96+
println!("Finished copying.");
7197

72-
store.blobs().export(ticket.hash(), abs_path).await?;
98+
// Gracefully shut down the endpoint and the store
99+
println!("Shutting down.");
100+
endpoint.close().await;
101+
store.shutdown().await?;
102+
Ok(())
103+
}
73104

74-
println!("Finished copying.");
105+
#[tokio::main]
106+
async fn main() -> anyhow::Result<()> {
107+
setup_logging();
108+
let cli = Cli::parse();
75109

76-
// Gracefully shut down the node
77-
println!("Shutting down.");
78-
endpoint.close().await;
110+
match cli.command {
111+
Command::Send { file } => {
112+
send(file).await?;
79113
}
80-
_ => {
81-
println!("Couldn't parse command line arguments: {args:?}");
82-
println!("Usage:");
83-
println!(" # to send:");
84-
println!(" cargo run --example transfer -- send [FILE]");
85-
println!(" # this will print a ticket.");
86-
println!();
87-
println!(" # to receive:");
88-
println!(" cargo run --example transfer -- receive [TICKET] [FILE]");
114+
Command::Receive { ticket, filename } => {
115+
receive(ticket, filename).await?;
89116
}
90117
}
91-
92118
Ok(())
93119
}

0 commit comments

Comments
 (0)