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.write_all(Pipe::Stdout, bytes).await
}
pub async fn write_all_stderr(&mut self, bytes: &[u8]) -> Result<(), TransportError<T>> {
self.write_all(Pipe::Stderr, bytes).await
}
async fn write_all(&mut self, pipe: Pipe, bytes: &[u8]) -> Result<(), TransportError<T>> {
let mut slice = bytes;
while !slice.is_empty() {
let mut writer = Writer::new(self.transport, pipe);
let bytes_written = usize::min(bytes.len(), writer.buffer().len());
let (transfer, slice_rest) = slice.split_at(bytes_written);
writer.buffer()[..bytes_written].copy_from_slice(transfer);
writer.write_all(bytes_written).await?;
slice = slice_rest;
}
Ok(())
}
}
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(len, self.pipe).await
}
}