1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Use Hermes IPFS to distribute content using DHT
#![allow(clippy::println_empty_string)]

use hermes_ipfs::{HermesIpfs, IpfsPath};

/// Connect Node A, upload file and provide CID by adding to DHT
async fn connect_node_a_upload_and_provide(
    file_content: Vec<u8>,
) -> anyhow::Result<(HermesIpfs, IpfsPath)> {
    let hermes_ipfs = HermesIpfs::start().await?;
    println!("***************************************");
    println!("* Hermes IPFS node A has started.");
    println!("");
    let peer_id_a = hermes_ipfs.identity(None).await?;
    let addresses = hermes_ipfs.listening_addresses().await?;
    println!("* Peer ID: {peer_id_a}");
    for addr in addresses {
        println!("    * {addr}");
    }
    println!("***************************************");
    println!("");
    println!("***************************************");
    println!("* Adding file to IPFS:");
    println!("");
    let ipfs_path = hermes_ipfs.add_ipfs_file(file_content.into()).await?;
    println!("* IPFS file published at {ipfs_path}");
    let cid = ipfs_path.root().cid().ok_or(anyhow::anyhow!(
        "ERROR! Could not extract CID from IPFS path."
    ))?;
    println!("* CID: {cid}");
    println!("* CID Version: {:?}", cid.version());
    println!("***************************************");
    println!("");
    println!("***************************************");
    println!("* Providing content to DHT:");
    println!("");
    println!("* Providing {cid} as peer {peer_id_a}");
    println!("***************************************");
    println!("");
    Ok((hermes_ipfs, ipfs_path))
}

/// Connect Node A, upload file and provide CID by adding to DHT
async fn connect_node_b_to_node_a(node_a: &HermesIpfs) -> anyhow::Result<HermesIpfs> {
    let hermes_ipfs_b = HermesIpfs::start().await?;
    println!("***************************************");
    println!("* Hermes IPFS node B has started.");
    println!("");
    let peer_id_b = hermes_ipfs_b.identity(None).await?;
    // node_b.connect(peer_id_a).await?;
    println!("* Peer ID: {peer_id_b}");
    println!("* Listening addresses:");
    let addresses = hermes_ipfs_b.listening_addresses().await?;
    for addr in addresses {
        println!("    * {addr}");
    }
    println!("***************************************");
    println!("");
    println!("***************************************");
    println!("* Connecting Node B to Node A:");
    println!("");
    println!("* Adding peer listening addresses from Node A:");
    let node_a_addresses = node_a.listening_addresses().await?;
    let peer_a = node_a.identity(None).await?;
    for addr in node_a_addresses {
        hermes_ipfs_b.add_peer(peer_a, addr.clone()).await?;
        println!("    * {addr} - CONNECTED");
    }
    println!("***************************************");
    println!("");
    Ok(hermes_ipfs_b)
}

/// Example application.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // File to be uploaded
    let ipfs_file = b"DEMO FILE DISTRIBUTED WITH IPFS".to_vec();
    // Start Node A, publish file, and make node provider for CID
    let (hermes_ipfs_a, ipfs_path) = connect_node_a_upload_and_provide(ipfs_file.clone()).await?;
    // Start Node B, add listening addresses from Node A, and
    // connect to Node A's peer ID.
    let hermes_ipfs_b = connect_node_b_to_node_a(&hermes_ipfs_a).await?;

    println!("***************************************");
    println!("* Get content from IPFS path {ipfs_path}");
    println!("");
    // For illustration, the `ipfs_path` can be obtained from a known CID
    let ipfs_path_string = format!("{ipfs_path}");

    // Fetch the content from the `ipfs_path`.
    let fetched_bytes = hermes_ipfs_b
        .get_ipfs_file(ipfs_path_string.parse()?)
        .await?;
    assert_eq!(ipfs_file, fetched_bytes);
    let fetched_file = String::from_utf8(fetched_bytes)?;
    println!("* Fetched: {fetched_file:?}");
    println!("***************************************");
    println!("");
    // Stop the nodes and exit.
    hermes_ipfs_a.stop().await;
    println!("***************************************");
    println!("* Hermes IPFS node A has stopped.");
    println!("***************************************");
    hermes_ipfs_b.stop().await;
    println!("");
    println!("***************************************");
    println!("* Hermes IPFS node B has stopped.");
    println!("***************************************");
    Ok(())
}