use rand_core::OsRng; use reticulum::destination::DestinationName; use reticulum::identity::PrivateIdentity; use tokio::fs; use clap::Parser; use serde::{Deserialize, Serialize}; // RETICULUM INCLUDES use reticulum::iface::tcp_client::TcpClient; use reticulum::iface::tcp_server::TcpServer; use reticulum::iface::udp::UdpInterface; use reticulum::transport::{Transport, TransportConfig}; use tokio::time::{Duration, interval}; #[derive(Serialize, Deserialize, Debug, Clone)] struct TcpServerConfig { bind_addr: String, } #[derive(Serialize, Deserialize, Debug, Clone)] struct TcpClientConfig { bind_addr: String, } #[derive(Serialize, Deserialize, Debug, Clone)] struct UdpConfig { bind_addr: String, forward_addr: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] enum InterfaceConfig { TcpServer(TcpServerConfig), TcpClient(TcpClientConfig), Udp(UdpConfig), } #[derive(Serialize, Deserialize, Debug, Clone)] struct Config { interfaces: Vec, broadcast: bool, retransmit: bool, } #[derive(Parser)] struct Cli { #[arg(short, long)] config_file: String, } #[tokio::main] async fn main() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); log::info!(">>> TRANSPORT NODE <<<"); let cli = Cli::parse(); let config: Config = toml::from_str(&fs::read_to_string(cli.config_file).await.unwrap()).unwrap(); println!("{config:?}"); let mut transport_config = TransportConfig::default(); transport_config.set_retransmit(config.retransmit); transport_config.set_broadcast(config.broadcast); // set up the reticulum transport let mut transport = Transport::new(transport_config); // set up destination let id = PrivateIdentity::new_from_rand(OsRng); let hb_destination = transport .add_destination(id, DestinationName::new("transport node", "heartbeat")) .await; log::info!("dest ID: {}", hb_destination.lock().await.desc.address_hash); // set up interfaces for iface_config in config.interfaces { match iface_config { InterfaceConfig::TcpServer(cfg) => { let _ = transport.iface_manager().lock().await.spawn( TcpServer::new(cfg.bind_addr, transport.iface_manager()), TcpServer::spawn, ); } InterfaceConfig::TcpClient(cfg) => { let _ = transport .iface_manager() .lock() .await .spawn(TcpClient::new(cfg.bind_addr), TcpClient::spawn); } InterfaceConfig::Udp(cfg) => { let _ = transport.iface_manager().lock().await.spawn( UdpInterface::new(cfg.bind_addr, cfg.forward_addr), UdpInterface::spawn, ); } } } let mut heartbeat_interval = interval(Duration::from_secs(5)); loop { tokio::select! { _ = tokio::signal::ctrl_c() => { break; } _ = heartbeat_interval.tick() => { log::trace!("send heartbeat"); transport.send_announce(&hb_destination, None).await; } } } log::info!("exit!"); }