Connection Manager
This example implements a basic connection manager that provides an interactive CLI for managing Wi-Fi, Ethernet, and VPN connections.
Features
- List and scan networks
- Connect and disconnect Wi-Fi
- Manage VPN connections
- List devices and saved profiles
- Interactive menu-driven interface
Code
use nmrs::{NetworkManager, WifiSecurity, ConnectionError}; use std::io::{self, Write}; #[tokio::main] async fn main() -> nmrs::Result<()> { let nm = NetworkManager::new().await?; loop { println!("\n=== nmrs Connection Manager ==="); println!("1. Scan networks"); println!("2. List visible networks"); println!("3. Connect to Wi-Fi"); println!("4. Disconnect Wi-Fi"); println!("5. Current connection"); println!("6. List devices"); println!("7. List saved connections"); println!("8. Forget a connection"); println!("9. List VPN connections"); println!("0. Exit"); print!("\nChoice: "); io::stdout().flush().ok(); let choice = read_line(); match choice.trim() { "1" => scan(&nm).await, "2" => list_networks(&nm).await, "3" => connect_wifi(&nm).await, "4" => disconnect(&nm).await, "5" => current(&nm).await, "6" => devices(&nm).await, "7" => saved(&nm).await, "8" => forget(&nm).await, "9" => vpns(&nm).await, "0" => break, _ => println!("Invalid choice"), } } Ok(()) } async fn scan(nm: &NetworkManager) { println!("Scanning..."); match nm.scan_networks().await { Ok(_) => println!("Scan complete"), Err(e) => eprintln!("Scan failed: {}", e), } } async fn list_networks(nm: &NetworkManager) { match nm.list_networks().await { Ok(networks) => { println!("\n{:<5} {:<30} {:>6} {:>10}", "#", "SSID", "Signal", "Security"); println!("{}", "-".repeat(55)); for (i, net) in networks.iter().enumerate() { let sec = if net.is_eap { "EAP" } else if net.is_psk { "PSK" } else { "Open" }; println!("{:<5} {:<30} {:>5}% {:>10}", i + 1, net.ssid, net.strength.unwrap_or(0), sec); } } Err(e) => eprintln!("Error: {}", e), } } async fn connect_wifi(nm: &NetworkManager) { print!("SSID: "); io::stdout().flush().ok(); let ssid = read_line(); let ssid = ssid.trim(); print!("Password (empty for open): "); io::stdout().flush().ok(); let password = read_line(); let password = password.trim(); let security = if password.is_empty() { WifiSecurity::Open } else { WifiSecurity::WpaPsk { psk: password.into() } }; println!("Connecting to '{}'...", ssid); match nm.connect(ssid, security).await { Ok(_) => println!("Connected!"), Err(ConnectionError::AuthFailed) => eprintln!("Wrong password"), Err(ConnectionError::NotFound) => eprintln!("Network not found"), Err(ConnectionError::Timeout) => eprintln!("Connection timed out"), Err(e) => eprintln!("Error: {}", e), } } async fn disconnect(nm: &NetworkManager) { match nm.disconnect().await { Ok(_) => println!("Disconnected"), Err(e) => eprintln!("Error: {}", e), } } async fn current(nm: &NetworkManager) { match nm.current_network().await { Ok(Some(net)) => { println!("Connected to: {} ({}%)", net.ssid, net.strength.unwrap_or(0)); } Ok(None) => println!("Not connected"), Err(e) => eprintln!("Error: {}", e), } } async fn devices(nm: &NetworkManager) { match nm.list_devices().await { Ok(devices) => { for dev in &devices { println!("{:<10} {:<12} {:<15} {}", dev.interface, format!("{}", dev.device_type), format!("{}", dev.state), dev.identity.current_mac, ); } } Err(e) => eprintln!("Error: {}", e), } } async fn saved(nm: &NetworkManager) { match nm.list_saved_connections().await { Ok(connections) => { for name in &connections { println!(" {}", name); } } Err(e) => eprintln!("Error: {}", e), } } async fn forget(nm: &NetworkManager) { print!("Connection name to forget: "); io::stdout().flush().ok(); let name = read_line(); let name = name.trim(); match nm.forget(name).await { Ok(_) => println!("Forgot '{}'", name), Err(e) => eprintln!("Error: {}", e), } } async fn vpns(nm: &NetworkManager) { match nm.list_vpn_connections().await { Ok(vpns) => { if vpns.is_empty() { println!("No VPN connections"); } for vpn in &vpns { println!(" {} ({:?}) — {:?}", vpn.name, vpn.vpn_type, vpn.state); } } Err(e) => eprintln!("Error: {}", e), } } fn read_line() -> String { let mut input = String::new(); io::stdin().read_line(&mut input).unwrap_or_default(); input }
Running
cargo run --example connection_manager
Enhancements
- VPN connect/disconnect: Add menu options for VPN operations
- Bluetooth: Add Bluetooth device listing and connection
- Network details: Show
NetworkInfofor selected networks - Color output: Use a crate like
coloredfor terminal formatting - Persistent config: Store preferred networks in a config file