use crate::{util::run_ssh2_fn, Error};
use futures::prelude::*;
use smol::Async;
use ssh2::{self, ExitSignal, ExtendedData, PtyModes, ReadWindow, Stream, WriteWindow};
use std::{
convert::From,
io,
io::{Read, Write},
net::TcpStream,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
pub struct Channel {
inner: ssh2::Channel,
stream: Arc<Async<TcpStream>>,
}
impl Channel {
pub(crate) fn new(channel: ssh2::Channel, stream: Arc<Async<TcpStream>>) -> Self {
Self {
inner: channel,
stream,
}
}
pub async fn setenv(&mut self, var: &str, val: &str) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.setenv(var, val)).await
}
pub async fn request_pty(
&mut self,
term: &str,
mode: Option<PtyModes>,
dim: Option<(u32, u32, u32, u32)>,
) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || {
self.inner.request_pty(term, mode.clone(), dim)
})
.await
}
pub async fn request_pty_size(
&mut self,
width: u32,
height: u32,
width_px: Option<u32>,
height_px: Option<u32>,
) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || {
self.inner
.request_pty_size(width, height, width_px, height_px)
})
.await
}
pub async fn exec(&mut self, command: &str) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.exec(command)).await
}
pub async fn shell(&mut self) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.shell()).await
}
pub async fn subsystem(&mut self, system: &str) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.subsystem(system)).await
}
pub async fn process_startup(
&mut self,
request: &str,
message: Option<&str>,
) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || {
self.inner.process_startup(request, message)
})
.await
}
pub fn stderr(&mut self) -> Stream {
self.inner.stderr()
}
pub fn stream(&mut self, stream_id: i32) -> Stream {
self.inner.stream(stream_id)
}
pub async fn handle_extended_data(&mut self, mode: ExtendedData) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || {
self.inner.handle_extended_data(mode)
})
.await
}
pub fn exit_status(&self) -> Result<i32, Error> {
self.inner.exit_status().map_err(From::from)
}
pub fn exit_signal(&self) -> Result<ExitSignal, Error> {
self.inner.exit_signal().map_err(From::from)
}
pub fn read_window(&self) -> ReadWindow {
self.inner.read_window()
}
pub fn write_window(&self) -> WriteWindow {
self.inner.write_window()
}
pub async fn adjust_receive_window(&mut self, adjust: u64, force: bool) -> Result<u64, Error> {
run_ssh2_fn(&self.stream.clone(), || {
self.inner.adjust_receive_window(adjust, force)
})
.await
}
pub fn eof(&self) -> bool {
self.inner.eof()
}
pub async fn send_eof(&mut self) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.send_eof()).await
}
pub async fn wait_eof(&mut self) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.wait_eof()).await
}
pub async fn close(&mut self) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.close()).await
}
pub async fn wait_close(&mut self) -> Result<(), Error> {
run_ssh2_fn(&self.stream.clone(), || self.inner.wait_close()).await
}
}
impl AsyncRead for Channel {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
self.stream
.clone()
.with(|_s| self.inner.read(buf))
.boxed()
.poll_unpin(cx)
}
}
impl AsyncWrite for Channel {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>> {
self.stream
.clone()
.with(|_s| self.inner.write(buf))
.boxed()
.poll_unpin(cx)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.stream
.clone()
.with(|_s| self.inner.flush())
.boxed()
.poll_unpin(cx)
}
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}