aboutsummaryrefslogtreecommitdiffstats
path: root/examples/network.rs
blob: be3e0efa43faba58f1afb75a3a67fec50e70324f (plain)
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
//! Multi-node network example (equivalent to example2.cpp).
//!
//! Creates N nodes on localhost, joins them recursively
//! via the first node, then prints state periodically.
//!
//! Usage:
//!   cargo run --example network
//!   RUST_LOG=debug cargo run --example network

use std::time::{Duration, Instant};
use tesseras_dht::Node;
use tesseras_dht::nat::NatState;

const NUM_NODES: usize = 20;
const POLL_ROUNDS: usize = 30;

fn main() {
    env_logger::Builder::from_env(
        env_logger::Env::default().default_filter_or("info"),
    )
    .format(|buf, record| {
        use std::io::Write;
        writeln!(
            buf,
            "{} [{}] {}",
            record.level(),
            record.target(),
            record.args()
        )
    })
    .init();

    println!("Creating {NUM_NODES} nodes...");
    let start = Instant::now();

    // Create bootstrap node
    let mut nodes: Vec<Node> = Vec::new();
    let bootstrap = Node::bind(0).expect("bind bootstrap");
    let bootstrap_port = bootstrap.local_addr().unwrap().port();
    println!("Bootstrap: {} @ port {bootstrap_port}", bootstrap.id_hex());
    nodes.push(bootstrap);

    // Create and join remaining nodes
    for i in 1..NUM_NODES {
        let mut node = Node::bind(0).expect("bind node");
        node.set_nat_state(NatState::Global);
        node.join("127.0.0.1", bootstrap_port).expect("join");
        println!("Node {i}: {} joined", &node.id_hex()[..8]);
        nodes.push(node);
    }
    nodes[0].set_nat_state(NatState::Global);

    println!("\nAll {NUM_NODES} nodes created in {:?}", start.elapsed());

    // Poll all nodes to exchange messages
    println!("\nPolling {POLL_ROUNDS} rounds...");
    for round in 0..POLL_ROUNDS {
        for node in nodes.iter_mut() {
            node.poll().ok();
        }
        std::thread::sleep(Duration::from_millis(50));

        if (round + 1) % 10 == 0 {
            let sizes: Vec<usize> =
                nodes.iter().map(|n| n.routing_table_size()).collect();
            let avg = sizes.iter().sum::<usize>() / sizes.len();
            let max = sizes.iter().max().unwrap();
            println!(
                "  Round {}: avg routing table = {avg}, max = {max}",
                round + 1
            );
        }
    }

    // Print final state
    println!("\n--- Final state ---");
    for (i, node) in nodes.iter().enumerate() {
        println!(
            "Node {i}: {} | rt={} peers={} storage={}",
            &node.id_hex()[..8],
            node.routing_table_size(),
            node.peer_count(),
            node.storage_count(),
        );
    }
}