//! Simulated mesh leg: **A (LoRa)** → **B (LoRa + TCP relay)** → **C (TCP)** → zurück über B → **A**. //! //! Uses [`quicprochat_p2p::transport_lora::LoRaMockMedium`] — keine Hardware. //! //! ```text //! Node A Node B Node C //! LoRa addr 0x01 LoRa 0x02 + TCP listen TCP (WiFi / LAN) //! │ │ │ //! └──── LoRa ───────┘ │ //! └──────── TCP ──────────────┘ //! ``` //! //! Run: `cargo run -p quicprochat-p2p --example mesh_lora_relay_demo` use std::sync::Arc; use std::time::Duration; use quicprochat_p2p::transport::{MeshTransport, TransportAddr}; use quicprochat_p2p::transport_lora::{DutyCycleTracker, LoRaConfig, LoRaMockMedium}; use quicprochat_p2p::transport_tcp::TcpTransport; const ADDR_A: [u8; 4] = [0x01, 0, 0, 0]; const ADDR_B: [u8; 4] = [0x02, 0, 0, 0]; #[tokio::main] async fn main() -> anyhow::Result<()> { let medium = LoRaMockMedium::new(); let duty = Arc::new(DutyCycleTracker::new(3_600_000)); let lora_a = medium .connect(ADDR_A, LoRaConfig::default(), Arc::clone(&duty)) .await?; let lora_b = medium .connect(ADDR_B, LoRaConfig::default(), Arc::clone(&duty)) .await?; let tcp_b = TcpTransport::bind("127.0.0.1:0").await?; let tcp_c = TcpTransport::bind("127.0.0.1:0").await?; let c_listen = tcp_c.local_addr(); let b_listen = tcp_b.local_addr(); let c_addr = TransportAddr::Socket(c_listen); let b_addr = TransportAddr::Socket(b_listen); println!( "LoRa mock mesh demo: B relays LoRa <-> TCP (B TCP {}, C TCP {})", b_listen, c_listen ); let relay = tokio::spawn(async move { for _ in 0..2 { tokio::select! { p = lora_b.recv() => { let p = p.expect("B LoRa recv"); println!("B: LoRa from {} -> TCP ({} bytes)", p.from, p.data.len()); tcp_b.send(&c_addr, &p.data).await.expect("B TCP send to C"); } p = tcp_b.recv() => { let p = p.expect("B TCP recv"); println!("B: TCP -> LoRa A ({} bytes)", p.data.len()); lora_b .send(&TransportAddr::LoRa(ADDR_A), &p.data) .await .expect("B LoRa send to A"); } } } }); let c_task = tokio::spawn(async move { let pkt = tcp_c.recv().await.expect("C TCP recv"); println!("C: got {} bytes from B relay", pkt.data.len()); assert_eq!(pkt.data, b"hello via mesh"); tcp_c .send(&b_addr, b"ack from C") .await .expect("C TCP send"); }); tokio::time::sleep(Duration::from_millis(50)).await; lora_a .send(&TransportAddr::LoRa(ADDR_B), b"hello via mesh") .await?; let reply = lora_a.recv().await?; println!("A: LoRa reply {} bytes", reply.data.len()); assert_eq!(reply.data, b"ack from C"); c_task.await.expect("node C task panicked"); relay.await.expect("relay task panicked"); lora_a.close().await.ok(); println!("Done: LoRa + TCP relay path OK."); Ok(()) }