diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 85cc2b5..ac167b0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1660,20 +1660,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "macos-task-manager" -version = "1.1.0" -dependencies = [ - "serde", - "serde_json", - "sysinfo", - "tauri", - "tauri-build", - "tauri-plugin-os", - "tauri-plugin-shell", - "window-vibrancy", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -1796,6 +1782,20 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "neohtop" +version = "1.1.0" +dependencies = [ + "serde", + "serde_json", + "sysinfo", + "tauri", + "tauri-build", + "tauri-plugin-os", + "tauri-plugin-shell", + "window-vibrancy", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 000e8b5..1067152 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "macos-task-manager" +name = "neohtop" version = "1.1.0" -description = "A Tauri App" +description = "A cross-platform system monitor" authors = ["you"] edition = "2021" diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index fe0a99a..78c6567 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,156 +1,66 @@ +//! Tauri command handlers +//! +//! This module contains the command handlers that are exposed to the frontend +//! through Tauri's IPC mechanism. These commands provide the interface between +//! the frontend and the system monitoring functionality. + +use crate::monitoring::{ProcessInfo, ProcessMonitor, SystemStats}; use crate::state::AppState; -use crate::system::collect_system_stats; -use crate::types::{ProcessInfo, ProcessStaticInfo, SystemStats}; -use std::time::{SystemTime, UNIX_EPOCH}; -use sysinfo::{PidExt, ProcessExt, ProcessStatus, SystemExt}; +use sysinfo::SystemExt; use tauri::State; +/// Retrieves the current list of processes and system statistics +/// +/// # Arguments +/// +/// * `state` - The application state containing system monitoring components +/// +/// # Returns +/// +/// A tuple containing: +/// * A vector of process information +/// * Current system statistics +/// +/// # Errors +/// +/// Returns an error string if: +/// * Failed to acquire locks on system state +/// * Failed to collect process information #[tauri::command] pub async fn get_processes( state: State<'_, AppState>, ) -> Result<(Vec, SystemStats), String> { - let processes_data; - let system_stats; - - let current_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(|e| format!("Failed to get system time: {}", e))? - .as_secs(); - - let mut sys = state - .sys - .lock() - .map_err(|e| format!("Failed to lock system state: {}", e))?; - + let mut sys = state.sys.lock().map_err(|e| e.to_string())?; sys.refresh_all(); sys.refresh_networks_list(); sys.refresh_disks_list(); - processes_data = collect_process_data(&sys, current_time); + let mut process_monitor = state.process_monitor.lock().map_err(|e| e.to_string())?; + let mut system_monitor = state.system_monitor.lock().map_err(|e| e.to_string())?; - system_stats = collect_system_stats(&mut sys, &state) - .map_err(|e| format!("Failed to collect system stats: {}", e))?; - - let mut process_cache = state - .process_cache - .lock() - .map_err(|e| format!("Failed to lock process cache: {}", e))?; - - let processes = build_process_info(processes_data, &mut process_cache); + let processes = process_monitor.collect_processes(&sys)?; + let system_stats = system_monitor.collect_stats(&sys); Ok((processes, system_stats)) } +/// Attempts to kill a process with the specified PID +/// +/// # Arguments +/// +/// * `pid` - Process ID to kill +/// * `state` - The application state +/// +/// # Returns +/// +/// * `true` if the process was successfully killed +/// * `false` if the process couldn't be killed or wasn't found +/// +/// # Errors +/// +/// Returns an error string if failed to acquire lock on system state #[tauri::command] pub async fn kill_process(pid: u32, state: State<'_, AppState>) -> Result { - let sys = state - .sys - .lock() - .map_err(|e| format!("Failed to lock system state for process termination: {}", e))?; - - if let Some(process) = sys.process(sysinfo::Pid::from(pid as usize)) { - Ok(process.kill()) - } else { - Ok(false) - } -} - -// Helper functions -fn collect_process_data(sys: &sysinfo::System, current_time: u64) -> Vec { - sys.processes() - .iter() - .map(|(pid, process)| { - let start_time = process.start_time(); - let run_time = if start_time > 0 { - current_time.saturating_sub(start_time) - } else { - 0 - }; - - ProcessData { - pid: pid.as_u32(), - name: process.name().to_string(), - cmd: process.cmd().to_vec(), - user_id: process.user_id().map(|uid| uid.to_string()), - cpu_usage: process.cpu_usage(), - memory: process.memory(), - status: process.status(), - ppid: process.parent().map(|p| p.as_u32()), - environ: process.environ().to_vec(), - root: process.root().to_string_lossy().into_owned(), - virtual_memory: process.virtual_memory(), - start_time, - run_time, - disk_read: process.disk_usage().read_bytes, - disk_written: process.disk_usage().written_bytes, - session_id: process.session_id().map(|id| id.as_u32()), - } - }) - .collect() -} - -// Helper struct for intermediate process data -struct ProcessData { - pid: u32, - name: String, - cmd: Vec, - user_id: Option, - cpu_usage: f32, - memory: u64, - status: ProcessStatus, - ppid: Option, - environ: Vec, - root: String, - virtual_memory: u64, - start_time: u64, - run_time: u64, - disk_read: u64, - disk_written: u64, - session_id: Option, -} - -// Helper function to build process info -fn build_process_info( - processes: Vec, - process_cache: &mut std::collections::HashMap, -) -> Vec { - processes - .into_iter() - .map(|data| { - // Update or get from cache - let cached_info = process_cache - .entry(data.pid) - .or_insert_with(|| ProcessStaticInfo { - name: data.name.clone(), - command: data.cmd.join(" "), - user: data.user_id.clone().unwrap_or_else(|| "-".to_string()), - }); - - let status_str = match data.status { - ProcessStatus::Run => "Running", - ProcessStatus::Sleep => "Sleeping", - ProcessStatus::Idle => "Idle", - _ => "Unknown", - }; - - ProcessInfo { - pid: data.pid, - ppid: data.ppid.unwrap_or(0), - name: cached_info.name.clone(), - cpu_usage: data.cpu_usage, - memory_usage: data.memory, - status: status_str.to_string(), - user: cached_info.user.clone(), - command: cached_info.command.clone(), - threads: None, - environ: data.environ, - root: data.root, - virtual_memory: data.virtual_memory, - start_time: data.start_time, - run_time: data.run_time, - disk_usage: (data.disk_read, data.disk_written), - session_id: data.session_id, - } - }) - .collect() + let sys = state.sys.lock().map_err(|e| e.to_string())?; + Ok(ProcessMonitor::kill_process(&sys, pid)) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d9be5c7..a829ed9 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,20 +1,30 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +//! NeoHtop - A modern system monitor built with Tauri +//! +//! This is the main entry point for the application. It sets up the Tauri +//! application, initializes plugins, and configures window effects. mod commands; +mod monitoring; mod state; -mod system; -mod types; -mod window; +mod ui; use state::AppState; use tauri::Manager; -use window::setup_window_effects; +/// Main entry point for the application +/// +/// # Panics +/// +/// Will panic if: +/// - Unable to create the main window +/// - Failed to apply window effects +/// - Failed to initialize the application state fn main() { tauri::Builder::default() .setup(|app| { let window = app.get_webview_window("main").unwrap(); - setup_window_effects(&window).expect("Failed to apply window effects"); + ui::setup_window_effects(&window).expect("Failed to apply window effects"); Ok(()) }) .plugin(tauri_plugin_shell::init()) @@ -22,7 +32,7 @@ fn main() { .manage(AppState::new()) .invoke_handler(tauri::generate_handler![ commands::get_processes, - commands::kill_process + commands::kill_process, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/monitoring/mod.rs b/src-tauri/src/monitoring/mod.rs new file mode 100644 index 0000000..0f8261a --- /dev/null +++ b/src-tauri/src/monitoring/mod.rs @@ -0,0 +1,13 @@ +//! System monitoring functionality +//! +//! This module provides types and functionality for monitoring system resources +//! and processes. It includes process monitoring, system statistics collection, +//! and data structures for representing system state. + +mod process_monitor; +mod system_monitor; +mod types; + +pub use process_monitor::ProcessMonitor; +pub use system_monitor::SystemMonitor; +pub use types::*; // Re-export all types diff --git a/src-tauri/src/monitoring/process_monitor.rs b/src-tauri/src/monitoring/process_monitor.rs new file mode 100644 index 0000000..761d29d --- /dev/null +++ b/src-tauri/src/monitoring/process_monitor.rs @@ -0,0 +1,167 @@ +//! Process monitoring functionality +//! +//! This module handles monitoring and managing system processes, including +//! collecting process information and managing process lifecycle. + +use super::{ProcessData, ProcessInfo, ProcessStaticInfo}; +use std::collections::HashMap; +use std::fmt::Debug; +use std::time::{SystemTime, UNIX_EPOCH}; +use sysinfo::{PidExt, ProcessExt, ProcessStatus, SystemExt}; + +/// Monitors and manages system processes +#[derive(Debug)] +pub struct ProcessMonitor { + /// Cache for static process information to avoid redundant allocations + process_cache: HashMap, +} + +impl ProcessMonitor { + /// Creates a new process monitor instance + pub fn new() -> Self { + Self { + process_cache: HashMap::new(), + } + } + + /// Collects information about all running processes + /// + /// # Arguments + /// + /// * `sys` - System information provider + /// + /// # Returns + /// + /// A vector of process information, or an error string if collection failed + pub fn collect_processes(&mut self, sys: &sysinfo::System) -> Result, String> { + let current_time = Self::get_current_time()?; + let processes_data = self.collect_process_data(sys, current_time); + Ok(self.build_process_info(processes_data)) + } + + /// Attempts to kill a process + /// + /// # Arguments + /// + /// * `sys` - System information provider + /// * `pid` - Process ID to kill + /// + /// # Returns + /// + /// Boolean indicating whether the process was successfully killed + pub fn kill_process(sys: &sysinfo::System, pid: u32) -> bool { + sys.process(sysinfo::Pid::from(pid as usize)) + .map(|process| process.kill()) + .unwrap_or(false) + } + + /// Gets the current system time in seconds since UNIX epoch + fn get_current_time() -> Result { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .map_err(|e| format!("Failed to get system time: {}", e)) + } + + /// Collects raw process data from the system + fn collect_process_data(&self, sys: &sysinfo::System, current_time: u64) -> Vec { + sys.processes() + .iter() + .map(|(pid, process)| { + let start_time = process.start_time(); + ProcessData { + pid: pid.as_u32(), + name: process.name().to_string(), + cmd: process.cmd().to_vec(), + user_id: process.user_id().map(|uid| uid.to_string()), + cpu_usage: process.cpu_usage(), + memory: process.memory(), + status: process.status(), + ppid: process.parent().map(|p| p.as_u32()), + environ: process.environ().to_vec(), + root: process.root().to_string_lossy().into_owned(), + virtual_memory: process.virtual_memory(), + start_time, + run_time: if start_time > 0 { + current_time.saturating_sub(start_time) + } else { + 0 + }, + disk_usage: process.disk_usage(), + session_id: process.session_id().map(|id| id.as_u32()), + } + }) + .collect() + } + + /// Builds process information from raw process data + fn build_process_info(&mut self, processes: Vec) -> Vec { + processes + .into_iter() + .map(|data| { + let cached_info = + self.process_cache + .entry(data.pid) + .or_insert_with(|| ProcessStaticInfo { + name: data.name.clone(), + command: data.cmd.join(" "), + user: data.user_id.unwrap_or_else(|| "-".to_string()), + }); + + ProcessInfo { + pid: data.pid, + ppid: data.ppid.unwrap_or(0), + name: cached_info.name.clone(), + cpu_usage: data.cpu_usage, + memory_usage: data.memory, + status: Self::format_status(data.status), + user: cached_info.user.clone(), + command: cached_info.command.clone(), + threads: None, + environ: data.environ, + root: data.root, + virtual_memory: data.virtual_memory, + start_time: data.start_time, + run_time: data.run_time, + disk_usage: (data.disk_usage.read_bytes, data.disk_usage.written_bytes), + session_id: data.session_id, + } + }) + .collect() + } + + /// Formats process status into a human-readable string + pub fn format_status(status: ProcessStatus) -> String { + match status { + ProcessStatus::Run => "Running", + ProcessStatus::Sleep => "Sleeping", + ProcessStatus::Idle => "Idle", + _ => "Unknown", + } + .to_string() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sysinfo::System; + + /// Tests creation of a new process monitor + #[test] + fn test_process_monitor_creation() { + let monitor = ProcessMonitor::new(); + assert!(monitor.process_cache.is_empty()); + } + + /// Tests process collection functionality + #[test] + fn test_process_collection() { + let mut monitor = ProcessMonitor::new(); + let mut sys = System::new(); + sys.refresh_all(); + + let result = monitor.collect_processes(&sys); + assert!(result.is_ok()); + } +} diff --git a/src-tauri/src/monitoring/system_monitor.rs b/src-tauri/src/monitoring/system_monitor.rs new file mode 100644 index 0000000..864d57f --- /dev/null +++ b/src-tauri/src/monitoring/system_monitor.rs @@ -0,0 +1,146 @@ +//! System statistics monitoring +//! +//! This module handles collection and monitoring of system-wide statistics +//! including CPU, memory, network, and disk usage. + +use super::SystemStats; +use std::fmt::Debug; +use std::path::Path; +use std::time::Instant; +use sysinfo::{CpuExt, Disk, DiskExt, NetworkExt, NetworksExt, SystemExt}; + +/// Monitors system-wide statistics +#[derive(Debug)] +pub struct SystemMonitor { + /// Tracks network usage between updates + last_network_update: (Instant, u64, u64), +} + +impl SystemMonitor { + /// Creates a new system monitor instance + /// + /// # Arguments + /// + /// * `sys` - System information provider for initial readings + pub fn new(sys: &sysinfo::System) -> Self { + let initial_rx: u64 = sys + .networks() + .iter() + .map(|(_, data)| data.total_received()) + .sum(); + let initial_tx: u64 = sys + .networks() + .iter() + .map(|(_, data)| data.total_transmitted()) + .sum(); + + Self { + last_network_update: (Instant::now(), initial_rx, initial_tx), + } + } + + /// Collects current system statistics + /// + /// # Arguments + /// + /// * `sys` - System information provider + pub fn collect_stats(&mut self, sys: &sysinfo::System) -> SystemStats { + let (network_rx, network_tx) = self.calculate_network_stats(sys); + let (disk_total, disk_used, disk_free) = self.calculate_disk_stats(sys); + + SystemStats { + cpu_usage: sys.cpus().iter().map(|cpu| cpu.cpu_usage()).collect(), + memory_total: sys.total_memory(), + memory_used: sys.used_memory(), + memory_free: sys.total_memory() - sys.used_memory(), + memory_cached: sys.total_memory() + - (sys.used_memory() + (sys.total_memory() - sys.used_memory())), + uptime: sys.uptime(), + load_avg: [ + sys.load_average().one, + sys.load_average().five, + sys.load_average().fifteen, + ], + network_rx_bytes: network_rx, + network_tx_bytes: network_tx, + disk_total_bytes: disk_total, + disk_used_bytes: disk_used, + disk_free_bytes: disk_free, + } + } + + /// Filters disks based on platform-specific criteria + #[cfg(not(target_os = "windows"))] + fn filter_disks(disks: &[Disk]) -> Vec<&Disk> { + disks + .iter() + .filter(|disk| disk.mount_point() == Path::new("/")) + .collect() + } + + /// Windows-specific disk filtering + #[cfg(target_os = "windows")] + fn filter_disks(disks: &[Disk]) -> Vec<&Disk> { + disks.iter().collect() + } + + /// Calculates network usage rates + fn calculate_network_stats(&mut self, sys: &sysinfo::System) -> (u64, u64) { + let current_rx: u64 = sys + .networks() + .iter() + .map(|(_, data)| data.total_received()) + .sum(); + let current_tx: u64 = sys + .networks() + .iter() + .map(|(_, data)| data.total_transmitted()) + .sum(); + + let elapsed = self.last_network_update.0.elapsed().as_secs_f64(); + let rx_rate = ((current_rx - self.last_network_update.1) as f64 / elapsed) as u64; + let tx_rate = ((current_tx - self.last_network_update.2) as f64 / elapsed) as u64; + + self.last_network_update = (Instant::now(), current_rx, current_tx); + (rx_rate, tx_rate) + } + + /// Calculates disk usage statistics + fn calculate_disk_stats(&self, sys: &sysinfo::System) -> (u64, u64, u64) { + let disks = Self::filter_disks(sys.disks()); + let total: u64 = disks.iter().map(|disk| disk.total_space()).sum(); + let used: u64 = disks + .iter() + .map(|disk| disk.total_space() - disk.available_space()) + .sum(); + let free: u64 = disks.iter().map(|disk| disk.available_space()).sum(); + (total, used, free) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sysinfo::System; + + /// Tests creation of system monitor + #[test] + fn test_system_monitor_creation() { + let sys = System::new(); + let monitor = SystemMonitor::new(&sys); + assert!(monitor.last_network_update.1 >= 0); + assert!(monitor.last_network_update.2 >= 0); + } + + /// Tests system statistics collection + #[test] + fn test_stats_collection() { + let mut sys = System::new(); + let mut monitor = SystemMonitor::new(&sys); + sys.refresh_all(); + + let stats = monitor.collect_stats(&sys); + assert!(!stats.cpu_usage.is_empty()); + assert!(stats.memory_total > 0); + } +} diff --git a/src-tauri/src/monitoring/types.rs b/src-tauri/src/monitoring/types.rs new file mode 100644 index 0000000..bf85c68 --- /dev/null +++ b/src-tauri/src/monitoring/types.rs @@ -0,0 +1,119 @@ +use serde::Serialize; +use std::fmt::Debug; +use sysinfo::{DiskUsage, ProcessStatus}; + +/// Internal representation of process data collected from the system +/// This struct is used internally and not exposed directly to the frontend +#[derive(Clone, Debug)] +pub(crate) struct ProcessData { + /// Process ID + pub pid: u32, + /// Name of the process + pub name: String, + /// Complete command line arguments + pub cmd: Vec, + /// User ID that owns the process + pub user_id: Option, + /// CPU usage as percentage (0-100) + pub cpu_usage: f32, + /// Physical memory usage in bytes + pub memory: u64, + /// Current process status + pub status: ProcessStatus, + /// Parent process ID + pub ppid: Option, + /// Environment variables + pub environ: Vec, + /// Root directory of the process + pub root: String, + /// Virtual memory usage in bytes + pub virtual_memory: u64, + /// Process start time (Unix timestamp) + pub start_time: u64, + /// Process running time in seconds + pub run_time: u64, + /// Disk I/O statistics + pub disk_usage: DiskUsage, + /// Session ID of the process + pub session_id: Option, +} + +/// Static information about a process that doesn't change frequently +/// Used for caching purposes to avoid frequent updates of stable data +#[derive(Clone, Debug)] +pub struct ProcessStaticInfo { + /// Process name + pub name: String, + /// Full command string + pub command: String, + /// Username of the process owner + pub user: String, +} + +/// Process information exposed to the frontend via Tauri +/// Contains formatted and filtered process data for UI consumption +#[derive(Serialize, Debug)] +pub struct ProcessInfo { + /// Process ID + pub pid: u32, + /// Parent process ID + pub ppid: u32, + /// Process name + pub name: String, + /// CPU usage as percentage (0-100) + pub cpu_usage: f32, + /// Physical memory usage in bytes + pub memory_usage: u64, + /// Process status as string + pub status: String, + /// Username of the process owner + pub user: String, + /// Full command string + pub command: String, + /// Number of threads (if available) + pub threads: Option, + /// Environment variables + pub environ: Vec, + /// Root directory of the process + pub root: String, + /// Virtual memory usage in bytes + pub virtual_memory: u64, + /// Process start time (Unix timestamp) + pub start_time: u64, + /// Process running time in seconds + pub run_time: u64, + /// Disk I/O statistics (read bytes, written bytes) + pub disk_usage: (u64, u64), + /// Session ID of the process + pub session_id: Option, +} + +/// System-wide statistics exposed to the frontend +/// Provides overall system resource usage and performance metrics +#[derive(Serialize, Debug)] +pub struct SystemStats { + /// CPU usage per core as percentage (0-100) + pub cpu_usage: Vec, + /// Total physical memory in bytes + pub memory_total: u64, + /// Used physical memory in bytes + pub memory_used: u64, + /// Free physical memory in bytes + pub memory_free: u64, + /// Cached memory in bytes + pub memory_cached: u64, + /// System uptime in seconds + pub uptime: u64, + /// Load averages for 1, 5, and 15 minutes + pub load_avg: [f64; 3], + /// Total bytes received over network + pub network_rx_bytes: u64, + /// Total bytes transmitted over network + pub network_tx_bytes: u64, + /// Total disk space in bytes + pub disk_total_bytes: u64, + /// Used disk space in bytes + pub disk_used_bytes: u64, + /// Free disk space in bytes + pub disk_free_bytes: u64, +} diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index 0dcb9fe..b049cc1 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,35 +1,41 @@ -use crate::types::ProcessStaticInfo; -use std::collections::HashMap; -use std::sync::Mutex; -use std::time::Instant; -use sysinfo::{NetworkExt, NetworksExt, System, SystemExt}; +//! Application state management +//! +//! This module handles the global application state, including system monitoring +//! and process tracking capabilities. +use crate::monitoring::{ProcessMonitor, SystemMonitor}; +use std::sync::Mutex; +use sysinfo::{System, SystemExt}; + +/// Global application state +/// +/// Maintains thread-safe access to system information and monitoring components +#[derive(Debug)] pub struct AppState { + /// System information handler pub sys: Mutex, - pub process_cache: Mutex>, - pub last_network_update: Mutex<(Instant, u64, u64)>, + /// Process monitoring component + pub process_monitor: Mutex, + /// System statistics monitoring component + pub system_monitor: Mutex, } impl AppState { + /// Creates a new instance of the application state + /// + /// Initializes system monitoring and process tracking components + /// + /// # Returns + /// + /// A new `AppState` instance with initialized monitors pub fn new() -> Self { let mut sys = System::new(); sys.refresh_all(); - let initial_rx = sys - .networks() - .iter() - .map(|(_, data)| data.total_received()) - .sum(); - let initial_tx = sys - .networks() - .iter() - .map(|(_, data)| data.total_transmitted()) - .sum(); - Self { + process_monitor: Mutex::new(ProcessMonitor::new()), + system_monitor: Mutex::new(SystemMonitor::new(&sys)), sys: Mutex::new(sys), - process_cache: Mutex::new(HashMap::new()), - last_network_update: Mutex::new((Instant::now(), initial_rx, initial_tx)), } } } diff --git a/src-tauri/src/system.rs b/src-tauri/src/system.rs deleted file mode 100644 index f4b52bd..0000000 --- a/src-tauri/src/system.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::state::AppState; -use crate::types::SystemStats; -use std::path::Path; -use std::time::Instant; -use sysinfo::{CpuExt, Disk, DiskExt, NetworkExt, NetworksExt, SystemExt}; - -#[cfg(not(target_os = "windows"))] -pub fn filter_disks(disks: &[Disk]) -> Vec<&sysinfo::Disk> { - disks - .iter() - .filter(|disk| { - // Filter for physical disks - typically those mounted at "/" - disk.mount_point() == Path::new("/") - }) - .collect() -} - -#[cfg(target_os = "windows")] -pub fn filter_disks(disks: &[Disk]) -> Vec<&sysinfo::Disk> { - disks.iter().collect() -} - -fn calculate_network_stats( - sys: &sysinfo::System, - last_update: &mut (Instant, u64, u64), - elapsed: f64, -) -> (u64, u64) { - let current_rx: u64 = sys - .networks() - .iter() - .map(|(_, data)| data.total_received()) - .sum(); - let current_tx: u64 = sys - .networks() - .iter() - .map(|(_, data)| data.total_transmitted()) - .sum(); - - let rx_rate = ((current_rx - last_update.1) as f64 / elapsed) as u64; - let tx_rate = ((current_tx - last_update.2) as f64 / elapsed) as u64; - - last_update.0 = Instant::now(); - last_update.1 = current_rx; - last_update.2 = current_tx; - - (rx_rate, tx_rate) -} - -fn calculate_disk_stats(sys: &sysinfo::System) -> (u64, u64, u64) { - let disks = filter_disks(sys.disks()); - let total: u64 = disks.iter().map(|disk| disk.total_space()).sum(); - let used: u64 = disks - .iter() - .map(|disk| disk.total_space() - disk.available_space()) - .sum(); - let free: u64 = disks.iter().map(|disk| disk.available_space()).sum(); - (total, used, free) -} - -pub fn collect_system_stats( - sys: &mut sysinfo::System, - state: &AppState, -) -> Result { - let mut last_update = state - .last_network_update - .lock() - .map_err(|e| format!("Failed to lock network state: {}", e))?; - - let elapsed = last_update.0.elapsed().as_secs_f64(); - - let (network_rx, network_tx) = calculate_network_stats(sys, &mut last_update, elapsed); - let (disk_total, disk_used, disk_free) = calculate_disk_stats(sys); - - Ok(SystemStats { - cpu_usage: sys.cpus().iter().map(|cpu| cpu.cpu_usage()).collect(), - memory_total: sys.total_memory(), - memory_used: sys.used_memory(), - memory_free: sys.total_memory() - sys.used_memory(), - memory_cached: sys.total_memory() - - (sys.used_memory() + (sys.total_memory() - sys.used_memory())), - uptime: sys.uptime(), - load_avg: [ - sys.load_average().one, - sys.load_average().five, - sys.load_average().fifteen, - ], - network_rx_bytes: network_rx, - network_tx_bytes: network_tx, - disk_total_bytes: disk_total, - disk_used_bytes: disk_used, - disk_free_bytes: disk_free, - }) -} diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs deleted file mode 100644 index d997b16..0000000 --- a/src-tauri/src/types.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::Serialize; - -#[derive(Clone)] -pub struct ProcessStaticInfo { - pub name: String, - pub command: String, - pub user: String, -} - -#[derive(Serialize)] -pub struct ProcessInfo { - pub pid: u32, - pub ppid: u32, - pub name: String, - pub cpu_usage: f32, - pub memory_usage: u64, - pub status: String, - pub user: String, - pub command: String, - pub threads: Option, - pub environ: Vec, - pub root: String, - pub virtual_memory: u64, - pub start_time: u64, - pub run_time: u64, - pub disk_usage: (u64, u64), - pub session_id: Option, -} - -#[derive(Serialize)] -pub struct SystemStats { - pub cpu_usage: Vec, - pub memory_total: u64, - pub memory_used: u64, - pub memory_free: u64, - pub memory_cached: u64, - pub uptime: u64, - pub load_avg: [f64; 3], - pub network_rx_bytes: u64, - pub network_tx_bytes: u64, - pub disk_total_bytes: u64, - pub disk_used_bytes: u64, - pub disk_free_bytes: u64, -} diff --git a/src-tauri/src/ui/mod.rs b/src-tauri/src/ui/mod.rs new file mode 100644 index 0000000..e37bfc1 --- /dev/null +++ b/src-tauri/src/ui/mod.rs @@ -0,0 +1,7 @@ +//! User interface functionality +//! +//! This module handles UI-specific functionality, including window effects +//! and platform-specific visual customizations. + +mod window; +pub use window::setup_window_effects; diff --git a/src-tauri/src/ui/window.rs b/src-tauri/src/ui/window.rs new file mode 100644 index 0000000..37f0c8b --- /dev/null +++ b/src-tauri/src/ui/window.rs @@ -0,0 +1,35 @@ +//! Window effects and customization +//! +//! Provides platform-specific window effects like transparency and vibrancy. + +use tauri::WebviewWindow; + +#[cfg(target_os = "windows")] +use window_vibrancy::apply_acrylic; +#[cfg(target_os = "macos")] +use window_vibrancy::{apply_vibrancy, NSVisualEffectMaterial, NSVisualEffectState}; + +/// Applies Windows-specific window effects +#[cfg(target_os = "windows")] +pub fn setup_window_effects(window: &WebviewWindow) -> Result<(), Box> { + apply_acrylic(window, Some((0, 0, 25, 125)))?; + Ok(()) +} + +/// Applies macOS-specific window effects +#[cfg(target_os = "macos")] +pub fn setup_window_effects(window: &WebviewWindow) -> Result<(), Box> { + apply_vibrancy( + window, + NSVisualEffectMaterial::HudWindow, + Some(NSVisualEffectState::Active), + None, + )?; + Ok(()) +} + +/// No-op for platforms without specific window effects +#[cfg(not(any(target_os = "windows", target_os = "macos")))] +pub fn setup_window_effects(_window: &WebviewWindow) -> Result<(), Box> { + Ok(()) +} diff --git a/src-tauri/src/window.rs b/src-tauri/src/window.rs deleted file mode 100644 index 9ec6b27..0000000 --- a/src-tauri/src/window.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[cfg(target_os = "windows")] -use window_vibrancy::apply_acrylic; -#[cfg(target_os = "macos")] -use window_vibrancy::{apply_vibrancy, NSVisualEffectMaterial, NSVisualEffectState}; - -#[cfg(target_os = "windows")] -pub fn setup_window_effects( - window: &tauri::WebviewWindow, -) -> Result<(), Box> { - apply_acrylic(window, Some((0, 0, 25, 125)))?; - Ok(()) -} - -#[cfg(target_os = "macos")] -pub fn setup_window_effects( - window: &tauri::WebviewWindow, -) -> Result<(), Box> { - apply_vibrancy( - window, - NSVisualEffectMaterial::HudWindow, - Some(NSVisualEffectState::Active), - None, - )?; - Ok(()) -} - -#[cfg(not(any(target_os = "windows", target_os = "macos")))] -pub fn setup_window_effects( - _window: &tauri::WebviewWindow, -) -> Result<(), Box> { - Ok(()) -}