modulized everthing

This commit is contained in:
2025-08-08 18:59:57 +02:00
parent f0b89a9c32
commit abfa0b6fc0
11 changed files with 690 additions and 570 deletions

View File

@@ -0,0 +1,256 @@
use anyhow::Result;
use std::error::Error;
//use std::result::Result;
use sysinfo::System;
#[derive(Debug)]
pub struct CpuInfo {
pub name: Option<String>,
pub cores: Option<i32>,
pub current_load: Option<f64>,
pub current_temp: Option<f64>,
}
pub async fn get_cpu_info() -> Result<CpuInfo, Box<dyn Error>> {
let mut sys = System::new();
sys.refresh_cpu_all();
let cpus = sys.cpus();
Ok(CpuInfo {
name: Some(
cpus.first()
.map(|c| c.brand().to_string())
.unwrap_or_default(),
),
cores: Some(cpus.len() as i32),
current_load: get_cpu_load(&mut sys).await.ok(),
current_temp: get_cpu_temp().await.ok(),
})
}
pub async fn get_cpu_load(sys: &mut System) -> Result<f64, Box<dyn Error>> {
sys.refresh_cpu_all();
tokio::task::yield_now().await; // Allow other tasks to run
Ok(sys.global_cpu_usage() as f64)
}
pub async fn get_cpu_temp() -> Result<f64, Box<dyn Error>> {
println!("Attempting to get CPU temperature...");
#[cfg(target_os = "linux")]
{
use std::fs;
use std::process::Command;
println!("");
if let Ok(output) = Command::new("sensors").output() {
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.contains("Package id") || line.contains("Tdie") || line.contains("CPU Temp")
{
if let Some(temp_str) = line
.split('+')
.nth(1)
.and_then(|s| s.split_whitespace().next())
{
if let Ok(temp) = temp_str.replace("°C", "").parse::<f32>() {
return Some(temp);
}
}
}
}
}
// 2. Sysfs (Intel/AMD)
if let Ok(content) = fs::read_to_string("/sys/class/thermal/thermal_zone0/temp") {
if let Ok(temp) = content.trim().parse::<f32>() {
return Some(temp / 1000.0);
}
}
// 3. Alternative Sysfs-Pfade
let paths = [
"/sys/class/hwmon/hwmontemp1_input",
"/sys/class/hwmon/hwmondevice/temp1_input",
];
for path_pattern in &paths {
if let Ok(paths) = glob::glob(path_pattern) {
for path in paths.flatten() {
if let Ok(content) = fs::read_to_string(&path) {
if let Ok(temp) = content.trim().parse::<f32>() {
return Some(temp / 1000.0);
}
}
}
}
}
Err(anyhow::anyhow!(
"Could not find CPU temperature using sensors or sysfs"
))
}
#[cfg(target_os = "windows")]
fn failed(hr: winapi::shared::winerror::HRESULT) -> bool {
hr < 0
}
#[cfg(target_os = "windows")]
{
use com::runtime::init_runtime;
use com::sys::CLSCTX_INPROC_SERVER;
use widestring::U16CString;
use winapi::shared::rpcdce::*;
use winapi::shared::wtypes::VT_I4;
use winapi::um::oaidl::VARIANT;
use winapi::um::objidlbase::EOAC_NONE;
use winapi::um::{combaseapi, wbemcli};
init_runtime().ok();
unsafe {
use anyhow::Ok;
let mut locator: *mut wbemcli::IWbemLocator = std::ptr::null_mut();
let hr = combaseapi::CoCreateInstance(
&wbemcli::CLSID_WbemLocator,
std::ptr::null_mut(),
CLSCTX_INPROC_SERVER,
&wbemcli::IID_IWbemLocator,
&mut locator as *mut _ as *mut _,
);
if hr != 0 {
eprintln!("Failed to create WbemLocator (HRESULT: {})", hr);
return Err(("Failed to create WbemLocator").into());
}
let mut services: *mut wbemcli::IWbemServices = std::ptr::null_mut();
let namespace = U16CString::from_str("root\\cimv2").unwrap(); // Changed to more common namespace
let hr = (*locator).ConnectServer(
namespace.as_ptr().cast_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
&mut services,
);
if hr != 0 {
eprintln!("Failed to connect to WMI (HRESULT: {})", hr);
(*locator).Release();
return Err(("Failed to connect to WMI").into());
}
// Set security levels
let hr = combaseapi::CoSetProxyBlanket(
services as *mut _,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
std::ptr::null_mut(),
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
std::ptr::null_mut(),
EOAC_NONE,
);
if hr != 0 {
eprintln!("Failed to set proxy blanket (HRESULT: {})", hr);
(*services).Release();
(*locator).Release();
return Err(("Failed to set proxy blanket").into());
}
// Try different temperature queries - some systems might have different WMI classes
let queries = [
"SELECT * FROM Win32_PerfFormattedData_Counters_ThermalZoneInformation",
"SELECT * FROM MSAcpi_ThermalZoneTemperature",
"SELECT * FROM Win32_TemperatureProbe",
];
let mut result = None;
for query_str in queries.iter() {
let query = U16CString::from_str(query_str).unwrap();
let mut enumerator: *mut wbemcli::IEnumWbemClassObject = std::ptr::null_mut();
let hr = (*services).ExecQuery(
U16CString::from_str("WQL").unwrap().as_ptr().cast_mut(),
query.as_ptr().cast_mut(),
wbemcli::WBEM_FLAG_FORWARD_ONLY as i32,
std::ptr::null_mut(),
&mut enumerator,
);
if hr != 0 {
continue; // Try next query if this one fails
}
let mut obj: *mut wbemcli::IWbemClassObject = std::ptr::null_mut();
let mut returned = 0;
let hr = (*enumerator).Next(
wbemcli::WBEM_INFINITE as i32, // Fixed: cast directly to i32
1,
&mut obj,
&mut returned,
);
if failed(hr) {
eprintln!("Failed to enumerate WMI objects (HRESULT: {})", hr);
(*enumerator).Release();
continue;
}
if returned == 0 {
// No more items
(*enumerator).Release();
continue;
}
if hr == 0 && returned > 0 {
let mut variant = std::mem::zeroed::<VARIANT>();
// Try different possible property names
let property_names = ["CurrentTemperature", "Temperature", "CurrentReading"];
for prop in property_names.iter() {
let hr = (*obj).Get(
U16CString::from_str(prop).unwrap().as_ptr(),
0,
&mut variant,
std::ptr::null_mut(),
std::ptr::null_mut(),
);
if hr == 0 && variant.n1.n2().vt as u32 == VT_I4 {
let temp_kelvin = *variant.n1.n2().n3.intVal() as f32 / 10.0;
result = Some(temp_kelvin - 273.15); // Convert to Celsius
break;
}
}
(*obj).Release();
(*enumerator).Release();
if result.is_some() {
break;
}
}
if !enumerator.is_null() {
(*enumerator).Release();
}
}
(*services).Release();
(*locator).Release();
return Ok(result.unwrap() as f64).map_err(|e| e.into());
}
}
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
{
println!("CPU temperature retrieval not supported on this OS.");
Err(anyhow::anyhow!("CPU temperature retrieval not supported on this OS").into())
}
}