1use crate::core::port::{parse_port, PortInfo};
9use crate::core::Process;
10use crate::error::{ProcError, Result};
11
12#[derive(Debug, Clone)]
14pub enum TargetType {
15 Port(u16),
17 Pid(u32),
19 Name(String),
21}
22
23pub fn parse_target(target: &str) -> TargetType {
25 let target = target.trim();
26
27 if target.starts_with(':') {
29 if let Ok(port) = parse_port(target) {
30 return TargetType::Port(port);
31 }
32 }
33
34 if let Ok(pid) = target.parse::<u32>() {
36 return TargetType::Pid(pid);
37 }
38
39 TargetType::Name(target.to_string())
41}
42
43pub fn resolve_target(target: &str) -> Result<Vec<Process>> {
45 match parse_target(target) {
46 TargetType::Port(port) => resolve_port(port),
47 TargetType::Pid(pid) => resolve_pid(pid),
48 TargetType::Name(name) => Process::find_by_name(&name),
49 }
50}
51
52pub fn resolve_target_single(target: &str) -> Result<Process> {
54 let processes = resolve_target(target)?;
55
56 if processes.is_empty() {
57 return Err(ProcError::ProcessNotFound(target.to_string()));
58 }
59
60 if processes.len() > 1 {
61 return Err(ProcError::InvalidInput(format!(
62 "Target '{}' matches {} processes. Be more specific.",
63 target,
64 processes.len()
65 )));
66 }
67
68 Ok(processes.into_iter().next().unwrap())
69}
70
71fn resolve_port(port: u16) -> Result<Vec<Process>> {
73 match PortInfo::find_by_port(port)? {
74 Some(port_info) => match Process::find_by_pid(port_info.pid)? {
75 Some(proc) => Ok(vec![proc]),
76 None => Err(ProcError::ProcessGone(port_info.pid)),
77 },
78 None => Err(ProcError::PortNotFound(port)),
79 }
80}
81
82fn resolve_pid(pid: u32) -> Result<Vec<Process>> {
84 match Process::find_by_pid(pid)? {
85 Some(proc) => Ok(vec![proc]),
86 None => Err(ProcError::ProcessNotFound(pid.to_string())),
87 }
88}
89
90pub fn find_ports_for_pid(pid: u32) -> Result<Vec<PortInfo>> {
92 let all_ports = PortInfo::get_all_listening()?;
93 Ok(all_ports.into_iter().filter(|p| p.pid == pid).collect())
94}