use std::io;
use std::process::{Command, Stdio};
use std::io::{BufRead, BufReader};
use std::sync::{Arc, Mutex};
use futures_core::stream::Stream;
use serde::{Serialize, Deserialize};
#[derive(Clone, Serialize, Deserialize)]
pub struct Payload {
pub success: bool,
pub output: String,
}
#[allow(dead_code)]
pub fn run(command: &str) -> Result<String, String> {
let output = Command::new("sh")
.arg("-c")
.arg(&command)
.output()
.map_err(|err| format!("Failed to execute the command: {}", err))?;
if output.status.success() {
let stdout = String::from_utf8(output.stdout).map_err(|err| format!("Failed to convert stdout to UTF-8: {}", err))?;
Ok(stdout)
} else {
let stderr = String::from_utf8(output.stderr).map_err(|err| format!("Failed to convert stderr to UTF-8: {}", err))?;
Err(stderr)
}
}
#[cfg(unix)]
fn run_command(command: &str) -> io::Result<std::process::Child> {
Command::new("sh")
.arg("-c")
.arg(&command)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
#[cfg(windows)]
fn run_command(command: &str) -> io::Result<std::process::Child> {
Command::new("cmd")
.args(&["/C", &command])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
pub fn run_stream<'a>(command: &'a str) -> impl Stream<Item=Payload> + 'a {
async_stream::stream! {
let cmd = run_command(command);
match cmd {
Ok(cmd) => {
let cmd = Arc::new(Mutex::new(cmd));
let stdout = cmd.as_ref().lock().unwrap().stdout.take(); match stdout {
Some(stdout) => {
let reader = BufReader::new(stdout);
for line in reader.lines() {
let line = line.unwrap();
yield Payload{ success: false, output: line };
}
let command_status = cmd.as_ref().lock().unwrap().wait();
match command_status {
Ok(_) => {
yield Payload{ success: true, output: "".to_string() };
}
Err(e) => {
yield Payload{ success: false, output: e.to_string() };
}
}
}
None => {
yield Payload{ success: false, output: "".to_string() };
}
}
}
Err(e) => {
yield Payload{ success: false, output: e.to_string() };
}
}
}
}