534 lines
19 KiB
Rust
534 lines
19 KiB
Rust
//! This mainly concerns converting collected data into things that the canvas
|
|
//! can actually handle.
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use crate::{
|
|
app::{data_farmer, data_harvester, App},
|
|
utils::gen_util::{get_exact_byte_values, get_simple_byte_values},
|
|
};
|
|
|
|
type Point = (f64, f64);
|
|
|
|
#[derive(Default, Debug)]
|
|
pub struct ConvertedBatteryData {
|
|
pub battery_name: String,
|
|
pub charge_percentage: f64,
|
|
pub watt_consumption: String,
|
|
pub duration_until_full: Option<String>,
|
|
pub duration_until_empty: Option<String>,
|
|
pub health: String,
|
|
}
|
|
|
|
#[derive(Default, Debug)]
|
|
pub struct ConvertedNetworkData {
|
|
pub rx: Vec<Point>,
|
|
pub tx: Vec<Point>,
|
|
pub rx_display: String,
|
|
pub tx_display: String,
|
|
pub total_rx_display: Option<String>,
|
|
pub total_tx_display: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Default, Debug)]
|
|
pub struct ConvertedProcessData {
|
|
pub pid: u32,
|
|
pub name: String,
|
|
pub cpu_percent_usage: f64,
|
|
pub mem_percent_usage: f64,
|
|
pub mem_usage_kb: u64,
|
|
pub mem_usage_str: (f64, String),
|
|
pub group_pids: Vec<u32>,
|
|
pub read_per_sec: String,
|
|
pub write_per_sec: String,
|
|
pub total_read: String,
|
|
pub total_write: String,
|
|
pub rps_f64: f64,
|
|
pub wps_f64: f64,
|
|
pub tr_f64: f64,
|
|
pub tw_f64: f64,
|
|
pub process_state: String,
|
|
}
|
|
|
|
#[derive(Clone, Default, Debug)]
|
|
pub struct SingleProcessData {
|
|
pub pid: u32,
|
|
pub cpu_percent_usage: f64,
|
|
pub mem_percent_usage: f64,
|
|
pub mem_usage_kb: u64,
|
|
pub group_pids: Vec<u32>,
|
|
pub read_per_sec: u64,
|
|
pub write_per_sec: u64,
|
|
pub total_read: u64,
|
|
pub total_write: u64,
|
|
pub process_state: String,
|
|
}
|
|
|
|
#[derive(Clone, Default, Debug)]
|
|
pub struct ConvertedCpuData {
|
|
pub cpu_name: String,
|
|
/// Tuple is time, value
|
|
pub cpu_data: Vec<Point>,
|
|
/// Represents the value displayed on the legend.
|
|
pub legend_value: String,
|
|
}
|
|
|
|
pub fn convert_temp_row(app: &App) -> Vec<Vec<String>> {
|
|
let mut sensor_vector: Vec<Vec<String>> = Vec::new();
|
|
|
|
let current_data = &app.data_collection;
|
|
let temp_type = &app.app_config_fields.temperature_type;
|
|
|
|
if current_data.temp_harvest.is_empty() {
|
|
sensor_vector.push(vec!["No Sensors Found".to_string(), "".to_string()])
|
|
} else {
|
|
for sensor in ¤t_data.temp_harvest {
|
|
sensor_vector.push(vec![
|
|
sensor.component_name.to_string(),
|
|
(sensor.temperature.ceil() as u64).to_string()
|
|
+ match temp_type {
|
|
data_harvester::temperature::TemperatureType::Celsius => "C",
|
|
data_harvester::temperature::TemperatureType::Kelvin => "K",
|
|
data_harvester::temperature::TemperatureType::Fahrenheit => "F",
|
|
},
|
|
]);
|
|
}
|
|
}
|
|
|
|
sensor_vector
|
|
}
|
|
|
|
pub fn convert_disk_row(current_data: &data_farmer::DataCollection) -> Vec<Vec<String>> {
|
|
let mut disk_vector: Vec<Vec<String>> = Vec::new();
|
|
current_data
|
|
.disk_harvest
|
|
.iter()
|
|
.zip(¤t_data.io_labels_and_prev)
|
|
.for_each(|(disk, (io_label, _io_prev))| {
|
|
let converted_read = get_simple_byte_values(io_label.0, false);
|
|
let converted_write = get_simple_byte_values(io_label.1, false);
|
|
let io_activity = (
|
|
format!("{:.*}{}/s", 0, converted_read.0, converted_read.1),
|
|
format!("{:.*}{}/s", 0, converted_write.0, converted_write.1),
|
|
);
|
|
|
|
let converted_free_space = get_simple_byte_values(disk.free_space, false);
|
|
let converted_total_space = get_simple_byte_values(disk.total_space, false);
|
|
disk_vector.push(vec![
|
|
disk.name.to_string(),
|
|
disk.mount_point.to_string(),
|
|
format!(
|
|
"{:.0}%",
|
|
disk.used_space as f64 / disk.total_space as f64 * 100_f64
|
|
),
|
|
format!("{:.*}{}", 0, converted_free_space.0, converted_free_space.1),
|
|
format!(
|
|
"{:.*}{}",
|
|
0, converted_total_space.0, converted_total_space.1
|
|
),
|
|
io_activity.0,
|
|
io_activity.1,
|
|
]);
|
|
});
|
|
|
|
disk_vector
|
|
}
|
|
|
|
pub fn convert_cpu_data_points(
|
|
current_data: &data_farmer::DataCollection, is_frozen: bool,
|
|
) -> Vec<ConvertedCpuData> {
|
|
let mut cpu_data_vector: Vec<ConvertedCpuData> = Vec::new();
|
|
let current_time = if is_frozen {
|
|
if let Some(frozen_instant) = current_data.frozen_instant {
|
|
frozen_instant
|
|
} else {
|
|
current_data.current_instant
|
|
}
|
|
} else {
|
|
current_data.current_instant
|
|
};
|
|
|
|
for (time, data) in ¤t_data.timed_data_vec {
|
|
let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor();
|
|
|
|
for (itx, cpu) in data.cpu_data.iter().enumerate() {
|
|
// Check if the vector exists yet
|
|
if cpu_data_vector.len() <= itx {
|
|
let mut new_cpu_data = ConvertedCpuData::default();
|
|
new_cpu_data.cpu_name = if let Some(cpu_harvest) = current_data.cpu_harvest.get(itx)
|
|
{
|
|
cpu_harvest.cpu_name.to_string()
|
|
} else {
|
|
String::default()
|
|
};
|
|
cpu_data_vector.push(new_cpu_data);
|
|
}
|
|
|
|
if let Some(cpu_data) = cpu_data_vector.get_mut(itx) {
|
|
cpu_data.legend_value = format!("{:.0}%", cpu.round());
|
|
cpu_data.cpu_data.push((-time_from_start, *cpu));
|
|
}
|
|
}
|
|
|
|
if *time == current_time {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let mut extended_vec = vec![ConvertedCpuData {
|
|
cpu_name: "All".to_string(),
|
|
cpu_data: vec![],
|
|
legend_value: String::new(),
|
|
}];
|
|
extended_vec.extend(cpu_data_vector);
|
|
extended_vec
|
|
}
|
|
|
|
pub fn convert_mem_data_points(
|
|
current_data: &data_farmer::DataCollection, is_frozen: bool,
|
|
) -> Vec<Point> {
|
|
let mut result: Vec<Point> = Vec::new();
|
|
let current_time = if is_frozen {
|
|
if let Some(frozen_instant) = current_data.frozen_instant {
|
|
frozen_instant
|
|
} else {
|
|
current_data.current_instant
|
|
}
|
|
} else {
|
|
current_data.current_instant
|
|
};
|
|
|
|
for (time, data) in ¤t_data.timed_data_vec {
|
|
let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor();
|
|
result.push((-time_from_start, data.mem_data));
|
|
if *time == current_time {
|
|
break;
|
|
}
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
pub fn convert_swap_data_points(
|
|
current_data: &data_farmer::DataCollection, is_frozen: bool,
|
|
) -> Vec<Point> {
|
|
let mut result: Vec<Point> = Vec::new();
|
|
let current_time = if is_frozen {
|
|
if let Some(frozen_instant) = current_data.frozen_instant {
|
|
frozen_instant
|
|
} else {
|
|
current_data.current_instant
|
|
}
|
|
} else {
|
|
current_data.current_instant
|
|
};
|
|
|
|
for (time, data) in ¤t_data.timed_data_vec {
|
|
let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor();
|
|
result.push((-time_from_start, data.swap_data));
|
|
if *time == current_time {
|
|
break;
|
|
}
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
pub fn convert_mem_labels(
|
|
current_data: &data_farmer::DataCollection,
|
|
) -> (String, String, String, String) {
|
|
(
|
|
format!(
|
|
"{:3.0}%",
|
|
match current_data.memory_harvest.mem_total_in_mb {
|
|
0 => 0.0,
|
|
_ =>
|
|
current_data.memory_harvest.mem_used_in_mb as f64 * 100.0
|
|
/ current_data.memory_harvest.mem_total_in_mb as f64,
|
|
}
|
|
),
|
|
format!(
|
|
" {:.1}GB/{:.1}GB",
|
|
current_data.memory_harvest.mem_used_in_mb as f64 / 1024.0,
|
|
(current_data.memory_harvest.mem_total_in_mb as f64 / 1024.0)
|
|
),
|
|
format!(
|
|
"{:3.0}%",
|
|
match current_data.swap_harvest.mem_total_in_mb {
|
|
0 => 0.0,
|
|
_ =>
|
|
current_data.swap_harvest.mem_used_in_mb as f64 * 100.0
|
|
/ current_data.swap_harvest.mem_total_in_mb as f64,
|
|
}
|
|
),
|
|
format!(
|
|
" {:.1}GB/{:.1}GB",
|
|
current_data.swap_harvest.mem_used_in_mb as f64 / 1024.0,
|
|
(current_data.swap_harvest.mem_total_in_mb as f64 / 1024.0)
|
|
),
|
|
)
|
|
}
|
|
|
|
pub fn get_rx_tx_data_points(
|
|
current_data: &data_farmer::DataCollection, is_frozen: bool,
|
|
) -> (Vec<Point>, Vec<Point>) {
|
|
let mut rx: Vec<Point> = Vec::new();
|
|
let mut tx: Vec<Point> = Vec::new();
|
|
|
|
let current_time = if is_frozen {
|
|
if let Some(frozen_instant) = current_data.frozen_instant {
|
|
frozen_instant
|
|
} else {
|
|
current_data.current_instant
|
|
}
|
|
} else {
|
|
current_data.current_instant
|
|
};
|
|
|
|
for (time, data) in ¤t_data.timed_data_vec {
|
|
let time_from_start: f64 = (current_time.duration_since(*time).as_millis() as f64).floor();
|
|
rx.push((-time_from_start, data.rx_data));
|
|
tx.push((-time_from_start, data.tx_data));
|
|
if *time == current_time {
|
|
break;
|
|
}
|
|
}
|
|
|
|
(rx, tx)
|
|
}
|
|
|
|
pub fn convert_network_data_points(
|
|
current_data: &data_farmer::DataCollection, is_frozen: bool, need_four_points: bool,
|
|
) -> ConvertedNetworkData {
|
|
let (rx, tx) = get_rx_tx_data_points(current_data, is_frozen);
|
|
|
|
let total_rx_converted_result: (f64, String);
|
|
let rx_converted_result: (f64, String);
|
|
let total_tx_converted_result: (f64, String);
|
|
let tx_converted_result: (f64, String);
|
|
|
|
rx_converted_result = get_exact_byte_values(current_data.network_harvest.rx, false);
|
|
total_rx_converted_result = get_exact_byte_values(current_data.network_harvest.total_rx, false);
|
|
|
|
tx_converted_result = get_exact_byte_values(current_data.network_harvest.tx, false);
|
|
total_tx_converted_result = get_exact_byte_values(current_data.network_harvest.total_tx, false);
|
|
|
|
if need_four_points {
|
|
let rx_display = format!("{:.*}{}", 1, rx_converted_result.0, rx_converted_result.1);
|
|
let total_rx_display = Some(format!(
|
|
"{:.*}{}",
|
|
1, total_rx_converted_result.0, total_rx_converted_result.1
|
|
));
|
|
let tx_display = format!("{:.*}{}", 1, tx_converted_result.0, tx_converted_result.1);
|
|
let total_tx_display = Some(format!(
|
|
"{:.*}{}",
|
|
1, total_tx_converted_result.0, total_tx_converted_result.1
|
|
));
|
|
ConvertedNetworkData {
|
|
rx,
|
|
tx,
|
|
rx_display,
|
|
tx_display,
|
|
total_rx_display,
|
|
total_tx_display,
|
|
}
|
|
} else {
|
|
let rx_display = format!(
|
|
"RX: {:<9} All: {:<9}",
|
|
format!("{:.1}{:3}", rx_converted_result.0, rx_converted_result.1),
|
|
format!(
|
|
"{:.1}{:3}",
|
|
total_rx_converted_result.0, total_rx_converted_result.1
|
|
)
|
|
);
|
|
let tx_display = format!(
|
|
"TX: {:<9} All: {:<9}",
|
|
format!("{:.1}{:3}", tx_converted_result.0, tx_converted_result.1),
|
|
format!(
|
|
"{:.1}{:3}",
|
|
total_tx_converted_result.0, total_tx_converted_result.1
|
|
)
|
|
);
|
|
|
|
ConvertedNetworkData {
|
|
rx,
|
|
tx,
|
|
rx_display,
|
|
tx_display,
|
|
total_rx_display: None,
|
|
total_tx_display: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum ProcessGroupingType {
|
|
Grouped,
|
|
Ungrouped,
|
|
}
|
|
|
|
pub enum ProcessNamingType {
|
|
Name,
|
|
Path,
|
|
}
|
|
|
|
pub fn convert_process_data(
|
|
current_data: &data_farmer::DataCollection, grouping_type: ProcessGroupingType,
|
|
name_type: ProcessNamingType,
|
|
) -> Vec<ConvertedProcessData> {
|
|
match grouping_type {
|
|
ProcessGroupingType::Ungrouped => current_data
|
|
.process_harvest
|
|
.iter()
|
|
.map(|process| {
|
|
let converted_rps = get_exact_byte_values(process.read_bytes_per_sec, false);
|
|
let converted_wps = get_exact_byte_values(process.write_bytes_per_sec, false);
|
|
let converted_total_read = get_exact_byte_values(process.total_read_bytes, false);
|
|
let converted_total_write = get_exact_byte_values(process.total_write_bytes, false);
|
|
|
|
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
|
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
|
let total_read =
|
|
format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
|
let total_write = format!(
|
|
"{:.*}{}",
|
|
0, converted_total_write.0, converted_total_write.1
|
|
);
|
|
|
|
ConvertedProcessData {
|
|
pid: process.pid,
|
|
name: match name_type {
|
|
ProcessNamingType::Name => process.name.to_string(),
|
|
ProcessNamingType::Path => process.path.to_string(),
|
|
},
|
|
cpu_percent_usage: process.cpu_usage_percent,
|
|
mem_percent_usage: process.mem_usage_percent,
|
|
mem_usage_kb: process.mem_usage_kb,
|
|
mem_usage_str: get_exact_byte_values(process.mem_usage_kb * 1024, false),
|
|
group_pids: vec![process.pid],
|
|
read_per_sec,
|
|
write_per_sec,
|
|
total_read,
|
|
total_write,
|
|
rps_f64: process.read_bytes_per_sec as f64,
|
|
wps_f64: process.write_bytes_per_sec as f64,
|
|
tr_f64: process.total_read_bytes as f64,
|
|
tw_f64: process.total_write_bytes as f64,
|
|
process_state: process.process_state.to_owned(),
|
|
}
|
|
})
|
|
.collect::<Vec<_>>(),
|
|
ProcessGroupingType::Grouped => {
|
|
let mut grouped_hashmap: HashMap<String, SingleProcessData> =
|
|
std::collections::HashMap::new();
|
|
|
|
current_data.process_harvest.iter().for_each(|process| {
|
|
let entry = grouped_hashmap
|
|
.entry(match name_type {
|
|
ProcessNamingType::Name => process.name.to_string(),
|
|
ProcessNamingType::Path => process.path.to_string(),
|
|
})
|
|
.or_insert(SingleProcessData {
|
|
pid: process.pid,
|
|
..SingleProcessData::default()
|
|
});
|
|
|
|
(*entry).cpu_percent_usage += process.cpu_usage_percent;
|
|
(*entry).mem_percent_usage += process.mem_usage_percent;
|
|
(*entry).mem_usage_kb += process.mem_usage_kb;
|
|
(*entry).group_pids.push(process.pid);
|
|
(*entry).read_per_sec += process.read_bytes_per_sec;
|
|
(*entry).write_per_sec += process.write_bytes_per_sec;
|
|
(*entry).total_read += process.total_read_bytes;
|
|
(*entry).total_write += process.total_write_bytes;
|
|
});
|
|
|
|
grouped_hashmap
|
|
.iter()
|
|
.map(|(identifier, process_details)| {
|
|
let p = process_details.clone();
|
|
let converted_rps = get_exact_byte_values(p.read_per_sec, false);
|
|
let converted_wps = get_exact_byte_values(p.write_per_sec, false);
|
|
let converted_total_read = get_exact_byte_values(p.total_read, false);
|
|
let converted_total_write = get_exact_byte_values(p.total_write, false);
|
|
|
|
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
|
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
|
let total_read =
|
|
format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
|
let total_write = format!(
|
|
"{:.*}{}",
|
|
0, converted_total_write.0, converted_total_write.1
|
|
);
|
|
|
|
ConvertedProcessData {
|
|
pid: p.pid,
|
|
name: identifier.to_string(),
|
|
cpu_percent_usage: p.cpu_percent_usage,
|
|
mem_percent_usage: p.mem_percent_usage,
|
|
mem_usage_kb: p.mem_usage_kb,
|
|
mem_usage_str: get_exact_byte_values(p.mem_usage_kb * 1024, false),
|
|
group_pids: p.group_pids,
|
|
read_per_sec,
|
|
write_per_sec,
|
|
total_read,
|
|
total_write,
|
|
rps_f64: p.read_per_sec as f64,
|
|
wps_f64: p.write_per_sec as f64,
|
|
tr_f64: p.total_read as f64,
|
|
tw_f64: p.total_write as f64,
|
|
process_state: p.process_state,
|
|
}
|
|
})
|
|
.collect::<Vec<_>>()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn convert_battery_harvest(
|
|
current_data: &data_farmer::DataCollection,
|
|
) -> Vec<ConvertedBatteryData> {
|
|
current_data
|
|
.battery_harvest
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(itx, battery_harvest)| ConvertedBatteryData {
|
|
battery_name: format!("Battery {}", itx),
|
|
charge_percentage: battery_harvest.charge_percent,
|
|
watt_consumption: format!("{:.2}W", battery_harvest.power_consumption_rate_watts),
|
|
duration_until_empty: if let Some(secs_till_empty) = battery_harvest.secs_until_empty {
|
|
let time = chrono::Duration::seconds(secs_till_empty);
|
|
let num_minutes = time.num_minutes() - time.num_hours() * 60;
|
|
let num_seconds = time.num_seconds() - time.num_minutes() * 60;
|
|
Some(format!(
|
|
"{} hour{}, {} minute{}, {} second{}",
|
|
time.num_hours(),
|
|
if time.num_hours() == 1 { "" } else { "s" },
|
|
num_minutes,
|
|
if num_minutes == 1 { "" } else { "s" },
|
|
num_seconds,
|
|
if num_seconds == 1 { "" } else { "s" },
|
|
))
|
|
} else {
|
|
None
|
|
},
|
|
duration_until_full: if let Some(secs_till_full) = battery_harvest.secs_until_full {
|
|
let time = chrono::Duration::seconds(secs_till_full);
|
|
let num_minutes = time.num_minutes() - time.num_hours() * 60;
|
|
let num_seconds = time.num_seconds() - time.num_minutes() * 60;
|
|
Some(format!(
|
|
"{} hour{}, {} minute{}, {} second{}",
|
|
time.num_hours(),
|
|
if time.num_hours() == 1 { "" } else { "s" },
|
|
num_minutes,
|
|
if num_minutes == 1 { "" } else { "s" },
|
|
num_seconds,
|
|
if num_seconds == 1 { "" } else { "s" },
|
|
))
|
|
} else {
|
|
None
|
|
},
|
|
health: format!("{:.2}%", battery_harvest.health_percent),
|
|
})
|
|
.collect()
|
|
}
|