projectable/external_event/
run_cmd.rs

1use std::{
2    sync::{
3        atomic::{AtomicBool, Ordering},
4        Arc,
5    },
6    thread,
7    time::Duration,
8};
9
10use anyhow::Result;
11use crossbeam_channel::Sender;
12use duct::Expression;
13
14use super::ExternalEvent;
15
16pub fn run_cmd(
17    cmd: Expression,
18    sender: Sender<ExternalEvent>,
19    refresh_time: Duration,
20    stop: Arc<AtomicBool>,
21) -> Result<()> {
22    let handle = cmd.start()?;
23    thread::spawn(move || loop {
24        if stop.load(Ordering::Acquire) {
25            if let Err(err) = handle.kill() {
26                sender
27                    .send(ExternalEvent::Error(err.into()))
28                    .expect("sender should not have deallocated");
29            }
30            return;
31        }
32        match handle.try_wait() {
33            Ok(Some(out)) => {
34                sender
35                    .send(ExternalEvent::CommandOutput(
36                        String::from_utf8_lossy(if out.stdout.is_empty() {
37                            &out.stderr
38                        } else {
39                            &out.stdout
40                        })
41                        .to_string(),
42                    ))
43                    .expect("sender should not have deallocated");
44                return;
45            }
46            Ok(None) => {}
47            Err(err) => {
48                sender
49                    .send(ExternalEvent::Error(err.into()))
50                    .expect("sender should not have deallocated");
51                return;
52            }
53        };
54        thread::sleep(refresh_time);
55    });
56
57    Ok(())
58}