async-ssh2-lite 0.2.2

Asynchronous ssh2.
Documentation
use std::io::{self, Read, Write, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};

use async_io::Async;
use futures_util::io::{AsyncRead, AsyncWrite, AsyncSeek};
use futures_util::ready;
use ssh2::{File, FileStat, OpenFlags, OpenType, RenameFlags, Sftp};

pub struct AsyncSftp<S> {
    inner: Sftp,
    async_io: Arc<Async<S>>,
}

impl<S> AsyncSftp<S> {
    pub(crate) fn from_parts(inner: Sftp, async_io: Arc<Async<S>>) -> Self {
        Self { inner, async_io }
    }
}

impl<S> AsyncSftp<S> {
    pub async fn open_mode(
        &self,
        filename: &Path,
        flags: OpenFlags,
        mode: i32,
        open_type: OpenType,
    ) -> io::Result<AsyncFile<S>> {
        let inner = &self.inner;

        let ret = self
            .async_io
            .write_with(|_| {
                inner
                    .open_mode(filename, flags, mode, open_type)
                    .map_err(Into::into)
            })
            .await;

        ret.map(|file| AsyncFile::from_parts(file, self.async_io.clone()))
    }

    pub async fn open(&self, filename: &Path) -> io::Result<AsyncFile<S>> {
        let inner = &self.inner;

        let ret = self
            .async_io
            .write_with(|_| inner.open(filename).map_err(Into::into))
            .await;

        ret.map(|file| AsyncFile::from_parts(file, self.async_io.clone()))
    }

    pub async fn create(&self, filename: &Path) -> io::Result<AsyncFile<S>> {
        let inner = &self.inner;

        let ret = self
            .async_io
            .write_with(|_| inner.create(filename).map_err(Into::into))
            .await;

        ret.map(|file| AsyncFile::from_parts(file, self.async_io.clone()))
    }

    pub async fn opendir(&self, dirname: &Path) -> io::Result<AsyncFile<S>> {
        let inner = &self.inner;

        let ret = self
            .async_io
            .write_with(|_| inner.opendir(dirname).map_err(Into::into))
            .await;

        ret.map(|file| AsyncFile::from_parts(file, self.async_io.clone()))
    }

    pub async fn readdir(&self, dirname: &Path) -> io::Result<Vec<(PathBuf, FileStat)>> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.readdir(dirname).map_err(Into::into))
            .await
    }

    pub async fn mkdir(&self, filename: &Path, mode: i32) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.mkdir(filename, mode).map_err(Into::into))
            .await
    }

    pub async fn rmdir(&self, filename: &Path) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.rmdir(filename).map_err(Into::into))
            .await
    }

    pub async fn stat(&self, filename: &Path) -> io::Result<FileStat> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.stat(filename).map_err(Into::into))
            .await
    }

    pub async fn lstat(&self, filename: &Path) -> io::Result<FileStat> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.lstat(filename).map_err(Into::into))
            .await
    }

    pub async fn setstat(&self, filename: &Path, stat: FileStat) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.setstat(filename, stat.clone()).map_err(Into::into))
            .await
    }

    pub async fn symlink(&self, path: &Path, target: &Path) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.symlink(path, target).map_err(Into::into))
            .await
    }

    pub async fn readlink(&self, path: &Path) -> io::Result<PathBuf> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.readlink(path).map_err(Into::into))
            .await
    }

    pub async fn realpath(&self, path: &Path) -> io::Result<PathBuf> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.realpath(path).map_err(Into::into))
            .await
    }

    pub async fn rename(
        &self,
        src: &Path,
        dst: &Path,
        flags: Option<RenameFlags>,
    ) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.rename(src, dst, flags).map_err(Into::into))
            .await
    }

    pub async fn unlink(&self, file: &Path) -> io::Result<()> {
        let inner = &self.inner;

        self.async_io
            .write_with(|_| inner.unlink(file).map_err(Into::into))
            .await
    }
}

//
//
//
pub struct AsyncFile<S> {
    inner: File,
    async_io: Arc<Async<S>>,
}

impl<S> AsyncFile<S> {
    pub(crate) fn from_parts(inner: File, async_io: Arc<Async<S>>) -> Self {
        Self { inner, async_io }
    }
}

impl<S> AsyncRead for AsyncFile<S> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        loop {
            match self.inner.read(buf) {
                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
                res => return Poll::Ready(res),
            }
            ready!(self.async_io.poll_readable(cx))?;
        }
    }
}

impl<S> AsyncWrite for AsyncFile<S> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        loop {
            match self.inner.write(buf) {
                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
                res => return Poll::Ready(res),
            }
            ready!(self.async_io.poll_writable(cx))?;
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        loop {
            match self.inner.flush() {
                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
                res => return Poll::Ready(res),
            }
            ready!(self.async_io.poll_writable(cx))?;
        }
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl<S> AsyncSeek for AsyncFile<S> {
    fn poll_seek(
        mut self: Pin<&mut Self>, 
        cx: &mut Context<'_>, 
        pos: SeekFrom
    ) -> Poll<io::Result<u64>> {
        loop {
            match self.inner.seek(pos) {
                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
                res => return Poll::Ready(res),
            }
            ready!(self.async_io.poll_readable(cx))?;
        }
    }
}