diff --git a/Cargo.toml b/Cargo.toml index d8c7807..a1f6fe3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" [dependencies] clap = { version = "4.5", features = ["derive"] } sysinfo = "0.33" -tabled = "0.17" +tabled = "0.18" serde = { version = "1.0", features = ["derive"] } dirs = "6.0.0" serde_json = "1.0" diff --git a/src/commands/list.rs b/src/commands/list.rs index 705c63b..c7a486e 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -1,7 +1,12 @@ use crate::config::dump::DumpConfig; use serde::{Deserialize, Serialize}; -use sysinfo::System; -use tabled::{Table, Tabled}; +use sysinfo::{Pid, System}; +use tabled::{settings::Style, Table, Tabled}; + +const DEFAULT_ID: &str = "0"; +const DEFAULT_NAMESPACE: &str = "default"; +const DEFAULT_VERSION: &str = "N/A"; +const DEFAULT_USER: &str = "N/A"; #[derive(Serialize, Deserialize)] pub struct PmrProcess { @@ -30,141 +35,158 @@ struct ProcessInfo { user: String, } -// 将秒数转换为可读的时间格式 fn time_to_readable(seconds: u64) -> String { if seconds == 0 { return "0s".to_string(); } - let days = seconds / (24 * 3600); - let hours = (seconds % (24 * 3600)) / 3600; - let minutes = (seconds % 3600) / 60; - let secs = seconds % 60; + let (days, hours, minutes, secs) = ( + seconds / 86400, + (seconds % 86400) / 3600, + (seconds % 3600) / 60, + seconds % 60, + ); - let mut result = String::new(); - if days > 0 { - result.push_str(&format!("{}d ", days)); - } - if hours > 0 { - result.push_str(&format!("{}h ", hours)); - } - if minutes > 0 { - result.push_str(&format!("{}m ", minutes)); - } - if secs > 0 && days == 0 && hours == 0 { - // 只在没有天和小时的时候显示秒 - result.push_str(&format!("{}s", secs)); - } + let parts = vec![ + if days > 0 { + format!("{}d", days) + } else { + String::new() + }, + if hours > 0 { + format!("{}h", hours) + } else { + String::new() + }, + if minutes > 0 { + format!("{}m", minutes) + } else { + String::new() + }, + if days == 0 && hours == 0 && secs > 0 { + format!("{}s", secs) + } else { + String::new() + }, + ]; - result.trim().to_string() + parts + .into_iter() + .filter(|s| !s.is_empty()) + .collect::>() + .join(" ") } pub fn read_pmr_processes() -> Vec { let dump_config = DumpConfig::get_instance(); - match dump_config.list_processes() { - Ok(processes) => processes - .into_iter() - .map(|p| PmrProcess { - pmr_id: p.pmr_id, - pid: p.pid, - name: p.name, - namespace: p.namespace, - program: p.program, - args: p.args, - status: p.status, - restarts: p.restarts, - }) - .collect(), - Err(e) => { + dump_config + .list_processes() + .map(|v| { + v.into_iter() + .map(|p| PmrProcess { + pmr_id: p.pmr_id, + pid: p.pid, + name: p.name, + namespace: p.namespace, + program: p.program, + args: p.args, + status: p.status, + restarts: p.restarts, + }) + .collect() + }) + .unwrap_or_else(|e| { eprintln!("Failed to read processes: {}", e); Vec::new() - } - } + }) } pub fn list_processes(system: bool) { let sys = System::new_all(); - if system { - let processes: Vec = sys - .processes() + let processes: Vec = if system { + sys.processes() .iter() - .map(|(&pid, process)| ProcessInfo { - id: "0".to_string(), - name: process.name().to_str().unwrap_or("unknown").to_string(), - namespace: "default".to_string(), - version: "N/A".to_string(), - pid: pid.to_string(), - uptime: time_to_readable(process.run_time()), - restarts: "0".to_string(), - status: process.status().to_string(), - cpu: format!("{:.1}%", process.cpu_usage()), - mem: format!("{:.1} MB", process.memory() as f64 / 1024.0 / 1024.0), - user: "N/A".to_string(), - }) - .collect(); - - let table = Table::new(processes).to_string(); - println!("{}", table); + .map(|(pid, process)| create_process_info(*pid, process, &sys)) + .collect() } else { - let pmr_processes = read_pmr_processes(); - let processes: Vec = pmr_processes - .iter() - .map(|p| { - let status = if p.pid > 0 { - // 检查进程是否真的在运行 - if let Some(sys_proc) = sys.process(sysinfo::Pid::from(p.pid as usize)) { - let run_time = sys_proc.run_time(); - ProcessInfo { - id: p.pmr_id.to_string(), - name: p.name.clone(), - namespace: p.namespace.clone(), - version: "N/A".to_string(), - pid: p.pid.to_string(), - uptime: time_to_readable(run_time), - restarts: p.restarts.to_string(), - status: "running".to_string(), - cpu: format!("{:.1}%", sys_proc.cpu_usage()), - mem: format!("{:.1} MB", sys_proc.memory() as f64 / 1024.0 / 1024.0), - user: "N/A".to_string(), - } - } else { - // 进程不存在,但PID > 0,说明进程已经退出 - ProcessInfo { - id: p.pmr_id.to_string(), - name: p.name.clone(), - namespace: p.namespace.clone(), - version: "N/A".to_string(), - pid: p.pid.to_string(), - uptime: "0s".to_string(), - restarts: p.restarts.to_string(), - status: "stopped".to_string(), - cpu: "0%".to_string(), - mem: "0 MB".to_string(), - user: "N/A".to_string(), - } - } - } else { - // 原本就是停止状态 - ProcessInfo { - id: p.pmr_id.to_string(), - name: p.name.clone(), - namespace: p.namespace.clone(), - version: "N/A".to_string(), - pid: "0".to_string(), - uptime: "0s".to_string(), - restarts: p.restarts.to_string(), - status: "stopped".to_string(), - cpu: "0%".to_string(), - mem: "0 MB".to_string(), - user: "N/A".to_string(), - } - }; - status - }) - .collect(); + read_pmr_processes() + .into_iter() + .map(|p| create_pmr_process_info(&p, &sys)) + .collect() + }; - let table = Table::new(processes).to_string(); - println!("{}", table); + let mut table = Table::new(processes); + if system { + table.with(Style::modern()); + } else { + table.with(Style::rounded()); + } + println!("{}", table); +} + +fn create_process_info(pid: Pid, process: &sysinfo::Process, sys: &System) -> ProcessInfo { + let (status, sys_proc) = if process.name().to_str() == Some("system") { + (process.status().to_string(), None) + } else { + (String::new(), sys.process(pid)) + }; + + let (cpu, mem) = if let Some(proc) = sys_proc.or(Some(process)) { + ( + format!("{:.1}%", proc.cpu_usage()), + format!("{:.1} MB", proc.memory() as f64 / 1024.0 / 1024.0), + ) + } else { + ("0%".to_string(), "0 MB".to_string()) + }; + + ProcessInfo { + id: DEFAULT_ID.to_string(), + name: process.name().to_str().unwrap_or("unknown").to_string(), + namespace: DEFAULT_NAMESPACE.to_string(), + version: DEFAULT_VERSION.to_string(), + pid: pid.as_u32().to_string(), + uptime: time_to_readable(process.run_time()), + restarts: "0".to_string(), + status, + cpu, + mem, + user: DEFAULT_USER.to_string(), + } +} + +fn create_pmr_process_info(p: &PmrProcess, sys: &System) -> ProcessInfo { + let (status, run_time, sys_proc) = if p.pid > 0 { + let pid = Pid::from(p.pid as usize); + match sys.process(pid) { + Some(proc) => ("running".to_string(), proc.run_time(), Some(proc)), + None => ("stopped".to_string(), 0, None), + } + } else { + ("stopped".to_string(), 0, None) + }; + + let (cpu, mem) = sys_proc + .map(|proc| { + ( + format!("{:.1}%", proc.cpu_usage()), + format!("{:.1} MB", proc.memory() as f64 / 1024.0 / 1024.0), + ) + }) + .unwrap_or_else(|| ("0%".to_string(), "0 MB".to_string())); + + ProcessInfo { + id: p.pmr_id.to_string(), + name: p.name.clone(), + namespace: p.namespace.clone(), + version: DEFAULT_VERSION.to_string(), + pid: p.pid.to_string(), + uptime: time_to_readable(run_time), + restarts: p.restarts.to_string(), + status, + cpu, + mem, + user: DEFAULT_USER.to_string(), } }