ConfigClient is an option no more; config client degraded mode

This commit is contained in:
veeso
2021-07-08 15:07:24 +02:00
parent b9cb961da6
commit e6b44e1461
12 changed files with 350 additions and 310 deletions

View File

@@ -67,12 +67,12 @@ impl ActivityManager {
pub fn new(local_dir: &Path, interval: Duration) -> Result<ActivityManager, HostError> { pub fn new(local_dir: &Path, interval: Duration) -> Result<ActivityManager, HostError> {
// Prepare Context // Prepare Context
// Initialize configuration client // Initialize configuration client
let (config_client, error): (Option<ConfigClient>, Option<String>) = let (config_client, error): (ConfigClient, Option<String>) =
match Self::init_config_client() { match Self::init_config_client() {
Ok(cli) => (Some(cli), None), Ok(cli) => (cli, None),
Err(err) => { Err(err) => {
error!("Failed to initialize config client: {}", err); error!("Failed to initialize config client: {}", err);
(None, Some(err)) (ConfigClient::degraded(), Some(err))
} }
}; };
let theme_provider: ThemeProvider = Self::init_theme_provider(); let theme_provider: ThemeProvider = Self::init_theme_provider();

View File

@@ -49,13 +49,14 @@ pub struct ConfigClient {
config: UserConfig, // Configuration loaded config: UserConfig, // Configuration loaded
config_path: PathBuf, // Configuration TOML Path config_path: PathBuf, // Configuration TOML Path
ssh_key_dir: PathBuf, // SSH Key storage directory ssh_key_dir: PathBuf, // SSH Key storage directory
degraded: bool, // Indicates the `ConfigClient` is working in degraded mode
} }
impl ConfigClient { impl ConfigClient {
/// ### new /// ### new
/// ///
/// Instantiate a new `ConfigClient` with provided path /// Instantiate a new `ConfigClient` with provided path
pub fn new(config_path: &Path, ssh_key_dir: &Path) -> Result<ConfigClient, SerializerError> { pub fn new(config_path: &Path, ssh_key_dir: &Path) -> Result<Self, SerializerError> {
// Initialize a default configuration // Initialize a default configuration
let default_config: UserConfig = UserConfig::default(); let default_config: UserConfig = UserConfig::default();
info!( info!(
@@ -68,6 +69,7 @@ impl ConfigClient {
config: default_config, config: default_config,
config_path: PathBuf::from(config_path), config_path: PathBuf::from(config_path),
ssh_key_dir: PathBuf::from(ssh_key_dir), ssh_key_dir: PathBuf::from(ssh_key_dir),
degraded: false,
}; };
// If ssh key directory doesn't exist, create it // If ssh key directory doesn't exist, create it
if !ssh_key_dir.exists() { if !ssh_key_dir.exists() {
@@ -102,6 +104,20 @@ impl ConfigClient {
Ok(client) Ok(client)
} }
/// ### degraded
///
/// Instantiate a ConfigClient in degraded mode.
/// When in degraded mode, the configuration in use will be the default configuration
/// and the IO operation on configuration won't be available
pub fn degraded() -> Self {
Self {
config: UserConfig::default(),
config_path: PathBuf::default(),
ssh_key_dir: PathBuf::default(),
degraded: true,
}
}
// Text editor // Text editor
/// ### get_text_editor /// ### get_text_editor
@@ -234,6 +250,12 @@ impl ConfigClient {
username: &str, username: &str,
ssh_key: &str, ssh_key: &str,
) -> Result<(), SerializerError> { ) -> Result<(), SerializerError> {
if self.degraded {
return Err(SerializerError::new_ex(
SerializerErrorKind::GenericError,
String::from("Configuration won't be saved, since in degraded mode"),
));
}
let host_name: String = Self::make_ssh_host_key(host, username); let host_name: String = Self::make_ssh_host_key(host, username);
// Get key path // Get key path
let ssh_key_path: PathBuf = { let ssh_key_path: PathBuf = {
@@ -267,6 +289,12 @@ impl ConfigClient {
/// This operation also unlinks the key file in `ssh_key_dir` /// This operation also unlinks the key file in `ssh_key_dir`
/// and also commits changes to configuration, to prevent incoerent data /// and also commits changes to configuration, to prevent incoerent data
pub fn del_ssh_key(&mut self, host: &str, username: &str) -> Result<(), SerializerError> { pub fn del_ssh_key(&mut self, host: &str, username: &str) -> Result<(), SerializerError> {
if self.degraded {
return Err(SerializerError::new_ex(
SerializerErrorKind::GenericError,
String::from("Configuration won't be saved, since in degraded mode"),
));
}
// Remove key from configuration and get key path // Remove key from configuration and get key path
info!("Removing key for {}@{}", host, username); info!("Removing key for {}@{}", host, username);
let key_path: PathBuf = match self let key_path: PathBuf = match self
@@ -293,6 +321,9 @@ impl ConfigClient {
/// None is returned if key doesn't exist /// None is returned if key doesn't exist
/// `std::io::Error` is returned in case it was not possible to read the key file /// `std::io::Error` is returned in case it was not possible to read the key file
pub fn get_ssh_key(&self, mkey: &str) -> std::io::Result<Option<SshHost>> { pub fn get_ssh_key(&self, mkey: &str) -> std::io::Result<Option<SshHost>> {
if self.degraded {
return Ok(None);
}
// Check if Key exists // Check if Key exists
match self.config.remote.ssh_keys.get(mkey) { match self.config.remote.ssh_keys.get(mkey) {
None => Ok(None), None => Ok(None),
@@ -318,6 +349,12 @@ impl ConfigClient {
/// ///
/// Write configuration to file /// Write configuration to file
pub fn write_config(&self) -> Result<(), SerializerError> { pub fn write_config(&self) -> Result<(), SerializerError> {
if self.degraded {
return Err(SerializerError::new_ex(
SerializerErrorKind::GenericError,
String::from("Configuration won't be saved, since in degraded mode"),
));
}
// Open file // Open file
match OpenOptions::new() match OpenOptions::new()
.create(true) .create(true)
@@ -340,6 +377,12 @@ impl ConfigClient {
/// ///
/// Read configuration from file (or reload it if already read) /// Read configuration from file (or reload it if already read)
pub fn read_config(&mut self) -> Result<(), SerializerError> { pub fn read_config(&mut self) -> Result<(), SerializerError> {
if self.degraded {
return Err(SerializerError::new_ex(
SerializerErrorKind::GenericError,
String::from("Configuration won't be loaded, since in degraded mode"),
));
}
// Open bookmarks file for read // Open bookmarks file for read
match OpenOptions::new() match OpenOptions::new()
.read(true) .read(true)
@@ -415,6 +458,7 @@ mod tests {
.unwrap(); .unwrap();
// Verify parameters // Verify parameters
let default_config: UserConfig = UserConfig::default(); let default_config: UserConfig = UserConfig::default();
assert_eq!(client.degraded, false);
assert_eq!(client.config.remote.ssh_keys.len(), 0); assert_eq!(client.config.remote.ssh_keys.len(), 0);
assert_eq!( assert_eq!(
client.config.user_interface.default_protocol, client.config.user_interface.default_protocol,
@@ -428,6 +472,20 @@ mod tests {
assert_eq!(client.ssh_key_dir, ssh_keys_path); assert_eq!(client.ssh_key_dir, ssh_keys_path);
} }
#[test]
fn test_system_config_degraded() {
let mut client: ConfigClient = ConfigClient::degraded();
assert_eq!(client.degraded, true);
assert_eq!(client.config_path, PathBuf::default());
assert_eq!(client.ssh_key_dir, PathBuf::default());
// I/O
assert!(client.add_ssh_key("Omar", "omar", "omar").is_err());
assert!(client.del_ssh_key("omar", "omar").is_err());
assert!(client.get_ssh_key("omar").ok().unwrap().is_none());
assert!(client.write_config().is_err());
assert!(client.read_config().is_err());
}
#[test] #[test]
fn test_system_config_new_err() { fn test_system_config_new_err() {
assert!( assert!(

View File

@@ -111,33 +111,36 @@ impl AuthActivity {
fn check_for_updates(&mut self) { fn check_for_updates(&mut self) {
debug!("Check for updates..."); debug!("Check for updates...");
// Check version only if unset in the store // Check version only if unset in the store
let ctx: &Context = self.context.as_ref().unwrap(); let ctx: &mut Context = self.context.as_mut().unwrap();
if !ctx.store.isset(STORE_KEY_LATEST_VERSION) { if !ctx.store.isset(STORE_KEY_LATEST_VERSION) {
debug!("Version is not set in storage"); debug!("Version is not set in storage");
let mut github_tag: Option<git::GithubTag> = match ctx.config_client.as_ref() { if ctx.config_client.get_check_for_updates() {
Some(client) => {
if client.get_check_for_updates() {
debug!("Check for updates is enabled"); debug!("Check for updates is enabled");
// Send request // Send request
match git::check_for_updates(env!("CARGO_PKG_VERSION")) { match git::check_for_updates(env!("CARGO_PKG_VERSION")) {
Ok(github_tag) => github_tag, Ok(Some(git::GithubTag { tag_name, body })) => {
// If some, store version and release notes
info!("Latest version is: {}", tag_name);
ctx.store.set_string(STORE_KEY_LATEST_VERSION, tag_name);
ctx.store.set_string(STORE_KEY_RELEASE_NOTES, body);
}
Ok(None) => {
info!("Latest version is: {} (current)", env!("CARGO_PKG_VERSION"));
// Just set flag as check
ctx.store.set(STORE_KEY_LATEST_VERSION);
}
Err(err) => { Err(err) => {
// Report error // Report error
error!("Failed to get latest version: {}", err); error!("Failed to get latest version: {}", err);
self.mount_error( self.mount_error(
format!("Could not check for new updates: {}", err).as_str(), format!("Could not check for new updates: {}", err).as_str(),
); );
// None
None
} }
} }
} else { } else {
info!("Check for updates is disabled"); info!("Check for updates is disabled");
None
} }
} /*
None => None,
};
let ctx: &mut Context = self.context.as_mut().unwrap(); let ctx: &mut Context = self.context.as_mut().unwrap();
// Set version into the store (or just a flag) // Set version into the store (or just a flag)
match github_tag.take() { match github_tag.take() {
@@ -152,7 +155,7 @@ impl AuthActivity {
// Just set flag as check // Just set flag as check
ctx.store.set(STORE_KEY_LATEST_VERSION); ctx.store.set(STORE_KEY_LATEST_VERSION);
} }
} }*/
} }
} }
@@ -194,7 +197,7 @@ impl Activity for AuthActivity {
self.view_recent_connections(); self.view_recent_connections();
} }
// Verify error state from context // Verify error state from context
if let Some(err) = self.context.as_mut().unwrap().get_error() { if let Some(err) = self.context.as_mut().unwrap().error() {
self.mount_error(err.as_str()); self.mount_error(err.as_str());
} }
info!("Activity initialized"); info!("Activity initialized");

View File

@@ -109,11 +109,12 @@ impl AuthActivity {
)), )),
); );
// Get default protocol // Get default protocol
let default_protocol: FileTransferProtocol = let default_protocol: FileTransferProtocol = self
match self.context.as_ref().unwrap().config_client.as_ref() { .context
Some(cli) => cli.get_default_protocol(), .as_ref()
None => FileTransferProtocol::Sftp, .unwrap()
}; .config_client
.get_default_protocol();
// Protocol // Protocol
self.view.mount( self.view.mount(
super::COMPONENT_RADIO_PROTOCOL, super::COMPONENT_RADIO_PROTOCOL,

View File

@@ -103,10 +103,7 @@ impl FileTransferActivity {
/// ///
/// Set text editor to use /// Set text editor to use
pub(super) fn setup_text_editor(&self) { pub(super) fn setup_text_editor(&self) {
if let Some(config_cli) = self.context.as_ref().unwrap().config_client.as_ref() { env::set_var("EDITOR", self.config().get_text_editor());
// Set text editor
env::set_var("EDITOR", config_cli.get_text_editor());
}
} }
/// ### read_input_event /// ### read_input_event

View File

@@ -210,6 +210,13 @@ impl FileTransferActivity {
}) })
} }
/// ### config
///
/// Returns config client reference
fn config(&self) -> &ConfigClient {
&self.context.as_ref().unwrap().config_client
}
/// ### theme /// ### theme
/// ///
/// Get a reference to `Theme` /// Get a reference to `Theme`
@@ -249,7 +256,7 @@ impl Activity for FileTransferActivity {
self.init(); self.init();
debug!("Initialized view"); debug!("Initialized view");
// Verify error state from context // Verify error state from context
if let Some(err) = self.context.as_mut().unwrap().get_error() { if let Some(err) = self.context.as_mut().unwrap().error() {
error!("Fatal error on create: {}", err); error!("Fatal error on create: {}", err);
self.mount_fatal(&err); self.mount_fatal(&err);
} }

View File

@@ -80,20 +80,18 @@ impl SetupActivity {
/// delete of a ssh key /// delete of a ssh key
pub(super) fn action_delete_ssh_key(&mut self) { pub(super) fn action_delete_ssh_key(&mut self) {
// Get key // Get key
if let Some(config_cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// get index // get index
let idx: Option<usize> = match self.view.get_state(super::COMPONENT_LIST_SSH_KEYS) { let idx: Option<usize> = match self.view.get_state(super::COMPONENT_LIST_SSH_KEYS) {
Some(Payload::One(Value::Usize(idx))) => Some(idx), Some(Payload::One(Value::Usize(idx))) => Some(idx),
_ => None, _ => None,
}; };
if let Some(idx) = idx { if let Some(idx) = idx {
let key: Option<String> = config_cli.iter_ssh_keys().nth(idx).cloned(); let key: Option<String> = self.config().iter_ssh_keys().nth(idx).cloned();
if let Some(key) = key { if let Some(key) = key {
match config_cli.get_ssh_key(&key) { match self.config().get_ssh_key(&key) {
Ok(opt) => { Ok(opt) => {
if let Some((host, username, _)) = opt { if let Some((host, username, _)) = opt {
if let Err(err) = if let Err(err) = self.delete_ssh_key(host.as_str(), username.as_str())
self.delete_ssh_key(host.as_str(), username.as_str())
{ {
// Report error // Report error
self.mount_error(err.as_str()); self.mount_error(err.as_str());
@@ -110,13 +108,11 @@ impl SetupActivity {
} }
} }
} }
}
/// ### action_new_ssh_key /// ### action_new_ssh_key
/// ///
/// Create a new ssh key /// Create a new ssh key
pub(super) fn action_new_ssh_key(&mut self) { pub(super) fn action_new_ssh_key(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// get parameters // get parameters
let host: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_HOST) { let host: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_HOST) {
Some(Payload::One(Value::Str(host))) => host, Some(Payload::One(Value::Str(host))) => host,
@@ -127,7 +123,7 @@ impl SetupActivity {
_ => String::new(), _ => String::new(),
}; };
// Prepare text editor // Prepare text editor
env::set_var("EDITOR", cli.get_text_editor()); env::set_var("EDITOR", self.config().get_text_editor());
let placeholder: String = format!("# Type private SSH key for {}@{}\n", username, host); let placeholder: String = format!("# Type private SSH key for {}@{}\n", username, host);
// Put input mode back to normal // Put input mode back to normal
if let Err(err) = disable_raw_mode() { if let Err(err) = disable_raw_mode() {
@@ -163,9 +159,7 @@ impl SetupActivity {
} }
Err(err) => { Err(err) => {
// Report error // Report error
self.mount_error( self.mount_error(format!("Could not write private key to file: {}", err).as_str());
format!("Could not write private key to file: {}", err).as_str(),
);
} }
} }
// Restore terminal // Restore terminal
@@ -177,7 +171,6 @@ impl SetupActivity {
ctx.enter_alternate_screen(); ctx.enter_alternate_screen();
} }
} }
}
/// ### set_color /// ### set_color
/// ///

View File

@@ -37,12 +37,9 @@ impl SetupActivity {
/// ///
/// Save configuration /// Save configuration
pub(super) fn save_config(&mut self) -> Result<(), String> { pub(super) fn save_config(&mut self) -> Result<(), String> {
match self.context.as_ref().unwrap().config_client.as_ref() { match self.config().write_config() {
Some(cli) => match cli.write_config() {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(format!("Could not save configuration: {}", err)), Err(err) => Err(format!("Could not save configuration: {}", err)),
},
None => Ok(()),
} }
} }
@@ -51,13 +48,9 @@ impl SetupActivity {
/// Reset configuration changes; pratically read config from file, overwriting any change made /// Reset configuration changes; pratically read config from file, overwriting any change made
/// since last write action /// since last write action
pub(super) fn reset_config_changes(&mut self) -> Result<(), String> { pub(super) fn reset_config_changes(&mut self) -> Result<(), String> {
match self.context.as_mut().unwrap().config_client.as_mut() { self.config_mut()
Some(cli) => match cli.read_config() { .read_config()
Ok(_) => Ok(()), .map_err(|e| format!("Could not reload configuration: {}", e))
Err(err) => Err(format!("Could not restore configuration: {}", err)),
},
None => Ok(()),
}
} }
/// ### save_theme /// ### save_theme
@@ -82,15 +75,12 @@ impl SetupActivity {
/// ///
/// Delete ssh key from config cli /// Delete ssh key from config cli
pub(super) fn delete_ssh_key(&mut self, host: &str, username: &str) -> Result<(), String> { pub(super) fn delete_ssh_key(&mut self, host: &str, username: &str) -> Result<(), String> {
match self.context.as_mut().unwrap().config_client.as_mut() { match self.config_mut().del_ssh_key(host, username) {
Some(cli) => match cli.del_ssh_key(host, username) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(format!( Err(err) => Err(format!(
"Could not delete ssh key \"{}@{}\": {}", "Could not delete ssh key \"{}@{}\": {}",
host, username, err host, username, err
)), )),
},
None => Ok(()),
} }
} }
@@ -102,9 +92,7 @@ impl SetupActivity {
None => Ok(()), None => Ok(()),
Some(ctx) => { Some(ctx) => {
// Set editor if config client exists // Set editor if config client exists
if let Some(config_cli) = ctx.config_client.as_ref() { env::set_var("EDITOR", ctx.config_client.get_text_editor());
env::set_var("EDITOR", config_cli.get_text_editor());
}
// Prepare terminal // Prepare terminal
if let Err(err) = disable_raw_mode() { if let Err(err) = disable_raw_mode() {
error!("Failed to disable raw mode: {}", err); error!("Failed to disable raw mode: {}", err);
@@ -113,19 +101,16 @@ impl SetupActivity {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
ctx.leave_alternate_screen(); ctx.leave_alternate_screen();
// Get result // Get result
let result: Result<(), String> = match ctx.config_client.as_ref() { let result: Result<(), String> = match ctx.config_client.iter_ssh_keys().nth(idx) {
Some(config_cli) => match config_cli.iter_ssh_keys().nth(idx) {
Some(key) => { Some(key) => {
// Get key path // Get key path
match config_cli.get_ssh_key(key) { match ctx.config_client.get_ssh_key(key) {
Ok(ssh_key) => match ssh_key { Ok(ssh_key) => match ssh_key {
None => Ok(()), None => Ok(()),
Some((_, _, key_path)) => { Some((_, _, key_path)) => {
match edit::edit_file(key_path.as_path()) { match edit::edit_file(key_path.as_path()) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => { Err(err) => Err(format!("Could not edit ssh key: {}", err)),
Err(format!("Could not edit ssh key: {}", err))
}
} }
} }
}, },
@@ -133,8 +118,6 @@ impl SetupActivity {
} }
} }
None => Ok(()), None => Ok(()),
},
None => Ok(()),
}; };
// Restore terminal // Restore terminal
// Clear screen // Clear screen
@@ -161,15 +144,8 @@ impl SetupActivity {
username: &str, username: &str,
rsa_key: &str, rsa_key: &str,
) -> Result<(), String> { ) -> Result<(), String> {
match self.context.as_mut().unwrap().config_client.as_mut() { self.config_mut()
Some(cli) => { .add_ssh_key(host, username, rsa_key)
// Add key to client .map_err(|e| format!("Could not add SSH key: {}", e))
match cli.add_ssh_key(host, username, rsa_key) {
Ok(_) => Ok(()),
Err(err) => Err(format!("Could not add SSH key: {}", err)),
}
}
None => Ok(()),
}
} }
} }

View File

@@ -35,6 +35,7 @@ mod view;
// Locals // Locals
use super::{Activity, Context, ExitReason}; use super::{Activity, Context, ExitReason};
use crate::config::themes::Theme; use crate::config::themes::Theme;
use crate::system::config_client::ConfigClient;
use crate::system::theme_provider::ThemeProvider; use crate::system::theme_provider::ThemeProvider;
// Ext // Ext
use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
@@ -133,6 +134,14 @@ impl Default for SetupActivity {
} }
impl SetupActivity { impl SetupActivity {
fn config(&self) -> &ConfigClient {
&self.context.as_ref().unwrap().config_client
}
fn config_mut(&mut self) -> &mut ConfigClient {
&mut self.context.as_mut().unwrap().config_client
}
fn theme(&self) -> &Theme { fn theme(&self) -> &Theme {
self.context.as_ref().unwrap().theme_provider.theme() self.context.as_ref().unwrap().theme_provider.theme()
} }
@@ -164,7 +173,7 @@ impl Activity for SetupActivity {
// Init view // Init view
self.init(ViewLayout::SetupForm); self.init(ViewLayout::SetupForm);
// Verify error state from context // Verify error state from context
if let Some(err) = self.context.as_mut().unwrap().get_error() { if let Some(err) = self.context.as_mut().unwrap().error() {
self.mount_error(err.as_str()); self.mount_error(err.as_str());
} }
} }

View File

@@ -286,11 +286,10 @@ impl SetupActivity {
/// ///
/// Load values from configuration into input fields /// Load values from configuration into input fields
pub(crate) fn load_input_values(&mut self) { pub(crate) fn load_input_values(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
// Text editor // Text editor
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_TEXT_EDITOR) { if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_TEXT_EDITOR) {
let text_editor: String = let text_editor: String =
String::from(cli.get_text_editor().as_path().to_string_lossy()); String::from(self.config().get_text_editor().as_path().to_string_lossy());
let props = InputPropsBuilder::from(props) let props = InputPropsBuilder::from(props)
.with_value(text_editor) .with_value(text_editor)
.build(); .build();
@@ -298,7 +297,7 @@ impl SetupActivity {
} }
// Protocol // Protocol
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DEFAULT_PROTOCOL) { if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_DEFAULT_PROTOCOL) {
let protocol: usize = match cli.get_default_protocol() { let protocol: usize = match self.config().get_default_protocol() {
FileTransferProtocol::Sftp => 0, FileTransferProtocol::Sftp => 0,
FileTransferProtocol::Scp => 1, FileTransferProtocol::Scp => 1,
FileTransferProtocol::Ftp(false) => 2, FileTransferProtocol::Ftp(false) => 2,
@@ -311,7 +310,7 @@ impl SetupActivity {
} }
// Hidden files // Hidden files
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_HIDDEN_FILES) { if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_HIDDEN_FILES) {
let hidden: usize = match cli.get_show_hidden_files() { let hidden: usize = match self.config().get_show_hidden_files() {
true => 0, true => 0,
false => 1, false => 1,
}; };
@@ -320,7 +319,7 @@ impl SetupActivity {
} }
// Updates // Updates
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_UPDATES) { if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_UPDATES) {
let updates: usize = match cli.get_check_for_updates() { let updates: usize = match self.config().get_check_for_updates() {
true => 0, true => 0,
false => 1, false => 1,
}; };
@@ -329,7 +328,7 @@ impl SetupActivity {
} }
// Group dirs // Group dirs
if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_GROUP_DIRS) { if let Some(props) = self.view.get_props(super::COMPONENT_RADIO_GROUP_DIRS) {
let dirs: usize = match cli.get_group_dirs() { let dirs: usize = match self.config().get_group_dirs() {
Some(GroupDirs::First) => 0, Some(GroupDirs::First) => 0,
Some(GroupDirs::Last) => 1, Some(GroupDirs::Last) => 1,
None => 2, None => 2,
@@ -339,7 +338,7 @@ impl SetupActivity {
} }
// Local File Fmt // Local File Fmt
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_LOCAL_FILE_FMT) { if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_LOCAL_FILE_FMT) {
let file_fmt: String = cli.get_local_file_fmt().unwrap_or_default(); let file_fmt: String = self.config().get_local_file_fmt().unwrap_or_default();
let props = InputPropsBuilder::from(props).with_value(file_fmt).build(); let props = InputPropsBuilder::from(props).with_value(file_fmt).build();
let _ = self let _ = self
.view .view
@@ -347,24 +346,23 @@ impl SetupActivity {
} }
// Remote File Fmt // Remote File Fmt
if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_REMOTE_FILE_FMT) { if let Some(props) = self.view.get_props(super::COMPONENT_INPUT_REMOTE_FILE_FMT) {
let file_fmt: String = cli.get_remote_file_fmt().unwrap_or_default(); let file_fmt: String = self.config().get_remote_file_fmt().unwrap_or_default();
let props = InputPropsBuilder::from(props).with_value(file_fmt).build(); let props = InputPropsBuilder::from(props).with_value(file_fmt).build();
let _ = self let _ = self
.view .view
.update(super::COMPONENT_INPUT_REMOTE_FILE_FMT, props); .update(super::COMPONENT_INPUT_REMOTE_FILE_FMT, props);
} }
} }
}
/// ### collect_input_values /// ### collect_input_values
/// ///
/// Collect values from input and put them into the configuration /// Collect values from input and put them into the configuration
pub(crate) fn collect_input_values(&mut self) { pub(crate) fn collect_input_values(&mut self) {
if let Some(cli) = self.context.as_mut().unwrap().config_client.as_mut() {
if let Some(Payload::One(Value::Str(editor))) = if let Some(Payload::One(Value::Str(editor))) =
self.view.get_state(super::COMPONENT_INPUT_TEXT_EDITOR) self.view.get_state(super::COMPONENT_INPUT_TEXT_EDITOR)
{ {
cli.set_text_editor(PathBuf::from(editor.as_str())); self.config_mut()
.set_text_editor(PathBuf::from(editor.as_str()));
} }
if let Some(Payload::One(Value::Usize(protocol))) = if let Some(Payload::One(Value::Usize(protocol))) =
self.view.get_state(super::COMPONENT_RADIO_DEFAULT_PROTOCOL) self.view.get_state(super::COMPONENT_RADIO_DEFAULT_PROTOCOL)
@@ -375,29 +373,29 @@ impl SetupActivity {
3 => FileTransferProtocol::Ftp(true), 3 => FileTransferProtocol::Ftp(true),
_ => FileTransferProtocol::Sftp, _ => FileTransferProtocol::Sftp,
}; };
cli.set_default_protocol(protocol); self.config_mut().set_default_protocol(protocol);
} }
if let Some(Payload::One(Value::Usize(opt))) = if let Some(Payload::One(Value::Usize(opt))) =
self.view.get_state(super::COMPONENT_RADIO_HIDDEN_FILES) self.view.get_state(super::COMPONENT_RADIO_HIDDEN_FILES)
{ {
let show: bool = matches!(opt, 0); let show: bool = matches!(opt, 0);
cli.set_show_hidden_files(show); self.config_mut().set_show_hidden_files(show);
} }
if let Some(Payload::One(Value::Usize(opt))) = if let Some(Payload::One(Value::Usize(opt))) =
self.view.get_state(super::COMPONENT_RADIO_UPDATES) self.view.get_state(super::COMPONENT_RADIO_UPDATES)
{ {
let check: bool = matches!(opt, 0); let check: bool = matches!(opt, 0);
cli.set_check_for_updates(check); self.config_mut().set_check_for_updates(check);
} }
if let Some(Payload::One(Value::Str(fmt))) = if let Some(Payload::One(Value::Str(fmt))) =
self.view.get_state(super::COMPONENT_INPUT_LOCAL_FILE_FMT) self.view.get_state(super::COMPONENT_INPUT_LOCAL_FILE_FMT)
{ {
cli.set_local_file_fmt(fmt); self.config_mut().set_local_file_fmt(fmt);
} }
if let Some(Payload::One(Value::Str(fmt))) = if let Some(Payload::One(Value::Str(fmt))) =
self.view.get_state(super::COMPONENT_INPUT_REMOTE_FILE_FMT) self.view.get_state(super::COMPONENT_INPUT_REMOTE_FILE_FMT)
{ {
cli.set_remote_file_fmt(fmt); self.config_mut().set_remote_file_fmt(fmt);
} }
if let Some(Payload::One(Value::Usize(opt))) = if let Some(Payload::One(Value::Usize(opt))) =
self.view.get_state(super::COMPONENT_RADIO_GROUP_DIRS) self.view.get_state(super::COMPONENT_RADIO_GROUP_DIRS)
@@ -407,8 +405,7 @@ impl SetupActivity {
1 => Some(GroupDirs::Last), 1 => Some(GroupDirs::Last),
_ => None, _ => None,
}; };
cli.set_group_dirs(dirs); self.config_mut().set_group_dirs(dirs);
}
} }
} }
} }

View File

@@ -275,14 +275,14 @@ impl SetupActivity {
/// ///
/// Reload ssh keys /// Reload ssh keys
pub(crate) fn reload_ssh_keys(&mut self) { pub(crate) fn reload_ssh_keys(&mut self) {
if let Some(cli) = self.context.as_ref().unwrap().config_client.as_ref() {
// get props // get props
if let Some(props) = self.view.get_props(super::COMPONENT_LIST_SSH_KEYS) { if let Some(props) = self.view.get_props(super::COMPONENT_LIST_SSH_KEYS) {
// Create texts // Create texts
let keys: Vec<String> = cli let keys: Vec<String> = self
.config()
.iter_ssh_keys() .iter_ssh_keys()
.map(|x| { .map(|x| {
let (addr, username, _) = cli.get_ssh_key(x).ok().unwrap().unwrap(); let (addr, username, _) = self.config().get_ssh_key(x).ok().unwrap().unwrap();
format!("{} at {}", addr, username) format!("{} at {}", addr, username)
}) })
.collect(); .collect();
@@ -293,4 +293,3 @@ impl SetupActivity {
} }
} }
} }
}

View File

@@ -46,7 +46,7 @@ use tuirealm::tui::Terminal;
/// Context holds data structures used by the ui /// Context holds data structures used by the ui
pub struct Context { pub struct Context {
pub ft_params: Option<FileTransferParams>, pub ft_params: Option<FileTransferParams>,
pub(crate) config_client: Option<ConfigClient>, pub(crate) config_client: ConfigClient,
pub(crate) store: Store, pub(crate) store: Store,
pub(crate) input_hnd: InputHandler, pub(crate) input_hnd: InputHandler,
pub(crate) terminal: Terminal<CrosstermBackend<Stdout>>, pub(crate) terminal: Terminal<CrosstermBackend<Stdout>>,
@@ -71,7 +71,7 @@ impl Context {
/// ///
/// Instantiates a new Context /// Instantiates a new Context
pub fn new( pub fn new(
config_client: Option<ConfigClient>, config_client: ConfigClient,
theme_provider: ThemeProvider, theme_provider: ThemeProvider,
error: Option<String>, error: Option<String>,
) -> Context { ) -> Context {
@@ -96,10 +96,10 @@ impl Context {
self.error = Some(err); self.error = Some(err);
} }
/// ### get_error /// ### error
/// ///
/// Get error message and remove it from the context /// Get error message and remove it from the context
pub fn get_error(&mut self) -> Option<String> { pub fn error(&mut self) -> Option<String> {
self.error.take() self.error.take()
} }