From c603c2b7a48ce7fedce520abe09bbc0cddb1d881 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 24 Feb 2021 04:46:08 -0500 Subject: add examples for async-std and tokio as well --- Cargo.toml | 3 ++ examples/async-std.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ examples/tokio.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 examples/async-std.rs create mode 100644 examples/tokio.rs diff --git a/Cargo.toml b/Cargo.toml index 005d002..3c60ffd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,10 @@ tokio = { version = "1.2", optional = true, features = ["fs", "process", "net"] futures = { version = "0.3", optional = true } [dev-dependencies] +async-std = { version = "*", features = ["unstable"] } +async-executor = "*" smol = "*" +tokio = { version = "1.2", features = [ "rt-multi-thread", "macros", "io-std", "io-util" ] } [features] default = ["backend-std"] diff --git a/examples/async-std.rs b/examples/async-std.rs new file mode 100644 index 0000000..c65b1ac --- /dev/null +++ b/examples/async-std.rs @@ -0,0 +1,101 @@ +use async_std::io::prelude::WriteExt as _; +use async_std::io::ReadExt as _; +use async_std::prelude::FutureExt as _; +use pty_process::Command as _; +use std::os::unix::io::AsRawFd as _; +use std::os::unix::process::ExitStatusExt as _; + +struct RawGuard { + termios: nix::sys::termios::Termios, +} + +impl RawGuard { + fn new() -> Self { + let stdin = std::io::stdin().as_raw_fd(); + let termios = nix::sys::termios::tcgetattr(stdin).unwrap(); + let mut termios_raw = termios.clone(); + nix::sys::termios::cfmakeraw(&mut termios_raw); + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &termios_raw, + ) + .unwrap(); + Self { termios } + } +} + +impl Drop for RawGuard { + fn drop(&mut self) { + let stdin = std::io::stdin().as_raw_fd(); + let _ = nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &self.termios, + ); + } +} + +async fn run( + child: &pty_process::async_std::Child, +) -> std::result::Result<(), Box> { + let _raw = RawGuard::new(); + + let ex = async_executor::Executor::new(); + + let input = ex.spawn(async { + let mut buf = [0_u8; 4096]; + let mut stdin = async_std::io::stdin(); + loop { + match stdin.read(&mut buf).await { + Ok(bytes) => { + child.pty().write_all(&buf[..bytes]).await.unwrap(); + } + Err(e) => { + eprintln!("stdin read failed: {:?}", e); + break; + } + } + } + }); + let output = ex.spawn(async { + let mut buf = [0_u8; 4096]; + let mut stdout = async_std::io::stdout(); + loop { + match child.pty().read(&mut buf).await { + Ok(bytes) => { + stdout.write_all(&buf[..bytes]).await.unwrap(); + stdout.flush().await.unwrap(); + } + Err(e) => { + // EIO means that the process closed the other + // end of the pty + if e.raw_os_error() != Some(libc::EIO) { + eprintln!("pty read failed: {:?}", e); + } + break; + } + } + } + }); + + ex.run(input.race(output)).await; + + Ok(()) +} + +fn main() { + let status = async_std::task::block_on(async { + let mut child = async_std::process::Command::new("sleep") + .args(&["500"]) + .spawn_pty(Some(&pty_process::Size::new(24, 80))) + .unwrap(); + run(&child).await.unwrap(); + child.status().await.unwrap() + }); + std::process::exit( + status + .code() + .unwrap_or_else(|| status.signal().unwrap_or(0) + 128), + ); +} diff --git a/examples/tokio.rs b/examples/tokio.rs new file mode 100644 index 0000000..42cd643 --- /dev/null +++ b/examples/tokio.rs @@ -0,0 +1,92 @@ +use pty_process::Command as _; +use std::os::unix::io::AsRawFd as _; +use std::os::unix::process::ExitStatusExt as _; +use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _}; + +struct RawGuard { + termios: nix::sys::termios::Termios, +} + +impl RawGuard { + fn new() -> Self { + let stdin = std::io::stdin().as_raw_fd(); + let termios = nix::sys::termios::tcgetattr(stdin).unwrap(); + let mut termios_raw = termios.clone(); + nix::sys::termios::cfmakeraw(&mut termios_raw); + nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &termios_raw, + ) + .unwrap(); + Self { termios } + } +} + +impl Drop for RawGuard { + fn drop(&mut self) { + let stdin = std::io::stdin().as_raw_fd(); + let _ = nix::sys::termios::tcsetattr( + stdin, + nix::sys::termios::SetArg::TCSANOW, + &self.termios, + ); + } +} + +async fn run( + child: &mut pty_process::tokio::Child, +) -> std::result::Result<(), Box> { + let _raw = RawGuard::new(); + + let mut in_buf = [0_u8; 4096]; + let mut out_buf = [0_u8; 4096]; + + let mut stdin = tokio::io::stdin(); + let mut stdout = tokio::io::stdout(); + + loop { + tokio::select! { + bytes = stdin.read(&mut in_buf) => match bytes { + Ok(bytes) => { + child.pty_mut().write_all(&in_buf[..bytes]).await.unwrap(); + } + Err(e) => { + eprintln!("stdin read failed: {:?}", e); + break; + } + }, + bytes = child.pty_mut().read(&mut out_buf) => match bytes { + Ok(bytes) => { + stdout.write_all(&out_buf[..bytes]).await.unwrap(); + stdout.flush().await.unwrap(); + } + Err(e) => { + // EIO means that the process closed the other + // end of the pty + if e.raw_os_error() != Some(libc::EIO) { + eprintln!("pty read failed: {:?}", e); + } + break; + } + }, + } + } + + Ok(()) +} + +#[tokio::main] +async fn main() { + let mut child = tokio::process::Command::new("sleep") + .args(&["500"]) + .spawn_pty(Some(&pty_process::Size::new(24, 80))) + .unwrap(); + run(&mut child).await.unwrap(); + let status = child.wait().await.unwrap(); + std::process::exit( + status + .code() + .unwrap_or_else(|| status.signal().unwrap_or(0) + 128), + ); +} -- cgit v1.2.3-54-g00ecf