//! 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::>() ); 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()); }