aboutsummaryrefslogtreecommitdiffstats
path: root/examples/remote_get.rs
diff options
context:
space:
mode:
authormurilo ijanc2026-03-24 15:04:03 -0300
committermurilo ijanc2026-03-24 15:04:03 -0300
commit9821aabf0b50d2487b07502d3d2cd89e7d62bdbe (patch)
tree53da095ff90cc755bac3d4bf699172b5e8cd07d6 /examples/remote_get.rs
downloadtesseras-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.rs106
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());
+}