use std::convert::Infallible; use bytes::Bytes; use serde::Deserialize; use tokio::io::AsyncWriteExt; use tokio_stream::StreamExt; use tokio_util::codec::{BytesCodec, FramedRead}; use crate::pty::open_shell; use super::Ctx; #[derive(Debug, Deserialize)] pub struct OpenTerminalMessage(Bytes); impl TryFrom for OpenTerminalMessage { type Error = Infallible; fn try_from(value: Bytes) -> Result { Ok(Self(value)) } } #[derive(Debug, Deserialize)] pub struct TerminalInput(Bytes); impl TryFrom for TerminalInput { type Error = Infallible; fn try_from(value: Bytes) -> Result { Ok(Self(value)) } } pub async fn open_terminal( mut ctx: Ctx, ) -> anyhow::Result> { let pty = crate::pty::Pty::open()?; let shell = open_shell(pty.child()?, "/bin/bash")?; let _out_stream = FramedRead::new(pty.try_clone()?, BytesCodec::new()).filter_map(|inner| { inner .map(|bytes| bytes.freeze()) .map_err(|err| { tracing::warn!(%err, "pseudoterminal read error"); }) .ok() }); ctx.terminals.insert(String::from("test"), (pty, shell)); Ok(ctx) } pub async fn terminal_input( terminal_id: &str, mut ctx: Ctx, ) -> anyhow::Result> { let (pty, _) = ctx.terminals.get_mut(terminal_id).unwrap(); if let Err(err) = pty.write_all(&ctx.body.0[..]).await { tracing::warn!(%err, "pseudoterminal write error"); } Ok(ctx) }