From 5309b3182a30d0555137fbe9fba21ed1d06a91d0 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 27 Oct 2019 15:47:32 -0400 Subject: move resizing out into a separate crate --- Cargo.lock | 19 ++++++++-- Cargo.toml | 3 +- src/cmd/record.rs | 58 ++++++++++++++---------------- src/cmd/stream.rs | 58 +++++++++++++++--------------- src/cmd/watch.rs | 18 +++++++--- src/error.rs | 5 +++ src/main.rs | 1 - src/resize.rs | 103 ------------------------------------------------------ 8 files changed, 93 insertions(+), 172 deletions(-) delete mode 100644 src/resize.rs diff --git a/Cargo.lock b/Cargo.lock index 0f4d7a3..9948535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1648,6 +1648,7 @@ dependencies = [ "tokio", "tokio-pty-process-stream", "tokio-signal", + "tokio-terminal-resize", "tokio-tls", "ttyrec", "twoway", @@ -1825,9 +1826,9 @@ dependencies = [ [[package]] name = "tokio-pty-process-stream" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d5702467cedd1b8180d3aef8d6e195ed3a6151ddca36b3b6d4c57e65b5e0c85" +checksum = "87c73e73b3907c8a3142162c28ca75a4a941f1f737f3bd31e3faeb6608f2d9f8" dependencies = [ "component-future", "futures", @@ -1835,6 +1836,7 @@ dependencies = [ "snafu", "tokio", "tokio-pty-process", + "tokio-terminal-resize", ] [[package]] @@ -1897,6 +1899,19 @@ dependencies = [ "tokio-reactor", ] +[[package]] +name = "tokio-terminal-resize" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901915a5bf94a2ae7189de1af32da3161a80efc4609dd36ec8eba570e5c04ec4" +dependencies = [ + "futures", + "snafu", + "term_size", + "tokio", + "tokio-signal", +] + [[package]] name = "tokio-threadpool" version = "0.1.16" diff --git a/Cargo.toml b/Cargo.toml index 9f44de0..9941011 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,9 @@ reqwest = "0.9.22" serde = "1" snafu = { version = "0.5", features = ["rust_1_30", "futures-01"], default_features = false } tokio = { version = "0.1.22", features = ["codec", "fs", "io", "reactor", "rt-full", "sync", "tcp", "timer"], default_features = false } -tokio-pty-process-stream = "0.1" +tokio-pty-process-stream = "0.2" tokio-signal = "0.2" +tokio-terminal-resize = "0.1" tokio-tls = "0.2" ttyrec = "0.1" twoway = "0.2" diff --git a/src/cmd/record.rs b/src/cmd/record.rs index 2d9116c..d25df4e 100644 --- a/src/cmd/record.rs +++ b/src/cmd/record.rs @@ -68,7 +68,8 @@ enum FileState { struct RecordSession { file: FileState, - process: crate::resize::ResizingProcess, + process: + tokio_pty_process_stream::ResizingProcess, stdout: tokio::io::Stdout, buffer: crate::term::Buffer, sent_local: usize, @@ -85,7 +86,7 @@ impl RecordSession { args: &[String], ) -> Self { let input = crate::async_stdin::Stdin::new(); - let process = crate::resize::ResizingProcess::new( + let process = tokio_pty_process_stream::ResizingProcess::new( tokio_pty_process_stream::Process::new(cmd, args, input), ); @@ -157,47 +158,40 @@ impl RecordSession { } fn poll_read_process(&mut self) -> component_future::Poll<(), Error> { - match component_future::try_ready!(self.process.poll()) { - Some(crate::resize::Event::Process(e)) => { - match e { - tokio_pty_process_stream::Event::CommandStart { - .. - } => { - if self.raw_screen.is_none() { - self.raw_screen = Some( - crossterm::RawScreen::into_raw_mode() - .context(crate::error::ToRawMode)?, - ); - } - } - tokio_pty_process_stream::Event::CommandExit { - .. - } => { - self.done = true; - } - tokio_pty_process_stream::Event::Output { data } => { - self.record_bytes(&data); - if let FileState::Open { writer } = &mut self.file { - writer - .frame(&data) - .context(crate::error::WriteTtyrec)?; - } - } + match component_future::try_ready!(self + .process + .poll() + .context(crate::error::Subprocess)) + { + Some(tokio_pty_process_stream::Event::CommandStart { + .. + }) => { + if self.raw_screen.is_none() { + self.raw_screen = Some( + crossterm::RawScreen::into_raw_mode() + .context(crate::error::ToRawMode)?, + ); } - Ok(component_future::Async::DidWork) } - Some(crate::resize::Event::Resize(_)) => { - Ok(component_future::Async::DidWork) + Some(tokio_pty_process_stream::Event::CommandExit { .. }) => { + self.done = true; } + Some(tokio_pty_process_stream::Event::Output { data }) => { + self.record_bytes(&data); + if let FileState::Open { writer } = &mut self.file { + writer.frame(&data).context(crate::error::WriteTtyrec)?; + } + } + Some(tokio_pty_process_stream::Event::Resize { .. }) => {} None => { if !self.done { unreachable!() } // don't return final event here - wait until we are done // writing all data to the file (see poll_write_file) - Ok(component_future::Async::DidWork) } } + Ok(component_future::Async::DidWork) } fn poll_write_terminal(&mut self) -> component_future::Poll<(), Error> { diff --git a/src/cmd/stream.rs b/src/cmd/stream.rs index 9d2cf83..b4f1a26 100644 --- a/src/cmd/stream.rs +++ b/src/cmd/stream.rs @@ -119,7 +119,8 @@ struct StreamSession< S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static, > { client: crate::client::Client, - process: crate::resize::ResizingProcess, + process: + tokio_pty_process_stream::ResizingProcess, stdout: tokio::io::Stdout, buffer: crate::term::Buffer, sent_local: usize, @@ -148,7 +149,7 @@ impl // let input = tokio::io::stdin(); let input = crate::async_stdin::Stdin::new(); - let process = crate::resize::ResizingProcess::new( + let process = tokio_pty_process_stream::ResizingProcess::new( tokio_pty_process_stream::Process::new(cmd, args, input), ); @@ -235,34 +236,33 @@ impl } fn poll_read_process(&mut self) -> component_future::Poll<(), Error> { - match component_future::try_ready!(self.process.poll()) { - Some(crate::resize::Event::Process(e)) => { - match e { - tokio_pty_process_stream::Event::CommandStart { - .. - } => { - if self.raw_screen.is_none() { - self.raw_screen = Some( - crossterm::RawScreen::into_raw_mode() - .context(crate::error::ToRawMode)?, - ); - } - } - tokio_pty_process_stream::Event::CommandExit { - .. - } => { - self.done = true; - } - tokio_pty_process_stream::Event::Output { data } => { - self.record_bytes(&data); - } + match component_future::try_ready!(self + .process + .poll() + .context(crate::error::Subprocess)) + { + Some(tokio_pty_process_stream::Event::CommandStart { + .. + }) => { + if self.raw_screen.is_none() { + self.raw_screen = Some( + crossterm::RawScreen::into_raw_mode() + .context(crate::error::ToRawMode)?, + ); } - Ok(component_future::Async::DidWork) } - Some(crate::resize::Event::Resize(size)) => { - self.client - .send_message(crate::protocol::Message::resize(&size)); - Ok(component_future::Async::DidWork) + Some(tokio_pty_process_stream::Event::CommandExit { .. }) => { + self.done = true; + } + Some(tokio_pty_process_stream::Event::Output { data }) => { + self.record_bytes(&data); + } + Some(tokio_pty_process_stream::Event::Resize { + size: (rows, cols), + }) => { + self.client.send_message(crate::protocol::Message::resize( + &crate::term::Size { rows, cols }, + )); } None => { if !self.done { @@ -270,9 +270,9 @@ impl } // don't return final event here - wait until we are done // sending all data to the server (see poll_write_server) - Ok(component_future::Async::DidWork) } } + Ok(component_future::Async::DidWork) } fn poll_write_terminal(&mut self) -> component_future::Poll<(), Error> { diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 67e3507..0e4e197 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -190,7 +190,12 @@ struct WatchSession< key_reader: crate::key_reader::KeyReader, list_client: crate::client::Client, - resizer: crate::resize::Resizer, + resizer: Box< + dyn futures::stream::Stream< + Item = (u16, u16), + Error = crate::error::Error, + > + Send, + >, state: State, raw_screen: Option, needs_redraw: bool, @@ -212,7 +217,11 @@ impl key_reader: crate::key_reader::KeyReader::new(), list_client, - resizer: crate::resize::Resizer::new(), + resizer: Box::new( + tokio_terminal_resize::resizes() + .flatten_stream() + .context(crate::error::Resize), + ), state: State::new(), raw_screen: None, needs_redraw: true, @@ -577,8 +586,9 @@ impl ]; fn poll_resizer(&mut self) -> component_future::Poll<(), Error> { - let size = component_future::try_ready!(self.resizer.poll()).unwrap(); - self.resize(size)?; + let (rows, cols) = + component_future::try_ready!(self.resizer.poll()).unwrap(); + self.resize(crate::term::Size { rows, cols })?; Ok(component_future::Async::DidWork) } diff --git a/src/error.rs b/src/error.rs index 087bc72..e6e4530 100644 --- a/src/error.rs +++ b/src/error.rs @@ -274,6 +274,11 @@ pub enum Error { #[snafu(display("failed to read ttyrec: {}", source))] ReadTtyrec { source: ttyrec::Error }, + #[snafu(display("failed to poll for terminal resizing: {}", source))] + Resize { + source: tokio_terminal_resize::Error, + }, + #[snafu(display( "failed to resolve address {}:{}: {}", host, diff --git a/src/main.rs b/src/main.rs index e0db244..d85ebda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,6 @@ mod error; mod key_reader; mod oauth; mod protocol; -mod resize; mod server; mod session_list; mod term; diff --git a/src/resize.rs b/src/resize.rs deleted file mode 100644 index d792708..0000000 --- a/src/resize.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::prelude::*; - -pub struct Resizer { - winches: - Box + Send>, - sent_initial_size: bool, -} - -impl Resizer { - pub fn new() -> Self { - let winches = tokio_signal::unix::Signal::new( - tokio_signal::unix::libc::SIGWINCH, - ) - .flatten_stream() - .map(|_| ()) - .context(crate::error::SigWinchHandler); - Self { - winches: Box::new(winches), - sent_initial_size: false, - } - } -} - -#[must_use = "streams do nothing unless polled"] -impl futures::stream::Stream for Resizer { - type Item = crate::term::Size; - type Error = Error; - - fn poll(&mut self) -> futures::Poll, Self::Error> { - if !self.sent_initial_size { - self.sent_initial_size = true; - return Ok(futures::Async::Ready( - Some(crate::term::Size::get()?), - )); - } - let _ = futures::try_ready!(self.winches.poll()); - Ok(futures::Async::Ready(Some(crate::term::Size::get()?))) - } -} - -pub enum Event { - Process( - as futures::stream::Stream>::Item - ), - Resize(crate::term::Size), -} - -pub struct ResizingProcess { - process: tokio_pty_process_stream::Process, - resizer: Resizer, -} - -impl ResizingProcess { - pub fn new(process: tokio_pty_process_stream::Process) -> Self { - Self { - process, - resizer: Resizer::new(), - } - } -} - -impl ResizingProcess { - const POLL_FNS: - &'static [&'static dyn for<'a> Fn( - &'a mut Self, - ) - -> component_future::Poll< - Option>, - Error, - >] = &[&Self::poll_resize, &Self::poll_process]; - - fn poll_resize( - &mut self, - ) -> component_future::Poll>, Error> { - let size = component_future::try_ready!(self.resizer.poll()).unwrap(); - self.process.resize(size.rows, size.cols); - Ok(component_future::Async::Ready(Some(Event::Resize(size)))) - } - - fn poll_process( - &mut self, - ) -> component_future::Poll>, Error> { - Ok(component_future::Async::Ready( - component_future::try_ready!(self - .process - .poll() - .context(crate::error::Subprocess)) - .map(Event::Process), - )) - } -} - -#[must_use = "streams do nothing unless polled"] -impl futures::stream::Stream - for ResizingProcess -{ - type Item = Event; - type Error = Error; - - fn poll(&mut self) -> futures::Poll, Self::Error> { - component_future::poll_stream(self, Self::POLL_FNS) - } -} -- cgit v1.2.3-54-g00ecf