1use std::sync::Arc;
2
3use tokio::task::JoinSet;
4
5use crate::{
6 common::{Exec, Process, ProcessState},
7 error::Result,
8 state::State,
9};
10
11#[derive(Clone, Debug, Default, PartialEq)]
12pub struct StopArgs {
13 pub kill: bool,
14 pub processes: Vec<String>,
15}
16
17pub struct Stop {
18 args: StopArgs,
19 state: Arc<State>,
20}
21
22impl Stop {
23 pub fn new(args: StopArgs, state: Arc<State>) -> Self {
24 Stop { args, state }
25 }
26}
27
28impl Exec<()> for Stop {
29 async fn exec(&self) -> Result<()> {
30 let processes = self.state.filter_processes(&self.args.processes).await?;
31 let mut handles = JoinSet::new();
32 for process in processes {
33 let state = self.state.clone();
34 handles.spawn(run(state, process, self.args.clone()));
35 }
36
37 while let Some(res) = handles.join_next().await {
38 match res {
39 Err(e) => println!("Error while stopping process: {e}"),
40 Ok(ok) => {
41 if let Err(ee) = ok {
42 println!("Error while stopping process inner: {ee}")
43 }
44 }
45 }
46 }
47
48 Ok(())
49 }
50}
51
52async fn run(state: Arc<State>, process: Process, args: StopArgs) -> Result<()> {
53 let process_name = process.name().to_string();
54 if process.state == ProcessState::Stopped {
55 println!("Process is already stopped: {process_name}");
56 return Ok(());
57 }
58 if let Some(pid) = process.pid {
59 println!("Stopping process {process_name} ...");
60 state.scheduler().stop(pid, args.kill).await?;
61 }
62 state
63 .set_state(&process_name, ProcessState::Stopped)
64 .await?;
65 state.set_pid(&process_name, None).await?;
66 println!("Process {process_name} stopped");
67 Ok(())
68}