403 lines
13 KiB
Rust
403 lines
13 KiB
Rust
//! Data retrieval for the purpose of hydrating HTML templates.
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use log::info;
|
|
use peach_lib::{
|
|
config_manager, dyndns_client,
|
|
error::PeachError,
|
|
jsonrpc_client_core::{Error, ErrorKind},
|
|
jsonrpc_core::types::error::ErrorCode,
|
|
};
|
|
use peach_network::{
|
|
network,
|
|
network::{Scan, Status, Traffic},
|
|
};
|
|
|
|
use crate::error::PeachWebError;
|
|
|
|
#[derive(Debug)]
|
|
pub struct AccessPoint {
|
|
pub detail: Option<Scan>,
|
|
pub signal: Option<i32>,
|
|
pub state: String,
|
|
}
|
|
|
|
pub fn ap_state() -> String {
|
|
match network::state("ap0") {
|
|
Ok(Some(state)) => state,
|
|
_ => "Interface unavailable".to_string(),
|
|
}
|
|
}
|
|
|
|
fn convert_traffic(traffic: Traffic) -> Option<IfaceTraffic> {
|
|
// 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)]
|
|
pub struct ConfigureDNSContext {
|
|
pub external_domain: String,
|
|
pub dyndns_subdomain: String,
|
|
pub enable_dyndns: bool,
|
|
pub is_dyndns_online: bool,
|
|
}
|
|
|
|
impl ConfigureDNSContext {
|
|
pub fn build() -> ConfigureDNSContext {
|
|
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,
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: this should probably rather go into the appropriate `routes` file
|
|
pub fn save_dns_configuration(
|
|
external_domain: String,
|
|
enable_dyndns: bool,
|
|
dynamic_domain: String,
|
|
) -> Result<(), PeachWebError> {
|
|
// first save local configurations
|
|
config_manager::set_external_domain(&external_domain)?;
|
|
config_manager::set_dyndns_enabled_value(enable_dyndns)?;
|
|
|
|
// if dynamic dns is enabled and this is a new domain name, then register it
|
|
if enable_dyndns {
|
|
let full_dynamic_domain = dyndns_client::get_full_dynamic_domain(&dynamic_domain);
|
|
// check if this is a new domain or if its already registered
|
|
let is_new_domain = dyndns_client::check_is_new_dyndns_domain(&full_dynamic_domain);
|
|
if is_new_domain {
|
|
match dyndns_client::register_domain(&full_dynamic_domain) {
|
|
Ok(_) => {
|
|
info!("Registered new dyndns domain");
|
|
// successful update
|
|
Ok(())
|
|
}
|
|
Err(err) => {
|
|
info!("Failed to register dyndns domain: {:?}", err);
|
|
// json response for failed update
|
|
let msg: String = match err {
|
|
// TODO: make this a nest high-level match
|
|
// PeachError::JsonRpcClientCore(Error(ErrorKind::JsonRpcError(err), _))
|
|
PeachError::JsonRpcClientCore(source) => {
|
|
match source {
|
|
Error(ErrorKind::JsonRpcError(err), _state) => match err.code {
|
|
ErrorCode::ServerError(-32030) => {
|
|
format!("Error registering domain: {} was previously registered", full_dynamic_domain)
|
|
}
|
|
_ => {
|
|
format!("Failed to register dyndns domain {:?}", err)
|
|
}
|
|
},
|
|
_ => {
|
|
format!("Failed to register dyndns domain: {:?}", source)
|
|
}
|
|
}
|
|
}
|
|
_ => "Failed to register dyndns domain".to_string(),
|
|
};
|
|
Err(PeachWebError::FailedToRegisterDynDomain(msg))
|
|
}
|
|
}
|
|
}
|
|
// if the domain is already registered, then dont re-register, and just return success
|
|
else {
|
|
Ok(())
|
|
}
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct IfaceTraffic {
|
|
pub rx: u64,
|
|
pub rx_unit: String,
|
|
pub tx: u64,
|
|
pub tx_unit: String,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct NetworkDetailContext {
|
|
pub saved_aps: Vec<String>,
|
|
pub wlan_ip: String,
|
|
pub wlan_networks: HashMap<String, AccessPoint>,
|
|
pub wlan_rssi: Option<String>,
|
|
pub wlan_ssid: String,
|
|
pub wlan_state: String,
|
|
pub wlan_status: Option<Status>,
|
|
pub wlan_traffic: Option<IfaceTraffic>,
|
|
}
|
|
|
|
impl NetworkDetailContext {
|
|
pub fn build() -> NetworkDetailContext {
|
|
// TODO: read this value from the config file
|
|
let wlan_iface = "wlan0".to_string();
|
|
|
|
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::<i32>().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 {
|
|
saved_aps,
|
|
wlan_ip,
|
|
wlan_networks,
|
|
wlan_rssi,
|
|
wlan_ssid,
|
|
wlan_state,
|
|
wlan_status,
|
|
wlan_traffic,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct NetworkListContext {
|
|
pub ap_state: String,
|
|
pub wlan_networks: HashMap<String, String>,
|
|
pub wlan_ssid: String,
|
|
}
|
|
|
|
impl NetworkListContext {
|
|
pub fn build() -> NetworkListContext {
|
|
// TODO: read these values from the config file
|
|
let ap_iface = "ap0".to_string();
|
|
let wlan_iface = "wlan0".to_string();
|
|
//let wlan_iface = "wlp0s20f0u2".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 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,
|
|
wlan_networks,
|
|
wlan_ssid,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct NetworkStatusContext {
|
|
pub ap_ip: String,
|
|
pub ap_ssid: String,
|
|
pub ap_state: String,
|
|
pub ap_traffic: Option<IfaceTraffic>,
|
|
pub wlan_ip: String,
|
|
pub wlan_rssi: Option<String>,
|
|
pub wlan_ssid: String,
|
|
pub wlan_state: String,
|
|
pub wlan_status: Option<Status>,
|
|
pub wlan_traffic: Option<IfaceTraffic>,
|
|
}
|
|
|
|
impl NetworkStatusContext {
|
|
pub fn build() -> Self {
|
|
// TODO: read these values from config file
|
|
let ap_iface = "ap0".to_string();
|
|
let wlan_iface = "wlan0".to_string();
|
|
|
|
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,
|
|
}
|
|
}
|
|
}
|