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
|
//! Remote get example: FIND_VALUE across the network.
//!
//! Node 1 stores a value locally. Node 3 retrieves it
//! via iterative FIND_VALUE, even though it never
//! received a STORE.
//!
//! Usage:
//! cargo run --example remote_get
use std::time::Duration;
use tesseras_dht::Node;
use tesseras_dht::nat::NatState;
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();
// Create 3 nodes
let mut node1 = Node::bind(0).expect("bind");
node1.set_nat_state(NatState::Global);
let port1 = node1.local_addr().unwrap().port();
let mut node2 = Node::bind(0).expect("bind");
node2.set_nat_state(NatState::Global);
node2.join("127.0.0.1", port1).expect("join");
let mut node3 = Node::bind(0).expect("bind");
node3.set_nat_state(NatState::Global);
node3.join("127.0.0.1", port1).expect("join");
println!("Node 1: {} (has the value)", &node1.id_hex()[..8]);
println!("Node 2: {} (relay)", &node2.id_hex()[..8]);
println!("Node 3: {} (will search)", &node3.id_hex()[..8]);
// Let them discover each other
for _ in 0..10 {
node1.poll().ok();
node2.poll().ok();
node3.poll().ok();
std::thread::sleep(Duration::from_millis(20));
}
println!(
"\nRouting tables: N1={} N2={} N3={}",
node1.routing_table_size(),
node2.routing_table_size(),
node3.routing_table_size(),
);
// Node 1 stores a value locally only (no STORE sent)
println!("\n--- Node 1 stores 'secret-key' ---");
node1.put(b"secret-key", b"secret-value", 300, false);
// Verify: Node 3 does NOT have it
assert!(
node3.get(b"secret-key").is_empty(),
"Node 3 should not have the value yet"
);
println!("Node 3 get('secret-key'): [] (not found)");
// Node 3 does get() — triggers FIND_VALUE
println!("\n--- Node 3 searches via FIND_VALUE ---");
let _ = node3.get(b"secret-key"); // starts query
// Poll to let FIND_VALUE propagate
for _ in 0..15 {
node1.poll().ok();
node2.poll().ok();
node3.poll().ok();
std::thread::sleep(Duration::from_millis(30));
}
// Now Node 3 should have cached the value
let result = node3.get(b"secret-key");
println!(
"Node 3 get('secret-key'): {:?}",
result
.iter()
.map(|v| String::from_utf8_lossy(v).to_string())
.collect::<Vec<_>>()
);
if result.is_empty() {
println!("\n(Value not found — may need more poll rounds)");
} else {
println!("\nRemote get successful!");
}
// Storage summary
println!("\n--- Storage ---");
println!("Node 1: {} values", node1.storage_count());
println!("Node 2: {} values", node2.storage_count());
println!("Node 3: {} values", node3.storage_count());
}
|