From f8316f8ee421706f5e274b5d35351ea9e6f1362f Mon Sep 17 00:00:00 2001 From: D0RYU Date: Sat, 3 May 2025 01:08:55 -0400 Subject: [PATCH] refactored formatted scripts cpu struct types being worked on cpu error handling fixed moved from anyhow -> thiserror other shit i'm too tired to mention --- Cargo.lock | 77 ++++++++++++++-- src/collections/sparse_set.rs | 34 +++++-- src/lib.rs | 2 +- subcrates/telemetry/Cargo.toml | 5 +- subcrates/telemetry/src/lib.rs | 42 ++++++--- subcrates/telemetry/src/main.rs | 12 ++- subcrates/telemetry/src/modules/cpu.rs | 72 ++++++++------- subcrates/telemetry/src/modules/devices.rs | 64 ++++++------- subcrates/telemetry/src/modules/external.rs | 6 +- .../src/modules/formatted/architecture.rs | 20 ++++- .../telemetry/src/modules/formatted/bytes.rs | 38 -------- .../src/modules/formatted/date_time.rs | 25 +++++- .../modules/formatted/desktop_environment.rs | 89 ++++++++----------- .../telemetry/src/modules/formatted/mod.rs | 2 +- .../src/modules/formatted/numbers.rs | 54 +++++++++++ .../src/modules/formatted/offset_time.rs | 46 +++++----- .../src/modules/formatted/relative_time.rs | 34 ++++--- .../src/modules/formatted/version.rs | 36 ++++---- subcrates/telemetry/src/modules/gpu/mod.rs | 20 ++--- subcrates/telemetry/src/modules/gpu/vram.rs | 4 +- .../src/modules/macros/custom_anyhow.rs | 11 --- subcrates/telemetry/src/modules/macros/mod.rs | 1 - subcrates/telemetry/src/modules/memory.rs | 11 +-- subcrates/telemetry/src/modules/meta.rs | 23 +++-- subcrates/telemetry/src/modules/mod.rs | 24 +---- subcrates/telemetry/src/modules/network.rs | 10 +-- subcrates/telemetry/src/modules/os.rs | 43 +++++---- subcrates/telemetry/src/modules/storage.rs | 53 +++++------ subcrates/telemetry/src/modules/uptime.rs | 69 ++++++++------ subcrates/zlog/src/config.rs | 4 +- subcrates/zlog/src/lib.rs | 26 +++--- subcrates/zlog/src/tests.rs | 16 ++-- 32 files changed, 568 insertions(+), 405 deletions(-) delete mode 100644 subcrates/telemetry/src/modules/formatted/bytes.rs create mode 100644 subcrates/telemetry/src/modules/formatted/numbers.rs delete mode 100644 subcrates/telemetry/src/modules/macros/custom_anyhow.rs delete mode 100644 subcrates/telemetry/src/modules/macros/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 409464d..ab4c1ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,6 +555,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -671,6 +680,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "detect-desktop-environment" version = "1.2.0" @@ -1016,9 +1047,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1455,7 +1486,7 @@ dependencies = [ "petgraph", "rustc-hash", "spirv", - "strum", + "strum 0.26.3", "thiserror 2.0.12", "unicode-ident", ] @@ -2637,9 +2668,15 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", ] +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" + [[package]] name = "strum_macros" version = "0.26.4" @@ -2653,6 +2690,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.101" @@ -2710,17 +2760,20 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" name = "telemetry" version = "0.1.0" dependencies = [ - "anyhow", "ash", "chrono", + "derive_more", "detect-desktop-environment", "hidapi", "humansize", "metal 0.32.0", "serde", "serde_json", + "strum 0.27.1", + "strum_macros 0.27.1", "sys-locale", "sysinfo", + "thiserror 2.0.12", "timeago", "versions", "wgpu", @@ -2966,6 +3019,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "v_frame" version = "0.3.8" @@ -3861,9 +3920,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.9" +version = "0.30.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +checksum = "b0d05bd8908e14618c9609471db04007e644fd9cce6529756046cfc577f9155e" dependencies = [ "ahash", "android-activity", @@ -3913,9 +3972,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" +checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b" dependencies = [ "memchr", ] diff --git a/src/collections/sparse_set.rs b/src/collections/sparse_set.rs index 5e0ec84..72c7381 100644 --- a/src/collections/sparse_set.rs +++ b/src/collections/sparse_set.rs @@ -236,7 +236,10 @@ mod tests { assert_eq!(sparse_set.remove(SPARSE_PAGESIZE + 2).unwrap(), 3); assert_eq!(sparse_set.sparse[1].as_ref().unwrap().1, 2); - assert_eq!(sparse_set.keys(), [10, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1]); + assert_eq!( + sparse_set.keys(), + [10, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1] + ); assert_eq!(sparse_set.values(), [1, 2, 2, 1, 2]); assert_eq!(sparse_set.remove(SPARSE_PAGESIZE + 1).unwrap(), 2); @@ -249,25 +252,44 @@ mod tests { assert_eq!(sparse_set.keys(), [10, 11, 12]); assert_eq!(sparse_set.values(), [1, 2, 2]); - sparse_set.insert(SPARSE_PAGESIZE, 1); sparse_set.insert(SPARSE_PAGESIZE + 1, 2); sparse_set.insert(SPARSE_PAGESIZE + 2, 3); assert_eq!(sparse_set.remove(10).unwrap(), 1); assert_eq!(sparse_set.sparse[0].as_ref().unwrap().1, 2); - // swap-remove - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, 11, 12, SPARSE_PAGESIZE, SPARSE_PAGESIZE + 1]); + // swap-remove + assert_eq!( + sparse_set.keys(), + [ + SPARSE_PAGESIZE + 2, + 11, + 12, + SPARSE_PAGESIZE, + SPARSE_PAGESIZE + 1 + ] + ); assert_eq!(sparse_set.values(), [3, 2, 2, 1, 2]); assert_eq!(sparse_set.remove(11).unwrap(), 2); assert_eq!(sparse_set.sparse[0].as_ref().unwrap().1, 1); - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, 12, SPARSE_PAGESIZE]); + assert_eq!( + sparse_set.keys(), + [ + SPARSE_PAGESIZE + 2, + SPARSE_PAGESIZE + 1, + 12, + SPARSE_PAGESIZE + ] + ); assert_eq!(sparse_set.values(), [3, 2, 2, 1]); assert_eq!(sparse_set.remove(12).unwrap(), 2); assert!(sparse_set.sparse[0].is_none()); - assert_eq!(sparse_set.keys(), [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, SPARSE_PAGESIZE]); + assert_eq!( + sparse_set.keys(), + [SPARSE_PAGESIZE + 2, SPARSE_PAGESIZE + 1, SPARSE_PAGESIZE] + ); assert_eq!(sparse_set.values(), [3, 2, 1]); } } diff --git a/src/lib.rs b/src/lib.rs index f9a73ed..d5be06a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1 @@ -include!("main.rs"); \ No newline at end of file +include!("main.rs"); diff --git a/subcrates/telemetry/Cargo.toml b/subcrates/telemetry/Cargo.toml index 81ffb9b..7a483ae 100644 --- a/subcrates/telemetry/Cargo.toml +++ b/subcrates/telemetry/Cargo.toml @@ -4,17 +4,20 @@ version = "0.1.0" edition = "2024" [dependencies] -anyhow = "1.0.98" ash = "0.38.0" chrono = { version = "0.4.40", features = ["serde"] } +derive_more = { version = "2.0.1", features = ["add", "add_assign", "as_ref", "deref_mut", "from", "from_str", "full", "into", "mul", "mul_assign", "not", "sum", "try_from", "try_into", "try_unwrap", "unwrap"] } detect-desktop-environment = "1.2.0" hidapi = "2.6.3" humansize = "2.1.3" metal = { version = "0.32.0", optional = true } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" +strum = "0.27.1" +strum_macros = "0.27.1" sys-locale = "0.3.2" sysinfo = { version = "0.34.2", features = ["serde"] } +thiserror = "2.0.12" timeago = "0.4.2" versions = { version = "7.0.0", features = ["serde"] } wgpu = "25.0.0" diff --git a/subcrates/telemetry/src/lib.rs b/subcrates/telemetry/src/lib.rs index 6c1647e..4b1b333 100644 --- a/subcrates/telemetry/src/lib.rs +++ b/subcrates/telemetry/src/lib.rs @@ -1,35 +1,57 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; #[macro_use] mod modules; -use crate::modules::{cpu, devices, external, gpu, memory, meta, network, os, storage, uptime}; -use anyhow::Result; +pub use crate::modules::{cpu, devices, external, gpu, memory, meta, network, os, storage, uptime}; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TelemetryInfo { telemetry: AllInfo, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AllInfo { gpu: gpu::GPUInfo, - cpu: cpu::CPUInfo, + cpu: Vec, memory: memory::MemoryInfo, os: os::OSInfo, storage: Vec, network: network::NetworkInfo, external: external::ExternalInfo, - devices: devices::DevicesInfo, + devices: Vec, meta: meta::MetaInfo, uptime: uptime::UptimeInfo, } +#[derive(Debug, Error)] +pub enum TelemetryError { + // #[error("Failed to get GPU information")] + // GPUError(#[from] gpu::GPUError), + #[error("Failed to get CPU information")] + CPUError(#[from] cpu::CPUError), + #[error("Failed to get OS information")] + OSError(#[from] os::OSError), + #[error("Failed to get storage information")] + StorageError(#[from] storage::StorageError), + // #[error("Failed to get external information")] + // ExternalError(#[from] external::ExternalError), + #[error("Failed to get devices information")] + DevicesError(#[from] devices::DevicesError), + #[error("Failed to get meta information")] + MetaError(#[from] meta::MetaError), + #[error("Failed to get uptime information")] + UptimeError(#[from] uptime::UptimeError), + #[error("Failed to build JSON for TelemetryInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { +pub fn get_struct() -> Result { Ok(TelemetryInfo { telemetry: AllInfo { gpu: gpu::get_struct(), - cpu: cpu::get_struct(), + cpu: cpu::get_struct()?, memory: memory::get_struct(), os: os::get_struct()?, storage: storage::get_list()?, @@ -43,6 +65,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/main.rs b/subcrates/telemetry/src/main.rs index 2806341..37405d5 100644 --- a/subcrates/telemetry/src/main.rs +++ b/subcrates/telemetry/src/main.rs @@ -1,3 +1,13 @@ +use serde_json; + fn main() { - println!("{:#?}", telemetry::get_struct()); + //println!("{:#?}", telemetry::get_struct()); + //println!("{:#?}", telemetry::os::get_json()); + //telemetry::os::get_json(); + + match telemetry::get_struct() { + //Ok(telemetry) => println!("{:#?}", serde_json::from_value(telemetry)), + Ok(telemetry) => println!("{:#?}", telemetry), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/subcrates/telemetry/src/modules/cpu.rs b/subcrates/telemetry/src/modules/cpu.rs index b40d671..7548feb 100644 --- a/subcrates/telemetry/src/modules/cpu.rs +++ b/subcrates/telemetry/src/modules/cpu.rs @@ -1,69 +1,67 @@ -use super::Defaults::Unknown; -use serde::Serialize; +use crate::modules::{FmtCores, FmtThreads}; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use std::collections::HashMap; use sysinfo::{CpuRefreshKind, RefreshKind, System}; +use thiserror::Error; -#[derive(Debug, Serialize)] -pub struct ProcessorInfo { +#[derive(Debug, Serialize, Deserialize)] +pub struct CPUInfo { vendor: String, brand: String, - total_system_cores: String, - threads: u16, + total_system_cores: FmtCores, + threads: FmtThreads, architecture: String, byte_order: String, } -#[derive(Debug, Serialize)] -pub struct CPUInfo { - cpus: Vec, +#[derive(Debug, Error)] +pub enum CPUError { + #[error("No CPU information available")] + NoCpusFound, + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), } #[allow(dead_code)] -pub fn get_struct() -> CPUInfo { - let system = +pub fn get_struct() -> Result, CPUError> { + let mut system = System::new_with_specifics(RefreshKind::nothing().with_cpu(CpuRefreshKind::everything())); + system.refresh_cpu_all(); - let mut processors = Vec::new(); - let mut processor_count: HashMap = HashMap::new(); + let mut processor_map: HashMap = HashMap::new(); for cpu in system.cpus() { - let brand = cpu.brand().trim(); - let total_cores = System::physical_core_count(); - - if processor_count.contains_key(brand) { - processor_count.get_mut(brand).unwrap().threads += 1; - continue; - } - processor_count.insert( - brand.to_string(), - ProcessorInfo { + let brand = cpu.brand().trim().to_string(); + let entry = processor_map + .entry(brand.clone()) + .or_insert_with(|| CPUInfo { vendor: cpu.vendor_id().trim().to_string(), - brand: brand.to_string(), - total_system_cores: if let Some(cores) = total_cores { - cores.to_string() - } else { - Unknown.into() - }, - threads: 1, + brand: brand.clone(), + total_system_cores: System::physical_core_count() + .map(|cores| cores.into()) + .unwrap_or_else(|| 0.into()), + threads: 0.into(), architecture: System::cpu_arch().trim().to_string(), byte_order: if cfg!(target_endian = "little") { String::from("little-endian") } else { String::from("big-endian") }, - }, - ); + }); + + entry.threads += 1.into(); } - for (_brand, info) in processor_count { - processors.push(info); + let cpus: Vec<_> = processor_map.into_values().collect(); + if cpus.is_empty() { + return Err(CPUError::NoCpusFound); } - CPUInfo { cpus: processors } + Ok(cpus) } #[allow(dead_code)] -pub fn get_json() -> Value { - json!(get_struct()) +pub fn get_json() -> Result { + Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/devices.rs b/subcrates/telemetry/src/modules/devices.rs index 81cf169..6a74d2f 100644 --- a/subcrates/telemetry/src/modules/devices.rs +++ b/subcrates/telemetry/src/modules/devices.rs @@ -1,59 +1,59 @@ -//use crate::custom_anyhow; -use anyhow::Result; -use serde::Serialize; +use super::UNKNOWN; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; +use thiserror::Error; extern crate hidapi; -use hidapi::HidApi; +use hidapi::{HidApi, HidError}; use std::collections::HashMap; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DeviceInfo { manufacturer: String, products: Vec, } -#[derive(Debug, Serialize)] -pub struct DevicesInfo { - devices: Vec, +#[derive(Debug, Error)] +pub enum DevicesError { + #[error("Failed to initialize HID API: {0}")] + HidApiInitError(#[from] HidError), + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), } #[allow(dead_code)] -pub fn get_struct() -> Result { - let api = HidApi::new().unwrap(); - let mut grouped_devices: HashMap> = HashMap::new(); +pub fn get_struct() -> Result, DevicesError> { + let api = HidApi::new()?; + let mut grouped: HashMap> = HashMap::new(); for device in api.device_list() { let manufacturer = device .manufacturer_string() - .unwrap_or("Unknown") - .to_string() - .to_lowercase(); - let product = device.product_string().unwrap_or("Unknown").to_string(); + .unwrap_or(UNKNOWN) + .to_ascii_lowercase(); + let product = device.product_string().unwrap_or(UNKNOWN).to_string(); if !manufacturer.trim().is_empty() && !product.trim().is_empty() { - let entry = grouped_devices.entry(manufacturer).or_default(); - - if !entry.contains(&product) { - entry.push(product); - } + grouped.entry(manufacturer).or_default().push(product) } } - let mut devices = Vec::new(); - let mut grouped_vec: Vec<_> = grouped_devices.into_iter().collect(); - grouped_vec.sort_by(|a, b| a.0.to_lowercase().cmp(&b.0.to_lowercase())); + let mut sorted_devices: Vec<_> = grouped.into_iter().collect(); + sorted_devices.sort_by(|a, b| a.0.cmp(&b.0)); - for (manufacturer, products) in grouped_vec { - devices.push(DeviceInfo { - manufacturer, - products, - }); - } - - Ok(DevicesInfo { devices }) + Ok(sorted_devices + .into_iter() + .map(|(manufacturer, mut products)| { + products.sort(); // optional: sort product names + products.dedup(); // remove duplicates + DeviceInfo { + manufacturer, + products, + } + }) + .collect()) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/external.rs b/subcrates/telemetry/src/modules/external.rs index 7987df8..a89e9d5 100644 --- a/subcrates/telemetry/src/modules/external.rs +++ b/subcrates/telemetry/src/modules/external.rs @@ -1,15 +1,15 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use std::{cmp::Ordering::Equal, collections::HashMap}; use sysinfo::{System, Users}; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct SoftwareInfo { name: String, count: usize, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ExternalInfo { softwares: Vec, } diff --git a/subcrates/telemetry/src/modules/formatted/architecture.rs b/subcrates/telemetry/src/modules/formatted/architecture.rs index b875991..fad7499 100644 --- a/subcrates/telemetry/src/modules/formatted/architecture.rs +++ b/subcrates/telemetry/src/modules/formatted/architecture.rs @@ -1,10 +1,10 @@ -use serde::Serialize; +use serde::{Serialize, Serializer, Deserialize, Deserializer, de::Error as DeError}; use std::{ fmt::{Debug, Display, Formatter, Result as FmtResult}, ops::Deref, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub enum TargetPointerWidth { W32Bit, W64Bit, @@ -40,12 +40,26 @@ impl Debug for FmtOSArchitecture { impl Serialize for FmtOSArchitecture { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } +impl<'de> Deserialize<'de> for FmtOSArchitecture { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "32 Bit" => Ok(FmtOSArchitecture(TargetPointerWidth::W32Bit)), + "64 Bit" => Ok(FmtOSArchitecture(TargetPointerWidth::W64Bit)), + _ => Err(DeError::custom(format!("Invalid architecture: {}", s))), + } + } +} + impl Deref for FmtOSArchitecture { type Target = TargetPointerWidth; diff --git a/subcrates/telemetry/src/modules/formatted/bytes.rs b/subcrates/telemetry/src/modules/formatted/bytes.rs deleted file mode 100644 index 598fc81..0000000 --- a/subcrates/telemetry/src/modules/formatted/bytes.rs +++ /dev/null @@ -1,38 +0,0 @@ -use serde::Serialize; -use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, -}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct FmtBytes(pub u64); - -impl Display for FmtBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - use humansize::{DECIMAL, format_size}; - write!(f, "{}", format_size(self.0, DECIMAL)) - } -} - -impl Debug for FmtBytes { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) - } -} - -impl Serialize for FmtBytes { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deref for FmtBytes { - type Target = u64; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/subcrates/telemetry/src/modules/formatted/date_time.rs b/subcrates/telemetry/src/modules/formatted/date_time.rs index 8c26003..efd8bbe 100644 --- a/subcrates/telemetry/src/modules/formatted/date_time.rs +++ b/subcrates/telemetry/src/modules/formatted/date_time.rs @@ -1,11 +1,11 @@ use chrono::{DateTime, Local, TimeZone, Utc}; -use serde::Serialize; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ fmt::{Debug, Display, Formatter, Result as FMTResult}, ops::Deref, }; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DateTimeInfo { date: String, time: String, @@ -46,12 +46,31 @@ where { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } +impl<'de, Tz> Deserialize<'de> for FmtDateTime +where + Tz: TimeZone, + DateTime: ToString + std::str::FromStr, + as std::str::FromStr>::Err: std::fmt::Display, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // 1. Pull a String out of the deserializer + let s = String::deserialize(deserializer)?; + // 2. Parse it, mapping any parse-error into a Serde error + as std::str::FromStr>::from_str(&s) // explicit, no ambiguity + .map(FmtDateTime) + .map_err(serde::de::Error::custom) + } +} + impl Deref for FmtDateTime { type Target = DateTime; diff --git a/subcrates/telemetry/src/modules/formatted/desktop_environment.rs b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs index 7f636c1..5876441 100644 --- a/subcrates/telemetry/src/modules/formatted/desktop_environment.rs +++ b/subcrates/telemetry/src/modules/formatted/desktop_environment.rs @@ -1,59 +1,44 @@ +use std::str::FromStr; + +use serde::{Serialize, Deserialize}; use detect_desktop_environment::DesktopEnvironment; -use serde::{Serialize, Serializer}; -use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, -}; +use strum_macros::EnumString; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SerdeDE(pub DesktopEnvironment); - -impl Serialize for SerdeDE { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&format!("{:?}", self.0)) - } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumString)] +#[strum(serialize_all = "PascalCase", ascii_case_insensitive)] +#[non_exhaustive] +pub enum FmtDE { + Cinnamon, + Cosmic, + CosmicEpoch, + Dde, + Ede, + Endless, + Enlightenment, + Gnome, + Hyprland, + Kde, + Lxde, + Lxqt, + MacOs, + Mate, + Old, + Pantheon, + Razor, + Rox, + Sway, + Tde, + Unity, + Windows, + Xfce, } -impl SerdeDE { - pub fn detect() -> Option { - DesktopEnvironment::detect().map(SerdeDE) - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct FmtDE(pub SerdeDE); - impl FmtDE { pub fn detect() -> Option { - SerdeDE::detect().map(FmtDE) + DesktopEnvironment::detect().and_then(|inner_de| { + let s = format!("{:?}", inner_de); + + FmtDE::from_str(&s).ok() + }) } -} - -impl Display for FmtDE { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{:?}", self.0.0) - } -} - -impl Debug for FmtDE { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) - } -} - -impl Serialize for FmtDE { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deref for FmtDE { - type Target = SerdeDE; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/mod.rs b/subcrates/telemetry/src/modules/formatted/mod.rs index 38987d8..3eeb56b 100644 --- a/subcrates/telemetry/src/modules/formatted/mod.rs +++ b/subcrates/telemetry/src/modules/formatted/mod.rs @@ -1,7 +1,7 @@ pub mod architecture; -pub mod bytes; pub mod date_time; pub mod desktop_environment; pub mod offset_time; pub mod relative_time; pub mod version; +pub mod numbers; \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/numbers.rs b/subcrates/telemetry/src/modules/formatted/numbers.rs new file mode 100644 index 0000000..7948537 --- /dev/null +++ b/subcrates/telemetry/src/modules/formatted/numbers.rs @@ -0,0 +1,54 @@ +use derive_more::{ + Add, AddAssign, Deref, Div, DivAssign, From, Mul, MulAssign, Sub, SubAssign, +}; +use serde::{Serialize, Deserialize}; +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; + +enum DisplayKind { + Plural(&'static str, &'static str), + HumanBytes, +} + +macro_rules! define_fmt_wrapper { + ($name:ident, $ty:ty, $display_kind:expr) => { + #[derive( + Copy, Clone, PartialEq, Eq, PartialOrd, Ord, + Add, Sub, Mul, Div, + AddAssign, SubAssign, MulAssign, DivAssign, + From, Deref, Serialize, Deserialize + )] + pub struct $name(pub $ty); + + impl $name { + #[allow(dead_code)] + pub fn new(value: $ty) -> Self { + Self(value) + } + } + + impl Display for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match $display_kind { + DisplayKind::Plural(singular, plural) => { + let label = if self.0 == 1 { singular } else { plural }; + write!(f, "{} {}", self.0, label) + }, + DisplayKind::HumanBytes => { + use humansize::{format_size, DECIMAL}; + write!(f, "{}", format_size(self.0, DECIMAL)) + }, + } + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + Display::fmt(self, f) + } + } + }; +} + +define_fmt_wrapper!(FmtThreads, u16, DisplayKind::Plural("Thread", "Threads")); +define_fmt_wrapper!(FmtCores, usize, DisplayKind::Plural("Core", "Cores")); +define_fmt_wrapper!(FmtBytes, u64, DisplayKind::HumanBytes); \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/offset_time.rs b/subcrates/telemetry/src/modules/formatted/offset_time.rs index 36d4215..37e4fab 100644 --- a/subcrates/telemetry/src/modules/formatted/offset_time.rs +++ b/subcrates/telemetry/src/modules/formatted/offset_time.rs @@ -1,20 +1,15 @@ use chrono::{DateTime, Local, Offset}; -use serde::Serialize; +use derive_more::{Deref, Display, From}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ cmp::Ordering, fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, }; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, From, Deref, Display)] +#[display("UTC {}", "_0.offset()")] pub struct FmtOffsetTime(pub DateTime); -impl Display for FmtOffsetTime { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "UTC{}", self.0.offset()) - } -} - impl Debug for FmtOffsetTime { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { Display::fmt(self, f) @@ -24,17 +19,28 @@ impl Debug for FmtOffsetTime { impl Serialize for FmtOffsetTime { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } -impl Deref for FmtOffsetTime { - type Target = DateTime; +impl<'de> Deserialize<'de> for FmtOffsetTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Deserialize the input as a string + let s = String::deserialize(deserializer)?; - fn deref(&self) -> &Self::Target { - &self.0 + // Attempt to parse the string into a DateTime + match DateTime::parse_from_rfc3339(&s) { + Ok(dt) => Ok(FmtOffsetTime(dt.with_timezone(&Local))), + Err(e) => Err(serde::de::Error::custom(format!( + "Failed to parse DateTime: {}", + e + ))), + } } } @@ -48,21 +54,13 @@ impl PartialEq for FmtOffsetTime { impl PartialOrd for FmtOffsetTime { fn partial_cmp(&self, other: &Self) -> Option { Some( - self.0 - .offset() - .fix() - .local_minus_utc() - .cmp(&other.0.offset().fix().local_minus_utc()), + self.0.offset().fix().local_minus_utc().cmp(&other.0.offset().fix().local_minus_utc()), ) } } impl Ord for FmtOffsetTime { fn cmp(&self, other: &Self) -> Ordering { - self.0 - .offset() - .fix() - .local_minus_utc() - .cmp(&other.0.offset().fix().local_minus_utc()) + self.0.offset().fix().local_minus_utc().cmp(&other.0.offset().fix().local_minus_utc()) } } diff --git a/subcrates/telemetry/src/modules/formatted/relative_time.rs b/subcrates/telemetry/src/modules/formatted/relative_time.rs index 0e08c62..2933fea 100644 --- a/subcrates/telemetry/src/modules/formatted/relative_time.rs +++ b/subcrates/telemetry/src/modules/formatted/relative_time.rs @@ -1,11 +1,19 @@ -use serde::Serialize; +use derive_more::{From, Deref, with_trait::Display as Display}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, + fmt::{Debug, Formatter, Result as FmtResult}, time::Duration, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive( + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + From, + Deref, +)] pub struct FmtRelativeTime(pub Duration); impl Display for FmtRelativeTime { @@ -25,16 +33,18 @@ impl Debug for FmtRelativeTime { impl Serialize for FmtRelativeTime { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { - serializer.serialize_str(&self.to_string()) + serializer.serialize_u64(self.0.as_secs()) } } -impl Deref for FmtRelativeTime { - type Target = Duration; - - fn deref(&self) -> &Self::Target { - &self.0 +impl<'de> Deserialize<'de> for FmtRelativeTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let secs = u64::deserialize(deserializer)?; + Ok(FmtRelativeTime(Duration::from_secs(secs))) } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/formatted/version.rs b/subcrates/telemetry/src/modules/formatted/version.rs index ccd741e..b83d888 100644 --- a/subcrates/telemetry/src/modules/formatted/version.rs +++ b/subcrates/telemetry/src/modules/formatted/version.rs @@ -1,38 +1,38 @@ -use serde::Serialize; +use derive_more::{Display, From, Deref, with_trait::Display as TDisplay}; +use serde::{Serialize, Serializer, Deserialize, Deserializer}; use std::{ - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::Deref, + fmt::{Debug, Formatter, Result as FmtResult}, + str::FromStr, }; use versions::Versioning; -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, From, Deref, Display)] +#[display("{_0}")] pub struct FmtVersion(pub Versioning); -impl Display for FmtVersion { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{}", self.0) - } -} - impl Debug for FmtVersion { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Display::fmt(self, f) + TDisplay::fmt(self, f) } } impl Serialize for FmtVersion { fn serialize(&self, serializer: S) -> Result where - S: serde::Serializer, + S: Serializer, { serializer.serialize_str(&self.to_string()) } } -impl Deref for FmtVersion { - type Target = Versioning; - - fn deref(&self) -> &Self::Target { - &self.0 +impl<'de> Deserialize<'de> for FmtVersion { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Versioning::from_str(&s) + .map(FmtVersion) + .map_err(serde::de::Error::custom) } -} +} \ No newline at end of file diff --git a/subcrates/telemetry/src/modules/gpu/mod.rs b/subcrates/telemetry/src/modules/gpu/mod.rs index af1e374..f1206ad 100644 --- a/subcrates/telemetry/src/modules/gpu/mod.rs +++ b/subcrates/telemetry/src/modules/gpu/mod.rs @@ -1,5 +1,5 @@ -use super::Defaults::Unknown; -use serde::Serialize; +use super::UNKNOWN; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use wgpu; use winit::{ @@ -11,13 +11,13 @@ use winit::{ mod vram; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct DriverInfo { version: String, name: String, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct AdapterInfo { vendor: String, model: String, @@ -26,13 +26,13 @@ pub struct AdapterInfo { display: DisplayInfo, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GPUInfo { supported_backends: Vec, gpus: Vec, } -#[derive(Debug, Serialize, Default)] +#[derive(Debug, Serialize, Deserialize, Default)] pub struct DisplayInfo { resolution: String, refresh_rate: String, @@ -48,11 +48,11 @@ impl ApplicationHandler for DisplayInfo { self.refresh_rate = if let Some(refresh) = refresh_rate { format!("{} hz", refresh / 1000) } else { - Unknown.into() + UNKNOWN.to_string() } } else { - self.resolution = Unknown.into(); - self.refresh_rate = Unknown.into(); + self.resolution = UNKNOWN.to_string(); + self.refresh_rate = UNKNOWN.to_string(); } event_loop.exit(); @@ -75,7 +75,7 @@ fn vendor_name(vendor: u32) -> &'static str { 0x13B5 => "ARM(Advanced RISC Machines)", 0x5143 => "Qualcomm(Quality Communications)", 0x1010 => "Apple Inc.", - _ => "Unknown", + _ => UNKNOWN, } } diff --git a/subcrates/telemetry/src/modules/gpu/vram.rs b/subcrates/telemetry/src/modules/gpu/vram.rs index 0fd854c..3044104 100644 --- a/subcrates/telemetry/src/modules/gpu/vram.rs +++ b/subcrates/telemetry/src/modules/gpu/vram.rs @@ -1,4 +1,4 @@ -use super::super::Defaults::Unknown; +use super::super::UNKNOWN; use ash::vk::{API_VERSION_1_2, ApplicationInfo, InstanceCreateInfo, MemoryHeapFlags}; use humansize::{DECIMAL, make_format}; @@ -62,6 +62,6 @@ pub fn get(vendor: u32, device_id: u32) -> String { match vendor { 0x10DE | 0x1002 | 0x8086 | 0x5143 => formatter(get_vulkan(device_id)), 0x1010 => formatter(get_metal()), - _ => Unknown.into(), + _ => UNKNOWN.to_string(), } } diff --git a/subcrates/telemetry/src/modules/macros/custom_anyhow.rs b/subcrates/telemetry/src/modules/macros/custom_anyhow.rs deleted file mode 100644 index 7b0ca67..0000000 --- a/subcrates/telemetry/src/modules/macros/custom_anyhow.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[macro_export] -macro_rules! custom_anyhow { - ($fmt:literal $(, $arg:expr)* $(,)?) => { - ::anyhow::anyhow!( - concat!($fmt, " (file: {}, line: {})"), - $($arg,)* - file!(), - line!() - ) - }; -} diff --git a/subcrates/telemetry/src/modules/macros/mod.rs b/subcrates/telemetry/src/modules/macros/mod.rs deleted file mode 100644 index ec3320c..0000000 --- a/subcrates/telemetry/src/modules/macros/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod custom_anyhow; diff --git a/subcrates/telemetry/src/modules/memory.rs b/subcrates/telemetry/src/modules/memory.rs index 0dd39b0..9888d3a 100644 --- a/subcrates/telemetry/src/modules/memory.rs +++ b/subcrates/telemetry/src/modules/memory.rs @@ -1,9 +1,9 @@ use crate::modules::FmtBytes; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::System; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct PhysicalInfo { total: FmtBytes, used: FmtBytes, @@ -11,14 +11,14 @@ pub struct PhysicalInfo { available: FmtBytes, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct VirtualInfo { total: FmtBytes, used: FmtBytes, free: FmtBytes, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MemoryInfo { physical: PhysicalInfo, virtual_swap: VirtualInfo, @@ -26,7 +26,8 @@ pub struct MemoryInfo { #[allow(dead_code)] pub fn get_struct() -> MemoryInfo { - let system = System::new_all(); + let mut system = System::new_all(); + system.refresh_memory(); MemoryInfo { physical: PhysicalInfo { diff --git a/subcrates/telemetry/src/modules/meta.rs b/subcrates/telemetry/src/modules/meta.rs index c0a91f2..60d94b3 100644 --- a/subcrates/telemetry/src/modules/meta.rs +++ b/subcrates/telemetry/src/modules/meta.rs @@ -1,24 +1,31 @@ -use crate::{custom_anyhow, modules::FmtVersion}; -use anyhow::Result; -use serde::Serialize; +use crate::modules::FmtVersion; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sys_locale::get_locale; +use thiserror::Error; use versions::Versioning; include!(concat!(env!("OUT_DIR"), "/built.rs")); -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct MetaInfo { version: FmtVersion, commit_hash: String, locale: String, } +#[derive(Debug, Error)] +pub enum MetaError { + #[error("Invalid Semver version")] + InvalidVersion, + #[error("Failed to build JSON for MetaInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { +pub fn get_struct() -> Result { let locale = get_locale().unwrap_or_else(|| String::from("en-US")); - let version = Versioning::new(env!("CARGO_PKG_VERSION")) - .ok_or(custom_anyhow!("Invalid version").context("Invalid Semver version"))?; + let version = Versioning::new(env!("CARGO_PKG_VERSION")).ok_or(MetaError::InvalidVersion)?; Ok(MetaInfo { version: FmtVersion(version), @@ -28,6 +35,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/mod.rs b/subcrates/telemetry/src/modules/mod.rs index 2d3ade2..d714f7b 100644 --- a/subcrates/telemetry/src/modules/mod.rs +++ b/subcrates/telemetry/src/modules/mod.rs @@ -1,11 +1,8 @@ -use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; - pub mod cpu; pub mod devices; pub mod external; pub mod formatted; pub mod gpu; -pub mod macros; pub mod memory; pub mod meta; pub mod network; @@ -16,27 +13,14 @@ pub mod uptime; #[allow(unused_imports)] pub use formatted::{ architecture::FmtOSArchitecture, - bytes::FmtBytes, + numbers::FmtBytes, date_time::{FmtDateTime, IntoDateTime}, desktop_environment::FmtDE, offset_time::FmtOffsetTime, relative_time::FmtRelativeTime, version::FmtVersion, + numbers::FmtCores, + numbers::FmtThreads, }; -#[derive(Debug)] -pub enum Defaults { - Unknown, -} - -impl Display for Defaults { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{:?}", self) - } -} - -impl From for String { - fn from(value: Defaults) -> Self { - value.to_string() - } -} +pub const UNKNOWN: &str = "Unknown"; diff --git a/subcrates/telemetry/src/modules/network.rs b/subcrates/telemetry/src/modules/network.rs index 4d8dc47..02155d9 100644 --- a/subcrates/telemetry/src/modules/network.rs +++ b/subcrates/telemetry/src/modules/network.rs @@ -1,8 +1,8 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::Networks; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct NetworkInfo { adapters: Vec, } @@ -10,11 +10,7 @@ pub struct NetworkInfo { #[allow(dead_code)] pub fn get_struct() -> NetworkInfo { let networks = Networks::new_with_refreshed_list(); - let mut adapters = Vec::new(); - - for (interface_name, _network_data) in &networks { - adapters.push(interface_name.to_string()); - } + let adapters = networks.iter().map(|(name, _)| name.to_string()).collect(); NetworkInfo { adapters } } diff --git a/subcrates/telemetry/src/modules/os.rs b/subcrates/telemetry/src/modules/os.rs index dd3a4e2..8a121a7 100644 --- a/subcrates/telemetry/src/modules/os.rs +++ b/subcrates/telemetry/src/modules/os.rs @@ -1,14 +1,11 @@ -use super::Defaults::Unknown; -use crate::{ - custom_anyhow, - modules::{FmtDE, FmtOSArchitecture}, -}; -use anyhow::Result; -use serde::Serialize; +use super::UNKNOWN; +use crate::modules::{FmtDE, FmtOSArchitecture}; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; use sysinfo::System; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct OSInfo { name: String, edition: String, @@ -18,20 +15,28 @@ pub struct OSInfo { desktop_environment: Option, } +#[derive(Debug, Error)] +pub enum OSError { + #[error("Unsupported pointer width: 16 bit systems are not supported")] + UnsupportedPointerWidth, + #[error("Failed to build JSON for OSInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { - let architecture = if cfg!(target_pointer_width = "64") { - Ok(FmtOSArchitecture::W64_BIT) - } else if cfg!(target_pointer_width = "32") { - Ok(FmtOSArchitecture::W32_BIT) - } else { - Err(custom_anyhow!("Unsupported pointer width").context("16 bit systems are not supported")) +pub fn get_struct() -> Result { + let architecture = match std::mem::size_of::() { + 8 => Ok(FmtOSArchitecture::W64_BIT), + 4 => Ok(FmtOSArchitecture::W32_BIT), + _ => Err(OSError::UnsupportedPointerWidth), }?; + let kernel = if cfg!(target_os = "linux") || cfg!(target_os = "macos") { Some(System::kernel_long_version()) } else { None }; + let desktop_environment = if cfg!(target_os = "linux") { FmtDE::detect() } else { @@ -39,9 +44,9 @@ pub fn get_struct() -> Result { }; Ok(OSInfo { - name: System::name().unwrap_or(Unknown.into()), - edition: System::long_os_version().unwrap_or(Unknown.into()), - version: System::os_version().unwrap_or(Unknown.into()), + name: System::name().unwrap_or(UNKNOWN.to_string()), + edition: System::long_os_version().unwrap_or(UNKNOWN.to_string()), + version: System::os_version().unwrap_or(UNKNOWN.to_string()), architecture, kernel, desktop_environment, @@ -49,6 +54,6 @@ pub fn get_struct() -> Result { } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/telemetry/src/modules/storage.rs b/subcrates/telemetry/src/modules/storage.rs index 62c9a23..625e611 100644 --- a/subcrates/telemetry/src/modules/storage.rs +++ b/subcrates/telemetry/src/modules/storage.rs @@ -1,11 +1,11 @@ -use crate::{custom_anyhow, modules::FmtBytes}; -use anyhow::Result; -use serde::Serialize; +use crate::modules::FmtBytes; +use serde::{Serialize, Deserialize}; use serde_json::{Value, json}; pub use sysinfo::DiskKind; use sysinfo::Disks; +use thiserror::Error; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct StorageInfo { name: String, mount_point: String, @@ -14,33 +14,36 @@ pub struct StorageInfo { total: FmtBytes, } -#[allow(dead_code)] -pub fn get_list() -> Result> { - let disks = Disks::new_with_refreshed_list(); - let mut drive_data = Vec::new(); +#[derive(Debug, Error)] +pub enum StorageError { + #[error("No storage drives found")] + NoDisksFound, + #[error("Failed to build JSON for Vec")] + JsonError(#[from] serde_json::Error), +} - for disk in disks.list() { - drive_data.push(StorageInfo { - name: format!("{:?}", disk.name()).trim_matches('\"').to_string(), - mount_point: format!("{:?}", disk.mount_point()) - .replace("\\", "") - .trim_matches('\"') - .to_string(), +#[allow(dead_code)] +pub fn get_list() -> Result, StorageError> { + let disks = Disks::new_with_refreshed_list(); + let disk_list = disks.list(); + + if disk_list.is_empty() { + return Err(StorageError::NoDisksFound); + } + + Ok(disk_list + .iter() + .map(|disk| StorageInfo { + name: disk.name().to_string_lossy().into_owned(), + mount_point: disk.mount_point().to_string_lossy().replace('\\', ""), disk_kind: disk.kind(), space_left: FmtBytes(disk.available_space()), total: FmtBytes(disk.total_space()), - }); - } - - if drive_data.is_empty() { - return Err(custom_anyhow!("No storage drives found") - .context("Drive_data is empty, expected disks.list() to return non-zero at line 39")); - } - - Ok(drive_data) + }) + .collect()) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_list()?)) } diff --git a/subcrates/telemetry/src/modules/uptime.rs b/subcrates/telemetry/src/modules/uptime.rs index 1c0dbe6..c6bed58 100644 --- a/subcrates/telemetry/src/modules/uptime.rs +++ b/subcrates/telemetry/src/modules/uptime.rs @@ -1,54 +1,71 @@ -use crate::{ - custom_anyhow, - modules::{FmtDateTime, FmtOffsetTime, FmtRelativeTime}, -}; -use anyhow::Result; -use chrono::{DateTime, Local, Utc}; -use serde::Serialize; +use crate::modules::{FmtDateTime, FmtOffsetTime, FmtRelativeTime}; +use chrono::{DateTime, Local, Utc, TimeZone}; +use serde::{Serialize, Serializer, Deserialize}; use serde_json::{Value, json}; -use std::time::Duration as StdDuration; +use std::{ + time::Duration as StdDuration, + fmt::Display, +}; use sysinfo::System; +use thiserror::Error; -#[derive(Debug, Serialize)] +fn serialize_datetime(date: &DateTime, serializer: S) -> Result +where + S: Serializer, + Tz::Offset: Display, + Tz: TimeZone, +{ + let formatted = date.format("%+").to_string(); // Format as RFC 3339 + serializer.serialize_str(&formatted) +} + +#[derive(Debug, Serialize, Deserialize)] struct DateInfo { + #[serde(serialize_with = "serialize_datetime")] time_offset: FmtOffsetTime, + #[serde(serialize_with = "serialize_datetime")] local_date_time: FmtDateTime, + #[serde(serialize_with = "serialize_datetime")] utc_date_time: FmtDateTime, } -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct UptimeInfo { boot: DateInfo, now: DateInfo, relative: FmtRelativeTime, } +#[derive(Debug, Error)] +pub enum UptimeError { + #[error("Invalid or out of range timestamp: check seconds < 8_220_000_000_000")] + InvalidTimestamp, + #[error("Failed to build JSON for UptimeInfo")] + JsonError(#[from] serde_json::Error), +} + #[allow(dead_code)] -pub fn get_struct() -> Result { - let boot_time_utc = DateTime::::from_timestamp(System::boot_time() as i64, 0).ok_or( - custom_anyhow!("Invalid, or out of range timestamp") - .context("Invalid timestamp: check seconds < 8_220_000_000_000"), - )?; +pub fn get_struct() -> Result { + let boot_time_utc = DateTime::::from_timestamp(System::boot_time() as i64, 0) + .ok_or(UptimeError::InvalidTimestamp)?; let boot_time_local: DateTime = boot_time_utc.with_timezone(&Local); let relative_time = StdDuration::from_secs((Local::now() - boot_time_local).num_seconds() as u64); + let make_info = |utc_dt: DateTime| DateInfo { + time_offset: FmtOffsetTime(Local::now()), + local_date_time: FmtDateTime(utc_dt.with_timezone(&Local)), + utc_date_time: FmtDateTime(utc_dt), + }; + Ok(UptimeInfo { - boot: DateInfo { - time_offset: FmtOffsetTime(Local::now()), - local_date_time: FmtDateTime(boot_time_local), - utc_date_time: FmtDateTime(boot_time_utc), - }, - now: DateInfo { - time_offset: FmtOffsetTime(Local::now()), - local_date_time: FmtDateTime(Local::now()), - utc_date_time: FmtDateTime(Utc::now()), - }, + boot: make_info(boot_time_utc), + now: make_info(Utc::now()), relative: FmtRelativeTime(relative_time), }) } #[allow(dead_code)] -pub fn get_json() -> Result { +pub fn get_json() -> Result { Ok(json!(get_struct()?)) } diff --git a/subcrates/zlog/src/config.rs b/subcrates/zlog/src/config.rs index dc50fbe..b540573 100644 --- a/subcrates/zlog/src/config.rs +++ b/subcrates/zlog/src/config.rs @@ -74,7 +74,7 @@ impl LoggerConfig { self.log_json_show_message = i; self } - + pub fn log_json_show_additional_fields(mut self, i: bool) -> Self { self.log_json_show_additional_fields = i; self @@ -96,7 +96,7 @@ impl Default for LoggerConfig { log_json_show_timestamp: false, log_json_show_level: false, log_json_show_message: false, - log_json_show_additional_fields: false + log_json_show_additional_fields: false, } } } diff --git a/subcrates/zlog/src/lib.rs b/subcrates/zlog/src/lib.rs index e6b64a4..0399099 100644 --- a/subcrates/zlog/src/lib.rs +++ b/subcrates/zlog/src/lib.rs @@ -113,7 +113,7 @@ where level, message, #[cfg(feature = "json")] - additional_fields + additional_fields, }); if let LogEvent::Log(ref entry) = log_entry { @@ -212,13 +212,7 @@ impl Logger { for msg in rx { match msg { LogEvent::Log(mut entry) => { - println!( - "{}", - format_entry( - &mut entry, - &config_clone - ) - ); + println!("{}", format_entry(&mut entry, &config_clone)); } LogEvent::Shutdown => break, } @@ -298,12 +292,12 @@ fn format_entry(entry: &mut LogEntry, log_config: &LoggerConfig) -> String { if log_config.log_use_json { return format_entry_json(entry, log_config); } - + if log_config.log_to_stdout || log_config.log_to_file { return format_entry_string(entry, log_config); } else { return String::new(); - } + } } fn format_entry_string(entry: &LogEntry, log_config: &LoggerConfig) -> String { @@ -327,7 +321,10 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String let mut json_object = serde_json::Map::new(); if log_config.log_json_show_timestamp { - json_object.insert("timestamp".to_string(), Value::String(DateTime::::from(entry.timestamp).to_rfc3339())); + json_object.insert( + "timestamp".to_string(), + Value::String(DateTime::::from(entry.timestamp).to_rfc3339()), + ); } if log_config.log_json_show_level { @@ -335,7 +332,10 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String } if log_config.log_json_show_message { - json_object.insert("message".to_string(), Value::String(entry.message.to_string())); + json_object.insert( + "message".to_string(), + Value::String(entry.message.to_string()), + ); } if log_config.log_json_show_additional_fields { @@ -343,4 +343,4 @@ fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String } serde_json::to_string(&json_object).unwrap() -} \ No newline at end of file +} diff --git a/subcrates/zlog/src/tests.rs b/subcrates/zlog/src/tests.rs index 13c90ab..930b909 100644 --- a/subcrates/zlog/src/tests.rs +++ b/subcrates/zlog/src/tests.rs @@ -1,7 +1,7 @@ use pretty_assertions::assert_eq; -use tracing::Level; +use serde::{Deserialize, Serialize}; use serde_json::Map; -use serde::{Serialize, Deserialize}; +use tracing::Level; use super::*; @@ -126,9 +126,15 @@ fn test_logger_sequential_consistency_json() { for log in logger.get_logs(LogQuery::All) { let mut json_object = serde_json::Map::new(); - json_object.insert("timestamp".to_string(), Value::String(DateTime::::from(log.timestamp).to_rfc3339())); + json_object.insert( + "timestamp".to_string(), + Value::String(DateTime::::from(log.timestamp).to_rfc3339()), + ); json_object.insert("level".to_string(), Value::String(log.level.to_string())); - json_object.insert("message".to_string(), Value::String(log.message.to_string())); + json_object.insert( + "message".to_string(), + Value::String(log.message.to_string()), + ); log_json.push(json_object); } @@ -136,4 +142,4 @@ fn test_logger_sequential_consistency_json() { for log in log_json { serde_json::to_string(&log).unwrap(); } -} \ No newline at end of file +}