Files
client/src/app/command.rs
T
2026-05-22 08:24:20 +02:00

55 lines
1.4 KiB
Rust

use std::process::Stdio;
use tokio::{
io::{AsyncRead, AsyncReadExt},
process::Command,
};
pub async fn execute(command: &str, max_output_bytes: u64) -> (i32, String, String) {
let mut child = match Command::new("sh")
.arg("-c")
.arg(command)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Ok(child) => child,
Err(error) => return (-1, String::new(), error.to_string()),
};
let Some(stdout) = child.stdout.take() else {
return (-1, String::new(), "stdout pipe unavailable".to_string());
};
let Some(stderr) = child.stderr.take() else {
return (-1, String::new(), "stderr pipe unavailable".to_string());
};
let (stdout_data, stderr_data) = tokio::join!(
read_limited_output(stdout, max_output_bytes),
read_limited_output(stderr, max_output_bytes),
);
child.kill().await.ok();
let exit_code = child
.wait()
.await
.ok()
.and_then(|status| status.code())
.unwrap_or(-1);
(
exit_code,
String::from_utf8_lossy(&stdout_data).into_owned(),
String::from_utf8_lossy(&stderr_data).into_owned(),
)
}
async fn read_limited_output<R>(reader: R, max_output_bytes: u64) -> Vec<u8>
where
R: AsyncRead + Unpin,
{
let mut buffer = Vec::new();
let _ = reader.take(max_output_bytes).read_to_end(&mut buffer).await;
buffer
}