killport/killport.rs
1use crate::docker::DockerContainer;
2#[cfg(target_os = "linux")]
3use crate::linux::find_target_processes;
4#[cfg(target_os = "macos")]
5use crate::macos::find_target_processes;
6#[cfg(target_os = "windows")]
7use crate::windows::find_target_processes;
8use crate::{cli::Mode, signal::KillportSignal};
9use std::{fmt::Display, io::Error};
10
11/// Interface for killable targets such as native process and docker container.
12pub trait Killable {
13 fn kill(&self, signal: KillportSignal) -> Result<bool, Error>;
14
15 fn get_type(&self) -> KillableType;
16
17 fn get_name(&self) -> String;
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum KillableType {
22 Process,
23 Container,
24}
25
26impl Display for KillableType {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.write_str(match self {
29 KillableType::Process => "process",
30 KillableType::Container => "container",
31 })
32 }
33}
34
35impl Killable for DockerContainer {
36 /// Entry point to kill the docker containers.
37 ///
38 /// # Arguments
39 ///
40 /// * `signal` - A enum value representing the signal type.
41 fn kill(&self, signal: KillportSignal) -> Result<bool, Error> {
42 Self::kill_container(&self.name, signal)?;
43
44 Ok(true)
45 }
46
47 /// Returns the type of the killable target.
48 ///
49 /// This method is used to identify the type of the target (either a native process or a Docker container)
50 /// that is being handled. This information can be useful for logging, error handling, or other needs
51 /// where type of the target is relevant.
52 ///
53 /// # Returns
54 ///
55 /// * `String` - A string that describes the type of the killable target. For a `UnixProcess` it will return "process",
56 /// and for a `DockerContainer` it will return "container".
57 fn get_type(&self) -> KillableType {
58 KillableType::Container
59 }
60
61 fn get_name(&self) -> String {
62 self.name.to_string()
63 }
64}
65
66pub trait KillportOperations {
67 /// Finds the killables (native processes and docker containers) associated with the specified `port`.
68 fn find_target_killables(&self, port: u16, mode: Mode)
69 -> Result<Vec<Box<dyn Killable>>, Error>;
70
71 /// Manages the action of killing or simulating the killing of services by port.
72 fn kill_service_by_port(
73 &self,
74 port: u16,
75 signal: KillportSignal,
76 mode: Mode,
77 dry_run: bool,
78 ) -> Result<Vec<(KillableType, String)>, Error>;
79}
80
81pub struct Killport;
82
83impl KillportOperations for Killport {
84 /// Finds the killables (native processes and docker containers) associated with the specified `port`.
85 ///
86 /// Returns a `Vec` of killables.
87 ///
88 /// # Arguments
89 ///
90 /// * `port` - A u16 value representing the port number.
91 fn find_target_killables(
92 &self,
93 port: u16,
94 mode: Mode,
95 ) -> Result<Vec<Box<dyn Killable>>, Error> {
96 let mut target_killables: Vec<Box<dyn Killable>> = vec![];
97 let docker_present = mode != Mode::Process && DockerContainer::is_docker_present()?;
98
99 if mode != Mode::Container {
100 let target_processes = find_target_processes(port)?;
101
102 for process in target_processes {
103 // Check if the process name contains 'docker' and skip if in docker mode
104 if docker_present && process.get_name().to_lowercase().contains("docker") {
105 continue;
106 }
107
108 target_killables.push(Box::new(process));
109 }
110 }
111
112 // Add containers if Docker is present and mode is not set to only process
113 if docker_present && mode != Mode::Process {
114 let target_containers = DockerContainer::find_target_containers(port)?; // Assume this function returns Result<Vec<DockerContainer>, Error>
115
116 for container in target_containers {
117 target_killables.push(Box::new(container));
118 }
119 }
120
121 Ok(target_killables)
122 }
123
124 /// Manages the action of killing or simulating the killing of services by port.
125 /// This function can either actually kill processes or containers, or simulate the action based on the `dry_run` flag.
126 ///
127 /// # Arguments
128 /// * `port` - The port number to check for killable entities.
129 /// * `signal` - The signal to send if not simulating.
130 /// * `mode` - The mode of operation, determining if processes, containers, or both should be targeted.
131 /// * `dry_run` - If true, simulates the actions without actually killing any entities.
132 ///
133 /// # Returns
134 /// * `Result<Vec<(String, String)>, Error>` - A list of killable entities or an error.
135 fn kill_service_by_port(
136 &self,
137 port: u16,
138 signal: KillportSignal,
139 mode: Mode,
140 dry_run: bool,
141 ) -> Result<Vec<(KillableType, String)>, Error> {
142 let mut results = Vec::new();
143 let target_killables = self.find_target_killables(port, mode)?; // Use the existing function to find targets
144
145 for killable in target_killables {
146 if dry_run {
147 // In dry-run mode, collect information about the entity without killing
148 results.push((killable.get_type(), killable.get_name()));
149 } else {
150 // In actual mode, attempt to kill the entity and collect its information if successful
151 if killable.kill(signal.clone())? {
152 results.push((killable.get_type(), killable.get_name()));
153 }
154 }
155 }
156
157 Ok(results)
158 }
159}