From 25920c594a216b8f442e22ab9dfd745fe8719809 Mon Sep 17 00:00:00 2001 From: shm Date: Tue, 19 Nov 2024 01:14:08 +0900 Subject: [PATCH] Add: specta --- .vscode/settings.json | 10 +- biome.json | 3 + src-tauri/Cargo.lock | 82 ++++ src-tauri/Cargo.toml | 3 + src-tauri/src/commands/background_image.rs | 7 +- src-tauri/src/commands/config.rs | 23 +- src-tauri/src/commands/hardware.rs | 51 ++- src-tauri/src/commands/ui.rs | 1 + src-tauri/src/enums/hardware.rs | 3 +- src-tauri/src/lib.rs | 52 ++- src-tauri/src/services/nvidia_gpu_service.rs | 5 +- src-tauri/src/services/system_info_service.rs | 13 +- src-tauri/src/services/wmi_service.rs | 6 +- src-tauri/src/structs/hardware.rs | 15 +- src-tauri/src/utils/formatter.rs | 18 +- src/rspc/bindings.ts | 376 ++++++++++++++++++ 16 files changed, 605 insertions(+), 63 deletions(-) create mode 100644 src/rspc/bindings.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index d9c3160..1a4f6cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,7 +22,15 @@ "editor.formatOnSave": true, "editor.inlayHints.enabled": "off" }, - "cSpell.words": ["consts", "directx", "fullscreen", "nvapi", "tauri"], + "cSpell.words": [ + "consts", + "directx", + "fullscreen", + "nvapi", + "rspc", + "specta", + "tauri" + ], "tailwindCSS.experimental.classRegex": [ "tv\\(([^)(]*(?:\\([^)(]*(?:\\([^)(]*(?:\\([^)(]*\\)[^)(]*)*\\)[^)(]*)*\\)[^)(]*)*)\\)" ] diff --git a/biome.json b/biome.json index 83aad5d..b0ca73d 100644 --- a/biome.json +++ b/biome.json @@ -15,5 +15,8 @@ "formatter": { "indentStyle": "space", "indentWidth": 2 + }, + "files": { + "ignore": ["src/rspc/**"] } } diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 1c364cb..ef3de52 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "addr2line" version = "0.24.2" @@ -1704,6 +1710,8 @@ dependencies = [ "rust_decimal", "serde", "serde_json", + "specta", + "specta-typescript", "sys-locale", "sysinfo", "tauri", @@ -1711,6 +1719,7 @@ dependencies = [ "tauri-plugin-dialog", "tauri-plugin-store", "tauri-plugin-window-state", + "tauri-specta", "tempfile", "tokio", "tracing", @@ -4123,6 +4132,50 @@ dependencies = [ "system-deps", ] +[[package]] +name = "specta" +version = "2.0.0-rc.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccbb212565d2dc177bc15ecb7b039d66c4490da892436a4eee5b394d620c9bc" +dependencies = [ + "paste", + "specta-macros", + "thiserror 1.0.64", +] + +[[package]] +name = "specta-macros" +version = "2.0.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68999d29816965eb9e5201f60aec02a76512139811661a7e8e653abc810b8f72" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "specta-serde" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12260cbb21abb2e83a0375b1521867910e3aed8a7afa782206150ce552cd2e5a" +dependencies = [ + "specta", + "thiserror 1.0.64", +] + +[[package]] +name = "specta-typescript" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4472229365ceb6395487e3a60d921ad8e21f9ad06eaecc396f098902c9adc" +dependencies = [ + "specta", + "specta-serde", + "thiserror 1.0.64", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -4352,6 +4405,7 @@ dependencies = [ "serde_json", "serde_repr", "serialize-to-javascript", + "specta", "swift-rs", "tauri-build", "tauri-macros", @@ -4564,6 +4618,34 @@ dependencies = [ "wry", ] +[[package]] +name = "tauri-specta" +version = "2.0.0-rc.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d06336a2fa3ead0c8d08719e78cbc1fb73650845789605bd2ab908cbde72815" +dependencies = [ + "heck 0.5.0", + "serde", + "serde_json", + "specta", + "specta-typescript", + "tauri", + "tauri-specta-macros", + "thiserror 1.0.64", +] + +[[package]] +name = "tauri-specta-macros" +version = "2.0.0-rc.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4aa93823e07859546aa796b8a5d608190cd8037a3a5dce3eb63d491c34bda8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "tauri-utils" version = "2.1.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1c25b40..8cb4aa6 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -47,6 +47,9 @@ winapi = { version = "0.3", features = ["dxgi"] } regex = "1.11.1" tempfile = "3.14.0" sys-locale = "0.3.2" +tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] } +specta-typescript = "0.0.7" +specta="=2.0.0-rc.20" [dependencies.uuid] version = "1.11.0" diff --git a/src-tauri/src/commands/background_image.rs b/src-tauri/src/commands/background_image.rs index 86e4d42..ade71c3 100644 --- a/src-tauri/src/commands/background_image.rs +++ b/src-tauri/src/commands/background_image.rs @@ -3,6 +3,7 @@ use base64::Engine; use image::load_from_memory; use image::ImageFormat; use serde::{Deserialize, Serialize}; +use specta::Type; use tauri::command; use tokio::fs; use tokio::io::AsyncWriteExt; @@ -19,6 +20,7 @@ const BG_IMG_DIR_NAME: &str = "BgImages"; /// - `file_id`: 画像ファイルID /// #[command] +#[specta::specta] pub async fn get_background_image(file_id: String) -> Result { let dir_path = get_app_data_dir(BG_IMG_DIR_NAME); @@ -43,7 +45,7 @@ pub async fn get_background_image(file_id: String) -> Result { /// - `file_id` : 画像ファイルID /// - `image_data` : 画像データのBase64文字列 /// -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Type)] #[serde(rename_all = "camelCase")] pub struct BackgroundImage { pub file_id: String, @@ -54,6 +56,7 @@ pub struct BackgroundImage { /// BG_IMG_DIR_NAME ディレクトリ内の背景画像一覧を取得 /// #[command] +#[specta::specta] pub async fn get_background_images() -> Result, String> { let dir_path = get_app_data_dir(BG_IMG_DIR_NAME); @@ -100,6 +103,7 @@ pub async fn get_background_images() -> Result, String> { /// - returns: `file_id` /// #[command] +#[specta::specta] pub async fn save_background_image(image_data: String) -> Result { let dir_path = get_app_data_dir(BG_IMG_DIR_NAME); @@ -159,6 +163,7 @@ pub async fn save_background_image(image_data: String) -> Result /// - `file_id`: 画像ファイルID /// #[tauri::command] +#[specta::specta] pub async fn delete_background_image(file_id: String) -> Result<(), String> { let dir_path = get_app_data_dir(BG_IMG_DIR_NAME); let file_name = FILE_NAME_FORMAT.replace("{}", &file_id); diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs index 8cab667..06a58dc 100644 --- a/src-tauri/src/commands/config.rs +++ b/src-tauri/src/commands/config.rs @@ -4,9 +4,12 @@ use crate::utils::color; use crate::utils::file::get_app_data_dir; use crate::{log_debug, log_error, log_info, log_internal, log_warn, utils}; use serde::{Deserialize, Serialize}; +use specta::Type; +use specta_typescript::Typescript; use std::fs; use std::io::Write; use std::sync::Mutex; +use tauri_specta::{collect_commands, Builder}; use tempfile::NamedTempFile; const SETTINGS_FILENAME: &str = "settings.json"; @@ -16,7 +19,7 @@ trait Config { fn read_file(&mut self) -> Result<(), String>; } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Type)] #[serde(rename_all = "camelCase")] pub struct StateSettings { pub display: String, @@ -55,7 +58,7 @@ pub struct Settings { /// /// クライアントに送信する設定の構造体 /// -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Type)] #[serde(rename_all = "camelCase")] pub struct LineGraphColorStringSettings { pub cpu: String, @@ -63,7 +66,7 @@ pub struct LineGraphColorStringSettings { pub gpu: String, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Type)] #[serde(rename_all = "camelCase")] pub struct ClientSettings { language: String, @@ -412,6 +415,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn get_settings( state: tauri::State<'_, AppState>, ) -> Result { @@ -462,6 +466,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_language( window: Window, state: tauri::State<'_, AppState>, @@ -478,6 +483,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_theme( window: Window, state: tauri::State<'_, AppState>, @@ -494,6 +500,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_display_targets( window: Window, state: tauri::State<'_, AppState>, @@ -509,6 +516,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_graph_size( window: Window, state: tauri::State<'_, AppState>, @@ -524,6 +532,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_border( window: Window, state: tauri::State<'_, AppState>, @@ -539,6 +548,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_fill( window: Window, state: tauri::State<'_, AppState>, @@ -554,6 +564,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_color( window: Window, state: tauri::State<'_, AppState>, @@ -572,6 +583,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_mix( window: Window, state: tauri::State<'_, AppState>, @@ -587,6 +599,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_show_legend( window: Window, state: tauri::State<'_, AppState>, @@ -602,6 +615,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_line_graph_show_scale( window: Window, state: tauri::State<'_, AppState>, @@ -617,6 +631,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_background_img_opacity( window: Window, state: tauri::State<'_, AppState>, @@ -632,6 +647,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_selected_background_img( window: Window, state: tauri::State<'_, AppState>, @@ -647,6 +663,7 @@ pub mod commands { } #[tauri::command] + #[specta::specta] pub async fn set_state( window: Window, state: tauri::State<'_, AppState>, diff --git a/src-tauri/src/commands/hardware.rs b/src-tauri/src/commands/hardware.rs index e0f8ac4..f04ff4c 100644 --- a/src-tauri/src/commands/hardware.rs +++ b/src-tauri/src/commands/hardware.rs @@ -4,7 +4,8 @@ use crate::services::system_info_service; use crate::services::wmi_service; use crate::structs::hardware::{GraphicInfo, MemoryInfo}; use crate::{log_debug, log_error, log_info, log_internal, log_warn}; -use serde::{Serialize, Serializer}; +use serde::{Deserialize, Serialize, Serializer}; +use specta::Type; use std::collections::HashMap; use std::collections::VecDeque; use std::sync::{Arc, Mutex}; @@ -12,6 +13,7 @@ use std::thread; use std::time::Duration; use sysinfo::{Pid, ProcessesToUpdate, System}; use tauri::command; +use tauri_specta; pub struct AppState { pub system: Arc>, @@ -33,7 +35,7 @@ const SYSTEM_INFO_INIT_INTERVAL: u64 = 1; /// const HISTORY_CAPACITY: usize = 60; -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct ProcessInfo { pub pid: i32, @@ -59,6 +61,7 @@ where /// ## プロセスリストを取得 /// #[command] +#[specta::specta] pub fn get_process_list(state: tauri::State<'_, AppState>) -> Vec { let mut system = state.system.lock().unwrap(); let process_cpu_histories = state.process_cpu_histories.lock().unwrap(); @@ -111,6 +114,7 @@ pub fn get_process_list(state: tauri::State<'_, AppState>) -> Vec { /// - return: `i32` CPU使用率(%) /// #[command] +#[specta::specta] pub fn get_cpu_usage(state: tauri::State<'_, AppState>) -> i32 { let system = state.system.lock().unwrap(); let cpus = system.cpus(); @@ -120,7 +124,7 @@ pub fn get_cpu_usage(state: tauri::State<'_, AppState>) -> i32 { usage.round() as i32 } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct SysInfo { pub cpu: Option, @@ -132,6 +136,7 @@ pub struct SysInfo { /// ## システム情報を取得 /// #[command] +#[specta::specta] pub async fn get_hardware_info( state: tauri::State<'_, AppState>, ) -> Result { @@ -186,6 +191,7 @@ pub async fn get_hardware_info( /// - return: `i32` メモリ使用率(%) /// #[command] +#[specta::specta] pub fn get_memory_usage(state: tauri::State<'_, AppState>) -> i32 { let system = state.system.lock().unwrap(); let used_memory = system.used_memory() as f64; @@ -201,6 +207,7 @@ pub fn get_memory_usage(state: tauri::State<'_, AppState>) -> i32 { /// - return: `i32` GPU使用率(%) /// #[command] +#[specta::specta] pub async fn get_gpu_usage() -> Result { if let Ok(usage) = nvidia_gpu_service::get_nvidia_gpu_usage().await { return Ok((usage * 100.0).round() as i32); @@ -220,6 +227,7 @@ pub async fn get_gpu_usage() -> Result { /// ## GPU温度を取得 /// #[command] +#[specta::specta] pub async fn get_gpu_temperature() -> Result, String> { match nvidia_gpu_service::get_nvidia_gpu_temperature().await { Ok(temps) => Ok(temps), @@ -231,6 +239,7 @@ pub async fn get_gpu_temperature() -> Result, /// ## GPUのファン回転数を取得 /// #[command] +#[specta::specta] pub async fn get_nvidia_gpu_cooler() -> Result, String> { match nvidia_gpu_service::get_nvidia_gpu_cooler_stat().await { @@ -243,45 +252,63 @@ pub async fn get_nvidia_gpu_cooler() -> Result` アプリケーションの状態 -/// - param seconds: `usize` 取得する秒数 +/// - param seconds: `u32` 取得する秒数 /// #[command] +#[specta::specta] pub fn get_cpu_usage_history( state: tauri::State<'_, AppState>, - seconds: usize, + seconds: u32, ) -> Vec { let history = state.cpu_history.lock().unwrap(); - history.iter().rev().take(seconds).cloned().collect() + history + .iter() + .rev() + .take(seconds as usize) + .cloned() + .collect() } /// /// ## メモリ使用率の履歴を取得 /// /// - param state: `tauri::State` アプリケーションの状態 -/// - param seconds: `usize` 取得する秒数 +/// - param seconds: `u32` 取得する秒数 /// #[command] +#[specta::specta] pub fn get_memory_usage_history( state: tauri::State<'_, AppState>, - seconds: usize, + seconds: u32, ) -> Vec { let history = state.memory_history.lock().unwrap(); - history.iter().rev().take(seconds).cloned().collect() + history + .iter() + .rev() + .take(seconds as usize) + .cloned() + .collect() } /// /// ## GPU使用率の履歴を取得 /// /// - param state: `tauri::State` アプリケーションの状態 -/// - param seconds: `usize` 取得する秒数 +/// - param seconds: `u32` 取得する秒数 /// #[command] +#[specta::specta] pub fn get_gpu_usage_history( state: tauri::State<'_, AppState>, - seconds: usize, + seconds: u32, ) -> Vec { let history = state.gpu_history.lock().unwrap(); - history.iter().rev().take(seconds).cloned().collect() + history + .iter() + .rev() + .take(seconds as usize) + .cloned() + .collect() } /// diff --git a/src-tauri/src/commands/ui.rs b/src-tauri/src/commands/ui.rs index b746f0a..fef0215 100644 --- a/src-tauri/src/commands/ui.rs +++ b/src-tauri/src/commands/ui.rs @@ -14,6 +14,7 @@ pub fn init(app: &mut App) { } #[tauri::command] +#[specta::specta] pub fn set_decoration(window: tauri::WebviewWindow, is_decorated: bool) { let _ = window.set_fullscreen(!is_decorated); } diff --git a/src-tauri/src/enums/hardware.rs b/src-tauri/src/enums/hardware.rs index 3b76c97..722a5cb 100644 --- a/src-tauri/src/enums/hardware.rs +++ b/src-tauri/src/enums/hardware.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use specta::Type; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Type)] pub enum HardwareType { CPU, Memory, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 60f33f4..f7f028f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -12,8 +12,11 @@ use commands::background_image; use commands::config; use commands::hardware; use commands::ui; +use serde::{Deserialize, Serialize}; +use specta_typescript::Typescript; use tauri::Manager; use tauri::Wry; +use tauri_specta::{collect_commands, Builder}; use std::collections::{HashMap, VecDeque}; use std::sync::{Arc, Mutex}; @@ -50,24 +53,9 @@ pub fn run() { process_memory_histories, ); - tauri::Builder::::default() - .setup(|app| { - let path_resolver = app.path(); - - // ロガーの初期化 - utils::logger::init(path_resolver.app_log_dir().unwrap()); - - // UIの初期化 - commands::ui::init(app); - - Ok(()) - }) - .plugin(tauri_plugin_store::Builder::new().build()) - .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_window_state::Builder::default().build()) - .manage(state) - .manage(app_state) - .invoke_handler(tauri::generate_handler![ + let mut builder = Builder::::new() + // Then register them (separated by a comma) + .commands(collect_commands![ hardware::get_process_list, hardware::get_cpu_usage, hardware::get_hardware_info, @@ -97,7 +85,33 @@ pub fn run() { background_image::save_background_image, background_image::delete_background_image, ui::set_decoration, - ]) + ]); + + #[cfg(debug_assertions)] + builder + .export(Typescript::default(), "../src/rspc/bindings.ts") + .expect("Failed to export typescript bindings"); + + tauri::Builder::::default() + .invoke_handler(builder.invoke_handler()) + .setup(move |app| { + let path_resolver = app.path(); + + // ロガーの初期化 + utils::logger::init(path_resolver.app_log_dir().unwrap()); + + // UIの初期化 + commands::ui::init(app); + + builder.mount_events(app); + + Ok(()) + }) + .plugin(tauri_plugin_store::Builder::new().build()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_window_state::Builder::default().build()) + .manage(state) + .manage(app_state) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/services/nvidia_gpu_service.rs b/src-tauri/src/services/nvidia_gpu_service.rs index 4a95812..0c1088d 100644 --- a/src-tauri/src/services/nvidia_gpu_service.rs +++ b/src-tauri/src/services/nvidia_gpu_service.rs @@ -3,6 +3,7 @@ use crate::utils::{self, formatter}; use crate::{log_debug, log_error, log_info, log_internal, log_warn}; use nvapi; use nvapi::UtilizationDomain; +use specta::Type; use tokio::task::spawn_blocking; use tokio::task::JoinError; @@ -72,7 +73,7 @@ pub async fn get_nvidia_gpu_usage() -> Result { })? } -#[derive(Debug, Clone, serde::Serialize)] +#[derive(Debug, Clone, serde::Serialize, Type)] #[serde(rename_all = "camelCase")] pub struct NameValue { name: String, @@ -259,7 +260,7 @@ pub async fn get_nvidia_gpu_info() -> Result, String> { id: gpu_id, name, vendor_name: "NVIDIA".to_string(), - clock: frequency, + clock: frequency as u32, memory_size: utils::formatter::RoundedKibibytes { kibibytes: memory_info.shared, precision: 1, diff --git a/src-tauri/src/services/system_info_service.rs b/src-tauri/src/services/system_info_service.rs index 43e6ce1..05a53ce 100644 --- a/src-tauri/src/services/system_info_service.rs +++ b/src-tauri/src/services/system_info_service.rs @@ -1,16 +1,17 @@ use crate::utils; -use serde::Serialize; +use serde::{Deserialize, Serialize}; +use specta::Type; use std::sync::MutexGuard; use sysinfo::System; -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct CpuInfo { name: String, vendor: String, - core_count: usize, - clock: u64, + core_count: u32, + clock: u32, clock_unit: String, cpu_name: String, } @@ -29,8 +30,8 @@ pub fn get_cpu_info(system: MutexGuard<'_, System>) -> Result { let cpu_info = CpuInfo { name: cpus[0].brand().to_string(), vendor: utils::formatter::format_vendor_name(cpus[0].vendor_id()), - core_count: cpus.len(), - clock: cpus[0].frequency(), + core_count: cpus.len() as u32, + clock: cpus[0].frequency() as u32, clock_unit: "MHz".to_string(), cpu_name: cpus[0].name().to_string(), }; diff --git a/src-tauri/src/services/wmi_service.rs b/src-tauri/src/services/wmi_service.rs index 0525df6..305c9c5 100644 --- a/src-tauri/src/services/wmi_service.rs +++ b/src-tauri/src/services/wmi_service.rs @@ -46,10 +46,10 @@ pub fn get_memory_info() -> Result { let memory_info = MemoryInfo { size: formatter::format_size(physical_memory.iter().map(|mem| mem.capacity).sum(), 1), - clock: physical_memory[0].speed as u64, + clock: physical_memory[0].speed as u32, clock_unit: "MHz".to_string(), - memory_count: physical_memory.len(), - total_slots: physical_memory_array[0].memory_devices.unwrap_or(0) as usize, + memory_count: physical_memory.len() as u32, + total_slots: physical_memory_array[0].memory_devices.unwrap_or(0), memory_type: get_memory_type_with_fallback( physical_memory[0].memory_type, physical_memory[0].smbios_memory_type, diff --git a/src-tauri/src/structs/hardware.rs b/src-tauri/src/structs/hardware.rs index c5992e5..a9e7638 100644 --- a/src-tauri/src/structs/hardware.rs +++ b/src-tauri/src/structs/hardware.rs @@ -1,23 +1,24 @@ -use serde::Serialize; +use serde::{Deserialize, Serialize}; +use specta::Type; -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct MemoryInfo { pub size: String, - pub clock: u64, + pub clock: u32, pub clock_unit: String, - pub memory_count: usize, - pub total_slots: usize, + pub memory_count: u32, + pub total_slots: u32, pub memory_type: String, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct GraphicInfo { pub id: String, pub name: String, pub vendor_name: String, - pub clock: u64, + pub clock: u32, pub memory_size: String, pub memory_size_dedicated: String, } diff --git a/src-tauri/src/utils/formatter.rs b/src-tauri/src/utils/formatter.rs index 23f3812..fa50ce2 100644 --- a/src-tauri/src/utils/formatter.rs +++ b/src-tauri/src/utils/formatter.rs @@ -6,7 +6,7 @@ use std::fmt; pub struct RoundedKibibytes { pub kibibytes: Kibibytes, - pub precision: usize, + pub precision: u32, } /// @@ -23,7 +23,7 @@ impl fmt::Display for RoundedKibibytes { f, "{:.precision$} MB", value_in_mib, - precision = self.precision + precision = self.precision as usize ) // 指定された桁数でフォーマット } else { let value_in_gib = value as f32 / 1048576.0; @@ -31,7 +31,7 @@ impl fmt::Display for RoundedKibibytes { f, "{:.precision$} GB", value_in_gib, - precision = self.precision + precision = self.precision as usize ) // 指定された桁数でフォーマット } } @@ -40,16 +40,16 @@ impl fmt::Display for RoundedKibibytes { /// /// ## 小数を指定桁数で丸める(四捨五入) /// -pub fn round(num: f64, precision: usize) -> f64 { +pub fn round(num: f64, precision: u32) -> f64 { Decimal::from_f64(num) - .map(|d| d.round_dp(precision as u32).to_f64().unwrap_or(0.0)) + .map(|d| d.round_dp(precision).to_f64().unwrap_or(0.0)) .unwrap_or(0.0) } /// /// ## バイト数を単位付きの文字列に変換 /// -pub fn format_size(bytes: u64, precision: usize) -> String { +pub fn format_size(bytes: u64, precision: u32) -> String { const KILOBYTE: u64 = 1024; const MEGABYTE: u64 = KILOBYTE * 1024; const GIGABYTE: u64 = MEGABYTE * 1024; @@ -57,12 +57,14 @@ pub fn format_size(bytes: u64, precision: usize) -> String { if bytes >= GIGABYTE { format!( "{:.precision$} GB", - round(bytes as f64 / GIGABYTE as f64, precision) + round(bytes as f64 / GIGABYTE as f64, precision), + precision = precision as usize ) } else if bytes >= MEGABYTE { format!( "{:.precision$} MB", - round(bytes as f64 / MEGABYTE as f64, precision) + round(bytes as f64 / MEGABYTE as f64, precision), + precision = precision as usize ) } else { format!("{} bytes", bytes) diff --git a/src/rspc/bindings.ts b/src/rspc/bindings.ts new file mode 100644 index 0000000..9570676 --- /dev/null +++ b/src/rspc/bindings.ts @@ -0,0 +1,376 @@ + +// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. + +/** user-defined commands **/ + + +export const commands = { +/** + * ## プロセスリストを取得 + * + */ +async getProcessList() : Promise { + return await TAURI_INVOKE("get_process_list"); +}, +/** + * ## CPU使用率(%)を取得 + * + * - pram state: `tauri::State` アプリケーションの状態 + * - return: `i32` CPU使用率(%) + * + */ +async getCpuUsage() : Promise { + return await TAURI_INVOKE("get_cpu_usage"); +}, +/** + * ## システム情報を取得 + * + */ +async getHardwareInfo() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_hardware_info") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * ## メモリ使用率(%)を取得 + * + * - pram state: `tauri::State` アプリケーションの状態 + * - return: `i32` メモリ使用率(%) + * + */ +async getMemoryUsage() : Promise { + return await TAURI_INVOKE("get_memory_usage"); +}, +/** + * ## GPU使用率(%)を取得(Nvidia 限定) + * + * - param state: `tauri::State` アプリケーションの状態 + * - return: `i32` GPU使用率(%) + * + */ +async getGpuUsage() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_gpu_usage") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * ## GPU温度を取得 + * + */ +async getGpuTemperature() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_gpu_temperature") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * ## GPUのファン回転数を取得 + * + */ +async getNvidiaGpuCooler() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_nvidia_gpu_cooler") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * ## CPU使用率の履歴を取得 + * + * - param state: `tauri::State` アプリケーションの状態 + * - param seconds: `u32` 取得する秒数 + * + */ +async getCpuUsageHistory(seconds: number) : Promise { + return await TAURI_INVOKE("get_cpu_usage_history", { seconds }); +}, +/** + * ## メモリ使用率の履歴を取得 + * + * - param state: `tauri::State` アプリケーションの状態 + * - param seconds: `u32` 取得する秒数 + * + */ +async getMemoryUsageHistory(seconds: number) : Promise { + return await TAURI_INVOKE("get_memory_usage_history", { seconds }); +}, +/** + * ## GPU使用率の履歴を取得 + * + * - param state: `tauri::State` アプリケーションの状態 + * - param seconds: `u32` 取得する秒数 + * + */ +async getGpuUsageHistory(seconds: number) : Promise { + return await TAURI_INVOKE("get_gpu_usage_history", { seconds }); +}, +async getSettings() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_settings") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLanguage(newLanguage: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_language", { newLanguage }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setTheme(newTheme: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_theme", { newTheme }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setDisplayTargets(newTargets: HardwareType[]) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_display_targets", { newTargets }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setGraphSize(newSize: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_graph_size", { newSize }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphBorder(newValue: boolean) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_border", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphFill(newValue: boolean) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_fill", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphColor(target: HardwareType, newColor: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_color", { target, newColor }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphMix(newValue: boolean) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_mix", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphShowLegend(newValue: boolean) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_show_legend", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setLineGraphShowScale(newValue: boolean) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_line_graph_show_scale", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setBackgroundImgOpacity(newValue: number) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_background_img_opacity", { newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setState(key: string, newValue: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_state", { key, newValue }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setSelectedBackgroundImg(fileId: string | null) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("set_selected_background_img", { fileId }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * 背景画像を取得 + * + * - `file_id`: 画像ファイルID + * + */ +async getBackgroundImage(fileId: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_background_image", { fileId }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * BG_IMG_DIR_NAME ディレクトリ内の背景画像一覧を取得 + * + */ +async getBackgroundImages() : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_background_images") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * 背景画像を保存 + * + * - `image_data`: 画像データのBase64文字列 + * - returns: `file_id` + * + */ +async saveBackgroundImage(imageData: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("save_background_image", { imageData }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * 背景画像を削除 + * - `file_id`: 画像ファイルID + * + */ +async deleteBackgroundImage(fileId: string) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("delete_background_image", { fileId }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async setDecoration(isDecorated: boolean) : Promise { + await TAURI_INVOKE("set_decoration", { isDecorated }); +} +} + +/** user-defined events **/ + + + +/** user-defined constants **/ + + + +/** user-defined types **/ + +/** + * - `file_id` : 画像ファイルID + * - `image_data` : 画像データのBase64文字列 + * + */ +export type BackgroundImage = { fileId: string; imageData: string } +export type ClientSettings = { language: string; theme: string; displayTargets: HardwareType[]; graphSize: string; lineGraphBorder: boolean; lineGraphFill: boolean; lineGraphColor: LineGraphColorStringSettings; lineGraphMix: boolean; lineGraphShowLegend: boolean; lineGraphShowScale: boolean; backgroundImgOpacity: number; selectedBackgroundImg: string | null; state: StateSettings } +export type CpuInfo = { name: string; vendor: string; coreCount: number; clock: number; clockUnit: string; cpuName: string } +export type GraphicInfo = { id: string; name: string; vendorName: string; clock: number; memorySize: string; memorySizeDedicated: string } +export type HardwareType = "CPU" | "Memory" | "GPU" +/** + * クライアントに送信する設定の構造体 + * + */ +export type LineGraphColorStringSettings = { cpu: string; memory: string; gpu: string } +export type MemoryInfo = { size: string; clock: number; clockUnit: string; memoryCount: number; totalSlots: number; memoryType: string } +export type NameValue = { name: string; value: number } +export type ProcessInfo = { pid: number; name: string; cpuUsage: number; memoryUsage: number } +export type StateSettings = { display: string } +export type SysInfo = { cpu: CpuInfo | null; memory: MemoryInfo | null; gpus: GraphicInfo[] | null } + +/** tauri-specta globals **/ + +import { + invoke as TAURI_INVOKE, + Channel as TAURI_CHANNEL, +} from "@tauri-apps/api/core"; +import * as TAURI_API_EVENT from "@tauri-apps/api/event"; +import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow"; + +type __EventObj__ = { + listen: ( + cb: TAURI_API_EVENT.EventCallback, + ) => ReturnType>; + once: ( + cb: TAURI_API_EVENT.EventCallback, + ) => ReturnType>; + emit: null extends T + ? (payload?: T) => ReturnType + : (payload: T) => ReturnType; +}; + +export type Result = + | { status: "ok"; data: T } + | { status: "error"; error: E }; + +function __makeEvents__>( + mappings: Record, +) { + return new Proxy( + {} as unknown as { + [K in keyof T]: __EventObj__ & { + (handle: __WebviewWindow__): __EventObj__; + }; + }, + { + get: (_, event) => { + const name = mappings[event as keyof T]; + + return new Proxy((() => {}) as any, { + apply: (_, __, [window]: [__WebviewWindow__]) => ({ + listen: (arg: any) => window.listen(name, arg), + once: (arg: any) => window.once(name, arg), + emit: (arg: any) => window.emit(name, arg), + }), + get: (_, command: keyof __EventObj__) => { + switch (command) { + case "listen": + return (arg: any) => TAURI_API_EVENT.listen(name, arg); + case "once": + return (arg: any) => TAURI_API_EVENT.once(name, arg); + case "emit": + return (arg: any) => TAURI_API_EVENT.emit(name, arg); + } + }, + }); + }, + }, + ); +}