mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
ConfigClient is an option no more; config client degraded mode
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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) => {
|
debug!("Check for updates is enabled");
|
||||||
if client.get_check_for_updates() {
|
// Send request
|
||||||
debug!("Check for updates is enabled");
|
match git::check_for_updates(env!("CARGO_PKG_VERSION")) {
|
||||||
// Send request
|
Ok(Some(git::GithubTag { tag_name, body })) => {
|
||||||
match git::check_for_updates(env!("CARGO_PKG_VERSION")) {
|
// If some, store version and release notes
|
||||||
Ok(github_tag) => github_tag,
|
info!("Latest version is: {}", tag_name);
|
||||||
Err(err) => {
|
ctx.store.set_string(STORE_KEY_LATEST_VERSION, tag_name);
|
||||||
// Report error
|
ctx.store.set_string(STORE_KEY_RELEASE_NOTES, body);
|
||||||
error!("Failed to get latest version: {}", err);
|
}
|
||||||
self.mount_error(
|
Ok(None) => {
|
||||||
format!("Could not check for new updates: {}", err).as_str(),
|
info!("Latest version is: {} (current)", env!("CARGO_PKG_VERSION"));
|
||||||
);
|
// Just set flag as check
|
||||||
// None
|
ctx.store.set(STORE_KEY_LATEST_VERSION);
|
||||||
None
|
}
|
||||||
}
|
Err(err) => {
|
||||||
}
|
// Report error
|
||||||
} else {
|
error!("Failed to get latest version: {}", err);
|
||||||
info!("Check for updates is disabled");
|
self.mount_error(
|
||||||
None
|
format!("Could not check for new updates: {}", err).as_str(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => None,
|
} else {
|
||||||
};
|
info!("Check for updates is disabled");
|
||||||
|
}
|
||||||
|
/*
|
||||||
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");
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,32 +80,29 @@ 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> = self.config().iter_ssh_keys().nth(idx).cloned();
|
||||||
let key: Option<String> = config_cli.iter_ssh_keys().nth(idx).cloned();
|
if let Some(key) = key {
|
||||||
if let Some(key) = key {
|
match self.config().get_ssh_key(&key) {
|
||||||
match config_cli.get_ssh_key(&key) {
|
Ok(opt) => {
|
||||||
Ok(opt) => {
|
if let Some((host, username, _)) = opt {
|
||||||
if let Some((host, username, _)) = opt {
|
if let Err(err) = self.delete_ssh_key(host.as_str(), username.as_str())
|
||||||
if let Err(err) =
|
{
|
||||||
self.delete_ssh_key(host.as_str(), username.as_str())
|
// Report error
|
||||||
{
|
self.mount_error(err.as_str());
|
||||||
// Report error
|
|
||||||
self.mount_error(err.as_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
}
|
||||||
// Report error
|
Err(err) => {
|
||||||
self.mount_error(
|
// Report error
|
||||||
format!("Could not get ssh key \"{}\": {}", key, err).as_str(),
|
self.mount_error(
|
||||||
);
|
format!("Could not get ssh key \"{}\": {}", key, err).as_str(),
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,67 +113,63 @@ impl SetupActivity {
|
|||||||
///
|
///
|
||||||
/// 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,
|
_ => String::new(),
|
||||||
_ => String::new(),
|
};
|
||||||
};
|
let username: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_USERNAME) {
|
||||||
let username: String = match self.view.get_state(super::COMPONENT_INPUT_SSH_USERNAME) {
|
Some(Payload::One(Value::Str(user))) => user,
|
||||||
Some(Payload::One(Value::Str(user))) => user,
|
_ => String::new(),
|
||||||
_ => String::new(),
|
};
|
||||||
};
|
// Prepare text editor
|
||||||
// Prepare text editor
|
env::set_var("EDITOR", self.config().get_text_editor());
|
||||||
env::set_var("EDITOR", cli.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() {
|
error!("Failed to disable raw mode: {}", err);
|
||||||
error!("Failed to disable raw mode: {}", err);
|
}
|
||||||
}
|
// Leave alternate mode
|
||||||
// Leave alternate mode
|
#[cfg(not(target_os = "windows"))]
|
||||||
#[cfg(not(target_os = "windows"))]
|
if let Some(ctx) = self.context.as_mut() {
|
||||||
if let Some(ctx) = self.context.as_mut() {
|
ctx.leave_alternate_screen();
|
||||||
ctx.leave_alternate_screen();
|
}
|
||||||
}
|
// Re-enable raw mode
|
||||||
// Re-enable raw mode
|
if let Err(err) = enable_raw_mode() {
|
||||||
if let Err(err) = enable_raw_mode() {
|
error!("Failed to enter raw mode: {}", err);
|
||||||
error!("Failed to enter raw mode: {}", err);
|
}
|
||||||
}
|
// Write key to file
|
||||||
// Write key to file
|
match edit::edit(placeholder.as_bytes()) {
|
||||||
match edit::edit(placeholder.as_bytes()) {
|
Ok(rsa_key) => {
|
||||||
Ok(rsa_key) => {
|
// Remove placeholder from `rsa_key`
|
||||||
// Remove placeholder from `rsa_key`
|
let rsa_key: String = rsa_key.as_str().replace(placeholder.as_str(), "");
|
||||||
let rsa_key: String = rsa_key.as_str().replace(placeholder.as_str(), "");
|
if rsa_key.is_empty() {
|
||||||
if rsa_key.is_empty() {
|
// Report error: empty key
|
||||||
// Report error: empty key
|
self.mount_error("SSH key is empty!");
|
||||||
self.mount_error("SSH key is empty!");
|
} else {
|
||||||
} else {
|
// Add key
|
||||||
// Add key
|
if let Err(err) =
|
||||||
if let Err(err) =
|
self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str())
|
||||||
self.add_ssh_key(host.as_str(), username.as_str(), rsa_key.as_str())
|
{
|
||||||
{
|
self.mount_error(
|
||||||
self.mount_error(
|
format!("Could not create new private key: {}", err).as_str(),
|
||||||
format!("Could not create new private key: {}", err).as_str(),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
|
||||||
// Report error
|
|
||||||
self.mount_error(
|
|
||||||
format!("Could not write private key to file: {}", err).as_str(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Restore terminal
|
Err(err) => {
|
||||||
#[cfg(not(target_os = "windows"))]
|
// Report error
|
||||||
if let Some(ctx) = self.context.as_mut() {
|
self.mount_error(format!("Could not write private key to file: {}", err).as_str());
|
||||||
// Clear screen
|
|
||||||
ctx.clear_screen();
|
|
||||||
// Enter alternate mode
|
|
||||||
ctx.enter_alternate_screen();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Restore terminal
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
if let Some(ctx) = self.context.as_mut() {
|
||||||
|
// Clear screen
|
||||||
|
ctx.clear_screen();
|
||||||
|
// Enter alternate mode
|
||||||
|
ctx.enter_alternate_screen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### set_color
|
/// ### set_color
|
||||||
|
|||||||
@@ -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,27 +101,22 @@ 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 ctx.config_client.get_ssh_key(key) {
|
||||||
match config_cli.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(format!("Could not edit ssh key: {}", err)),
|
||||||
Err(err) => {
|
|
||||||
Err(format!("Could not edit ssh key: {}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(err) => Err(format!("Could not read ssh key: {}", err)),
|
},
|
||||||
}
|
Err(err) => Err(format!("Could not read ssh key: {}", err)),
|
||||||
}
|
}
|
||||||
None => Ok(()),
|
}
|
||||||
},
|
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
};
|
};
|
||||||
// Restore terminal
|
// Restore terminal
|
||||||
@@ -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(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,73 +286,71 @@ 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(self.config().get_text_editor().as_path().to_string_lossy());
|
||||||
String::from(cli.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();
|
let _ = self.view.update(super::COMPONENT_INPUT_TEXT_EDITOR, props);
|
||||||
let _ = self.view.update(super::COMPONENT_INPUT_TEXT_EDITOR, props);
|
}
|
||||||
}
|
// 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 self.config().get_default_protocol() {
|
||||||
let protocol: usize = match cli.get_default_protocol() {
|
FileTransferProtocol::Sftp => 0,
|
||||||
FileTransferProtocol::Sftp => 0,
|
FileTransferProtocol::Scp => 1,
|
||||||
FileTransferProtocol::Scp => 1,
|
FileTransferProtocol::Ftp(false) => 2,
|
||||||
FileTransferProtocol::Ftp(false) => 2,
|
FileTransferProtocol::Ftp(true) => 3,
|
||||||
FileTransferProtocol::Ftp(true) => 3,
|
};
|
||||||
};
|
let props = RadioPropsBuilder::from(props).with_value(protocol).build();
|
||||||
let props = RadioPropsBuilder::from(props).with_value(protocol).build();
|
let _ = self
|
||||||
let _ = self
|
.view
|
||||||
.view
|
.update(super::COMPONENT_RADIO_DEFAULT_PROTOCOL, props);
|
||||||
.update(super::COMPONENT_RADIO_DEFAULT_PROTOCOL, props);
|
}
|
||||||
}
|
// 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 self.config().get_show_hidden_files() {
|
||||||
let hidden: usize = match cli.get_show_hidden_files() {
|
true => 0,
|
||||||
true => 0,
|
false => 1,
|
||||||
false => 1,
|
};
|
||||||
};
|
let props = RadioPropsBuilder::from(props).with_value(hidden).build();
|
||||||
let props = RadioPropsBuilder::from(props).with_value(hidden).build();
|
let _ = self.view.update(super::COMPONENT_RADIO_HIDDEN_FILES, props);
|
||||||
let _ = self.view.update(super::COMPONENT_RADIO_HIDDEN_FILES, props);
|
}
|
||||||
}
|
// 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 self.config().get_check_for_updates() {
|
||||||
let updates: usize = match cli.get_check_for_updates() {
|
true => 0,
|
||||||
true => 0,
|
false => 1,
|
||||||
false => 1,
|
};
|
||||||
};
|
let props = RadioPropsBuilder::from(props).with_value(updates).build();
|
||||||
let props = RadioPropsBuilder::from(props).with_value(updates).build();
|
let _ = self.view.update(super::COMPONENT_RADIO_UPDATES, props);
|
||||||
let _ = self.view.update(super::COMPONENT_RADIO_UPDATES, props);
|
}
|
||||||
}
|
// 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 self.config().get_group_dirs() {
|
||||||
let dirs: usize = match cli.get_group_dirs() {
|
Some(GroupDirs::First) => 0,
|
||||||
Some(GroupDirs::First) => 0,
|
Some(GroupDirs::Last) => 1,
|
||||||
Some(GroupDirs::Last) => 1,
|
None => 2,
|
||||||
None => 2,
|
};
|
||||||
};
|
let props = RadioPropsBuilder::from(props).with_value(dirs).build();
|
||||||
let props = RadioPropsBuilder::from(props).with_value(dirs).build();
|
let _ = self.view.update(super::COMPONENT_RADIO_GROUP_DIRS, props);
|
||||||
let _ = self.view.update(super::COMPONENT_RADIO_GROUP_DIRS, props);
|
}
|
||||||
}
|
// 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 = self.config().get_local_file_fmt().unwrap_or_default();
|
||||||
let file_fmt: String = cli.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
|
.update(super::COMPONENT_INPUT_LOCAL_FILE_FMT, props);
|
||||||
.update(super::COMPONENT_INPUT_LOCAL_FILE_FMT, props);
|
}
|
||||||
}
|
// 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 = self.config().get_remote_file_fmt().unwrap_or_default();
|
||||||
let file_fmt: String = cli.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,55 +358,54 @@ impl SetupActivity {
|
|||||||
///
|
///
|
||||||
/// 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)
|
{
|
||||||
{
|
self.config_mut()
|
||||||
cli.set_text_editor(PathBuf::from(editor.as_str()));
|
.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)
|
||||||
{
|
{
|
||||||
let protocol: FileTransferProtocol = match protocol {
|
let protocol: FileTransferProtocol = match protocol {
|
||||||
1 => FileTransferProtocol::Scp,
|
1 => FileTransferProtocol::Scp,
|
||||||
2 => FileTransferProtocol::Ftp(false),
|
2 => FileTransferProtocol::Ftp(false),
|
||||||
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)
|
||||||
{
|
{
|
||||||
let dirs: Option<GroupDirs> = match opt {
|
let dirs: Option<GroupDirs> = match opt {
|
||||||
0 => Some(GroupDirs::First),
|
0 => Some(GroupDirs::First),
|
||||||
1 => Some(GroupDirs::Last),
|
1 => Some(GroupDirs::Last),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
cli.set_group_dirs(dirs);
|
self.config_mut().set_group_dirs(dirs);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -275,22 +275,21 @@ 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> = self
|
||||||
let keys: Vec<String> = cli
|
.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();
|
||||||
let props = BookmarkListPropsBuilder::from(props)
|
let props = BookmarkListPropsBuilder::from(props)
|
||||||
.with_bookmarks(Some(String::from("SSH Keys")), keys)
|
.with_bookmarks(Some(String::from("SSH Keys")), keys)
|
||||||
.build();
|
.build();
|
||||||
self.view.update(super::COMPONENT_LIST_SSH_KEYS, props);
|
self.view.update(super::COMPONENT_LIST_SSH_KEYS, props);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user