use std::process::Command;
use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime};
use sysinfo::System;
use crate::models::*;
use crate::Result;
pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>,
_api: PluginApi<R, C>,
) -> Result<Hwinfo<R>> {
Ok(Hwinfo(app.clone()))
}
pub struct Hwinfo<R: Runtime>(AppHandle<R>);
impl<R: Runtime> Hwinfo<R> {
pub async fn cpu_info(&self) -> Result<CpuInfo> {
#[cfg(target_os = "linux")]
{
let output = Command::new("lscpu").output()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let mut manufacturer = String::new();
let mut model = String::new();
let mut max_freq = 0;
let mut threads = 0;
for line in stdout.lines() {
if line.starts_with("Vendor ID:") {
manufacturer = line.split(':').nth(1).unwrap_or("").trim().to_string();
}
if line.starts_with("Model name:") {
model = line.split(':').nth(1).unwrap_or("").trim().to_string();
}
if line.starts_with("CPU MHz:") {
max_freq = line
.split(':')
.nth(1)
.unwrap_or("")
.trim()
.parse::<f32>()
.unwrap_or(0.0)
.round() as u32;
}
if line.starts_with("CPU(s):") {
threads = line
.split(':')
.nth(1)
.unwrap_or("")
.trim()
.parse()
.unwrap_or(0);
}
}
return Ok(CpuInfo {
manufacturer,
model,
max_frequency: max_freq,
threads,
});
}
#[cfg(target_os = "windows")]
{
let output = Command::new("wmic")
.args([
"cpu",
"get",
"Name,NumberOfLogicalProcessors,MaxClockSpeed,Manufacturer",
])
.output()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let lines: Vec<&str> = stdout.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() >= 2 {
let values = lines[1];
let fields: Vec<&str> = values.split_whitespace().collect();
let manufacturer = fields.get(0).unwrap_or(&"Unknown").to_string();
let max_freq = fields.get(1).unwrap_or(&"0").parse().unwrap_or(0);
let model_slice = &fields[2..fields.len().saturating_sub(1)];
let model = model_slice.join(" ");
let threads = fields.last().unwrap_or(&"0").parse().unwrap_or(0);
return Ok(CpuInfo {
manufacturer,
model,
max_frequency: max_freq,
threads,
});
}
return Ok(CpuInfo {
manufacturer: "Unknown".into(),
model: "Unknown".into(),
max_frequency: 0,
threads: 0,
});
}
#[cfg(target_os = "macos")]
{
let output = Command::new("system_profiler")
.arg("SPHardwareDataType")
.output()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let mut manufacturer = "Apple".to_string();
let mut model = String::new();
let mut max_freq = 0;
let mut threads = 0;
for line in stdout.lines() {
if line.contains("Chip:") || line.contains("Processor Name:") {
model = line.split(':').nth(1).unwrap_or("").trim().to_string();
}
if line.contains("Total Number of Cores:") || line.contains("Total Number of Threads:") {
threads = line
.split(':')
.nth(1)
.unwrap_or("")
.trim()
.parse()
.unwrap_or(0);
}
}
return Ok(CpuInfo {
manufacturer,
model,
max_frequency: max_freq,
threads,
});
}
#[allow(unreachable_code)]
Ok(CpuInfo {
manufacturer: "Unknown".into(),
model: "Unknown".into(),
max_frequency: 0,
threads: 0,
})
}
pub async fn ram_info(&self) -> Result<RamInfo> {
let mut sys = System::new_all();
sys.refresh_memory();
let size_mb = sys.total_memory() / 1024 / 1024; Ok(RamInfo { size_mb })
}
pub async fn gpu_info(&self) -> Result<GpuInfo> {
#[cfg(target_os = "windows")]
{
use std::{fs, env};
let temp_path = env::temp_dir().join("dxdiag_output.txt");
let status = Command::new("dxdiag")
.args(["/t", temp_path.to_str().unwrap()])
.status()?;
if !status.success() {
return Ok(GpuInfo {
manufacturer: "Unknown".into(),
model: "Unknown".into(),
vram_mb: 0,
});
}
let contents = fs::read_to_string(&temp_path)?;
let _ = fs::remove_file(&temp_path);
let mut manufacturer = String::new();
let mut model = String::new();
let mut vram_mb = 0;
for line in contents.lines() {
if line.trim_start().starts_with("Card name:") {
model = line.split(':').nth(1).unwrap_or("").trim().to_string();
} else if line.trim_start().starts_with("Manufacturer:") {
manufacturer = line.split(':').nth(1).unwrap_or("").trim().to_string();
} else if line.trim_start().starts_with("Dedicated Memory:") {
let value = line.split(':').nth(1).unwrap_or("").trim();
if let Some(num_part) = value.split_whitespace().next() {
vram_mb = num_part.replace(',', "").parse::<u64>().unwrap_or(0);
}
}
if !manufacturer.is_empty() && !model.is_empty() && vram_mb > 0 {
break;
}
}
return Ok(GpuInfo {
manufacturer,
model,
vram_mb,
});
}
#[cfg(target_os = "linux")]
{
let mut manufacturer = String::from("Unknown");
let mut model = String::from("Unknown");
let mut vram_mb = 0;
if let Ok(output) = Command::new("lspci").arg("-mm").output() {
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.to_lowercase().contains("vga compatible controller") {
let parts: Vec<&str> = line.split('"').collect();
if let Some(name) = parts.get(5) {
model = name.to_string();
if name.contains("AMD") {
manufacturer = "Advanced Micro Devices, Inc.".into();
} else if name.contains("NVIDIA") {
manufacturer = "NVIDIA Corporation".into();
} else if name.contains("Intel") {
manufacturer = "Intel Corporation".into();
}
} else {
break;
}
}
}
}
if let Ok(output) = Command::new("glxinfo").arg("-B").output() {
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if line.contains("Video memory") || line.contains("Video memory:") {
if let Some(num_part) = line.split_whitespace().last() {
vram_mb = num_part.parse::<u64>().unwrap_or(0);
}
}
}
}
return Ok(GpuInfo {
manufacturer,
model,
vram_mb,
});
}
#[cfg(target_os = "macos")]
{
let output = Command::new("system_profiler")
.arg("SPDisplaysDataType")
.output()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let mut manufacturer = "Apple Inc.".to_string();
let mut model = String::new();
let mut vram_mb = 0;
for line in stdout.lines() {
if line.contains("Chipset Model:") {
model = model.replace("(Metal)", "").trim().to_string();
}
if line.contains("VRAM") {
if let Some(raw) = line.split(':').nth(1) {
let v = raw.trim().replace("GB", "").replace("MB", "").trim().to_string();
if v.contains('.') {
vram_mb = (v.parse::<f32>().unwrap_or(0.0) * 1024.0) as u64;
} else {
vram_mb = v.parse::<u64>().unwrap_or(0);
}
}
}
}
return Ok(GpuInfo {
manufacturer,
model,
vram_mb,
});
}
#[allow(unreachable_code)]
Ok(GpuInfo {
manufacturer: "Unknown".into(),
model: "Unknown".into(),
vram_mb: 0,
})
}
pub async fn os_info(&self) -> Result<OsInfo> {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
{
let info = os_info::get();
let name = info.os_type().to_string();
let version = info.version().to_string();
return Ok(OsInfo { name, version });
}
#[allow(unreachable_code)]
{
return Ok(OsInfo {
name: "Unknown".into(),
version: "Unknown".into(),
});
}
}
}