From d8c40e072486b133efe3ae805bdae22d2a5f443a Mon Sep 17 00:00:00 2001 From: glyph Date: Thu, 13 Jan 2022 15:47:14 +0200 Subject: [PATCH] move context builders into dedicated directory --- peach-web/src/context/dns.rs | 36 +++ peach-web/src/context/mod.rs | 2 + peach-web/src/context/network.rs | 398 +++++++++++++++++++++++++++++++ 3 files changed, 436 insertions(+) create mode 100644 peach-web/src/context/dns.rs create mode 100644 peach-web/src/context/mod.rs create mode 100644 peach-web/src/context/network.rs diff --git a/peach-web/src/context/dns.rs b/peach-web/src/context/dns.rs new file mode 100644 index 0000000..9d74ced --- /dev/null +++ b/peach-web/src/context/dns.rs @@ -0,0 +1,36 @@ +use peach_lib::{config_manager, dyndns_client}; +use rocket::serde::Serialize; + +#[derive(Debug, Serialize)] +pub struct ConfigureDNSContext { + pub external_domain: String, + pub dyndns_subdomain: String, + pub enable_dyndns: bool, + pub is_dyndns_online: bool, + pub back: Option, + pub title: Option, + pub flash_name: Option, + pub flash_msg: Option, +} + +impl ConfigureDNSContext { + pub fn build() -> ConfigureDNSContext { + // TODO: replace `unwrap` with resilient error handling + let peach_config = config_manager::load_peach_config().unwrap(); + let dyndns_fulldomain = peach_config.dyn_domain; + let is_dyndns_online = dyndns_client::is_dns_updater_online().unwrap(); + let dyndns_subdomain = + dyndns_client::get_dyndns_subdomain(&dyndns_fulldomain).unwrap_or(dyndns_fulldomain); + + ConfigureDNSContext { + external_domain: peach_config.external_domain, + dyndns_subdomain, + enable_dyndns: peach_config.dyn_enabled, + is_dyndns_online, + back: None, + title: None, + flash_name: None, + flash_msg: None, + } + } +} diff --git a/peach-web/src/context/mod.rs b/peach-web/src/context/mod.rs new file mode 100644 index 0000000..d2d350c --- /dev/null +++ b/peach-web/src/context/mod.rs @@ -0,0 +1,2 @@ +pub mod dns; +pub mod network; diff --git a/peach-web/src/context/network.rs b/peach-web/src/context/network.rs new file mode 100644 index 0000000..3ce1ee5 --- /dev/null +++ b/peach-web/src/context/network.rs @@ -0,0 +1,398 @@ +//! Data retrieval for the purpose of serving routes and hydrating +//! network-related HTML templates. + +use std::collections::HashMap; + +use rocket::{ + form::FromForm, + serde::{Deserialize, Serialize}, + UriDisplayQuery, +}; + +use peach_network::{ + network, + network::{Scan, Status, Traffic}, +}; + +use crate::{ + utils::{ + monitor, + monitor::{Alert, Data, Threshold}, + }, + AP_IFACE, WLAN_IFACE, +}; + +#[derive(Debug, Serialize)] +pub struct AccessPoint { + pub detail: Option, + pub signal: Option, + pub state: String, +} + +pub fn ap_state() -> String { + match network::state(&*AP_IFACE) { + Ok(Some(state)) => state, + _ => "Interface unavailable".to_string(), + } +} + +#[derive(Debug, Deserialize, FromForm, UriDisplayQuery)] +pub struct Ssid { + pub ssid: String, +} + +#[derive(Debug, Deserialize, FromForm)] +pub struct WiFi { + pub ssid: String, + pub pass: String, +} + +fn convert_traffic(traffic: Traffic) -> Option { + // modify traffic values & assign measurement unit + // based on received and transmitted values + let (rx, rx_unit) = if traffic.received > 1_047_527_424 { + // convert to GB + (traffic.received / 1_073_741_824, "GB".to_string()) + } else if traffic.received > 0 { + // otherwise, convert it to MB + ((traffic.received / 1024) / 1024, "MB".to_string()) + } else { + (0, "MB".to_string()) + }; + + let (tx, tx_unit) = if traffic.transmitted > 1_047_527_424 { + // convert to GB + (traffic.transmitted / 1_073_741_824, "GB".to_string()) + } else if traffic.transmitted > 0 { + ((traffic.transmitted / 1024) / 1024, "MB".to_string()) + } else { + (0, "MB".to_string()) + }; + + Some(IfaceTraffic { + rx, + rx_unit, + tx, + tx_unit, + }) +} + +#[derive(Debug, Serialize)] +pub struct IfaceTraffic { + pub rx: u64, + pub rx_unit: String, + pub tx: u64, + pub tx_unit: String, +} + +#[derive(Debug, Serialize)] +pub struct NetworkAlertContext { + pub alert: Alert, + pub back: Option, + pub data_total: Option, // combined stored and current wifi traffic in bytes + pub flash_name: Option, + pub flash_msg: Option, + pub threshold: Threshold, + pub title: Option, + pub traffic: Option, // current wifi traffic in bytes (since boot) +} + +impl NetworkAlertContext { + pub fn build() -> NetworkAlertContext { + let alert = monitor::get_alerts().unwrap(); + // stored wifi data values as bytes + let stored_traffic = monitor::get_data().unwrap(); + let threshold = monitor::get_thresholds().unwrap(); + + let (traffic, data_total) = match network::traffic(&*WLAN_IFACE) { + // convert bytes to mb or gb and add appropriate units + Ok(Some(t)) => { + let current_traffic = t.received + t.transmitted; + let traffic = convert_traffic(t); + let total = stored_traffic.total + current_traffic; + let data_total = Data { total }; + (traffic, Some(data_total)) + } + _ => (None, None), + }; + + NetworkAlertContext { + alert, + back: None, + data_total, + flash_name: None, + flash_msg: None, + threshold, + title: None, + traffic, + } + } +} + +#[derive(Debug, Serialize)] +pub struct NetworkDetailContext { + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub selected: Option, + pub title: Option, + pub saved_aps: Vec, + pub wlan_ip: String, + pub wlan_networks: HashMap, + pub wlan_rssi: Option, + pub wlan_ssid: String, + pub wlan_state: String, + pub wlan_status: Option, + pub wlan_traffic: Option, +} + +impl NetworkDetailContext { + pub fn build() -> NetworkDetailContext { + let wlan_ip = match network::ip(&*WLAN_IFACE) { + Ok(Some(ip)) => ip, + _ => "x.x.x.x".to_string(), + }; + + // list of networks saved in wpa_supplicant.conf + let wlan_list = match network::saved_networks() { + Ok(Some(ssids)) => ssids, + _ => Vec::new(), + }; + + // list of networks saved in wpa_supplicant.conf + let saved_aps = wlan_list.clone(); + + let wlan_rssi = match network::rssi_percent(&*WLAN_IFACE) { + Ok(rssi) => rssi, + Err(_) => None, + }; + + // list of networks currently in range (online & accessible) + let wlan_scan = match network::available_networks(&*WLAN_IFACE) { + Ok(Some(networks)) => networks, + _ => Vec::new(), + }; + + let wlan_ssid = match network::ssid(&*WLAN_IFACE) { + Ok(Some(ssid)) => ssid, + _ => "Not connected".to_string(), + }; + + let wlan_state = match network::state(&*WLAN_IFACE) { + Ok(Some(state)) => state, + _ => "Interface unavailable".to_string(), + }; + + let wlan_status = match network::status(&*WLAN_IFACE) { + Ok(status) => status, + // interface unavailable + _ => None, + }; + + let wlan_traffic = match network::traffic(&*WLAN_IFACE) { + // convert bytes to mb or gb and add appropriate units + Ok(Some(traffic)) => convert_traffic(traffic), + _ => None, + }; + + // create a hashmap to combine wlan_list & wlan_scan without repetition + let mut wlan_networks = HashMap::new(); + + for ap in wlan_scan { + let ssid = ap.ssid.clone(); + let rssi = ap.signal_level.clone(); + // parse the string to a signed integer (for math) + let rssi_parsed = rssi.parse::().unwrap(); + // perform rssi (dBm) to quality (%) conversion + let quality_percent = 2 * (rssi_parsed + 100); + let ap_detail = AccessPoint { + detail: Some(ap), + state: "Available".to_string(), + signal: Some(quality_percent), + }; + wlan_networks.insert(ssid, ap_detail); + } + + for network in wlan_list { + // avoid repetition by checking that ssid is not already in list + if !wlan_networks.contains_key(&network) { + let ssid = network.clone(); + let net_detail = AccessPoint { + detail: None, + state: "Not in range".to_string(), + signal: None, + }; + wlan_networks.insert(ssid, net_detail); + } + } + + NetworkDetailContext { + back: None, + flash_name: None, + flash_msg: None, + selected: None, + title: None, + saved_aps, + wlan_ip, + wlan_networks, + wlan_rssi, + wlan_ssid, + wlan_state, + wlan_status, + wlan_traffic, + } + } +} + +#[derive(Debug, Serialize)] +pub struct NetworkListContext { + pub ap_state: String, + pub back: Option, + pub flash_name: Option, + pub flash_msg: Option, + pub title: Option, + pub wlan_networks: HashMap, + pub wlan_ssid: String, +} + +impl NetworkListContext { + pub fn build() -> NetworkListContext { + // list of networks saved in wpa_supplicant.conf + let wlan_list = match network::saved_networks() { + Ok(Some(ssids)) => ssids, + _ => Vec::new(), + }; + + // list of networks currently in range (online & accessible) + let wlan_scan = match network::available_networks(&*WLAN_IFACE) { + Ok(Some(networks)) => networks, + _ => Vec::new(), + }; + + let wlan_ssid = match network::ssid(&*WLAN_IFACE) { + Ok(Some(ssid)) => ssid, + _ => "Not connected".to_string(), + }; + + // create a hashmap to combine wlan_list & wlan_scan without repetition + let mut wlan_networks = HashMap::new(); + for ap in wlan_scan { + wlan_networks.insert(ap.ssid, "Available".to_string()); + } + for network in wlan_list { + // insert ssid (with state) only if it doesn't already exist + wlan_networks + .entry(network) + .or_insert_with(|| "Not in range".to_string()); + } + + let ap_state = match network::state(&*AP_IFACE) { + Ok(Some(state)) => state, + _ => "Interface unavailable".to_string(), + }; + + NetworkListContext { + ap_state, + back: None, + flash_msg: None, + flash_name: None, + title: None, + wlan_networks, + wlan_ssid, + } + } +} + +#[derive(Debug, Serialize)] +pub struct NetworkStatusContext { + pub ap_ip: String, + pub ap_ssid: String, + pub ap_state: String, + pub ap_traffic: Option, + pub wlan_ip: String, + pub wlan_rssi: Option, + pub wlan_ssid: String, + pub wlan_state: String, + pub wlan_status: Option, + pub wlan_traffic: Option, + pub flash_name: Option, + pub flash_msg: Option, + // passing in the ssid of a chosen access point + pub selected: Option, + pub title: Option, + pub back: Option, +} + +impl NetworkStatusContext { + pub fn build() -> Self { + let ap_ip = match network::ip(&*AP_IFACE) { + Ok(Some(ip)) => ip, + _ => "x.x.x.x".to_string(), + }; + + let ap_ssid = match network::ssid(&*AP_IFACE) { + Ok(Some(ssid)) => ssid, + _ => "Not currently activated".to_string(), + }; + + let ap_state = match network::state(&*AP_IFACE) { + Ok(Some(state)) => state, + _ => "Interface unavailable".to_string(), + }; + + let ap_traffic = match network::traffic(&*AP_IFACE) { + // convert bytes to mb or gb and add appropriate units + Ok(Some(traffic)) => convert_traffic(traffic), + _ => None, + }; + + let wlan_ip = match network::ip(&*WLAN_IFACE) { + Ok(Some(ip)) => ip, + _ => "x.x.x.x".to_string(), + }; + + let wlan_rssi = match network::rssi_percent(&*WLAN_IFACE) { + Ok(rssi) => rssi, + _ => None, + }; + + let wlan_ssid = match network::ssid(&*WLAN_IFACE) { + Ok(Some(ssid)) => ssid, + _ => "Not connected".to_string(), + }; + + let wlan_state = match network::state(&*WLAN_IFACE) { + Ok(Some(state)) => state, + _ => "Interface unavailable".to_string(), + }; + + let wlan_status = match network::status(&*WLAN_IFACE) { + Ok(status) => status, + _ => None, + }; + + let wlan_traffic = match network::traffic(&*WLAN_IFACE) { + // convert bytes to mb or gb and add appropriate units + Ok(Some(traffic)) => convert_traffic(traffic), + _ => None, + }; + + NetworkStatusContext { + ap_ip, + ap_ssid, + ap_state, + ap_traffic, + wlan_ip, + wlan_rssi, + wlan_ssid, + wlan_state, + wlan_status, + wlan_traffic, + flash_name: None, + flash_msg: None, + selected: None, + title: None, + back: None, + } + } +}