use buffa::Message as _;
use nix::sys::signal::Signal;
use tokio::io::AsyncRead;
use crate::rpc::{MessageType, read_message};
pub(super) enum Control {
Stdin(Vec<u8>),
Eof,
Resize(arcbox_pty::WinSize),
Signal(Signal),
OutputWindow(u32),
}
pub(super) async fn next<R: AsyncRead + Unpin>(conn: &mut R) -> Option<Control> {
loop {
let (msg_type, _, payload) = match read_message(conn).await {
Ok(frame) => frame,
Err(e) => {
tracing::debug!(error = %format!("{e:#}"), "machine exec host connection ended");
return None;
}
};
match msg_type {
MessageType::MachineExecInput if payload.is_empty() => return Some(Control::Eof),
MessageType::MachineExecInput => return Some(Control::Stdin(payload)),
MessageType::MachineExecResize => {
match arcbox_connect::v1::TerminalSize::decode_from_slice(&payload) {
Ok(size) => {
return Some(Control::Resize(arcbox_pty::WinSize {
cols: u16::try_from(size.width).unwrap_or(u16::MAX),
rows: u16::try_from(size.height).unwrap_or(u16::MAX),
}));
}
Err(e) => tracing::warn!(error = %e, "bad machine exec resize frame"),
}
}
MessageType::MachineExecSignal => {
match arcbox_connect::v1::MachineExecSignal::decode_from_slice(&payload) {
Ok(frame) => match format!("SIG{}", frame.name).parse::<Signal>() {
Ok(signal) => return Some(Control::Signal(signal)),
Err(_) => {
tracing::warn!(name = %frame.name, "unknown signal for machine exec");
}
},
Err(e) => tracing::warn!(error = %e, "bad machine exec signal frame"),
}
}
MessageType::MachineExecOutputWindow => {
match arcbox_connect::v1::MachineExecWindow::decode_from_slice(&payload) {
Ok(frame) => return Some(Control::OutputWindow(frame.bytes)),
Err(e) => {
tracing::warn!(error = %e, "bad machine exec window frame");
return None;
}
}
}
other => tracing::warn!(?other, "unexpected frame during machine exec session"),
}
}
}