diff --git a/examples/transfer.rs b/examples/transfer.rs index 63e156579..960274db7 100644 --- a/examples/transfer.rs +++ b/examples/transfer.rs @@ -1,10 +1,11 @@ -use std::{path::PathBuf, str::FromStr}; +use std::path::PathBuf; use anyhow::Result; use iroh::{protocol::Router, Endpoint}; use iroh_blobs::{ net_protocol::Blobs, - rpc::client::blobs::{ReadAtLen, WrapOption}, + rpc::client::blobs::WrapOption, + store::{ExportFormat, ExportMode}, ticket::BlobTicket, util::SetTagOption, }; @@ -19,41 +20,53 @@ async fn main() -> Result<()> { // Now we build a router that accepts blobs connections & routes them // to the blobs protocol. - let node = Router::builder(endpoint) + let router = Router::builder(endpoint) .accept(iroh_blobs::ALPN, blobs.clone()) .spawn() .await?; - let blobs = blobs.client(); + // We use a blobs client to interact with the blobs protocol we're running locally: + let blobs_client = blobs.client(); - let args = std::env::args().collect::>(); - match &args.iter().map(String::as_str).collect::>()[..] { - [_cmd, "send", path] => { - let abs_path = PathBuf::from_str(path)?.canonicalize()?; + // Grab all passed in arguments, the first one is the binary itself, so we skip it. + let args: Vec = std::env::args().skip(1).collect(); + // Convert to &str, so we can pattern-match easily: + let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect(); - println!("Analyzing file."); + match arg_refs.as_slice() { + ["send", filename] => { + let filename: PathBuf = filename.parse()?; + let abs_path = std::path::absolute(&filename)?; - let blob = blobs - .add_from_path(abs_path, true, SetTagOption::Auto, WrapOption::NoWrap) + println!("Hashing file."); + + // keep the file in place and link it, instead of copying it into the in-memory blobs database + let in_place = true; + let blob = blobs_client + .add_from_path(abs_path, in_place, SetTagOption::Auto, WrapOption::NoWrap) .await? .finish() .await?; - let node_id = node.endpoint().node_id(); + let node_id = router.endpoint().node_id(); let ticket = BlobTicket::new(node_id.into(), blob.hash, blob.format)?; - println!("File analyzed. Fetch this file by running:"); - println!("cargo run --example transfer -- receive {ticket} {path}"); + println!("File hashed. Fetch this file by running:"); + println!( + "cargo run --example transfer -- receive {ticket} {}", + filename.display() + ); tokio::signal::ctrl_c().await?; } - [_cmd, "receive", ticket, path] => { - let path_buf = PathBuf::from_str(path)?; - let ticket = BlobTicket::from_str(ticket)?; + ["receive", ticket, filename] => { + let filename: PathBuf = filename.parse()?; + let abs_path = std::path::absolute(filename)?; + let ticket: BlobTicket = ticket.parse()?; println!("Starting download."); - blobs + blobs_client .download(ticket.hash(), ticket.node_addr().clone()) .await? .finish() @@ -62,14 +75,21 @@ async fn main() -> Result<()> { println!("Finished download."); println!("Copying to destination."); - let mut file = tokio::fs::File::create(path_buf).await?; - let mut reader = blobs.read_at(ticket.hash(), 0, ReadAtLen::All).await?; - tokio::io::copy(&mut reader, &mut file).await?; + blobs_client + .export( + ticket.hash(), + abs_path, + ExportFormat::Blob, + ExportMode::Copy, + ) + .await? + .finish() + .await?; println!("Finished copying."); } _ => { - println!("Couldn't parse command line arguments."); + println!("Couldn't parse command line arguments: {args:?}"); println!("Usage:"); println!(" # to send:"); println!(" cargo run --example transfer -- send [FILE]"); @@ -82,7 +102,7 @@ async fn main() -> Result<()> { // Gracefully shut down the node println!("Shutting down."); - node.shutdown().await?; + router.shutdown().await?; Ok(()) }