diff options
author | Jesse Luehrs <doy@tozt.net> | 2019-10-14 15:10:37 -0400 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2019-10-14 15:10:37 -0400 |
commit | 05a26723ee1329cf8e809961d5d7bc4fda6e1db6 (patch) | |
tree | 8ee83acee78c82731b12e23563f97e13f37c1f0a | |
parent | 9f530b0022b670c7480b26b4c6614df2d04b4700 (diff) | |
download | teleterm-05a26723ee1329cf8e809961d5d7bc4fda6e1db6.tar.gz teleterm-05a26723ee1329cf8e809961d5d7bc4fda6e1db6.zip |
consolidate errors
-rw-r--r-- | src/client.rs | 45 | ||||
-rw-r--r-- | src/cmd.rs | 37 | ||||
-rw-r--r-- | src/cmd/play.rs | 37 | ||||
-rw-r--r-- | src/cmd/record.rs | 51 | ||||
-rw-r--r-- | src/cmd/server.rs | 110 | ||||
-rw-r--r-- | src/cmd/stream.rs | 58 | ||||
-rw-r--r-- | src/cmd/watch.rs | 92 | ||||
-rw-r--r-- | src/error.rs | 253 | ||||
-rw-r--r-- | src/key_reader.rs | 25 | ||||
-rw-r--r-- | src/prelude.rs | 2 | ||||
-rw-r--r-- | src/process.rs | 53 | ||||
-rw-r--r-- | src/protocol.rs | 73 | ||||
-rw-r--r-- | src/server.rs | 93 | ||||
-rw-r--r-- | src/server/tls.rs | 32 | ||||
-rw-r--r-- | src/term.rs | 19 | ||||
-rw-r--r-- | src/ttyrec.rs | 38 | ||||
-rw-r--r-- | src/util.rs | 39 |
17 files changed, 441 insertions, 616 deletions
diff --git a/src/client.rs b/src/client.rs index 9ef1ae2..75edfbf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,29 +1,6 @@ use crate::prelude::*; use rand::Rng as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("{}", source))] - Resize { source: crate::term::Error }, - - #[snafu(display("heartbeat timer failed: {}", source))] - Timer { source: tokio::timer::Error }, - - #[snafu(display("failed to read message from server: {}", source))] - ReadServer { source: crate::protocol::Error }, - - #[snafu(display("failed to write message to server: {}", source))] - WriteServer { source: crate::protocol::Error }, - - #[snafu(display("SIGWINCH handler failed: {}", source))] - SigWinchHandler { source: std::io::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - const HEARTBEAT_DURATION: std::time::Duration = std::time::Duration::from_secs(30); const RECONNECT_BACKOFF_BASE: std::time::Duration = @@ -170,7 +147,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> ) .flatten_stream() .map(|_| ()) - .context(SigWinchHandler); + .context(crate::error::SigWinchHandler); Some(Box::new(winches)) } else { None @@ -261,7 +238,10 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> match &mut self.wsock { WriteSocket::NotConnected => { if let Some(timer) = &mut self.reconnect_timer { - match timer.poll().context(Timer)? { + match timer + .poll() + .context(crate::error::TimerReconnect)? + { futures::Async::Ready(..) => { self.reconnect_timer = None; } @@ -299,7 +279,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> let term = std::env::var("TERM") .unwrap_or_else(|_| "".to_string()); - let size = crate::term::Size::get().context(Resize)?; + let size = crate::term::Size::get()?; let msg = crate::protocol::Message::login_plain( &self.username, &term, @@ -342,8 +322,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> let mut tmp = ReadSocket::NotConnected; std::mem::swap(&mut self.rsock, &mut tmp); if let ReadSocket::Connected(s) = tmp { - let fut = crate::protocol::Message::read_async(s) - .context(ReadServer); + let fut = crate::protocol::Message::read_async(s); self.rsock = ReadSocket::ReadingMessage(Box::new(fut)); } else { unreachable!() @@ -392,7 +371,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> std::mem::swap(&mut self.wsock, &mut tmp); if let WriteSocket::Connected(s) = tmp { if let Some(msg) = self.to_send.pop_front() { - let fut = msg.write_async(s).context(WriteServer); + let fut = msg.write_async(s); self.wsock = WriteSocket::WritingMessage(Box::new(fut)); } else { @@ -424,7 +403,11 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> fn poll_heartbeat( &mut self, ) -> Result<crate::component_future::Poll<Event>> { - match self.heartbeat_timer.poll().context(Timer)? { + match self + .heartbeat_timer + .poll() + .context(crate::error::TimerHeartbeat)? + { futures::Async::Ready(..) => { self.send_message(crate::protocol::Message::heartbeat()); Ok(crate::component_future::Poll::DidWork) @@ -441,7 +424,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> if let Some(winches) = &mut self.winches { match winches.poll()? { futures::Async::Ready(Some(_)) => { - let size = crate::term::Size::get().context(Resize)?; + let size = crate::term::Size::get()?; self.send_message(crate::protocol::Message::resize( &size, )); @@ -6,32 +6,6 @@ mod server; mod stream; mod watch; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("failed to determine program name: {}", source))] - FindProgramName { source: crate::util::Error }, - - #[snafu(display("{}", source))] - Parse { source: clap::Error }, - - #[snafu(display("{}", source))] - Play { source: crate::cmd::play::Error }, - - #[snafu(display("{}", source))] - Record { source: crate::cmd::record::Error }, - - #[snafu(display("{}", source))] - Stream { source: crate::cmd::stream::Error }, - - #[snafu(display("{}", source))] - Server { source: crate::cmd::server::Error }, - - #[snafu(display("{}", source))] - Watch { source: crate::cmd::watch::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - struct Command { name: &'static str, cmd: &'static dyn for<'a, 'b> Fn(clap::App<'a, 'b>) -> clap::App<'a, 'b>, @@ -67,18 +41,17 @@ const COMMANDS: &[Command] = &[ ]; pub fn parse<'a>() -> Result<clap::ArgMatches<'a>> { - let mut app = - clap::App::new(crate::util::program_name().context(FindProgramName)?) - .about("Stream your terminal for other people to watch") - .author(clap::crate_authors!()) - .version(clap::crate_version!()); + let mut app = clap::App::new(crate::util::program_name()?) + .about("Stream your terminal for other people to watch") + .author(clap::crate_authors!()) + .version(clap::crate_version!()); for cmd in COMMANDS { let subcommand = clap::SubCommand::with_name(cmd.name); app = app.subcommand((cmd.cmd)(subcommand)); } - app.get_matches_safe().context(Parse) + app.get_matches_safe().context(crate::error::ParseArgs) } pub fn run(matches: &clap::ArgMatches<'_>) -> Result<()> { diff --git a/src/cmd/play.rs b/src/cmd/play.rs index 1a337fa..996fd90 100644 --- a/src/cmd/play.rs +++ b/src/cmd/play.rs @@ -1,29 +1,6 @@ use crate::prelude::*; use std::io::Write as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("failed to open file: {}", source))] - OpenFile { source: tokio::io::Error }, - - #[snafu(display("failed to sleep until next frame: {}", source))] - Sleep { source: tokio::timer::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - WriteTerminal { source: tokio::io::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - FlushTerminal { source: tokio::io::Error }, - - #[snafu(display("failed to read from file: {}", source))] - ReadFile { source: crate::ttyrec::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Play recorded terminal sessions").arg( clap::Arg::with_name("filename") @@ -33,9 +10,9 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { ) } -pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { +pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> Result<()> { let filename = matches.value_of("filename").unwrap(); - run_impl(filename).context(super::Play) + run_impl(filename) } fn run_impl(filename: &str) -> Result<()> { @@ -100,7 +77,7 @@ impl PlaySession { Ok(crate::component_future::Poll::DidWork) } FileState::Opening { fut } => { - match fut.poll().context(OpenFile)? { + match fut.poll().context(crate::error::OpenFile)? { futures::Async::Ready(file) => { let file = crate::ttyrec::File::new(file); self.file = FileState::Open { file }; @@ -119,7 +96,7 @@ impl PlaySession { &mut self, ) -> Result<crate::component_future::Poll<()>> { if let FileState::Open { file } = &mut self.file { - match file.poll_read().context(ReadFile)? { + match file.poll_read()? { futures::Async::Ready(Some(frame)) => { self.to_write.insert_at(frame.data, frame.time); Ok(crate::component_future::Poll::DidWork) @@ -140,13 +117,13 @@ impl PlaySession { fn poll_write_terminal( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.to_write.poll().context(Sleep)? { + match self.to_write.poll().context(crate::error::Sleep)? { futures::Async::Ready(Some(data)) => { // TODO async let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - stdout.write(&data).context(WriteTerminal)?; - stdout.flush().context(FlushTerminal)?; + stdout.write(&data).context(crate::error::WriteTerminal)?; + stdout.flush().context(crate::error::FlushTerminal)?; Ok(crate::component_future::Poll::DidWork) } futures::Async::Ready(None) => { diff --git a/src/cmd/record.rs b/src/cmd/record.rs index 5f9e8c4..4577687 100644 --- a/src/cmd/record.rs +++ b/src/cmd/record.rs @@ -1,29 +1,6 @@ use crate::prelude::*; use tokio::io::AsyncWrite as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("process failed: {}", source))] - Process { source: crate::process::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - WriteTerminal { source: tokio::io::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - FlushTerminal { source: tokio::io::Error }, - - #[snafu(display("failed to open file: {}", source))] - OpenFile { source: tokio::io::Error }, - - #[snafu(display("failed to write to file: {}", source))] - WriteFile { source: crate::ttyrec::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Record a terminal session to a file") .arg( @@ -41,7 +18,7 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { .arg(clap::Arg::with_name("args").index(2).multiple(true)) } -pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { +pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> Result<()> { let filename = matches.value_of("filename").unwrap(); let buffer_size = matches @@ -49,8 +26,6 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { .map_or(Ok(4 * 1024 * 1024), |s| { s.parse() .context(crate::error::ParseBufferSize { input: s }) - .context(Common) - .context(super::Record) })?; let command = matches.value_of("command").map_or_else( || std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()), @@ -61,7 +36,7 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { } else { vec![] }; - run_impl(filename, buffer_size, &command, &args).context(super::Record) + run_impl(filename, buffer_size, &command, &args) } fn run_impl( @@ -159,11 +134,10 @@ impl RecordSession { Ok(crate::component_future::Poll::DidWork) } FileState::Opening { fut } => { - match fut.poll().context(OpenFile)? { + match fut.poll().context(crate::error::OpenFile)? { futures::Async::Ready(file) => { let mut file = crate::ttyrec::File::new(file); - file.write_frame(self.buffer.contents()) - .context(WriteFile)?; + file.write_frame(self.buffer.contents())?; self.file = FileState::Open { file }; Ok(crate::component_future::Poll::DidWork) } @@ -181,7 +155,7 @@ impl RecordSession { fn poll_read_process( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.process.poll().context(Process)? { + match self.process.poll()? { futures::Async::Ready(Some(e)) => { match e { crate::process::Event::CommandStart(..) => {} @@ -191,7 +165,7 @@ impl RecordSession { crate::process::Event::Output(output) => { self.record_bytes(&output); if let FileState::Open { file } = &mut self.file { - file.write_frame(&output).context(WriteFile)?; + file.write_frame(&output)?; } } } @@ -221,7 +195,7 @@ impl RecordSession { match self .stdout .poll_write(&self.buffer.contents()[self.sent_local..]) - .context(WriteTerminal)? + .context(crate::error::WriteTerminal)? { futures::Async::Ready(n) => { self.sent_local += n; @@ -241,7 +215,11 @@ impl RecordSession { return Ok(crate::component_future::Poll::NothingToDo); } - match self.stdout.poll_flush().context(FlushTerminal)? { + match self + .stdout + .poll_flush() + .context(crate::error::FlushTerminal)? + { futures::Async::Ready(()) => { self.needs_flush = false; Ok(crate::component_future::Poll::DidWork) @@ -262,7 +240,7 @@ impl RecordSession { } }; - match file.poll_write().context(WriteFile)? { + match file.poll_write()? { futures::Async::Ready(()) => { Ok(crate::component_future::Poll::DidWork) } @@ -287,8 +265,7 @@ impl futures::future::Future for RecordSession { if self.raw_screen.is_none() { self.raw_screen = Some( crossterm::RawScreen::into_raw_mode() - .context(crate::error::IntoRawMode) - .context(Common)?, + .context(crate::error::ToRawMode)?, ); } crate::component_future::poll_future(self, Self::POLL_FNS) diff --git a/src/cmd/server.rs b/src/cmd/server.rs index a4ccc8f..07d9321 100644 --- a/src/cmd/server.rs +++ b/src/cmd/server.rs @@ -1,62 +1,6 @@ use crate::prelude::*; use std::io::Read as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("failed to bind: {}", source))] - Bind { source: tokio::io::Error }, - - #[snafu(display( - "failed to parse read timeout '{}': {}", - input, - source - ))] - ParseReadTimeout { - input: String, - source: std::num::ParseIntError, - }, - - #[snafu(display("failed to accept: {}", source))] - Acceptor { source: tokio::io::Error }, - - #[snafu(display( - "failed to send accepted socket to server thread: {}", - source - ))] - SocketChannel { - source: tokio::sync::mpsc::error::TrySendError<tokio::net::TcpStream>, - }, - - #[snafu(display("failed to send accepted socket to server thread"))] - TlsSocketChannel { - // XXX tokio_tls::Accept doesn't implement Debug or Display - // source: tokio::sync::mpsc::error::TrySendError<tokio_tls::Accept<tokio::net::TcpStream>>, - }, - - #[snafu(display("failed to run server: {}", source))] - Server { source: crate::server::Error }, - - #[snafu(display("failed to run server: {}", source))] - TlsServer { source: crate::server::tls::Error }, - - #[snafu(display("failed to open identity file: {}", source))] - OpenIdentityFile { source: std::io::Error }, - - #[snafu(display("failed to read identity file: {}", source))] - ReadIdentityFile { source: std::io::Error }, - - #[snafu(display("failed to parse identity file: {}", source))] - ParseIdentity { source: native_tls::Error }, - - #[snafu(display("failed to create tls acceptor: {}", source))] - CreateAcceptor { source: native_tls::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Run a teleterm server") .arg( @@ -84,12 +28,7 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { let address = matches.value_of("address").map_or_else( || Ok("0.0.0.0:4144".parse().unwrap()), - |s| { - s.parse() - .context(crate::error::ParseAddr) - .context(Common) - .context(super::Server) - }, + |s| s.parse().context(crate::error::ParseAddr), )?; let buffer_size = matches @@ -97,21 +36,17 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { .map_or(Ok(4 * 1024 * 1024), |s| { s.parse() .context(crate::error::ParseBufferSize { input: s }) - .context(Common) - .context(super::Server) })?; let read_timeout = matches.value_of("read-timeout").map_or( Ok(std::time::Duration::from_secs(120)), |s| { s.parse() .map(std::time::Duration::from_secs) - .context(ParseReadTimeout { input: s }) - .context(super::Server) + .context(crate::error::ParseReadTimeout { input: s }) }, )?; let tls_identity_file = matches.value_of("tls-identity-file"); run_impl(address, buffer_size, read_timeout, tls_identity_file) - .context(super::Server) } fn run_impl( @@ -152,14 +87,18 @@ fn create_server( Box<dyn futures::future::Future<Item = (), Error = Error> + Send>, )> { let (mut sock_w, sock_r) = tokio::sync::mpsc::channel(100); - let listener = tokio::net::TcpListener::bind(&address).context(Bind)?; + let listener = tokio::net::TcpListener::bind(&address) + .context(crate::error::Bind)?; let acceptor = listener .incoming() - .context(Acceptor) - .for_each(move |sock| sock_w.try_send(sock).context(SocketChannel)); + .context(crate::error::Acceptor) + .for_each(move |sock| { + sock_w + .try_send(sock) + .context(crate::error::SendSocketChannel) + }); let server = - crate::server::Server::new(buffer_size, read_timeout, sock_r) - .context(Server); + crate::server::Server::new(buffer_size, read_timeout, sock_r); Ok((Box::new(acceptor), Box::new(server))) } @@ -173,27 +112,30 @@ fn create_server_tls( Box<dyn futures::future::Future<Item = (), Error = Error> + Send>, )> { let (mut sock_w, sock_r) = tokio::sync::mpsc::channel(100); - let listener = tokio::net::TcpListener::bind(&address).context(Bind)?; + let listener = tokio::net::TcpListener::bind(&address) + .context(crate::error::Bind)?; - let mut file = - std::fs::File::open(tls_identity_file).context(OpenIdentityFile)?; + let mut file = std::fs::File::open(tls_identity_file) + .context(crate::error::OpenIdentityFile)?; let mut identity = vec![]; - file.read_to_end(&mut identity).context(ReadIdentityFile)?; + file.read_to_end(&mut identity) + .context(crate::error::ReadIdentityFile)?; let identity = native_tls::Identity::from_pkcs12(&identity, "") - .context(ParseIdentity)?; - let acceptor = - native_tls::TlsAcceptor::new(identity).context(CreateAcceptor)?; + .context(crate::error::ParseIdentity)?; + let acceptor = native_tls::TlsAcceptor::new(identity) + .context(crate::error::CreateAcceptor)?; let acceptor = tokio_tls::TlsAcceptor::from(acceptor); - let acceptor = - listener.incoming().context(Acceptor).for_each(move |sock| { + let acceptor = listener + .incoming() + .context(crate::error::Acceptor) + .for_each(move |sock| { let sock = acceptor.accept(sock); sock_w .try_send(sock) - .map_err(|_| Error::TlsSocketChannel {}) + .map_err(|_| Error::SendSocketChannelTls {}) }); let server = - crate::server::tls::Server::new(buffer_size, read_timeout, sock_r) - .context(TlsServer); + crate::server::tls::Server::new(buffer_size, read_timeout, sock_r); Ok((Box::new(acceptor), Box::new(server))) } diff --git a/src/cmd/stream.rs b/src/cmd/stream.rs index b14c063..dac3d2c 100644 --- a/src/cmd/stream.rs +++ b/src/cmd/stream.rs @@ -1,32 +1,6 @@ use crate::prelude::*; use tokio::io::AsyncWrite as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("{}", source))] - Util { source: crate::util::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - WriteTerminal { source: tokio::io::Error }, - - #[snafu(display("failed to write to stdout: {}", source))] - FlushTerminal { source: tokio::io::Error }, - - #[snafu(display("process failed: {}", source))] - Process { source: crate::process::Error }, - - #[snafu(display("communication with server failed: {}", source))] - Client { source: crate::client::Error }, - - #[snafu(display("failed to create tls connector: {}", source))] - CreateConnector { source: native_tls::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Stream your terminal") .arg( @@ -54,13 +28,9 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { .value_of("username") .map(std::string::ToString::to_string) .or_else(|| std::env::var("USER").ok()) - .context(crate::error::CouldntFindUsername) - .context(Common) - .context(super::Stream)?; + .context(crate::error::CouldntFindUsername)?; let (host, address) = - crate::util::resolve_address(matches.value_of("address")) - .context(Util) - .context(super::Stream)?; + crate::util::resolve_address(matches.value_of("address"))?; let tls = matches.is_present("tls"); let buffer_size = matches @@ -68,8 +38,6 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { .map_or(Ok(4 * 1024 * 1024), |s| { s.parse() .context(crate::error::ParseBufferSize { input: s }) - .context(Common) - .context(super::Stream) })?; let command = matches.value_of("command").map_or_else( || std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()), @@ -81,7 +49,6 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { vec![] }; run_impl(&username, &host, address, tls, buffer_size, &command, &args) - .context(super::Stream) } fn run_impl( @@ -97,8 +64,8 @@ fn run_impl( let fut: Box< dyn futures::future::Future<Item = (), Error = Error> + Send, > = if tls { - let connector = - native_tls::TlsConnector::new().context(CreateConnector)?; + let connector = native_tls::TlsConnector::new() + .context(crate::error::CreateConnector)?; let connect: crate::client::Connector<_> = Box::new(move || { let host = host.clone(); let connector = connector.clone(); @@ -108,7 +75,7 @@ fn run_impl( move |stream| { connector .connect(&host, stream) - .context(crate::error::TlsConnect) + .context(crate::error::ConnectTls) }, )) }); @@ -223,7 +190,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> fn poll_read_client( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.client.poll().context(Client) { + match self.client.poll() { Ok(futures::Async::Ready(Some(e))) => match e { crate::client::Event::Disconnect => { Ok(crate::component_future::Poll::DidWork) @@ -262,7 +229,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> fn poll_read_process( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.process.poll().context(Process)? { + match self.process.poll()? { futures::Async::Ready(Some(e)) => { match e { crate::process::Event::CommandStart(..) => {} @@ -299,7 +266,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> match self .stdout .poll_write(&self.buffer.contents()[self.sent_local..]) - .context(WriteTerminal)? + .context(crate::error::WriteTerminal)? { futures::Async::Ready(n) => { self.sent_local += n; @@ -319,7 +286,11 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> return Ok(crate::component_future::Poll::NothingToDo); } - match self.stdout.poll_flush().context(FlushTerminal)? { + match self + .stdout + .poll_flush() + .context(crate::error::FlushTerminal)? + { futures::Async::Ready(()) => { self.needs_flush = false; Ok(crate::component_future::Poll::DidWork) @@ -362,8 +333,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> if self.raw_screen.is_none() { self.raw_screen = Some( crossterm::RawScreen::into_raw_mode() - .context(crate::error::IntoRawMode) - .context(Common)?, + .context(crate::error::ToRawMode)?, ); } crate::component_future::poll_future(self, Self::POLL_FNS) diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 6b395e2..3129bba 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -1,44 +1,6 @@ use crate::prelude::*; use std::io::Write as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("{}", source))] - Util { source: crate::util::Error }, - - #[snafu(display("{}", source))] - Resize { source: crate::term::Error }, - - #[snafu(display("failed to read key from terminal: {}", source))] - ReadKey { source: crate::key_reader::Error }, - - #[snafu(display("failed to write to terminal: {}", source))] - WriteTerminal { source: std::io::Error }, - - #[snafu(display("failed to write to terminal: {}", source))] - WriteTerminalCrossterm { source: crossterm::ErrorKind }, - - #[snafu(display("failed to flush writes to terminal: {}", source))] - FlushTerminal { source: std::io::Error }, - - #[snafu(display("communication with server failed: {}", source))] - Client { source: crate::client::Error }, - - #[snafu(display("received error from server: {}", message))] - Server { message: String }, - - #[snafu(display("failed to switch to alternate screen: {}", source))] - ToAlternateScreen { source: crossterm::ErrorKind }, - - #[snafu(display("failed to create tls connector: {}", source))] - CreateConnector { source: native_tls::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Watch teleterm streams") .arg( @@ -59,15 +21,11 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> { .value_of("username") .map(std::string::ToString::to_string) .or_else(|| std::env::var("USER").ok()) - .context(crate::error::CouldntFindUsername) - .context(Common) - .context(super::Watch)?; + .context(crate::error::CouldntFindUsername)?; let (host, address) = - crate::util::resolve_address(matches.value_of("address")) - .context(Util) - .context(super::Watch)?; + crate::util::resolve_address(matches.value_of("address"))?; let tls = matches.is_present("tls"); - run_impl(&username, &host, address, tls).context(super::Watch) + run_impl(&username, &host, address, tls) } fn run_impl( @@ -81,8 +39,8 @@ fn run_impl( let fut: Box< dyn futures::future::Future<Item = (), Error = Error> + Send, > = if tls { - let connector = - native_tls::TlsConnector::new().context(CreateConnector)?; + let connector = native_tls::TlsConnector::new() + .context(crate::error::CreateConnector)?; let make_connector: Box< dyn Fn() -> crate::client::Connector<_> + Send, > = Box::new(move || { @@ -97,7 +55,7 @@ fn run_impl( move |stream| { connector .connect(&host, stream) - .context(crate::error::TlsConnect) + .context(crate::error::ConnectTls) }, )) }) @@ -273,7 +231,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> self.state.choosing( crate::session_list::SessionList::new( sessions, - crate::term::Size::get().context(Resize)?, + crate::term::Size::get()?, ), )?; self.needs_redraw = true; @@ -287,8 +245,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> msg => { return Err(crate::error::Error::UnexpectedMessage { message: msg, - }) - .context(Common); + }); } } Ok(()) @@ -337,7 +294,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> self.state.watching(client); crossterm::terminal() .clear(crossterm::ClearType::All) - .context(WriteTerminalCrossterm)?; + .context(crate::error::WriteTerminalCrossterm)?; } } _ => {} @@ -367,8 +324,8 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> // TODO async let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - stdout.write(&data).context(WriteTerminal)?; - stdout.flush().context(FlushTerminal)?; + stdout.write(&data).context(crate::error::WriteTerminal)?; + stdout.flush().context(crate::error::FlushTerminal)?; } crate::protocol::Message::Disconnected => { self.reconnect(true)?; @@ -379,8 +336,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> msg => { return Err(crate::error::Error::UnexpectedMessage { message: msg, - }) - .context(Common); + }); } } Ok(()) @@ -424,12 +380,12 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> fn display_loading_screen(&self) -> Result<()> { crossterm::terminal() .clear(crossterm::ClearType::All) - .context(WriteTerminalCrossterm)?; + .context(crate::error::WriteTerminalCrossterm)?; let data = b"loading...\r\nq: quit --> "; let stdout = std::io::stdout(); let mut stdout = stdout.lock(); - stdout.write(data).context(WriteTerminal)?; - stdout.flush().context(FlushTerminal)?; + stdout.write(data).context(crate::error::WriteTerminal)?; + stdout.flush().context(crate::error::FlushTerminal)?; Ok(()) } @@ -482,7 +438,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> crossterm::terminal() .clear(crossterm::ClearType::All) - .context(WriteTerminalCrossterm)?; + .context(crate::error::WriteTerminalCrossterm)?; println!("welcome to teleterm\r"); println!("available sessions:\r"); println!("\r"); @@ -549,7 +505,9 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> sessions.current_page(), sessions.total_pages(), ); - std::io::stdout().flush().context(FlushTerminal)?; + std::io::stdout() + .flush() + .context(crate::error::FlushTerminal)?; Ok(()) } @@ -569,7 +527,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> ]; fn poll_input(&mut self) -> Result<crate::component_future::Poll<()>> { - match self.key_reader.poll().context(ReadKey)? { + match self.key_reader.poll()? { futures::Async::Ready(Some(e)) => { let quit = match &mut self.state { State::Temporary => unreachable!(), @@ -593,7 +551,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> fn poll_list_client( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.list_client.poll().context(Client)? { + match self.list_client.poll()? { futures::Async::Ready(Some(e)) => { match e { crate::client::Event::Disconnect => { @@ -632,7 +590,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> return Ok(crate::component_future::Poll::NothingToDo); }; - match client.poll().context(Client)? { + match client.poll()? { futures::Async::Ready(Some(e)) => { match e { crate::client::Event::Disconnect => { @@ -676,8 +634,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> if self.raw_screen.is_none() { self.raw_screen = Some( crossterm::RawScreen::into_raw_mode() - .context(crate::error::IntoRawMode) - .context(Common)?, + .context(crate::error::ToRawMode)?, ); } let res = crate::component_future::poll_future(self, Self::POLL_FNS); @@ -693,7 +650,8 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> } fn new_alternate_screen() -> Result<crossterm::AlternateScreen> { - crossterm::AlternateScreen::to_alternate(false).context(ToAlternateScreen) + crossterm::AlternateScreen::to_alternate(false) + .context(crate::error::ToAlternateScreen) } fn format_time(dur: u32) -> String { diff --git a/src/error.rs b/src/error.rs index 4b7a526..42135d8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,30 +1,275 @@ #[derive(Debug, snafu::Snafu)] #[snafu(visibility = "pub")] pub enum Error { + #[snafu(display("failed to accept: {}", source))] + Acceptor { source: tokio::io::Error }, + + #[snafu(display("failed to bind: {}", source))] + Bind { source: tokio::io::Error }, + #[snafu(display("failed to connect: {}", source))] Connect { source: std::io::Error }, #[snafu(display("failed to connect: {}", source))] - TlsConnect { source: native_tls::Error }, + ConnectTls { source: native_tls::Error }, #[snafu(display("couldn't find username"))] CouldntFindUsername, + #[snafu(display("failed to create tls acceptor: {}", source))] + CreateAcceptor { source: native_tls::Error }, + + #[snafu(display("failed to create tls connector: {}", source))] + CreateConnector { source: native_tls::Error }, + + #[snafu(display("eof"))] + EOF, + + #[snafu(display("failed to parse string: {:?}", data))] + ExtraMessageData { data: Vec<u8> }, + + #[snafu(display("failed to write to stdout: {}", source))] + FlushTerminal { source: tokio::io::Error }, + + #[snafu(display("failed to flush writes to terminal: {}", source))] + FlushTerminalSync { source: std::io::Error }, + + #[snafu(display("failed to get terminal size: {}", source))] + GetTerminalSize { source: crossterm::ErrorKind }, + + #[snafu(display("failed to find any resolved addresses"))] + HasResolvedAddr, + + #[snafu(display("invalid auth type: {}", ty))] + InvalidAuthType { ty: u32 }, + + #[snafu(display("invalid message type: {}", ty))] + InvalidMessageType { ty: u32 }, + + #[snafu(display("invalid watch id: {}", id))] + InvalidWatchId { id: String }, + #[snafu(display( - "failed to put the terminal into raw mode: {}", - source + "packet length must be at least {} bytes (got {})", + expected, + len ))] - IntoRawMode { source: crossterm::ErrorKind }, + LenTooSmall { len: u32, expected: usize }, + + #[snafu(display( + "packet length must be at most {} bytes (got {})", + expected, + len + ))] + LenTooBig { len: u32, expected: usize }, + + #[snafu(display("couldn't find name in argv"))] + MissingArgv, + + #[snafu(display( + "detected argv path was not a valid filename: {}", + path + ))] + NotAFileName { path: String }, + + #[snafu(display("failed to open file: {}", source))] + OpenFile { source: tokio::io::Error }, + + #[snafu(display("failed to open identity file: {}", source))] + OpenIdentityFile { source: std::io::Error }, + + #[snafu(display("failed to open a pty: {}", source))] + OpenPty { source: std::io::Error }, + + #[snafu(display("failed to parse address"))] + ParseAddress, #[snafu(display("failed to parse address: {}", source))] ParseAddr { source: std::net::AddrParseError }, + #[snafu(display("{}", source))] + ParseArgs { source: clap::Error }, + #[snafu(display("failed to parse buffer size '{}': {}", input, source))] ParseBufferSize { input: String, source: std::num::ParseIntError, }, + #[snafu(display("failed to parse identity file: {}", source))] + ParseIdentity { source: native_tls::Error }, + + #[snafu(display("failed to parse int: {}", source))] + ParseInt { + source: std::array::TryFromSliceError, + }, + + #[snafu(display("failed to parse address: {}", source))] + ParsePort { source: std::num::ParseIntError }, + + #[snafu(display( + "failed to parse read timeout '{}': {}", + input, + source + ))] + ParseReadTimeout { + input: String, + source: std::num::ParseIntError, + }, + + #[snafu(display("failed to parse string: {}", source))] + ParseString { source: std::string::FromUtf8Error }, + + #[snafu(display("failed to poll for process exit: {}", source))] + ProcessExitPoll { source: std::io::Error }, + + #[snafu(display("rate limit exceeded"))] + RateLimited, + + #[snafu(display("failed to read from event channel: {}", source))] + ReadChannel { + source: tokio::sync::mpsc::error::UnboundedRecvError, + }, + + #[snafu(display("failed to read from file: {}", source))] + ReadFile { source: tokio::io::Error }, + + #[snafu(display("failed to read identity file: {}", source))] + ReadIdentityFile { source: std::io::Error }, + + #[snafu(display("{}", source))] + ReadMessageWithTimeout { + #[snafu(source(from(tokio::timer::timeout::Error<Error>, Box::new)))] + source: Box<tokio::timer::timeout::Error<Error>>, + }, + + #[snafu(display("failed to read packet: {}", source))] + ReadPacket { source: std::io::Error }, + + #[snafu(display("failed to read packet: {}", source))] + ReadPacketAsync { source: tokio::io::Error }, + + #[snafu(display("failed to read from pty: {}", source))] + ReadPty { source: std::io::Error }, + + #[snafu(display("failed to read from terminal: {}", source))] + ReadTerminal { source: std::io::Error }, + + #[snafu(display("failed to resize pty: {}", source))] + ResizePty { source: std::io::Error }, + + #[snafu(display("failed to resolve address: {}", source))] + ResolveAddress { source: std::io::Error }, + + #[snafu(display( + "failed to send accepted socket to server thread: {}", + source + ))] + SendSocketChannel { + source: tokio::sync::mpsc::error::TrySendError<tokio::net::TcpStream>, + }, + + #[snafu(display("failed to send accepted socket to server thread"))] + SendSocketChannelTls { + // XXX tokio_tls::Accept doesn't implement Debug or Display + // source: tokio::sync::mpsc::error::TrySendError<tokio_tls::Accept<tokio::net::TcpStream>>, + }, + + #[snafu(display("received error from server: {}", message))] + Server { message: String }, + + #[snafu(display("SIGWINCH handler failed: {}", source))] + SigWinchHandler { source: std::io::Error }, + + #[snafu(display("failed to sleep until next frame: {}", source))] + Sleep { source: tokio::timer::Error }, + + #[snafu(display( + "failed to receive new socket over channel: channel closed" + ))] + SocketChannelClosed, + + #[snafu(display( + "failed to receive new socket over channel: {}", + source + ))] + SocketChannelReceive { + source: tokio::sync::mpsc::error::RecvError, + }, + + #[snafu(display("failed to spawn process for `{}`: {}", cmd, source))] + SpawnProcess { cmd: String, source: std::io::Error }, + + #[snafu(display( + "failed to spawn a background thread to read terminal input: {}", + source + ))] + TerminalInputReadingThread { source: std::io::Error }, + + #[snafu(display( + "terminal must be smaller than 1000 rows or columns (got {})", + size + ))] + TermTooBig { size: crate::term::Size }, + + #[snafu(display("timeout"))] + Timeout, + + #[snafu(display("heartbeat timer failed: {}", source))] + TimerHeartbeat { source: tokio::timer::Error }, + + #[snafu(display("read timeout timer failed: {}", source))] + TimerReadTimeout { source: tokio::timer::Error }, + + #[snafu(display("reconnect timer failed: {}", source))] + TimerReconnect { source: tokio::timer::Error }, + + #[snafu(display("failed to switch to alternate screen: {}", source))] + ToAlternateScreen { source: crossterm::ErrorKind }, + + #[snafu(display( + "failed to put the terminal into raw mode: {}", + source + ))] + ToRawMode { source: crossterm::ErrorKind }, + + #[snafu(display("unauthenticated message: {:?}", message))] + UnauthenticatedMessage { message: crate::protocol::Message }, + #[snafu(display("unexpected message: {:?}", message))] UnexpectedMessage { message: crate::protocol::Message }, + + #[snafu(display("failed to write to event channel: {}", source))] + WriteChannel { + source: tokio::sync::mpsc::error::UnboundedSendError, + }, + + #[snafu(display("failed to write to file: {}", source))] + WriteFile { source: tokio::io::Error }, + + #[snafu(display("{}", source))] + WriteMessageWithTimeout { + #[snafu(source(from(tokio::timer::timeout::Error<Error>, Box::new)))] + source: Box<tokio::timer::timeout::Error<Error>>, + }, + + #[snafu(display("failed to write packet: {}", source))] + WritePacket { source: std::io::Error }, + + #[snafu(display("failed to write packet: {}", source))] + WritePacketAsync { source: tokio::io::Error }, + + #[snafu(display("failed to write to pty: {}", source))] + WritePty { source: std::io::Error }, + + #[snafu(display("failed to write to stdout: {}", source))] + WriteTerminal { source: tokio::io::Error }, + + #[snafu(display("failed to write to terminal: {}", source))] + WriteTerminalCrossterm { source: crossterm::ErrorKind }, + + #[snafu(display("failed to write to terminal: {}", source))] + WriteTerminalSync { source: std::io::Error }, } + +pub type Result<T> = std::result::Result<T, Error>; diff --git a/src/key_reader.rs b/src/key_reader.rs index 8933667..1e1251a 100644 --- a/src/key_reader.rs +++ b/src/key_reader.rs @@ -1,22 +1,5 @@ use crate::prelude::*; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display( - "failed to spawn a background thread to read terminal input: {}", - source - ))] - TerminalInputReadingThread { source: std::io::Error }, - - #[snafu(display("failed to read from event channel: {}", source))] - ReadChannel { - source: tokio::sync::mpsc::error::UnboundedRecvError, - }, -} - -#[allow(dead_code)] -pub type Result<T> = std::result::Result<T, Error>; - pub struct KeyReader { events: Option<tokio::sync::mpsc::UnboundedReceiver<crossterm::InputEvent>>, @@ -58,13 +41,17 @@ impl futures::stream::Stream for KeyReader { } } }) - .context(TerminalInputReadingThread)?; + .context(crate::error::TerminalInputReadingThread)?; self.events = Some(events_rx); self.quit = Some(quit_tx); } - self.events.as_mut().unwrap().poll().context(ReadChannel) + self.events + .as_mut() + .unwrap() + .poll() + .context(crate::error::ReadChannel) } } diff --git a/src/prelude.rs b/src/prelude.rs index 762632d..05ebbe3 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,3 +4,5 @@ pub use futures::stream::Stream as _; pub use snafu::futures01::stream::StreamExt as _; pub use snafu::futures01::FutureExt as _; pub use snafu::{OptionExt as _, ResultExt as _}; + +pub use crate::error::{Error, Result}; diff --git a/src/process.rs b/src/process.rs index 7f19df6..3756837 100644 --- a/src/process.rs +++ b/src/process.rs @@ -3,32 +3,6 @@ use std::os::unix::io::AsRawFd as _; use tokio::io::{AsyncRead as _, AsyncWrite as _}; use tokio_pty_process::CommandExt as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Resize { source: crate::term::Error }, - - #[snafu(display("failed to open a pty: {}", source))] - OpenPty { source: std::io::Error }, - - #[snafu(display("failed to spawn process for `{}`: {}", cmd, source))] - SpawnProcess { cmd: String, source: std::io::Error }, - - #[snafu(display("failed to read from pty: {}", source))] - ReadFromPty { source: std::io::Error }, - - #[snafu(display("failed to write to pty: {}", source))] - WriteToPty { source: std::io::Error }, - - #[snafu(display("failed to read from terminal: {}", source))] - ReadFromTerminal { source: std::io::Error }, - - #[snafu(display("failed to poll for process exit: {}", source))] - ProcessExitPoll { source: std::io::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - const READ_BUFFER_SIZE: usize = 4 * 1024; #[derive(Debug, PartialEq, Eq)] @@ -121,7 +95,7 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { &mut self, ) -> Result<crate::component_future::Poll<Event>> { if let Some(size) = &self.needs_resize { - match size.resize_pty(self.state.pty()).context(Resize)? { + match size.resize_pty(self.state.pty())? { futures::Async::Ready(()) => { log::debug!("resize({:?})", size); self.needs_resize = None; @@ -160,7 +134,7 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { match self .input .poll_read(&mut self.buf) - .context(ReadFromTerminal)? + .context(crate::error::ReadTerminal)? { futures::Async::Ready(n) => { log::debug!("read_stdin({})", n); @@ -187,7 +161,12 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { let (a, b) = self.input_buf.as_slices(); let buf = if a.is_empty() { b } else { a }; - match self.state.pty_mut().poll_write(buf).context(WriteToPty)? { + match self + .state + .pty_mut() + .poll_write(buf) + .context(crate::error::WritePty)? + { futures::Async::Ready(n) => { log::debug!("write_stdin({})", n); for _ in 0..n { @@ -208,7 +187,7 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { .state .pty_mut() .poll_read(&mut self.buf) - .context(ReadFromPty) + .context(crate::error::ReadPty) { Ok(futures::Async::Ready(n)) => { log::debug!("read_stdout({})", n); @@ -221,7 +200,7 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { Err(e) => { // XXX this seems to be how eof is returned, but this seems... // wrong? i feel like there has to be a better way to do this - if let Error::ReadFromPty { source } = &e { + if let Error::ReadPty { source } = &e { if source.kind() == std::io::ErrorKind::Other { log::debug!("read_stdout(eof)"); self.stdout_closed = true; @@ -243,7 +222,12 @@ impl<R: tokio::io::AsyncRead + 'static> Process<R> { return Ok(crate::component_future::Poll::NothingToDo); } - match self.state.process().poll().context(ProcessExitPoll)? { + match self + .state + .process() + .poll() + .context(crate::error::ProcessExitPoll)? + { futures::Async::Ready(status) => { log::debug!("exit({})", status); self.exited = true; @@ -268,7 +252,8 @@ impl<R: tokio::io::AsyncRead + 'static> futures::stream::Stream fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> { if self.state.pty.is_none() { self.state.pty = Some( - tokio_pty_process::AsyncPtyMaster::open().context(OpenPty)?, + tokio_pty_process::AsyncPtyMaster::open() + .context(crate::error::OpenPty)?, ); log::debug!( "openpty({})", @@ -280,7 +265,7 @@ impl<R: tokio::io::AsyncRead + 'static> futures::stream::Stream std::process::Command::new(&self.cmd) .args(&self.args) .spawn_pty_async(self.state.pty()) - .context(SpawnProcess { + .context(crate::error::SpawnProcess { cmd: self.cmd.clone(), })?, ); diff --git a/src/protocol.rs b/src/protocol.rs index fb1b91f..ee9eb04 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,57 +1,6 @@ use crate::prelude::*; use std::convert::{TryFrom as _, TryInto as _}; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("failed to read packet: {}", source))] - Read { source: std::io::Error }, - - #[snafu(display("failed to read packet: {}", source))] - ReadAsync { source: tokio::io::Error }, - - #[snafu(display("failed to write packet: {}", source))] - Write { source: std::io::Error }, - - #[snafu(display("failed to write packet: {}", source))] - WriteAsync { source: tokio::io::Error }, - - #[snafu(display("failed to parse string: {}", source))] - ParseString { source: std::string::FromUtf8Error }, - - #[snafu(display("failed to parse int: {}", source))] - ParseInt { - source: std::array::TryFromSliceError, - }, - - #[snafu(display( - "packet length must be at least {} bytes (got {})", - expected, - len - ))] - LenTooSmall { len: u32, expected: usize }, - - #[snafu(display( - "packet length must be at most {} bytes (got {})", - expected, - len - ))] - LenTooBig { len: u32, expected: usize }, - - #[snafu(display("failed to parse string: {:?}", data))] - ExtraMessageData { data: Vec<u8> }, - - #[snafu(display("invalid message type: {}", ty))] - InvalidMessageType { ty: u32 }, - - #[snafu(display("invalid auth type: {}", ty))] - InvalidAuthType { ty: u32 }, - - #[snafu(display("eof"))] - EOF, -} - -pub type Result<T> = std::result::Result<T, Error>; - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Session { pub id: String, @@ -261,7 +210,8 @@ struct Packet { impl Packet { fn read<R: std::io::Read>(mut r: R) -> Result<Self> { let mut len_buf = [0_u8; std::mem::size_of::<u32>()]; - r.read_exact(&mut len_buf).context(Read)?; + r.read_exact(&mut len_buf) + .context(crate::error::ReadPacket)?; let len = u32::from_be_bytes(len_buf.try_into().unwrap()); if (len as usize) < std::mem::size_of::<u32>() { return Err(Error::LenTooSmall { @@ -271,7 +221,7 @@ impl Packet { } let mut data = vec![0_u8; len as usize]; - r.read_exact(&mut data).context(Read)?; + r.read_exact(&mut data).context(crate::error::ReadPacket)?; let (ty_buf, rest) = data.split_at(std::mem::size_of::<u32>()); let ty = u32::from_be_bytes(ty_buf.try_into().unwrap()); @@ -286,7 +236,7 @@ impl Packet { ) -> impl futures::future::Future<Item = (Self, FramedReader<T>), Error = Error> { r.0.into_future() - .map_err(|(e, _)| Error::ReadAsync { source: e }) + .map_err(|(e, _)| Error::ReadPacketAsync { source: e }) .and_then(|(data, r)| match data { Some(data) => Ok((data, r)), None => Err(Error::EOF), @@ -312,7 +262,7 @@ impl Packet { let len_buf = len.to_be_bytes(); let buf: Vec<u8> = len_buf.iter().chain(bytes.iter()).copied().collect(); - Ok(w.write_all(&buf).context(Write)?) + Ok(w.write_all(&buf).context(crate::error::WritePacket)?) } fn write_async<T: tokio::io::AsyncWrite>( @@ -322,7 +272,7 @@ impl Packet { { w.0.send(bytes::Bytes::from(self.as_bytes())) .map(FramedWriter) - .context(WriteAsync) + .context(crate::error::WritePacketAsync) } fn as_bytes(&self) -> Vec<u8> { @@ -481,7 +431,9 @@ impl std::convert::TryFrom<Packet> for Message { }); } let (buf, rest) = data.split_at(std::mem::size_of::<u32>()); - let val = u32::from_be_bytes(buf.try_into().context(ParseInt)?); + let val = u32::from_be_bytes( + buf.try_into().context(crate::error::ParseInt)?, + ); Ok((val, rest)) } fn read_u16(data: &[u8]) -> Result<(u16, &[u8])> { @@ -492,7 +444,9 @@ impl std::convert::TryFrom<Packet> for Message { }); } let (buf, rest) = data.split_at(std::mem::size_of::<u16>()); - let val = u16::from_be_bytes(buf.try_into().context(ParseInt)?); + let val = u16::from_be_bytes( + buf.try_into().context(crate::error::ParseInt)?, + ); Ok((val, rest)) } fn read_bytes(data: &[u8]) -> Result<(Vec<u8>, &[u8])> { @@ -509,7 +463,8 @@ impl std::convert::TryFrom<Packet> for Message { } fn read_str(data: &[u8]) -> Result<(String, &[u8])> { let (bytes, rest) = read_bytes(data)?; - let val = String::from_utf8(bytes).context(ParseString)?; + let val = String::from_utf8(bytes) + .context(crate::error::ParseString)?; Ok((val, rest)) } fn read_size(data: &[u8]) -> Result<(crate::term::Size, &[u8])> { diff --git a/src/server.rs b/src/server.rs index aac968a..8f7ea1c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,64 +3,6 @@ use tokio::util::FutureExt as _; pub mod tls; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display( - "failed to receive new socket over channel: {}", - source - ))] - SocketChannelReceive { - source: tokio::sync::mpsc::error::RecvError, - }, - - #[snafu(display( - "failed to receive new socket over channel: channel closed" - ))] - SocketChannelClosed, - - #[snafu(display("failed to read message: {}", source))] - ReadMessageWithTimeout { - source: tokio::timer::timeout::Error<crate::protocol::Error>, - }, - - #[snafu(display("failed to read message: {}", source))] - ReadMessage { source: crate::protocol::Error }, - - #[snafu(display("failed to write message: {}", source))] - WriteMessageWithTimeout { - source: tokio::timer::timeout::Error<crate::protocol::Error>, - }, - - #[snafu(display("failed to write message: {}", source))] - WriteMessage { source: crate::protocol::Error }, - - #[snafu(display("unauthenticated message: {:?}", message))] - UnauthenticatedMessage { message: crate::protocol::Message }, - - #[snafu(display( - "terminal must be smaller than 1000 rows or columns (got {})", - size - ))] - TermTooBig { size: crate::term::Size }, - - #[snafu(display("invalid watch id: {}", id))] - InvalidWatchId { id: String }, - - #[snafu(display("rate limit exceeded"))] - RateLimited, - - #[snafu(display("timeout"))] - Timeout, - - #[snafu(display("read timeout timer failed: {}", source))] - Timer { source: tokio::timer::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - enum ReadSocket< S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static, > { @@ -290,7 +232,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> ) -> Self { let sock_stream = sock_r .map(move |s| Connection::new(s, buffer_size)) - .context(SocketChannelReceive); + .context(crate::error::SocketChannelReceive); Self { buffer_size, read_timeout, @@ -390,8 +332,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> Err(Error::InvalidWatchId { id }) } } - m => Err(crate::error::Error::UnexpectedMessage { message: m }) - .context(Common), + m => Err(crate::error::Error::UnexpectedMessage { message: m }), } } @@ -440,8 +381,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> conn.last_activity = std::time::Instant::now(); Ok(()) } - m => Err(crate::error::Error::UnexpectedMessage { message: m }) - .context(Common), + m => Err(crate::error::Error::UnexpectedMessage { message: m }), } } @@ -469,8 +409,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> term_info.size = size; Ok(()) } - m => Err(crate::error::Error::UnexpectedMessage { message: m }) - .context(Common), + m => Err(crate::error::Error::UnexpectedMessage { message: m }), } } @@ -540,7 +479,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> let fut = Box::new( crate::protocol::Message::read_async(s) .timeout(self.read_timeout) - .context(ReadMessageWithTimeout), + .context(crate::error::ReadMessageWithTimeout), ); conn.rsock = Some(ReadSocket::Reading(fut)); } else { @@ -565,7 +504,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> if source.is_inner() { let source = source.into_inner().unwrap(); match source { - crate::protocol::Error::ReadAsync { + Error::ReadPacketAsync { source: ref tokio_err, } => { if tokio_err.kind() @@ -573,19 +512,19 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> { Ok(crate::component_future::Poll::Event(())) } else { - Err(Error::ReadMessage { source }) + Err(source) } } - crate::protocol::Error::EOF => Ok( + Error::EOF => Ok( crate::component_future::Poll::Event(()), ), - _ => Err(Error::ReadMessage { source }), + _ => Err(source), } } else if source.is_elapsed() { Err(Error::Timeout) } else { let source = source.into_timer().unwrap(); - Err(Error::Timer { source }) + Err(Error::TimerReadTimeout { source }) } } else { Err(e) @@ -608,7 +547,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> let fut = msg .write_async(s) .timeout(self.read_timeout) - .context(WriteMessageWithTimeout); + .context(crate::error::WriteMessageWithTimeout); conn.wsock = Some(WriteSocket::Writing(Box::new(fut))); } else { @@ -634,7 +573,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> if source.is_inner() { let source = source.into_inner().unwrap(); match source { - crate::protocol::Error::WriteAsync { + Error::WritePacketAsync { source: ref tokio_err, } => { if tokio_err.kind() @@ -644,19 +583,19 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static> (), )) } else { - Err(Error::WriteMessage { source }) + Err(source) } } - crate::protocol::Error::EOF => Ok( + Error::EOF => Ok( crate::component_future::Poll::Event(()), ), - _ => Err(Error::WriteMessage { source }), + _ => Err(source), } } else if source.is_elapsed() { Err(Error::Timeout) } else { let source = source.into_timer().unwrap(); - Err(Error::Timer { source }) + Err(Error::TimerReadTimeout { source }) } } else { Err(e) diff --git a/src/server/tls.rs b/src/server/tls.rs index 3ee2c8a..1edec77 100644 --- a/src/server/tls.rs +++ b/src/server/tls.rs @@ -1,29 +1,5 @@ use crate::prelude::*; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("{}", source))] - Common { source: crate::error::Error }, - - #[snafu(display("{}", source))] - InnerServer { source: super::Error }, - - #[snafu(display( - "failed to receive new socket over channel: {}", - source - ))] - SocketChannelReceive { - source: tokio::sync::mpsc::error::RecvError, - }, - - #[snafu(display( - "failed to receive new socket over channel: channel closed" - ))] - SocketChannelClosed, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub struct Server { server: super::Server<tokio_tls::TlsStream<tokio::net::TcpStream>>, sock_r: @@ -66,7 +42,11 @@ impl Server { fn poll_new_connections( &mut self, ) -> Result<crate::component_future::Poll<()>> { - match self.sock_r.poll().context(SocketChannelReceive)? { + match self + .sock_r + .poll() + .context(crate::error::SocketChannelReceive)? + { futures::Async::Ready(Some(sock)) => { self.accepting_sockets.push(sock); Ok(crate::component_future::Poll::DidWork) @@ -121,7 +101,7 @@ impl Server { } fn poll_server(&mut self) -> Result<crate::component_future::Poll<()>> { - match self.server.poll().context(InnerServer)? { + match self.server.poll()? { futures::Async::Ready(()) => { Ok(crate::component_future::Poll::DidWork) } diff --git a/src/term.rs b/src/term.rs index a804fff..1d3fec0 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,16 +1,5 @@ use crate::prelude::*; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("failed to get terminal size: {}", source))] - GetTerminalSize { source: crossterm::ErrorKind }, - - #[snafu(display("failed to resize pty: {}", source))] - ResizePty { source: std::io::Error }, -} - -pub type Result<T> = std::result::Result<T, Error>; - const RESET: &[&[u8]] = &[ b"\x1b[3J\x1b[H\x1b[2J", b"\x1b[H\x1b[J", @@ -28,8 +17,9 @@ pub struct Size { impl Size { pub fn get() -> Result<Self> { - let (cols, rows) = - crossterm::terminal().size().context(GetTerminalSize)?; + let (cols, rows) = crossterm::terminal() + .size() + .context(crate::error::GetTerminalSize)?; Ok(Self { rows, cols }) } @@ -37,7 +27,8 @@ impl Size { &self, pty: &T, ) -> futures::Poll<(), Error> { - pty.resize(self.rows, self.cols).context(ResizePty) + pty.resize(self.rows, self.cols) + .context(crate::error::ResizePty) } pub fn fits_in(&self, other: &Self) -> bool { diff --git a/src/ttyrec.rs b/src/ttyrec.rs index f9cde91..77b95bc 100644 --- a/src/ttyrec.rs +++ b/src/ttyrec.rs @@ -2,28 +2,6 @@ use crate::prelude::*; use std::convert::TryFrom as _; use tokio::io::{AsyncRead as _, AsyncWrite as _}; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("failed to read from event channel: {}", source))] - ReadChannel { - source: tokio::sync::mpsc::error::UnboundedRecvError, - }, - - #[snafu(display("failed to write to event channel: {}", source))] - WriteChannel { - source: tokio::sync::mpsc::error::UnboundedSendError, - }, - - #[snafu(display("failed to write to file: {}", source))] - WriteFile { source: tokio::io::Error }, - - #[snafu(display("failed to read from file: {}", source))] - ReadFile { source: tokio::io::Error }, -} - -#[allow(dead_code)] -pub type Result<T> = std::result::Result<T, Error>; - pub struct Frame { pub time: std::time::Instant, pub data: Vec<u8>, @@ -86,7 +64,7 @@ impl File { time: now, data: data.to_vec(), }) - .context(WriteChannel) + .context(crate::error::WriteChannel) } pub fn poll_write( @@ -94,7 +72,7 @@ impl File { ) -> std::result::Result<futures::Async<()>, Error> { loop { if self.writing.is_empty() { - match self.rframe.poll().context(ReadChannel)? { + match self.rframe.poll().context(crate::error::ReadChannel)? { futures::Async::Ready(Some(frame)) => { self.writing.extend( frame.as_bytes(self.base_time.unwrap()).iter(), @@ -110,7 +88,11 @@ impl File { let (a, b) = self.writing.as_slices(); let buf = if a.is_empty() { b } else { a }; - match self.file.poll_write(buf).context(WriteFile)? { + match self + .file + .poll_write(buf) + .context(crate::error::WriteFile)? + { futures::Async::Ready(n) => { for _ in 0..n { self.writing.pop_front(); @@ -131,7 +113,11 @@ impl File { return Ok(futures::Async::Ready(Some(frame))); } - match self.file.poll_read(&mut self.read_buf).context(ReadFile)? { + match self + .file + .poll_read(&mut self.read_buf) + .context(crate::error::ReadFile)? + { futures::Async::Ready(n) => { if n > 0 { self.reading.extend(self.read_buf[..n].iter()); diff --git a/src/util.rs b/src/util.rs index 23534c5..82bfb11 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,34 +1,9 @@ use crate::prelude::*; use std::net::ToSocketAddrs as _; -#[derive(Debug, snafu::Snafu)] -pub enum Error { - #[snafu(display("couldn't find name in argv"))] - MissingArgv, - - #[snafu(display( - "detected argv path was not a valid filename: {}", - path - ))] - NotAFileName { path: String }, - - #[snafu(display("failed to parse address"))] - ParseAddress, - - #[snafu(display("failed to parse address: {}", source))] - ParsePort { source: std::num::ParseIntError }, - - #[snafu(display("failed to resolve address: {}", source))] - ResolveAddress { source: std::io::Error }, - - #[snafu(display("failed to find any resolved addresses"))] - HasResolvedAddr, -} - -pub type Result<T> = std::result::Result<T, Error>; - pub fn program_name() -> Result<String> { - let program = std::env::args().next().context(MissingArgv)?; + let program = + std::env::args().next().context(crate::error::MissingArgv)?; let path = std::path::Path::new(&program); let filename = path.file_name(); Ok(filename @@ -44,13 +19,13 @@ pub fn resolve_address( ) -> Result<(String, std::net::SocketAddr)> { let address = address.unwrap_or("0.0.0.0:4144"); let mut address_parts = address.split(':'); - let host = address_parts.next().context(ParseAddress)?; - let port = address_parts.next().context(ParseAddress)?; - let port: u16 = port.parse().context(ParsePort)?; + let host = address_parts.next().context(crate::error::ParseAddress)?; + let port = address_parts.next().context(crate::error::ParseAddress)?; + let port: u16 = port.parse().context(crate::error::ParsePort)?; let socket_addr = (host, port) .to_socket_addrs() - .context(ResolveAddress)? + .context(crate::error::ResolveAddress)? .next() - .context(HasResolvedAddr)?; + .context(crate::error::HasResolvedAddr)?; Ok((host.to_string(), socket_addr)) } |