From 31535dfd1d36d255451fa8dd2785d03032d10ce3 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 19 Oct 2019 23:35:55 -0400 Subject: simplify config loading --- src/cmd/play.rs | 20 +--- src/cmd/record.rs | 55 ++------- src/cmd/server.rs | 94 ++------------- src/cmd/stream.rs | 127 +++++--------------- src/cmd/watch.rs | 83 ++++--------- src/config.rs | 340 +++++++++++++++++++++++++++++++++++++++++------------- 6 files changed, 339 insertions(+), 380 deletions(-) diff --git a/src/cmd/play.rs b/src/cmd/play.rs index 22bd220..7eae765 100644 --- a/src/cmd/play.rs +++ b/src/cmd/play.rs @@ -1,10 +1,9 @@ use crate::prelude::*; use std::io::Write as _; -#[derive(serde::Deserialize, Debug)] +#[derive(serde::Deserialize, Debug, Default)] pub struct Config { - #[serde(default = "crate::config::default_ttyrec_filename")] - filename: String, + ttyrec: crate::config::Ttyrec, } impl crate::config::Config for Config { @@ -12,14 +11,11 @@ impl crate::config::Config for Config { &mut self, matches: &clap::ArgMatches<'a>, ) -> Result<()> { - if matches.is_present("filename") { - self.filename = matches.value_of("filename").unwrap().to_string(); - } - Ok(()) + self.ttyrec.merge_args(matches) } fn run(&self) -> Result<()> { - let fut = PlaySession::new(&self.filename); + let fut = PlaySession::new(&self.ttyrec.filename); tokio::run(fut.map_err(|e| { eprintln!("{}", e); })); @@ -27,14 +23,6 @@ impl crate::config::Config for Config { } } -impl Default for Config { - fn default() -> Self { - Self { - filename: crate::config::default_ttyrec_filename(), - } - } -} - 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") diff --git a/src/cmd/record.rs b/src/cmd/record.rs index cf291b9..3e19ed8 100644 --- a/src/cmd/record.rs +++ b/src/cmd/record.rs @@ -1,19 +1,10 @@ use crate::prelude::*; use tokio::io::AsyncWrite as _; -#[derive(serde::Deserialize, Debug)] +#[derive(serde::Deserialize, Debug, Default)] pub struct Config { - #[serde(default = "crate::config::default_ttyrec_filename")] - filename: String, - - #[serde(default = "crate::config::default_connection_buffer_size")] - buffer_size: usize, - - #[serde(skip, default = "crate::config::default_command")] - command: String, - - #[serde(skip, default = "crate::config::default_args")] - args: Vec, + command: crate::config::Command, + ttyrec: crate::config::Ttyrec, } impl crate::config::Config for Config { @@ -21,34 +12,17 @@ impl crate::config::Config for Config { &mut self, matches: &clap::ArgMatches<'a>, ) -> Result<()> { - if matches.is_present("filename") { - self.filename = matches.value_of("filename").unwrap().to_string(); - } - if matches.is_present("buffer-size") { - let buffer_size = matches.value_of("buffer-size").unwrap(); - self.buffer_size = buffer_size.parse().context( - crate::error::ParseBufferSize { input: buffer_size }, - )?; - } - if matches.is_present("command") { - self.command = matches.value_of("command").unwrap().to_string(); - } - if matches.is_present("args") { - self.args = matches - .values_of("args") - .unwrap() - .map(std::string::ToString::to_string) - .collect(); - } + self.command.merge_args(matches)?; + self.ttyrec.merge_args(matches)?; Ok(()) } fn run(&self) -> Result<()> { let fut = RecordSession::new( - &self.filename, - self.buffer_size, - &self.command, - &self.args, + &self.ttyrec.filename, + self.command.buffer_size, + &self.command.command, + &self.command.args, ); tokio::run(fut.map_err(|e| { eprintln!("{}", e); @@ -57,17 +31,6 @@ impl crate::config::Config for Config { } } -impl Default for Config { - fn default() -> Self { - Self { - filename: crate::config::default_ttyrec_filename(), - buffer_size: crate::config::default_connection_buffer_size(), - command: crate::config::default_command(), - args: crate::config::default_args(), - } - } -} - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Record a terminal session to a file") .arg( diff --git a/src/cmd/server.rs b/src/cmd/server.rs index 858c6b8..ea238ba 100644 --- a/src/cmd/server.rs +++ b/src/cmd/server.rs @@ -1,32 +1,9 @@ use crate::prelude::*; -use std::convert::TryFrom as _; use std::io::Read as _; -#[derive(serde::Deserialize, Debug)] +#[derive(serde::Deserialize, Debug, Default)] pub struct Config { - #[serde( - deserialize_with = "crate::config::listen_address", - default = "crate::config::default_listen_address" - )] - listen_address: std::net::SocketAddr, - - #[serde(default = "crate::config::default_connection_buffer_size")] - buffer_size: usize, - - #[serde( - deserialize_with = "crate::config::read_timeout", - default = "crate::config::default_read_timeout" - )] - read_timeout: std::time::Duration, - - tls_identity_file: Option, - - #[serde( - deserialize_with = "crate::config::allowed_login_methods", - default = "crate::config::default_allowed_login_methods" - )] - allowed_login_methods: - std::collections::HashSet, + server: crate::config::Server, } impl crate::config::Config for Config { @@ -34,59 +11,25 @@ impl crate::config::Config for Config { &mut self, matches: &clap::ArgMatches<'a>, ) -> Result<()> { - if matches.is_present("address") { - self.listen_address = matches - .value_of("address") - .unwrap() - .parse() - .context(crate::error::ParseAddr)?; - } - if matches.is_present("buffer-size") { - let s = matches.value_of("buffer-size").unwrap(); - self.buffer_size = s - .parse() - .context(crate::error::ParseBufferSize { input: s })?; - } - if matches.is_present("read-timeout") { - let s = matches.value_of("read-timeout").unwrap(); - self.read_timeout = s - .parse() - .map(std::time::Duration::from_secs) - .context(crate::error::ParseReadTimeout { input: s })?; - } - if matches.is_present("tls-identity-file") { - self.tls_identity_file = Some( - matches.value_of("tls-identity-file").unwrap().to_string(), - ); - } - if matches.is_present("allowed-login-methods") { - self.allowed_login_methods = matches - .values_of("allowed-login-methods") - .unwrap() - .map(crate::protocol::AuthType::try_from) - .collect::, - >>()?; - } - Ok(()) + self.server.merge_args(matches) } fn run(&self) -> Result<()> { let (acceptor, server) = - if let Some(tls_identity_file) = &self.tls_identity_file { + if let Some(tls_identity_file) = &self.server.tls_identity_file { create_server_tls( - self.listen_address, - self.buffer_size, - self.read_timeout, + self.server.listen_address, + self.server.buffer_size, + self.server.read_timeout, tls_identity_file, - self.allowed_login_methods.clone(), + self.server.allowed_login_methods.clone(), )? } else { create_server( - self.listen_address, - self.buffer_size, - self.read_timeout, - self.allowed_login_methods.clone(), + self.server.listen_address, + self.server.buffer_size, + self.server.read_timeout, + self.server.allowed_login_methods.clone(), )? }; tokio::run(futures::future::lazy(move || { @@ -102,19 +45,6 @@ impl crate::config::Config for Config { } } -impl Default for Config { - fn default() -> Self { - Self { - listen_address: crate::config::default_listen_address(), - buffer_size: crate::config::default_connection_buffer_size(), - read_timeout: crate::config::default_read_timeout(), - tls_identity_file: None, - allowed_login_methods: - crate::config::default_allowed_login_methods(), - } - } -} - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Run a teleterm server") .arg( diff --git a/src/cmd/stream.rs b/src/cmd/stream.rs index 809e480..14f4fac 100644 --- a/src/cmd/stream.rs +++ b/src/cmd/stream.rs @@ -1,41 +1,10 @@ use crate::prelude::*; use tokio::io::AsyncWrite as _; -#[derive(serde::Deserialize, Debug)] +#[derive(serde::Deserialize, Debug, Default)] pub struct Config { - #[serde( - deserialize_with = "crate::config::auth", - default = "crate::config::default_auth" - )] - auth: crate::protocol::Auth, - - #[serde( - deserialize_with = "crate::config::connect_address", - default = "crate::config::default_connect_address" - )] - connect_address: (String, std::net::SocketAddr), - - #[serde(default = "crate::config::default_tls")] - tls: bool, - - #[serde(default = "crate::config::default_connection_buffer_size")] - buffer_size: usize, - - #[serde(skip, default = "crate::config::default_command")] - command: String, - - #[serde(skip, default = "crate::config::default_args")] - args: Vec, -} - -impl Config { - fn host(&self) -> &str { - &self.connect_address.0 - } - - fn addr(&self) -> &std::net::SocketAddr { - &self.connect_address.1 - } + client: crate::config::Client, + command: crate::config::Command, } impl crate::config::Config for Config { @@ -43,52 +12,33 @@ impl crate::config::Config for Config { &mut self, matches: &clap::ArgMatches<'a>, ) -> Result<()> { - if matches.is_present("login-recurse-center") { - let id = crate::oauth::load_client_auth_id( - crate::protocol::AuthType::RecurseCenter, - ); - self.auth = crate::protocol::Auth::recurse_center( - id.as_ref().map(std::string::String::as_str), - ); - } - if matches.is_present("login-plain") { - let username = - matches.value_of("login-plain").unwrap().to_string(); - self.auth = crate::protocol::Auth::plain(&username); - } - if matches.is_present("address") { - let address = matches.value_of("address").unwrap(); - self.connect_address = - crate::config::to_connect_address(address)?; - } - if matches.is_present("tls") { - self.tls = true; - } - if matches.is_present("buffer-size") { - let buffer_size = matches.value_of("buffer-size").unwrap(); - self.buffer_size = buffer_size.parse().context( - crate::error::ParseBufferSize { input: buffer_size }, - )?; - } - if matches.is_present("command") { - self.command = matches.value_of("command").unwrap().to_string(); - } - if matches.is_present("args") { - self.args = matches - .values_of("args") - .unwrap() - .map(std::string::ToString::to_string) - .collect(); - } + self.client.merge_args(matches)?; + self.command.merge_args(matches)?; Ok(()) } fn run(&self) -> Result<()> { - let host = self.host().to_string(); - let address = *self.addr(); + let host = self.client.host().to_string(); + let address = *self.client.addr(); + let auth = match self.client.auth { + crate::protocol::AuthType::Plain => { + let username = self + .client + .username + .clone() + .context(crate::error::CouldntFindUsername)?; + crate::protocol::Auth::plain(&username) + } + crate::protocol::AuthType::RecurseCenter => { + let id = crate::oauth::load_client_auth_id(self.client.auth); + crate::protocol::Auth::recurse_center( + id.as_ref().map(std::string::String::as_str), + ) + } + }; let fut: Box< dyn futures::future::Future + Send, - > = if self.tls { + > = if self.client.tls { let connector = native_tls::TlsConnector::new() .context(crate::error::CreateConnector)?; let connect: crate::client::Connector<_> = Box::new(move || { @@ -107,11 +57,11 @@ impl crate::config::Config for Config { ) }); Box::new(StreamSession::new( - &self.command, - &self.args, + &self.command.command, + &self.command.args, connect, - self.buffer_size, - &self.auth, + self.command.buffer_size, + &auth, )) } else { let connect: crate::client::Connector<_> = Box::new(move || { @@ -121,11 +71,11 @@ impl crate::config::Config for Config { ) }); Box::new(StreamSession::new( - &self.command, - &self.args, + &self.command.command, + &self.command.args, connect, - self.buffer_size, - &self.auth, + self.command.buffer_size, + &auth, )) }; tokio::run(fut.map_err(|e| { @@ -135,19 +85,6 @@ impl crate::config::Config for Config { } } -impl Default for Config { - fn default() -> Self { - Self { - auth: crate::config::default_auth(), - connect_address: crate::config::default_connect_address(), - tls: crate::config::default_tls(), - buffer_size: crate::config::default_connection_buffer_size(), - command: crate::config::default_command(), - args: crate::config::default_args(), - } - } -} - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Stream your terminal") .arg( diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 66a6881..62ef2e0 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -1,32 +1,9 @@ use crate::prelude::*; use std::io::Write as _; -#[derive(serde::Deserialize, Debug)] +#[derive(serde::Deserialize, Debug, Default)] pub struct Config { - #[serde( - deserialize_with = "crate::config::auth", - default = "crate::config::default_auth" - )] - auth: crate::protocol::Auth, - - #[serde( - deserialize_with = "crate::config::connect_address", - default = "crate::config::default_connect_address" - )] - connect_address: (String, std::net::SocketAddr), - - #[serde(default = "crate::config::default_tls")] - tls: bool, -} - -impl Config { - fn host(&self) -> &str { - &self.connect_address.0 - } - - fn addr(&self) -> &std::net::SocketAddr { - &self.connect_address.1 - } + client: crate::config::Client, } impl crate::config::Config for Config { @@ -34,37 +11,31 @@ impl crate::config::Config for Config { &mut self, matches: &clap::ArgMatches<'a>, ) -> Result<()> { - if matches.is_present("login-recurse-center") { - let id = crate::oauth::load_client_auth_id( - crate::protocol::AuthType::RecurseCenter, - ); - self.auth = crate::protocol::Auth::recurse_center( - id.as_ref().map(std::string::String::as_str), - ); - } - if matches.is_present("login-plain") { - let username = - matches.value_of("login-plain").unwrap().to_string(); - self.auth = crate::protocol::Auth::plain(&username); - } - if matches.is_present("address") { - let address = matches.value_of("address").unwrap(); - self.connect_address = - crate::config::to_connect_address(address)?; - } - if matches.is_present("tls") { - self.tls = true; - } - Ok(()) + self.client.merge_args(matches) } fn run(&self) -> Result<()> { - let host = self.host().to_string(); - let address = *self.addr(); - let auth = self.auth.clone(); + let host = self.client.host().to_string(); + let address = *self.client.addr(); + let auth = match self.client.auth { + crate::protocol::AuthType::Plain => { + let username = self + .client + .username + .clone() + .context(crate::error::CouldntFindUsername)?; + crate::protocol::Auth::plain(&username) + } + crate::protocol::AuthType::RecurseCenter => { + let id = crate::oauth::load_client_auth_id(self.client.auth); + crate::protocol::Auth::recurse_center( + id.as_ref().map(std::string::String::as_str), + ) + } + }; let fut: Box< dyn futures::future::Future + Send, - > = if self.tls { + > = if self.client.tls { let connector = native_tls::TlsConnector::new() .context(crate::error::CreateConnector)?; let make_connector: Box< @@ -110,16 +81,6 @@ impl crate::config::Config for Config { } } -impl Default for Config { - fn default() -> Self { - Self { - auth: crate::config::default_auth(), - connect_address: crate::config::default_connect_address(), - tls: crate::config::default_tls(), - } - } -} - pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> { app.about("Watch teleterm streams") .arg( diff --git a/src/config.rs b/src/config.rs index 5fed3d5..b59bbcf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ use std::net::ToSocketAddrs as _; const DEFAULT_LISTEN_ADDRESS: &str = "127.0.0.1:4144"; const DEFAULT_CONNECT_ADDRESS: &str = "127.0.0.1:4144"; -const DEFAULT_CONNECTION_BUFFER_SIZE: usize = 4 * 1024 * 1024; +const DEFAULT_BUFFER_SIZE: usize = 4 * 1024 * 1024; const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(120); const DEFAULT_AUTH_TYPE: crate::protocol::AuthType = @@ -21,25 +21,90 @@ pub trait Config: std::fmt::Debug { fn run(&self) -> Result<()>; } -pub fn listen_address<'a, D>( +#[derive(serde::Deserialize, Debug)] +pub struct Client { + #[serde(deserialize_with = "auth_type", default = "default_auth_type")] + pub auth: crate::protocol::AuthType, + + #[serde(default = "default_username")] + pub username: Option, + + #[serde( + deserialize_with = "connect_address", + default = "default_connect_address" + )] + pub connect_address: (String, std::net::SocketAddr), + + #[serde(default = "default_tls")] + pub tls: bool, +} + +impl Client { + pub fn host(&self) -> &str { + &self.connect_address.0 + } + + pub fn addr(&self) -> &std::net::SocketAddr { + &self.connect_address.1 + } + + pub fn merge_args<'a>( + &mut self, + matches: &clap::ArgMatches<'a>, + ) -> Result<()> { + if matches.is_present("login-recurse-center") { + self.auth = crate::protocol::AuthType::RecurseCenter; + } + if matches.is_present("login-plain") { + let username = matches + .value_of("login-plain") + .map(std::string::ToString::to_string); + self.auth = crate::protocol::AuthType::Plain; + self.username = username; + } + if matches.is_present("address") { + let address = matches.value_of("address").unwrap(); + self.connect_address = to_connect_address(address)?; + } + if matches.is_present("tls") { + self.tls = true; + } + Ok(()) + } +} + +impl Default for Client { + fn default() -> Self { + Self { + auth: default_auth_type(), + username: default_username(), + connect_address: default_connect_address(), + tls: default_tls(), + } + } +} + +fn auth_type<'a, D>( deserializer: D, -) -> std::result::Result +) -> std::result::Result where D: serde::de::Deserializer<'a>, { - to_listen_address(&::deserialize(deserializer)?) - .map_err(serde::de::Error::custom) + crate::protocol::AuthType::try_from( + ::deserialize(deserializer)?.as_ref(), + ) + .map_err(serde::de::Error::custom) } -pub fn default_listen_address() -> std::net::SocketAddr { - to_listen_address(DEFAULT_LISTEN_ADDRESS).unwrap() +fn default_auth_type() -> crate::protocol::AuthType { + DEFAULT_AUTH_TYPE } -pub fn to_listen_address(address: &str) -> Result { - address.parse().context(crate::error::ParseAddr) +fn default_username() -> Option { + std::env::var("USER").ok() } -pub fn connect_address<'a, D>( +fn connect_address<'a, D>( deserializer: D, ) -> std::result::Result<(String, std::net::SocketAddr), D::Error> where @@ -49,12 +114,12 @@ where .map_err(serde::de::Error::custom) } -pub fn default_connect_address() -> (String, std::net::SocketAddr) { +fn default_connect_address() -> (String, std::net::SocketAddr) { to_connect_address(DEFAULT_CONNECT_ADDRESS).unwrap() } // XXX this does a blocking dns lookup - should try to find an async version -pub fn to_connect_address( +fn to_connect_address( address: &str, ) -> Result<(String, std::net::SocketAddr)> { let mut address_parts = address.split(':'); @@ -72,47 +137,131 @@ pub fn to_connect_address( Ok((host.to_string(), socket_addr)) } -pub fn default_connection_buffer_size() -> usize { - DEFAULT_CONNECTION_BUFFER_SIZE +fn default_tls() -> bool { + DEFAULT_TLS } -pub fn read_timeout<'a, D>( +#[derive(serde::Deserialize, Debug)] +pub struct Server { + #[serde( + deserialize_with = "listen_address", + default = "default_listen_address" + )] + pub listen_address: std::net::SocketAddr, + + #[serde(default = "default_buffer_size")] + pub buffer_size: usize, + + #[serde( + rename = "read_timeout_secs", + deserialize_with = "read_timeout", + default = "default_read_timeout" + )] + pub read_timeout: std::time::Duration, + + pub tls_identity_file: Option, + + #[serde( + deserialize_with = "allowed_login_methods", + default = "default_allowed_login_methods" + )] + pub allowed_login_methods: + std::collections::HashSet, +} + +impl Server { + pub fn merge_args<'a>( + &mut self, + matches: &clap::ArgMatches<'a>, + ) -> Result<()> { + if matches.is_present("address") { + self.listen_address = matches + .value_of("address") + .unwrap() + .parse() + .context(crate::error::ParseAddr)?; + } + if matches.is_present("buffer-size") { + let s = matches.value_of("buffer-size").unwrap(); + self.buffer_size = s + .parse() + .context(crate::error::ParseBufferSize { input: s })?; + } + if matches.is_present("read-timeout") { + let s = matches.value_of("read-timeout").unwrap(); + self.read_timeout = s + .parse() + .map(std::time::Duration::from_secs) + .context(crate::error::ParseReadTimeout { input: s })?; + } + if matches.is_present("tls-identity-file") { + self.tls_identity_file = Some( + matches.value_of("tls-identity-file").unwrap().to_string(), + ); + } + if matches.is_present("allowed-login-methods") { + self.allowed_login_methods = matches + .values_of("allowed-login-methods") + .unwrap() + .map(crate::protocol::AuthType::try_from) + .collect::, + >>()?; + } + Ok(()) + } +} + +impl Default for Server { + fn default() -> Self { + Self { + listen_address: default_listen_address(), + buffer_size: default_buffer_size(), + read_timeout: default_read_timeout(), + tls_identity_file: None, + allowed_login_methods: default_allowed_login_methods(), + } + } +} + +fn listen_address<'a, D>( deserializer: D, -) -> std::result::Result +) -> std::result::Result where D: serde::de::Deserializer<'a>, { - Ok(std::time::Duration::from_secs(u64::deserialize( - deserializer, - )?)) -} - -pub fn default_read_timeout() -> std::time::Duration { - DEFAULT_READ_TIMEOUT + to_listen_address(&::deserialize(deserializer)?) + .map_err(serde::de::Error::custom) } -pub fn default_tls() -> bool { - DEFAULT_TLS +fn default_listen_address() -> std::net::SocketAddr { + to_listen_address(DEFAULT_LISTEN_ADDRESS).unwrap() } -pub fn default_command() -> String { - std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()) +fn to_listen_address(address: &str) -> Result { + address.parse().context(crate::error::ParseAddr) } -pub fn default_args() -> Vec { - vec![] +fn default_buffer_size() -> usize { + DEFAULT_BUFFER_SIZE } -pub fn default_ttyrec_filename() -> String { - DEFAULT_TTYREC_FILENAME.to_string() +fn read_timeout<'a, D>( + deserializer: D, +) -> std::result::Result +where + D: serde::de::Deserializer<'a>, +{ + Ok(std::time::Duration::from_secs(u64::deserialize( + deserializer, + )?)) } -pub fn default_allowed_login_methods( -) -> std::collections::HashSet { - crate::protocol::AuthType::iter().collect() +fn default_read_timeout() -> std::time::Duration { + DEFAULT_READ_TIMEOUT } -pub fn allowed_login_methods<'a, D>( +fn allowed_login_methods<'a, D>( deserializer: D, ) -> std::result::Result< std::collections::HashSet, @@ -169,61 +318,92 @@ where .collect() } -pub fn auth<'a, D>( - deserializer: D, -) -> std::result::Result -where - D: serde::de::Deserializer<'a>, -{ - LoginType::deserialize(deserializer).and_then(|login_type| { - match login_type.login_type { - crate::protocol::AuthType::Plain => login_type - .username +fn default_allowed_login_methods( +) -> std::collections::HashSet { + crate::protocol::AuthType::iter().collect() +} + +#[derive(serde::Deserialize, Debug)] +pub struct Command { + #[serde(default = "default_buffer_size")] + pub buffer_size: usize, + + #[serde(skip, default = "default_command")] + pub command: String, + + #[serde(skip, default = "default_args")] + pub args: Vec, +} + +impl Command { + pub fn merge_args<'a>( + &mut self, + matches: &clap::ArgMatches<'a>, + ) -> Result<()> { + if matches.is_present("buffer-size") { + let buffer_size = matches.value_of("buffer-size").unwrap(); + self.buffer_size = buffer_size.parse().context( + crate::error::ParseBufferSize { input: buffer_size }, + )?; + } + if matches.is_present("command") { + self.command = matches.value_of("command").unwrap().to_string(); + } + if matches.is_present("args") { + self.args = matches + .values_of("args") + .unwrap() .map(std::string::ToString::to_string) - .or_else(default_username) - .ok_or_else(|| Error::CouldntFindUsername) - .map(|username| crate::protocol::Auth::Plain { username }) - .map_err(serde::de::Error::custom), - crate::protocol::AuthType::RecurseCenter => { - Ok(crate::protocol::Auth::RecurseCenter { - id: login_type.id.map(std::string::ToString::to_string), - }) - } + .collect(); } - }) + Ok(()) + } } -pub fn default_auth() -> crate::protocol::Auth { - let username = default_username() - .ok_or_else(|| Error::CouldntFindUsername) - .unwrap(); - crate::protocol::Auth::Plain { username } +impl Default for Command { + fn default() -> Self { + Self { + buffer_size: default_buffer_size(), + command: default_command(), + args: default_args(), + } + } } -#[derive(serde::Deserialize)] -struct LoginType<'a> { - #[serde(deserialize_with = "auth_type", default = "default_auth_type")] - login_type: crate::protocol::AuthType, - username: Option<&'a str>, - id: Option<&'a str>, +fn default_command() -> String { + std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()) } -fn auth_type<'a, D>( - deserializer: D, -) -> std::result::Result -where - D: serde::de::Deserializer<'a>, -{ - crate::protocol::AuthType::try_from( - ::deserialize(deserializer)?.as_ref(), - ) - .map_err(serde::de::Error::custom) +fn default_args() -> Vec { + vec![] } -fn default_auth_type() -> crate::protocol::AuthType { - DEFAULT_AUTH_TYPE +#[derive(serde::Deserialize, Debug)] +pub struct Ttyrec { + #[serde(default = "default_ttyrec_filename")] + pub filename: String, } -fn default_username() -> Option { - std::env::var("USER").ok() +impl Ttyrec { + pub fn merge_args<'a>( + &mut self, + matches: &clap::ArgMatches<'a>, + ) -> Result<()> { + if matches.is_present("filename") { + self.filename = matches.value_of("filename").unwrap().to_string(); + } + Ok(()) + } +} + +impl Default for Ttyrec { + fn default() -> Self { + Self { + filename: default_ttyrec_filename(), + } + } +} + +fn default_ttyrec_filename() -> String { + DEFAULT_TTYREC_FILENAME.to_string() } -- cgit v1.2.3-54-g00ecf