use crate::transport::Transport;
use crate::types::{Behavior, Request, TransportError};
use crate::wire::into_u32;
#[derive(Debug, Clone, Copy)]
pub enum Pipe {
Stdout,
Stderr,
}
pub struct Channel<'a, 'b, T: Behavior> {
transport: &'b mut Transport<'a, T>,
}
impl<'a, 'b, T: Behavior> Channel<'a, 'b, T> {
pub(crate) fn new(transport: &'b mut Transport<'a, T>) -> Self {
Self { transport }
}
pub fn request(&self) -> Request<T::Command> {
self.transport.channel_request()
}
pub fn user(&self) -> T::User {
self.transport.channel_user()
}
pub fn client_ssh_id_string(&self) -> &str {
self.transport.client_ssh_id_string()
}
pub async fn exit(self, exit_status: u32) -> Result<(), TransportError<T>> {
self.transport.channel_exit(exit_status).await
}
pub async fn reader(
&mut self,
len: Option<usize>,
) -> Result<Reader<'a, '_, T>, TransportError<T>> {
self.transport.channel_adjust(len.map(into_u32)).await?;
Ok(Reader::new(self.transport)) }
pub async fn read_exact_stdin(
&mut self,
mut bytes: &mut [u8],
) -> Result<usize, TransportError<T>> {
let read_len = bytes.len();
let mut reader = self.reader(Some(read_len)).await?;
while let Some(read) = reader.read().await? {
let (dest, remaining) = bytes.split_at_mut(read.len());
dest.copy_from_slice(read);
bytes = remaining;
}
Ok(read_len - bytes.len())
}
pub fn writer(&mut self, pipe: Pipe) -> Writer<'a, '_, T> {
Writer::new(self.transport, pipe)
}
pub fn stdout(&mut self) -> Writer<'a, '_, T> {
self.writer(Pipe::Stdout)
}
pub fn stderr(&mut self) -> Writer<'a, '_, T> {
self.writer(Pipe::Stderr)
}
pub async fn write_all_stdout(&mut self, bytes: &[u8]) -> Result<(), TransportError<T>> {
self.stdout().write_all_internal(bytes).await
}
pub async fn write_all_stderr(&mut self, bytes: &[u8]) -> Result<(), TransportError<T>> {
self.stderr().write_all_internal(bytes).await
}
}
pub struct Reader<'a, 'b, T: Behavior> {
transport: &'b mut Transport<'a, T>,
}
impl<'a, 'b, T: Behavior> Reader<'a, 'b, T> {
fn new(transport: &'b mut Transport<'a, T>) -> Self {
Self { transport }
}
pub async fn read(&mut self) -> Result<Option<&[u8]>, TransportError<T>> {
self.transport.channel_read().await
}
pub fn is_eof(&mut self) -> bool {
self.transport.channel_is_eof()
}
}
pub struct Writer<'a, 'b, T: Behavior> {
transport: &'b mut Transport<'a, T>,
pipe: Pipe,
}
impl<'a, 'b, T: Behavior> Writer<'a, 'b, T> {
fn new(transport: &'b mut Transport<'a, T>, pipe: Pipe) -> Self {
Self { transport, pipe }
}
pub fn buffer(&mut self) -> &mut [u8] {
self.transport.channel_data_payload_buffer(self.pipe)
}
pub async fn write_all(self, len: usize) -> Result<(), TransportError<T>> {
self.transport.channel_write_all(len, self.pipe).await?;
Ok(())
}
async fn write_all_internal(mut self, bytes: &[u8]) -> Result<(), TransportError<T>> {
for chunk in bytes.chunks(self.buffer().len()) {
self.buffer()[..chunk.len()].copy_from_slice(chunk);
self.transport
.channel_write_all(chunk.len(), self.pipe)
.await?;
}
Ok(())
}
}