Files
mesh/agent/src/terminal/recv.rs
Gilles Soulier 1d177e96a6 first
2026-01-05 13:20:54 +01:00

91 lines
2.5 KiB
Rust

// Created by: Claude
// Date: 2026-01-04
// Purpose: Receive terminal output from QUIC stream
// Refs: protocol_events_v_2.md, AGENT.md
use crate::p2p::protocol::TerminalMessage;
use quinn::{RecvStream, SendStream};
use anyhow::Result;
use tracing::info;
use tokio::io::AsyncReadExt;
pub struct TerminalReceiver {
has_control: bool,
}
impl TerminalReceiver {
pub fn new() -> Self {
Self {
has_control: false,
}
}
/// Receive and display terminal output
pub async fn receive_output<F>(&self, mut stream: RecvStream, mut on_output: F) -> Result<()>
where
F: FnMut(String),
{
loop {
let msg = self.receive_message(&mut stream).await?;
match msg {
TerminalMessage::Output { data } => {
on_output(data);
}
_ => {
info!("Received terminal message: {:?}", msg);
}
}
}
}
/// Send input to remote terminal (if has_control)
pub async fn send_input(&self, stream: &mut SendStream, data: String) -> Result<()> {
if !self.has_control {
anyhow::bail!("Cannot send input: no control capability");
}
let msg = TerminalMessage::Input { data };
self.send_message(stream, &msg).await
}
/// Send resize command
pub async fn send_resize(&self, stream: &mut SendStream, cols: u16, rows: u16) -> Result<()> {
let msg = TerminalMessage::Resize { cols, rows };
self.send_message(stream, &msg).await
}
pub fn grant_control(&mut self) {
info!("Terminal control granted");
self.has_control = true;
}
pub fn revoke_control(&mut self) {
info!("Terminal control revoked");
self.has_control = false;
}
async fn receive_message(&self, stream: &mut RecvStream) -> Result<TerminalMessage> {
let mut len_buf = [0u8; 4];
stream.read_exact(&mut len_buf).await?;
let len = u32::from_be_bytes(len_buf) as usize;
let mut buf = vec![0u8; len];
stream.read_exact(&mut buf).await?;
Ok(serde_json::from_slice(&buf)?)
}
async fn send_message(&self, stream: &mut SendStream, msg: &TerminalMessage) -> Result<()> {
use tokio::io::AsyncWriteExt;
let json = serde_json::to_vec(msg)?;
let len = (json.len() as u32).to_be_bytes();
stream.write_all(&len).await?;
stream.write_all(&json).await?;
Ok(())
}
}