use std::time::Duration;
use tokio::sync::{mpsc, watch};
use super::constants::INPUT_POLL_TIMEOUT_MS;
use super::local_escape::{LocalAction, LocalEscapeDetector};
use super::raw_input::RawInputReader;
use crate::pty::PtyMessage;
pub(crate) fn run(
input_tx: mpsc::Sender<PtyMessage>,
cancel_rx: watch::Receiver<bool>,
pending_input: Vec<u8>,
) {
let mut reader = RawInputReader::new();
let mut buffer = [0_u8; 1024];
let mut escape_detector = LocalEscapeDetector::new();
if !pending_input.is_empty() && !forward_input(&input_tx, &mut escape_detector, &pending_input)
{
return;
}
loop {
if *cancel_rx.borrow() {
break;
}
match reader.poll(Duration::from_millis(INPUT_POLL_TIMEOUT_MS)) {
Ok(true) => match reader.read(&mut buffer) {
Ok(0) => {
tracing::debug!("EOF received on stdin");
break;
}
Ok(read) => {
if !forward_input(&input_tx, &mut escape_detector, &buffer[..read]) {
break;
}
}
Err(error) => {
let _ = input_tx.try_send(PtyMessage::Error(format!("Input error: {error}")));
break;
}
},
Ok(false) => continue,
Err(error) => {
let _ = input_tx.try_send(PtyMessage::Error(format!("Poll error: {error}")));
break;
}
}
}
}
fn forward_input(
input_tx: &mpsc::Sender<PtyMessage>,
detector: &mut LocalEscapeDetector,
bytes: &[u8],
) -> bool {
if let Some(action) = detector.process(bytes) {
match action {
LocalAction::Disconnect => {
tracing::debug!("Disconnect escape sequence detected");
let _ = input_tx.try_send(PtyMessage::Terminate);
false
}
LocalAction::Passthrough(data) => {
input_tx.try_send(PtyMessage::LocalInput(data)).is_ok()
}
}
} else {
let data = smallvec::SmallVec::from_slice(bytes);
input_tx.try_send(PtyMessage::LocalInput(data)).is_ok()
}
}