diff options
| author | murilo ijanc | 2026-03-24 15:04:03 -0300 |
|---|---|---|
| committer | murilo ijanc | 2026-03-24 15:04:03 -0300 |
| commit | 9821aabf0b50d2487b07502d3d2cd89e7d62bdbe (patch) | |
| tree | 53da095ff90cc755bac3d4bf699172b5e8cd07d6 /examples/remote_get.rs | |
| download | tesseras-dht-e908bc01403f4b8ef2a65fa6be43716fd1c6e003.tar.gz | |
Initial commitv0.1.0
NAT-aware Kademlia DHT library for peer-to-peer networks.
Features:
- Distributed key-value storage (iterative FIND_NODE, FIND_VALUE, STORE)
- NAT traversal via DTUN hole-punching and proxy relay
- Reliable Datagram Protocol (RDP) with 7-state connection machine
- Datagram transport with automatic fragmentation/reassembly
- Ed25519 packet authentication
- 256-bit node IDs (Ed25519 public keys)
- Rate limiting, ban list, and eclipse attack mitigation
- Persistence and metrics
- OpenBSD and Linux support
Diffstat (limited to 'examples/remote_get.rs')
| -rw-r--r-- | examples/remote_get.rs | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/examples/remote_get.rs b/examples/remote_get.rs new file mode 100644 index 0000000..60add19 --- /dev/null +++ b/examples/remote_get.rs @@ -0,0 +1,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()); +} |