//! Binary entry point that wires configuration, UDP listener, optional TLS listener, and allocation handling. //! Backlog: graceful shutdown signals, structured metrics, and coordinated lifecycle management across listeners. use std::net::SocketAddr; use std::sync::Arc; use tokio::net::UdpSocket; use tracing::{error, info}; // Use the library crate's public modules instead of local `mod` declarations. use niom_turn::alloc::AllocationManager; use niom_turn::auth::{AuthManager, InMemoryStore}; use niom_turn::config::{AuthOptions, Config}; use niom_turn::server::udp_reader_loop; #[tokio::main] async fn main() -> anyhow::Result<()> { niom_turn::logging::init_tracing(); info!("niom-turn starting"); // Bootstrap configuration: prefer appsettings.json, otherwise rely on baked-in demo defaults. let cfg = match Config::load_default() { Ok(c) => { info!("loaded config from appsettings.json"); c } Err(e) => { info!( "no appsettings.json found or failed to load: {} — using defaults", e ); // defaults Config { server: niom_turn::config::ServerOptions { bind: "0.0.0.0:3478".to_string(), tls_cert: None, tls_key: None, }, credentials: vec![niom_turn::config::CredentialEntry { username: "testuser".into(), password: "secretpassword".into(), }], auth: AuthOptions::default(), } } }; let bind_addr: SocketAddr = cfg.server.bind.parse()?; // Materialise the credential backend before starting network endpoints. let creds = InMemoryStore::new(); for c in cfg.credentials.iter() { creds.insert(&c.username, &c.password); } let auth = AuthManager::new(creds.clone(), &cfg.auth); // Bind the UDP socket that receives STUN/TURN traffic from WebRTC clients. let udp = UdpSocket::bind(bind_addr).await?; let udp = Arc::new(udp); // Allocation manager shared by UDP + TLS frontends. let alloc_mgr = AllocationManager::new(); // Spawn the asynchronous packet loop that handles all UDP requests. let udp_clone = udp.clone(); let auth_clone = auth.clone(); let alloc_clone = alloc_mgr.clone(); tokio::spawn(async move { if let Err(e) = udp_reader_loop(udp_clone, auth_clone, alloc_clone).await { error!("udp loop error: {:?}", e); } }); // Optionally start the TLS listener so `turns:` clients can connect via TCP/TLS. if let (Some(cert), Some(key)) = (cfg.server.tls_cert.clone(), cfg.server.tls_key.clone()) { let udp_for_tls = udp.clone(); let auth_for_tls = auth.clone(); let alloc_for_tls = alloc_mgr.clone(); tokio::spawn(async move { if let Err(e) = niom_turn::tls::serve_tls( "0.0.0.0:5349", &cert, &key, udp_for_tls, auth_for_tls, alloc_for_tls, ) .await { error!("tls serve failed: {:?}", e); } }); } // Keep the runtime alive while background tasks process packets. loop { tokio::time::sleep(std::time::Duration::from_secs(60)).await; } }