11use std:: path:: PathBuf ;
22
3- use clap:: Parser ;
4- use iroh:: { discovery:: pkarr:: PkarrResolver , protocol:: Router , Endpoint } ;
3+ use iroh:: { protocol:: Router , Endpoint } ;
54use 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- }
14-
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- }
305
31- async fn send ( filename : PathBuf ) -> anyhow:: Result < ( ) > {
6+ #[ tokio:: main]
7+ async fn main ( ) -> anyhow:: Result < ( ) > {
328 // Create an endpoint, it allows creating and accepting
339 // connections in the iroh p2p world
3410 let endpoint = Endpoint :: builder ( ) . discovery_n0 ( ) . bind ( ) . await ?;
@@ -38,82 +14,80 @@ async fn send(filename: PathBuf) -> anyhow::Result<()> {
3814 // Then we initialize a struct that can accept blobs requests over iroh connections
3915 let blobs = BlobsProtocol :: new ( & store, endpoint. clone ( ) , None ) ;
4016
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 ) ;
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 ( ) ;
4621
47- println ! ( "File hashed. Fetch this file by running:" ) ;
48- println ! (
49- "cargo run --example transfer -- receive {ticket} {}" ,
50- filename. display( )
51- ) ;
22+ match arg_refs. as_slice ( ) {
23+ [ "send" , filename] => {
24+ let filename: PathBuf = filename. parse ( ) ?;
25+ let abs_path = std:: path:: absolute ( & filename) ?;
5226
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 ( ) ;
27+ println ! ( "Hashing file." ) ;
5828
59- tokio:: signal:: ctrl_c ( ) . await ?;
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 ?;
6032
61- // Gracefully shut down the node
62- println ! ( "Shutting down." ) ;
63- router. shutdown ( ) . await ?;
64- Ok ( ( ) )
65- }
33+ let node_id = endpoint. node_id ( ) ;
34+ let ticket = BlobTicket :: new ( node_id. into ( ) , tag. hash , tag. format ) ;
6635
67- async fn receive ( ticket : BlobTicket , filename : PathBuf ) -> anyhow:: Result < ( ) > {
68- // Create a store to download blobs into
69- let store = MemStore :: new ( ) ;
36+ println ! ( "File hashed. Fetch this file by running:" ) ;
37+ println ! (
38+ "cargo run --example transfer -- receive {ticket} {}" ,
39+ filename. display( )
40+ ) ;
7041
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 ?;
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 ( ) ;
8047
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) ;
48+ tokio:: signal:: ctrl_c ( ) . await ?;
8449
85- println ! ( "Starting download." ) ;
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 ( ) ?;
8658
87- downloader
88- . download ( ticket . hash ( ) , [ ticket . node_addr ( ) . node_id ] )
89- . await ? ;
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 ) ;
9062
91- println ! ( "Finished download." ) ;
92- println ! ( "Copying to destination." ) ;
63+ println ! ( "Starting download." ) ;
9364
94- store. export ( ticket. hash ( ) , filename) . await ?;
65+ downloader
66+ . download ( ticket. hash ( ) , Some ( ticket. node_addr ( ) . node_id ) )
67+ . await ?;
9568
96- println ! ( "Finished copying." ) ;
69+ println ! ( "Finished download." ) ;
70+ println ! ( "Copying to destination." ) ;
9771
98- // Gracefully shut down the endpoint and the store
99- println ! ( "Shutting down." ) ;
100- endpoint. close ( ) . await ;
101- store. shutdown ( ) . await ?;
102- Ok ( ( ) )
103- }
72+ store. blobs ( ) . export ( ticket. hash ( ) , abs_path) . await ?;
10473
105- #[ tokio:: main]
106- async fn main ( ) -> anyhow:: Result < ( ) > {
107- setup_logging ( ) ;
108- let cli = Cli :: parse ( ) ;
74+ println ! ( "Finished copying." ) ;
10975
110- match cli . command {
111- Command :: Send { file } => {
112- send ( file ) . await ? ;
76+ // Gracefully shut down the node
77+ println ! ( "Shutting down." ) ;
78+ endpoint . close ( ) . await ;
11379 }
114- Command :: Receive { ticket, filename } => {
115- receive ( ticket, filename) . await ?;
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]" ) ;
11689 }
11790 }
91+
11892 Ok ( ( ) )
11993}
0 commit comments