Skip to content

Commit

Permalink
add: get hardware info
Browse files Browse the repository at this point in the history
  • Loading branch information
shm11C3 committed Sep 14, 2024
1 parent 4856abe commit 22db187
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 5 deletions.
46 changes: 44 additions & 2 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ tauri-build = { version = "1.5.2", features = [] }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.6.5", features = ["dialog-all"] }
sysinfo = "0.31.3"
sysinfo = "0.31.4"
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
nvapi = "=0.1.4"
tokio = { version = "1.40.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", default-features = true, features = ["env-filter"] }
chrono = "0.4"
wmi = "0.14"

[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
Expand Down
34 changes: 34 additions & 0 deletions src-tauri/src/commands/hardware.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::services::graphic_service;
use crate::services::system_info_service;
use crate::{log_debug, log_error, log_internal, log_warn};
use serde::Serialize;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::thread;
Expand Down Expand Up @@ -41,6 +43,38 @@ pub fn get_cpu_usage(state: tauri::State<'_, AppState>) -> i32 {
usage.round() as i32
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SysInfo {
pub cpu: system_info_service::CpuInfo,
pub memory: system_info_service::MemoryInfo,
//pub gpu: GpuInfo,
}

///
/// ## システム情報を取得
///
#[command]
pub fn get_hardware_info(state: tauri::State<'_, AppState>) -> Result<SysInfo, String> {
let cpu = system_info_service::get_cpu_info(state.system.lock().unwrap());
let memory = system_info_service::get_memory_info();

match (cpu, memory) {
(Ok(cpu_info), Ok(memory_info)) => Ok(SysInfo {
cpu: cpu_info,
memory: memory_info,
}),
(Err(e), _) | (_, Err(e)) => {
log_error!(
"get_sys_info_failed",
"get_hardware_info",
Some(e.to_string())
);
Err(format!("Failed to get hardware info: {}", e))
}
}
}

///
/// ## メモリ使用率(%)を取得
///
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ fn main() {
.menu(menu)
.invoke_handler(tauri::generate_handler![
hardware::get_cpu_usage,
hardware::get_hardware_info,
hardware::get_memory_usage,
hardware::get_gpu_usage,
hardware::get_cpu_usage_history,
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/services/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod graphic_service;
pub mod system_info_service;
pub mod window_menu_service;
193 changes: 193 additions & 0 deletions src-tauri/src/services/system_info_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use crate::utils::unit;
use crate::{log_debug, log_error, log_info, log_internal};

use serde::{Deserialize, Serialize};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::MutexGuard;
use std::thread;
use sysinfo::System;
use wmi::{COMLibrary, WMIConnection};

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CpuInfo {
name: String,
vendor: String,
core_count: usize,
frequency: u64,
cpu_name: String,
}

///
/// ## CPU情報を取得
///
pub fn get_cpu_info(system: MutexGuard<'_, System>) -> Result<CpuInfo, String> {
let cpus = system.cpus();

if cpus.is_empty() {
return Err("CPU information not available".to_string());
}

// CPU情報を収集
let cpu_info = CpuInfo {
name: cpus[0].brand().to_string(),
vendor: cpus[0].vendor_id().to_string(),
core_count: cpus.len(),
frequency: cpus[0].frequency(),
cpu_name: cpus[0].name().to_string(),
};

Ok(cpu_info)
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MemoryInfo {
size: String,
clock: u64,
clock_unit: String,
memory_count: usize,
memory_type: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Win32PhysicalMemory {
capacity: u64,
speed: u32,
memory_type: Option<u16>,
}

///
/// ## メモリ情報を取得
///
pub fn get_memory_info() -> Result<MemoryInfo, String> {
let results = get_memory_info_in_thread()?;

log_info!(
&format!("mem info: {:?}", results),
"get_memory_info",
None::<&str>
);

let memory_info = MemoryInfo {
size: unit::format_size(results.iter().map(|mem| mem.capacity).sum()),
clock: results[0].speed as u64,
clock_unit: "MHz".to_string(),
memory_count: results.len(),
memory_type: get_memory_type_description(results[0].memory_type),
};

Ok(memory_info)
}

///
/// ## MemoryTypeの値に対応するメモリの種類を文字列で返す
///
/// - [TODO] DDR5に対応する
///
fn get_memory_type_description(memory_type: Option<u16>) -> String {
log_info!(
&format!("mem type: {:?}", memory_type),
"get_memory_type_description",
None::<&str>
);

match memory_type {
Some(0) => "Unknown or Unsupported".to_string(),
Some(1) => "Other".to_string(),
Some(2) => "DRAM".to_string(),
Some(3) => "Synchronous DRAM".to_string(),
Some(4) => "Cache DRAM".to_string(),
Some(5) => "EDO".to_string(),
Some(6) => "EDRAM".to_string(),
Some(7) => "VRAM".to_string(),
Some(8) => "SRAM".to_string(),
Some(9) => "RAM".to_string(),
Some(10) => "ROM".to_string(),
Some(11) => "Flash".to_string(),
Some(12) => "EEPROM".to_string(),
Some(13) => "FEPROM".to_string(),
Some(14) => "EPROM".to_string(),
Some(15) => "CDRAM".to_string(),
Some(16) => "3DRAM".to_string(),
Some(17) => "SDRAM".to_string(),
Some(18) => "SGRAM".to_string(),
Some(19) => "RDRAM".to_string(),
Some(20) => "DDR".to_string(),
Some(21) => "DDR2".to_string(),
Some(22) => "DDR2 FB-DIMM".to_string(),
Some(24) => "DDR3".to_string(),
Some(25) => "FBD2".to_string(),
Some(26) => "DDR4".to_string(),
Some(mt) => format!("Other or Unknown Memory Type ({})", mt),
None => "Unknown".to_string(),
}
}

///
/// TODO
///
fn get_memory_type_with_fallback(
memory_type: Option<u16>,
smbios_memory_type: Option<u16>,
) -> String {
match memory_type {
Some(0) => match smbios_memory_type {
Some(20) => "DDR".to_string(),
Some(21) => "DDR2".to_string(),
Some(24) => "DDR3".to_string(),
Some(26) => "DDR4".to_string(),
Some(31) => "DDR5".to_string(),
Some(mt) => format!("Other SMBIOS Memory Type ({})", mt),
None => "Unknown".to_string(),
},
Some(mt) => get_memory_type_description(Some(mt)),
None => "Unknown".to_string(),
}
}

///
/// ## メモリ情報を別スレッドで取得する(WMIを使用)
///
fn get_memory_info_in_thread() -> Result<Vec<Win32PhysicalMemory>, String> {
let (tx, rx): (
Sender<Result<Vec<Win32PhysicalMemory>, String>>,
Receiver<Result<Vec<Win32PhysicalMemory>, String>>,
) = channel();

// 別スレッドを起動してWMIクエリを実行
thread::spawn(move || {
let result = (|| {
let com_con = COMLibrary::new()
.map_err(|e| format!("Failed to initialize COM Library: {:?}", e))?;
let wmi_con = WMIConnection::new(com_con)
.map_err(|e| format!("Failed to create WMI connection: {:?}", e))?;

// WMIクエリを実行してメモリ情報を取得
let results: Vec<Win32PhysicalMemory> = wmi_con
.raw_query("SELECT Capacity, Speed, MemoryType FROM Win32_PhysicalMemory")
.map_err(|e| format!("Failed to execute query: {:?}", e))?;

log_info!(
&format!("mem info: {:?}", results),
"get_memory_info_in_thread",
None::<&str>
);

Ok(results)
})();

// メインスレッドに結果を送信
if let Err(err) = tx.send(result) {
log_error!(
"Failed to send data from thread",
"get_wmi_data_in_thread",
Some(err.to_string())
);
}
});

// メインスレッドで結果を受信
rx.recv().map_err(|_| "Failed to receive data from thread".to_string())?
}
1 change: 1 addition & 0 deletions src-tauri/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod file;
pub mod logger;
pub mod unit;
16 changes: 16 additions & 0 deletions src-tauri/src/utils/unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
///
/// ## バイト数を単位付きの文字列に変換
///
pub fn format_size(bytes: u64) -> String {
const KILOBYTE: u64 = 1024;
const MEGABYTE: u64 = KILOBYTE * 1024;
const GIGABYTE: u64 = MEGABYTE * 1024;

if bytes >= GIGABYTE {
format!("{:.2} GB", bytes as f64 / GIGABYTE as f64)
} else if bytes >= MEGABYTE {
format!("{:.2} MB", bytes as f64 / MEGABYTE as f64)
} else {
format!("{} bytes", bytes)
}
}
Loading

0 comments on commit 22db187

Please sign in to comment.