diff --git a/Cargo.lock b/Cargo.lock index 3a9df6c..bc1b91c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,6 +267,87 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.21.7", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa 1.0.11", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.1", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-extra" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -642,6 +723,26 @@ dependencies = [ "uuid", ] +[[package]] +name = "coresd" +version = "0.1.0" +dependencies = [ + "axum", + "axum-extra", + "futures", + "futures-util", + "hardwareinfo", + "headers", + "log", + "serde", + "serde_json", + "simplelog", + "tokio", + "tokio-tungstenite", + "tower", + "tower-http", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -776,6 +877,12 @@ dependencies = [ "syn 2.0.68", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "debugid" version = "0.8.0" @@ -1215,6 +1322,21 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -1290,6 +1412,7 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1625,6 +1748,8 @@ dependencies = [ "indexmap 2.2.6", "netdev", "nvml-wrapper", + "serde", + "serde_json", "starship-battery", "sysinfo", ] @@ -1641,6 +1766,30 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.4.1" @@ -1739,6 +1888,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" + [[package]] name = "httparse" version = "1.9.4" @@ -1763,6 +1918,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa 1.0.11", "pin-project-lite", "smallvec", @@ -2135,9 +2291,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "loom" @@ -2207,6 +2363,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memalloc" version = "0.1.0" @@ -2234,6 +2396,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minisign-verify" version = "0.2.1" @@ -2492,6 +2664,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "nvml-wrapper" version = "0.10.0" @@ -3431,7 +3612,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-native-tls", "tokio-rustls", @@ -3842,6 +4023,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa 1.0.11", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -3992,6 +4183,17 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -4187,6 +4389,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" @@ -4687,6 +4895,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thin-slice" version = "0.1.1" @@ -4731,7 +4948,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa 1.0.11", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -4780,13 +4999,26 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", + "tokio-macros", "tracing", "windows-sys 0.48.0", ] +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -4808,6 +5040,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -4893,6 +5137,32 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.6.0", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", ] [[package]] @@ -4913,6 +5183,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4994,6 +5265,25 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" @@ -5061,6 +5351,15 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index 3ed92d7..9100e0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["platforms/core", "platforms/unix/hardwareinfo"] +members = ["platforms/core", "platforms/unix/daemon", "platforms/unix/hardwareinfo"] resolver = "2" [profile.release] diff --git a/platforms/unix/daemon/Cargo.toml b/platforms/unix/daemon/Cargo.toml new file mode 100644 index 0000000..16f2869 --- /dev/null +++ b/platforms/unix/daemon/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "coresd" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { version = "0.7.5", features = ["ws"] } +axum-extra = { version = "0.9.3", features = ["typed-header"] } +futures = "0.3" +futures-util = { version = "0.3", default-features = false, features = [ + "sink", + "std", +] } +headers = "0.4" +tokio = { version = "1.0", features = ["full"] } +tokio-tungstenite = "0.21" +tower = { version = "0.4", features = ["util"] } +tower-http = { version = "0.5.0", features = ["fs", "trace", "cors"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +hardwareinfo = { path = "../hardwareinfo" } +simplelog = "0.12" +log = "0.4" diff --git a/platforms/unix/daemon/src/main.rs b/platforms/unix/daemon/src/main.rs new file mode 100644 index 0000000..20a6920 --- /dev/null +++ b/platforms/unix/daemon/src/main.rs @@ -0,0 +1,207 @@ +use axum::extract::connect_info::ConnectInfo; +use axum::extract::ws::CloseFrame; +use axum::{ + extract::ws::{Message, WebSocket, WebSocketUpgrade}, + http::Method, + response::IntoResponse, + routing::get, + Router, +}; +use axum_extra::TypedHeader; +use futures::{sink::SinkExt, stream::StreamExt}; +use hardwareinfo::{refresh_hardware_info, Data, HardwareInfo, Networks, Nvml, System}; +use log::{info, LevelFilter}; +use serde::{Deserialize, Serialize}; +use simplelog::{ColorChoice, CombinedLogger, Config, TermLogger, TerminalMode}; +use std::borrow::Cow; +use std::net::SocketAddr; +use std::ops::ControlFlow; +use tower_http::{ + cors::{Any, CorsLayer}, + trace::{DefaultMakeSpan, TraceLayer}, +}; + +#[derive(Serialize, Deserialize)] +struct NetworkData { + pub r#type: String, + pub data: HardwareInfo, +} + +#[tokio::main] +async fn main() { + // Logger + CombinedLogger::init(vec![TermLogger::new( + LevelFilter::Info, + Config::default(), + TerminalMode::Mixed, + ColorChoice::Auto, + )]) + .unwrap(); + + let app = Router::new() + .route("/", get(handle_root_request)) + .route("/ws", get(ws_handler)) + .layer( + CorsLayer::new() + .allow_methods([Method::GET, Method::POST]) + .allow_origin(Any), + ) + .layer( + TraceLayer::new_for_http() + .make_span_with(DefaultMakeSpan::default().include_headers(true)), + ); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:5390") + .await + .unwrap(); + info!("listening on http://{}", listener.local_addr().unwrap()); + axum::serve( + listener, + app.into_make_service_with_connect_info::(), + ) + .await + .unwrap(); +} + +async fn handle_root_request() -> impl IntoResponse { + "OK" +} + +async fn ws_handler( + ws: WebSocketUpgrade, + user_agent: Option>, + ConnectInfo(addr): ConnectInfo, +) -> impl IntoResponse { + info!("WS Client connected"); + + ws.on_upgrade(move |socket| handle_socket(socket, addr)) +} + +/// Actual websocket statemachine (one will be spawned per connection) +async fn handle_socket(mut socket: WebSocket, who: SocketAddr) { + // send a ping (unsupported by some browsers) just to kick things off and get a response + if socket.send(Message::Ping(vec![1, 2, 3])).await.is_ok() { + info!("Pinged {who}..."); + } else { + info!("Could not send ping {who}!"); + + return; + } + + let (mut sender, mut receiver) = socket.split(); + + // Spawn a task that will push several messages to the client (does not matter what client does) + let mut send_task = tokio::spawn(async move { + let mut data = Data { + first_run: true, + sys: System::new_all(), + network: Networks::new_with_refreshed_list(), + hw_info: HardwareInfo::default(), + nvml: Nvml::init(), + }; + + let str = serde_json::to_string(&data.hw_info).unwrap(); + + let msg = format!("{}", str); + + loop { + data.sys.refresh_all(); + std::thread::sleep(hardwareinfo::MINIMUM_CPU_UPDATE_INTERVAL); + data.sys.refresh_all(); + data.network.refresh(); + refresh_hardware_info(&mut data); + + let network_data = NetworkData { + r#type: "data".to_string(), + data: data.hw_info.clone(), + }; + + if sender + .send(Message::Text(serde_json::to_string(&network_data).unwrap())) + .await + .is_err() + { + break; + } + + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + + info!("Sending close to {who}..."); + if let Err(e) = sender + .send(Message::Close(Some(CloseFrame { + code: axum::extract::ws::close_code::NORMAL, + reason: Cow::from("Goodbye"), + }))) + .await + { + info!("Could not send Close due to {e}, probably it is ok?"); + } + + return msg; + }); + + // This second task will receive messages from client and print them on server console + let mut recv_task = tokio::spawn(async move { + let mut cnt = 0; + while let Some(Ok(msg)) = receiver.next().await { + cnt += 1; + // print message and break if instructed to do so + if process_message(msg, who).is_break() { + break; + } + } + cnt + }); + + // If any one of the tasks exit, abort the other. + tokio::select! { + rv_a = (&mut send_task) => { + match rv_a { + Ok(a) => info!("{a} messages sent to {who}"), + Err(a) => info!("Error sending messages {a:?}") + } + recv_task.abort(); + }, + rv_b = (&mut recv_task) => { + match rv_b { + Ok(b) => info!("Received {b} messages"), + Err(b) => info!("Error receiving messages {b:?}") + } + send_task.abort(); + } + } + + // returning from the handler closes the websocket connection + info!("Websocket context {who} destroyed"); +} + +/// helper to print contents of messages to stdout. Has special treatment for Close. +fn process_message(msg: Message, who: SocketAddr) -> ControlFlow<(), ()> { + match msg { + Message::Text(t) => { + info!(">>> {who} sent str: {t:?}"); + } + Message::Binary(d) => { + info!(">>> {} sent {} bytes: {:?}", who, d.len(), d); + } + Message::Close(c) => { + if let Some(cf) = c { + info!( + ">>> {} sent close with code {} and reason `{}`", + who, cf.code, cf.reason + ); + } else { + info!(">>> {who} somehow sent close message without CloseFrame"); + } + return ControlFlow::Break(()); + } + Message::Pong(v) => { + info!(">>> {who} sent pong with {v:?}"); + } + Message::Ping(v) => { + info!(">>> {who} sent ping with {v:?}"); + } + } + ControlFlow::Continue(()) +} diff --git a/platforms/unix/hardwareinfo/Cargo.toml b/platforms/unix/hardwareinfo/Cargo.toml index 47d91b2..988aa05 100644 --- a/platforms/unix/hardwareinfo/Cargo.toml +++ b/platforms/unix/hardwareinfo/Cargo.toml @@ -9,3 +9,5 @@ sysinfo = "0.30.12" starship-battery = "0.8.3" indexmap = "2.2.6" nvml-wrapper = "0.10.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/platforms/unix/hardwareinfo/src/lib.rs b/platforms/unix/hardwareinfo/src/lib.rs index f262e15..4009753 100644 --- a/platforms/unix/hardwareinfo/src/lib.rs +++ b/platforms/unix/hardwareinfo/src/lib.rs @@ -2,12 +2,13 @@ use indexmap::IndexMap; use netdev::{get_default_interface, ip::Ipv4Net, mac::MacAddr, NetworkDevice}; use nvml_wrapper::enum_wrappers::device::{Clock, TemperatureSensor}; use nvml_wrapper::struct_wrappers::device::{MemoryInfo, Utilization}; -use nvml_wrapper::Nvml; +use serde::{Deserialize, Serialize}; use std::{ env, net::{IpAddr, Ipv4Addr}, }; +pub use nvml_wrapper::Nvml; pub use sysinfo::{Components, Disks, Networks, System, MINIMUM_CPU_UPDATE_INTERVAL}; #[derive(Debug)] @@ -19,7 +20,7 @@ pub struct Data { pub nvml: Result, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct CoresSensor { pub name: String, pub value: f64, @@ -27,7 +28,8 @@ pub struct CoresSensor { pub max: f64, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct CoresCPUInfo { pub manufacturer_name: String, pub socket_designation: String, @@ -36,16 +38,21 @@ pub struct CoresCPUInfo { pub thread_count: u32, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct CoresCPU { pub name: String, - pub info: CoresCPUInfo, + pub info: Vec, pub max_load: f64, pub load: Vec, pub clock: Vec, + pub temperature: Vec, + pub voltage: Vec, + pub power: Vec, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct CoresGPU { pub name: String, pub temperature: Vec, @@ -58,31 +65,45 @@ pub struct CoresGPU { pub fan: Vec, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CoresRAMInfo { + pub manufacturer_name: String, + pub configured_speed: u32, + // TODO +} + +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CoresRAM { pub load: Vec, + pub info: Vec, + pub layout: Vec, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CoresOS { pub name: String, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct CoresDisks { pub name: String, pub total_space: u64, pub free_space: u64, pub throughput_read: f64, pub throughput_write: f64, + pub temperature: CoresSensor, + pub health: String, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CoresStorage { pub disks: Vec, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct CoresNetInterface { pub name: String, pub description: String, @@ -98,19 +119,58 @@ pub struct CoresNetInterface { pub throughput_download: f64, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CoresNetwork { pub interfaces: Vec, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CoresMonitorDevice { + pub name: String, + pub resolution: String, + pub refresh_rate: String, + pub primary: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CoresMonitor { + pub monitors: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CoresMotherboard { + pub name: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CoresBIOS { + pub vendor: String, + pub version: String, + pub date: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CoresSuperIO { + pub name: String, + pub fan: Vec, + pub fan_control: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[allow(non_snake_case)] pub struct CoresSystem { pub network: CoresNetwork, pub storage: CoresStorage, pub os: CoresOS, + pub motherboard: CoresMotherboard, + pub bios: CoresBIOS, + pub superIO: CoresSuperIO, + pub monitor: CoresMonitor, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct HardwareInfo { pub cpu: CoresCPU, pub ram: CoresRAM, @@ -121,19 +181,26 @@ pub struct HardwareInfo { impl HardwareInfo { pub fn default() -> HardwareInfo { HardwareInfo { - ram: CoresRAM { load: Vec::new() }, + ram: CoresRAM { + load: Vec::new(), + info: Vec::new(), + layout: Vec::new(), + }, cpu: CoresCPU { name: "N/A".to_string(), max_load: 0.0, load: Vec::new(), clock: Vec::new(), - info: CoresCPUInfo { + temperature: Vec::new(), + voltage: Vec::new(), + power: Vec::new(), + info: vec![CoresCPUInfo { manufacturer_name: "N/A".to_string(), socket_designation: "N/A".to_string(), max_speed: 0.0, core_count: 0, thread_count: 0, - }, + }], }, gpu: CoresGPU { name: "N/A".to_string(), @@ -154,6 +221,22 @@ impl HardwareInfo { network: CoresNetwork { interfaces: Vec::new(), }, + motherboard: CoresMotherboard { + name: "N/A".to_string(), + }, + bios: CoresBIOS { + vendor: "N/A".to_string(), + version: "N/A".to_string(), + date: "N/A".to_string(), + }, + superIO: CoresSuperIO { + name: "N/A".to_string(), + fan: Vec::new(), + fan_control: Vec::new(), + }, + monitor: CoresMonitor { + monitors: Vec::new(), + }, }, } } @@ -246,8 +329,8 @@ pub fn refresh_hardware_info(data: &mut Data) { data.hw_info.cpu.max_load = cpu_info.cpu_usage() as f64; if data.first_run { - data.hw_info.cpu.info.core_count = data.sys.physical_core_count().unwrap() as u32; - data.hw_info.cpu.info.thread_count = data.sys.cpus().len() as u32; + data.hw_info.cpu.info[0].core_count = data.sys.physical_core_count().unwrap() as u32; + data.hw_info.cpu.info[0].thread_count = data.sys.cpus().len() as u32; } let mut cpu_count = 0; @@ -258,24 +341,26 @@ pub fn refresh_hardware_info(data: &mut Data) { if data.first_run { data.hw_info.cpu.load.push(CoresSensor { - name: format!("{} #{}", brand, name), + name: format!("{} #{}", brand, cpu_count), value: cpu.cpu_usage() as f64, min: cpu.cpu_usage() as f64, max: cpu.cpu_usage() as f64, }); data.hw_info.cpu.clock.push(CoresSensor { - name: format!("{} #{}", brand, name), + name: format!("{} #{}", brand, cpu_count), value: cpu.frequency() as f64, min: cpu.frequency() as f64, max: cpu.frequency() as f64, }); + + cpu_count += 1; } else { let prev_load = &data.hw_info.cpu.load[cpu_count]; let prev_clock = &data.hw_info.cpu.clock[cpu_count]; data.hw_info.cpu.load[cpu_count] = CoresSensor { - name: format!("{} #{}", brand, name), + name: format!("{} #{}", brand, cpu_count), value: cpu.cpu_usage() as f64, min: if (cpu.cpu_usage() as f64) < prev_load.min { cpu.cpu_usage() as f64 @@ -290,7 +375,7 @@ pub fn refresh_hardware_info(data: &mut Data) { }; data.hw_info.cpu.clock[cpu_count] = CoresSensor { - name: format!("{} #{}", brand, name), + name: format!("{} #{}", brand, cpu_count), value: cpu.frequency() as f64, min: if (cpu.frequency() as f64) < prev_clock.min { cpu.frequency() as f64 @@ -348,7 +433,12 @@ pub fn refresh_hardware_info(data: &mut Data) { max: temperature as f64, }); - data.hw_info.gpu.memory.push(CoresSensor::default()); + data.hw_info.gpu.memory.push(CoresSensor { + name: "GPU Memory Used".to_string(), + value: memory.used as f64 / gb, + min: memory.used as f64 / gb, + max: memory.used as f64 / gb, + }); data.hw_info.gpu.memory.push(CoresSensor::default()); data.hw_info.gpu.memory.push(CoresSensor { @@ -416,6 +506,8 @@ pub fn refresh_hardware_info(data: &mut Data) { free_space: free_space as u64, throughput_read: 0.0, throughput_write: 0.0, + temperature: CoresSensor::default(), + health: "N/A".to_string(), }); } }