diff --git a/src/activity_manager.rs b/src/activity_manager.rs index 133481e..3a852c6 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -56,6 +56,7 @@ pub enum NextActivity { pub struct ActivityManager { context: Option, interval: Duration, + local_dir: PathBuf, } impl ActivityManager { @@ -64,19 +65,16 @@ impl ActivityManager { /// Initializes a new Activity Manager pub fn new(local_dir: &Path, interval: Duration) -> Result { // Prepare Context - let host: Localhost = match Localhost::new(local_dir.to_path_buf()) { - Ok(h) => h, - Err(e) => return Err(e), - }; // Initialize configuration client let (config_client, error): (Option, Option) = match Self::init_config_client() { Ok(cli) => (Some(cli), None), Err(err) => (None, Some(err)), }; - let ctx: Context = Context::new(host, config_client, error); + let ctx: Context = Context::new(config_client, error); Ok(ActivityManager { context: Some(ctx), + local_dir: local_dir.to_path_buf(), interval, }) } @@ -182,7 +180,7 @@ impl ActivityManager { /// Returns the next activity to run fn run_filetransfer(&mut self) -> Option { // Get context - let ctx: Context = match self.context.take() { + let mut ctx: Context = match self.context.take() { Some(ctx) => ctx, None => return None, }; @@ -193,7 +191,15 @@ impl ActivityManager { }; // Prepare activity let protocol: FileTransferProtocol = ft_params.protocol; - let mut activity: FileTransferActivity = FileTransferActivity::new(protocol); + let host: Localhost = match Localhost::new(self.local_dir.clone()) { + Ok(host) => host, + Err(err) => { + // Set error in context + ctx.set_error(format!("Could not initialize localhost: {}", err)); + return None; + } + }; + let mut activity: FileTransferActivity = FileTransferActivity::new(host, protocol); // Prepare result let result: Option; // Create activity diff --git a/src/ui/activities/filetransfer_activity/actions.rs b/src/ui/activities/filetransfer_activity/actions.rs index e1bdd4a..daa5939 100644 --- a/src/ui/activities/filetransfer_activity/actions.rs +++ b/src/ui/activities/filetransfer_activity/actions.rs @@ -191,32 +191,30 @@ impl FileTransferActivity { if let Some(idx) = self.get_local_file_idx() { let dest_path: PathBuf = PathBuf::from(input); let entry: FsEntry = self.local.get(idx).unwrap().clone(); - if let Some(ctx) = self.context.as_mut() { - match ctx.local.copy(&entry, dest_path.as_path()) { - Ok(_) => { - self.log( - LogLevel::Info, - format!( - "Copied \"{}\" to \"{}\"", - entry.get_abs_path().display(), - dest_path.display() - ) - .as_str(), - ); - // Reload entries - let wrkdir: PathBuf = self.local.wrkdir.clone(); - self.local_scan(wrkdir.as_path()); - } - Err(err) => self.log_and_alert( - LogLevel::Error, + match self.host.copy(&entry, dest_path.as_path()) { + Ok(_) => { + self.log( + LogLevel::Info, format!( - "Could not copy \"{}\" to \"{}\": {}", + "Copied \"{}\" to \"{}\"", entry.get_abs_path().display(), - dest_path.display(), - err - ), - ), + dest_path.display() + ) + .as_str(), + ); + // Reload entries + let wrkdir: PathBuf = self.local.wrkdir.clone(); + self.local_scan(wrkdir.as_path()); } + Err(err) => self.log_and_alert( + LogLevel::Error, + format!( + "Could not copy \"{}\" to \"{}\": {}", + entry.get_abs_path().display(), + dest_path.display(), + err + ), + ), } } } @@ -255,13 +253,7 @@ impl FileTransferActivity { } pub(super) fn action_local_mkdir(&mut self, input: String) { - match self - .context - .as_mut() - .unwrap() - .local - .mkdir(PathBuf::from(input.as_str()).as_path()) - { + match self.host.mkdir(PathBuf::from(input.as_str()).as_path()) { Ok(_) => { // Reload files self.log( @@ -316,13 +308,7 @@ impl FileTransferActivity { } let full_path: PathBuf = entry.get_abs_path(); // Rename file or directory and report status as popup - match self - .context - .as_mut() - .unwrap() - .local - .rename(&entry, dst_path.as_path()) - { + match self.host.rename(&entry, dst_path.as_path()) { Ok(_) => { // Reload files let path: PathBuf = self.local.wrkdir.clone(); @@ -386,7 +372,7 @@ impl FileTransferActivity { if let Some(entry) = entry { let full_path: PathBuf = entry.get_abs_path(); // Delete file or directory and report status as popup - match self.context.as_mut().unwrap().local.remove(&entry) { + match self.host.remove(&entry) { Ok(_) => { // Reload files let p: PathBuf = self.local.wrkdir.clone(); @@ -473,22 +459,20 @@ impl FileTransferActivity { } // Create file let file_path: PathBuf = PathBuf::from(input.as_str()); - if let Some(ctx) = self.context.as_mut() { - if let Err(err) = ctx.local.open_file_write(file_path.as_path()) { - self.log_and_alert( - LogLevel::Error, - format!("Could not create file \"{}\": {}", file_path.display(), err), - ); - } else { - self.log( - LogLevel::Info, - format!("Created file \"{}\"", file_path.display()).as_str(), - ); - } - // Reload files - let path: PathBuf = self.local.wrkdir.clone(); - self.local_scan(path.as_path()); + if let Err(err) = self.host.open_file_write(file_path.as_path()) { + self.log_and_alert( + LogLevel::Error, + format!("Could not create file \"{}\": {}", file_path.display(), err), + ); + } else { + self.log( + LogLevel::Info, + format!("Created file \"{}\"", file_path.display()).as_str(), + ); } + // Reload files + let path: PathBuf = self.local.wrkdir.clone(); + self.local_scan(path.as_path()); } pub(super) fn action_remote_newfile(&mut self, input: String) { @@ -516,46 +500,39 @@ impl FileTransferActivity { ), Ok(tfile) => { // Stat tempfile - if let Some(ctx) = self.context.as_mut() { - let local_file: FsEntry = match ctx.local.stat(tfile.path()) { - Err(err) => { - self.log_and_alert( - LogLevel::Error, - format!("Could not stat tempfile: {}", err), - ); - return; - } - Ok(f) => f, - }; - if let FsEntry::File(local_file) = local_file { - // Create file - match self.client.send_file(&local_file, file_path.as_path()) { - Err(err) => self.log_and_alert( - LogLevel::Error, - format!( - "Could not create file \"{}\": {}", - file_path.display(), - err - ), - ), - Ok(writer) => { - // Finalize write - if let Err(err) = self.client.on_sent(writer) { - self.log_and_alert( - LogLevel::Warn, - format!("Could not finalize file: {}", err), - ); - } else { - self.log( - LogLevel::Info, - format!("Created file \"{}\"", file_path.display()) - .as_str(), - ); - } - // Reload files - let path: PathBuf = self.remote.wrkdir.clone(); - self.remote_scan(path.as_path()); + let local_file: FsEntry = match self.host.stat(tfile.path()) { + Err(err) => { + self.log_and_alert( + LogLevel::Error, + format!("Could not stat tempfile: {}", err), + ); + return; + } + Ok(f) => f, + }; + if let FsEntry::File(local_file) = local_file { + // Create file + match self.client.send_file(&local_file, file_path.as_path()) { + Err(err) => self.log_and_alert( + LogLevel::Error, + format!("Could not create file \"{}\": {}", file_path.display(), err), + ), + Ok(writer) => { + // Finalize write + if let Err(err) = self.client.on_sent(writer) { + self.log_and_alert( + LogLevel::Warn, + format!("Could not finalize file: {}", err), + ); + } else { + self.log( + LogLevel::Info, + format!("Created file \"{}\"", file_path.display()).as_str(), + ); } + // Reload files + let path: PathBuf = self.remote.wrkdir.clone(); + self.remote_scan(path.as_path()); } } } @@ -564,7 +541,7 @@ impl FileTransferActivity { } pub(super) fn action_local_exec(&mut self, input: String) { - match self.context.as_mut().unwrap().local.exec(input.as_str()) { + match self.host.exec(input.as_str()) { Ok(output) => { // Reload files self.log( @@ -605,7 +582,7 @@ impl FileTransferActivity { } pub(super) fn action_local_find(&mut self, input: String) -> Result, String> { - match self.context.as_mut().unwrap().local.find(input.as_str()) { + match self.host.find(input.as_str()) { Ok(entries) => Ok(entries), Err(err) => Err(format!("Could not search for files: {}", err)), } @@ -666,7 +643,7 @@ impl FileTransferActivity { FileExplorerTab::FindLocal | FileExplorerTab::Local => { let full_path: PathBuf = entry.get_abs_path(); // Delete file or directory and report status as popup - match self.context.as_mut().unwrap().local.remove(&entry) { + match self.host.remove(&entry) { Ok(_) => { // Reload files let p: PathBuf = self.local.wrkdir.clone(); diff --git a/src/ui/activities/filetransfer_activity/mod.rs b/src/ui/activities/filetransfer_activity/mod.rs index c0dd44e..d02eac5 100644 --- a/src/ui/activities/filetransfer_activity/mod.rs +++ b/src/ui/activities/filetransfer_activity/mod.rs @@ -46,6 +46,7 @@ use crate::filetransfer::sftp_transfer::SftpFileTransfer; use crate::filetransfer::{FileTransfer, FileTransferProtocol}; use crate::fs::explorer::FileExplorer; use crate::fs::FsEntry; +use crate::host::Localhost; use crate::system::config_client::ConfigClient; // Includes @@ -234,6 +235,7 @@ pub struct FileTransferActivity { exit_reason: Option, // Exit reason context: Option, // Context holder view: View, // View + host: Localhost, // Localhost client: Box, // File transfer client local: FileExplorer, // Local File explorer state remote: FileExplorer, // Remote File explorer state @@ -249,13 +251,14 @@ impl FileTransferActivity { /// ### new /// /// Instantiates a new FileTransferActivity - pub fn new(protocol: FileTransferProtocol) -> FileTransferActivity { + pub fn new(host: Localhost, protocol: FileTransferProtocol) -> FileTransferActivity { // Get config client let config_client: Option = Self::init_config_client(); FileTransferActivity { exit_reason: None, context: None, view: View::init(), + host, client: match protocol { FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new( Self::make_ssh_storage(config_client.as_ref()), @@ -296,7 +299,7 @@ impl Activity for FileTransferActivity { // Put raw mode on enabled let _ = enable_raw_mode(); // Set working directory - let pwd: PathBuf = self.context.as_ref().unwrap().local.pwd(); + let pwd: PathBuf = self.host.pwd(); // Get files at current wd self.local_scan(pwd.as_path()); self.local.wrkdir = pwd; diff --git a/src/ui/activities/filetransfer_activity/session.rs b/src/ui/activities/filetransfer_activity/session.rs index a98f55b..94f6af5 100644 --- a/src/ui/activities/filetransfer_activity/session.rs +++ b/src/ui/activities/filetransfer_activity/session.rs @@ -221,13 +221,7 @@ impl FileTransferActivity { format!("Created directory \"{}\"", remote_path.display()).as_ref(), ); // Get files in dir - match self - .context - .as_ref() - .unwrap() - .local - .scan_dir(dir.abs_path.as_path()) - { + match self.host.scan_dir(dir.abs_path.as_path()) { Ok(entries) => { // Iterate over files for entry in entries.iter() { @@ -322,9 +316,8 @@ impl FileTransferActivity { err, TransferErrorReason::Abrupted | TransferErrorReason::LocalIoError(_) ) { - let local = &mut self.context.as_mut().unwrap().local; // Stat file - match local.stat(local_file_path.as_path()) { + match self.host.stat(local_file_path.as_path()) { Err(err) => self.log( LogLevel::Error, format!( @@ -335,7 +328,7 @@ impl FileTransferActivity { .as_str(), ), Ok(entry) => { - if let Err(err) = local.remove(&entry) { + if let Err(err) = self.host.remove(&entry) { self.log( LogLevel::Error, format!( @@ -359,24 +352,12 @@ impl FileTransferActivity { None => local_dir_path.push(dir.name.as_str()), } // Create directory on local - match self - .context - .as_mut() - .unwrap() - .local - .mkdir_ex(local_dir_path.as_path(), true) - { + match self.host.mkdir_ex(local_dir_path.as_path(), true) { Ok(_) => { // Apply file mode to directory #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] if let Some(pex) = dir.unix_pex { - if let Err(err) = self - .context - .as_ref() - .unwrap() - .local - .chmod(local_dir_path.as_path(), pex) - { + if let Err(err) = self.host.chmod(local_dir_path.as_path(), pex) { self.log( LogLevel::Error, format!( @@ -464,13 +445,7 @@ impl FileTransferActivity { ) -> Result<(), TransferErrorReason> { // Upload file // Try to open local file - match self - .context - .as_ref() - .unwrap() - .local - .open_file_read(local.abs_path.as_path()) - { + match self.host.open_file_read(local.abs_path.as_path()) { Ok(mut fhnd) => match self.client.send_file(local, remote) { Ok(mut rhnd) => { // Write file @@ -580,7 +555,7 @@ impl FileTransferActivity { file_name: String, ) -> Result<(), TransferErrorReason> { // Try to open local file - match self.context.as_ref().unwrap().local.open_file_write(local) { + match self.host.open_file_write(local) { Ok(mut local_file) => { // Download file from remote match self.client.recv_file(remote) { @@ -657,8 +632,7 @@ impl FileTransferActivity { // Apply file mode to file #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] if let Some(pex) = remote.unix_pex { - if let Err(err) = self.context.as_ref().unwrap().local.chmod(local, pex) - { + if let Err(err) = self.host.chmod(local, pex) { self.log( LogLevel::Error, format!( @@ -696,7 +670,7 @@ impl FileTransferActivity { /// /// Scan current local directory pub(super) fn local_scan(&mut self, path: &Path) { - match self.context.as_ref().unwrap().local.scan_dir(path) { + match self.host.scan_dir(path) { Ok(files) => { // Set files and sort (sorting is implicit) self.local.set_files(files); @@ -735,7 +709,7 @@ impl FileTransferActivity { // Get current directory let prev_dir: PathBuf = self.local.wrkdir.clone(); // Change directory - match self.context.as_mut().unwrap().local.change_wrkdir(path) { + match self.host.change_wrkdir(path) { Ok(_) => { self.log( LogLevel::Info, @@ -858,8 +832,7 @@ impl FileTransferActivity { return Err(format!("Could not open file {}: {}", file.name, err)); } // Get current file modification time - let prev_mtime: SystemTime = match self.context.as_ref().unwrap().local.stat(tmpfile.path()) - { + let prev_mtime: SystemTime = match self.host.stat(tmpfile.path()) { Ok(e) => e.get_last_change_time(), Err(err) => { return Err(format!( @@ -874,8 +847,7 @@ impl FileTransferActivity { return Err(err); } // Get local fs entry - let tmpfile_entry: FsEntry = match self.context.as_ref().unwrap().local.stat(tmpfile.path()) - { + let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) { Ok(e) => e, Err(err) => { return Err(format!( @@ -897,17 +869,16 @@ impl FileTransferActivity { .as_ref(), ); // Get local fs entry - let tmpfile_entry: FsEntry = - match self.context.as_ref().unwrap().local.stat(tmpfile.path()) { - Ok(e) => e, - Err(err) => { - return Err(format!( - "Could not stat \"{}\": {}", - tmpfile.path().display(), - err - )) - } - }; + let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) { + Ok(e) => e, + Err(err) => { + return Err(format!( + "Could not stat \"{}\": {}", + tmpfile.path().display(), + err + )) + } + }; // Write file let tmpfile_entry: &FsFile = match &tmpfile_entry { FsEntry::Directory(_) => panic!("tempfile is a directory for some reason"), diff --git a/src/ui/context.rs b/src/ui/context.rs index 1199aed..a0fcfa7 100644 --- a/src/ui/context.rs +++ b/src/ui/context.rs @@ -33,7 +33,6 @@ extern crate tuirealm; use super::input::InputHandler; use super::store::Store; use crate::filetransfer::FileTransferProtocol; -use crate::host::Localhost; use crate::system::config_client::ConfigClient; // Includes @@ -49,7 +48,6 @@ use tuirealm::tui::Terminal; /// /// Context holds data structures used by the ui pub struct Context { - pub local: Localhost, pub ft_params: Option, pub(crate) config_client: Option, pub(crate) store: Store, @@ -74,16 +72,11 @@ impl Context { /// ### new /// /// Instantiates a new Context - pub fn new( - local: Localhost, - config_client: Option, - error: Option, - ) -> Context { + pub fn new(config_client: Option, error: Option) -> Context { // Create terminal let mut stdout = stdout(); assert!(execute!(stdout, EnterAlternateScreen).is_ok()); Context { - local, ft_params: None, config_client, store: Store::init(), @@ -93,14 +86,12 @@ impl Context { } } - /* NOTE: in case is necessary /// ### set_error /// /// Set context error pub fn set_error(&mut self, err: String) { self.error = Some(err); } - */ /// ### get_error /// @@ -165,7 +156,6 @@ mod tests { use super::*; use pretty_assertions::assert_eq; - use std::path::PathBuf; #[test] fn test_ui_context_ft_params() { @@ -181,16 +171,15 @@ mod tests { #[cfg(not(feature = "githubActions"))] fn test_ui_context() { // Prepare stuff - let wrkdir: PathBuf = std::env::current_dir().unwrap_or(PathBuf::from("/")); - let mut ctx: Context = Context::new( - Localhost::new(wrkdir).ok().unwrap(), - None, - Some(String::from("alles kaput")), - ); + let mut ctx: Context = Context::new(None, Some(String::from("alles kaput"))); assert!(ctx.error.is_some()); assert_eq!(ctx.get_error().unwrap().as_str(), "alles kaput"); assert!(ctx.error.is_none()); assert!(ctx.get_error().is_none()); + ctx.set_error(String::from("err")); + assert!(ctx.error.is_some()); + assert!(ctx.get_error().is_some()); + assert!(ctx.get_error().is_none()); // Try other methods ctx.enter_alternate_screen(); ctx.clear_screen();