update list command

This commit is contained in:
高桁一 2025-03-11 15:29:08 +08:00
parent 4a00d93759
commit 2182d78a63
2 changed files with 140 additions and 118 deletions

View File

@ -9,7 +9,7 @@ license = "MIT"
[dependencies] [dependencies]
clap = { version = "4.5", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
sysinfo = "0.33" sysinfo = "0.33"
tabled = "0.17" tabled = "0.18"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
dirs = "6.0.0" dirs = "6.0.0"
serde_json = "1.0" serde_json = "1.0"

View File

@ -1,7 +1,12 @@
use crate::config::dump::DumpConfig; use crate::config::dump::DumpConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sysinfo::System; use sysinfo::{Pid, System};
use tabled::{Table, Tabled}; 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)] #[derive(Serialize, Deserialize)]
pub struct PmrProcess { pub struct PmrProcess {
@ -30,40 +35,54 @@ struct ProcessInfo {
user: String, user: String,
} }
// 将秒数转换为可读的时间格式
fn time_to_readable(seconds: u64) -> String { fn time_to_readable(seconds: u64) -> String {
if seconds == 0 { if seconds == 0 {
return "0s".to_string(); return "0s".to_string();
} }
let days = seconds / (24 * 3600); let (days, hours, minutes, secs) = (
let hours = (seconds % (24 * 3600)) / 3600; seconds / 86400,
let minutes = (seconds % 3600) / 60; (seconds % 86400) / 3600,
let secs = seconds % 60; (seconds % 3600) / 60,
seconds % 60,
);
let mut result = String::new(); let parts = vec![
if days > 0 { if days > 0 {
result.push_str(&format!("{}d ", days)); format!("{}d", days)
} } else {
String::new()
},
if hours > 0 { if hours > 0 {
result.push_str(&format!("{}h ", hours)); format!("{}h", hours)
} } else {
String::new()
},
if minutes > 0 { if minutes > 0 {
result.push_str(&format!("{}m ", minutes)); format!("{}m", minutes)
} } else {
if secs > 0 && days == 0 && hours == 0 { String::new()
// 只在没有天和小时的时候显示秒 },
result.push_str(&format!("{}s", secs)); 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::<Vec<_>>()
.join(" ")
} }
pub fn read_pmr_processes() -> Vec<PmrProcess> { pub fn read_pmr_processes() -> Vec<PmrProcess> {
let dump_config = DumpConfig::get_instance(); let dump_config = DumpConfig::get_instance();
match dump_config.list_processes() { dump_config
Ok(processes) => processes .list_processes()
.into_iter() .map(|v| {
v.into_iter()
.map(|p| PmrProcess { .map(|p| PmrProcess {
pmr_id: p.pmr_id, pmr_id: p.pmr_id,
pid: p.pid, pid: p.pid,
@ -74,97 +93,100 @@ pub fn read_pmr_processes() -> Vec<PmrProcess> {
status: p.status, status: p.status,
restarts: p.restarts, restarts: p.restarts,
}) })
.collect(), .collect()
Err(e) => { })
.unwrap_or_else(|e| {
eprintln!("Failed to read processes: {}", e); eprintln!("Failed to read processes: {}", e);
Vec::new() Vec::new()
} })
}
} }
pub fn list_processes(system: bool) { pub fn list_processes(system: bool) {
let sys = System::new_all(); let sys = System::new_all();
if system { let processes: Vec<ProcessInfo> = if system {
let processes: Vec<ProcessInfo> = sys sys.processes()
.processes()
.iter() .iter()
.map(|(&pid, process)| ProcessInfo { .map(|(pid, process)| create_process_info(*pid, process, &sys))
id: "0".to_string(), .collect()
} else {
read_pmr_processes()
.into_iter()
.map(|p| create_pmr_process_info(&p, &sys))
.collect()
};
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(), name: process.name().to_str().unwrap_or("unknown").to_string(),
namespace: "default".to_string(), namespace: DEFAULT_NAMESPACE.to_string(),
version: "N/A".to_string(), version: DEFAULT_VERSION.to_string(),
pid: pid.to_string(), pid: pid.as_u32().to_string(),
uptime: time_to_readable(process.run_time()), uptime: time_to_readable(process.run_time()),
restarts: "0".to_string(), restarts: "0".to_string(),
status: process.status().to_string(), status,
cpu: format!("{:.1}%", process.cpu_usage()), cpu,
mem: format!("{:.1} MB", process.memory() as f64 / 1024.0 / 1024.0), mem,
user: "N/A".to_string(), user: DEFAULT_USER.to_string(),
}) }
.collect(); }
let table = Table::new(processes).to_string(); fn create_pmr_process_info(p: &PmrProcess, sys: &System) -> ProcessInfo {
println!("{}", table); 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 { } else {
let pmr_processes = read_pmr_processes(); ("stopped".to_string(), 0, None)
let processes: Vec<ProcessInfo> = pmr_processes };
.iter()
.map(|p| { let (cpu, mem) = sys_proc
let status = if p.pid > 0 { .map(|proc| {
// 检查进程是否真的在运行 (
if let Some(sys_proc) = sys.process(sysinfo::Pid::from(p.pid as usize)) { format!("{:.1}%", proc.cpu_usage()),
let run_time = sys_proc.run_time(); format!("{:.1} MB", proc.memory() as f64 / 1024.0 / 1024.0),
)
})
.unwrap_or_else(|| ("0%".to_string(), "0 MB".to_string()));
ProcessInfo { ProcessInfo {
id: p.pmr_id.to_string(), id: p.pmr_id.to_string(),
name: p.name.clone(), name: p.name.clone(),
namespace: p.namespace.clone(), namespace: p.namespace.clone(),
version: "N/A".to_string(), version: DEFAULT_VERSION.to_string(),
pid: p.pid.to_string(), pid: p.pid.to_string(),
uptime: time_to_readable(run_time), uptime: time_to_readable(run_time),
restarts: p.restarts.to_string(), restarts: p.restarts.to_string(),
status: "running".to_string(), status,
cpu: format!("{:.1}%", sys_proc.cpu_usage()), cpu,
mem: format!("{:.1} MB", sys_proc.memory() as f64 / 1024.0 / 1024.0), mem,
user: "N/A".to_string(), user: DEFAULT_USER.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();
let table = Table::new(processes).to_string();
println!("{}", table);
} }
} }