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),
16 Pid(u32),
17 Name(String),
18}
19
20pub fn parse_target(target: &str) -> TargetType {
22 let target = target.trim();
23
24 if target.starts_with(':') {
26 if let Ok(port) = parse_port(target) {
27 return TargetType::Port(port);
28 }
29 }
30
31 if let Ok(pid) = target.parse::<u32>() {
33 return TargetType::Pid(pid);
34 }
35
36 TargetType::Name(target.to_string())
38}
39
40pub fn resolve_target(target: &str) -> Result<Vec<Process>> {
42 match parse_target(target) {
43 TargetType::Port(port) => resolve_port(port),
44 TargetType::Pid(pid) => resolve_pid(pid),
45 TargetType::Name(name) => Process::find_by_name(&name),
46 }
47}
48
49pub fn resolve_target_single(target: &str) -> Result<Process> {
51 let processes = resolve_target(target)?;
52
53 if processes.is_empty() {
54 return Err(ProcError::ProcessNotFound(target.to_string()));
55 }
56
57 if processes.len() > 1 {
58 return Err(ProcError::InvalidInput(format!(
59 "Target '{}' matches {} processes. Be more specific.",
60 target,
61 processes.len()
62 )));
63 }
64
65 Ok(processes.into_iter().next().unwrap())
66}
67
68fn resolve_port(port: u16) -> Result<Vec<Process>> {
70 match PortInfo::find_by_port(port)? {
71 Some(port_info) => match Process::find_by_pid(port_info.pid)? {
72 Some(proc) => Ok(vec![proc]),
73 None => Err(ProcError::ProcessGone(port_info.pid)),
74 },
75 None => Err(ProcError::PortNotFound(port)),
76 }
77}
78
79fn resolve_pid(pid: u32) -> Result<Vec<Process>> {
81 match Process::find_by_pid(pid)? {
82 Some(proc) => Ok(vec![proc]),
83 None => Err(ProcError::ProcessNotFound(pid.to_string())),
84 }
85}
86
87pub fn find_ports_for_pid(pid: u32) -> Result<Vec<PortInfo>> {
89 let all_ports = PortInfo::get_all_listening()?;
90 Ok(all_ports.into_iter().filter(|p| p.pid == pid).collect())
91}