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]
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"

View File

@ -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::<Vec<_>>()
.join(" ")
}
pub fn read_pmr_processes() -> Vec<PmrProcess> {
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<ProcessInfo> = sys
.processes()
let processes: Vec<ProcessInfo> = 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<ProcessInfo> = 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(),
}
}