feat: added the ability to send commands

This commit is contained in:
Andrew Rioux
2023-09-05 19:05:26 -04:00
parent 47b2191335
commit 52538ac7d7
5 changed files with 188 additions and 23 deletions

View File

@@ -1,4 +1,6 @@
use std::{
io::{Read, Write},
process::{Command, Stdio},
sync::{
atomic::AtomicU64,
mpsc::{channel, Sender},
@@ -6,6 +8,8 @@ use std::{
thread::Scope,
};
use sparse_05_common::messages::Response;
use super::ConnectionInformation;
const CURRENT_COMMAND_ID: AtomicU64 = AtomicU64::new(0);
@@ -22,8 +26,78 @@ pub(super) fn spawn_command<'a, 'b: 'a>(
) -> anyhow::Result<CommandHandler> {
let (data_sender, data_receiver) = channel();
Ok(CommandHandler {
id: CURRENT_COMMAND_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
data_sender,
})
let id = CURRENT_COMMAND_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
dbg!(&command);
let mut command = Command::new("sh")
.arg("-c")
.arg(&command)
.env("TERM", "screen")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let resp = Response::AckRunCommand(id);
conninfo.send(conninfo.encrypt_and_sign_resp(resp)?)?;
s.spawn(move || -> anyhow::Result<()> {
if let Some(mut stdout) = command.stdout.take() {
s.spawn(move || {
let mut stdout_buffer = [0u8; 1024];
loop {
let Ok(count) = stdout.read(&mut stdout_buffer) else {
continue;
};
let resp = Response::SendStdout(stdout_buffer[..count].to_vec(), id);
let Ok(packet) = conninfo.encrypt_and_sign_resp(resp) else {
continue;
};
_ = conninfo.send(packet);
}
});
}
if let Some(mut stderr) = command.stderr.take() {
s.spawn(move || {
let mut stderr_buffer = [0u8; 1024];
loop {
let Ok(count) = stderr.read(&mut stderr_buffer) else {
continue;
};
let resp = Response::SendStderr(stderr_buffer[..count].to_vec(), id);
let Ok(packet) = conninfo.encrypt_and_sign_resp(resp) else {
continue;
};
_ = conninfo.send(packet);
}
});
}
if let Some(mut stdin) = command.stdin.take() {
s.spawn(move || loop {
let Ok(input): Result<Vec<u8>, _> = data_receiver.recv() else {
continue;
};
_ = stdin.write(&input);
});
}
let code = match command.wait() {
Ok(status) => status.code().unwrap_or(-1),
Err(_) => -1,
};
let resp = Response::CommandDone(id, code);
let resp = conninfo.encrypt_and_sign_resp(resp)?;
conninfo.send(resp)?;
Ok(())
});
Ok(CommandHandler { id, data_sender })
}