From 48483a5c99646e9a931bd0ccab643804eba8b34d Mon Sep 17 00:00:00 2001 From: veeso Date: Fri, 18 Jun 2021 13:02:04 +0200 Subject: [PATCH] Unique function to send and receive files in session.rs via `TransferPayload`. Fixed transfer size when sending multiple entries --- CHANGELOG.md | 1 + src/fs/mod.rs | 1 - .../activities/filetransfer/actions/copy.rs | 55 +++--- .../activities/filetransfer/actions/edit.rs | 41 ++--- .../activities/filetransfer/actions/find.rs | 65 +++++-- src/ui/activities/filetransfer/actions/mod.rs | 2 +- .../activities/filetransfer/actions/save.rs | 60 ++++++- src/ui/activities/filetransfer/mod.rs | 3 +- src/ui/activities/filetransfer/session.rs | 169 ++++++++++++++---- 9 files changed, 298 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 089393c..b9e17ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Released on FIXME: ?? - Fixed [Issue 44](https://github.com/veeso/termscp/issues/44): Could not move files to other paths in FTP - Fixed [Issue 43](https://github.com/veeso/termscp/issues/43): Could not remove non-empty directories in FTP - Fixed [Issue 39](https://github.com/veeso/termscp/issues/39): Help panels as `ScrollTable` to allow displaying entire content on small screens + - Fixed [Issue 38](https://github.com/veeso/termscp/issues/38): Transfer size was wrong when transferring "selected" files (with mark) - Fixed [Issue 37](https://github.com/veeso/termscp/issues/37): progress bar not visible when editing remote files - Dependencies: - Updated `textwrap` to `0.14.0` diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 447d8fc..07e06a9 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -227,7 +227,6 @@ impl FsEntry { } } - #[cfg(test)] /// ### unwrap_file /// /// Unwrap FsEntry as FsFile diff --git a/src/ui/activities/filetransfer/actions/copy.rs b/src/ui/activities/filetransfer/actions/copy.rs index 6b1bd6e..27e43a6 100644 --- a/src/ui/activities/filetransfer/actions/copy.rs +++ b/src/ui/activities/filetransfer/actions/copy.rs @@ -27,8 +27,9 @@ */ extern crate tempfile; // locals -use super::{FileTransferActivity, FsEntry, LogLevel, SelectedEntry}; +use super::{FileTransferActivity, FsEntry, LogLevel, SelectedEntry, TransferPayload}; use crate::filetransfer::FileTransferErrorType; +use crate::fs::FsFile; use std::path::{Path, PathBuf}; impl FileTransferActivity { @@ -66,7 +67,7 @@ impl FileTransferActivity { match self.get_remote_selected_entries() { SelectedEntry::One(entry) => { let dest_path: PathBuf = PathBuf::from(input); - self.remote_copy_file(&entry, dest_path.as_path()); + self.remote_copy_file(entry, dest_path.as_path()); // Reload entries self.reload_remote_dir(); } @@ -74,7 +75,7 @@ impl FileTransferActivity { // Try to copy each file to Input/{FILE_NAME} let base_path: PathBuf = PathBuf::from(input); // Iter files - for entry in entries.iter() { + for entry in entries.into_iter() { let mut dest_path: PathBuf = base_path.clone(); dest_path.push(entry.get_name()); self.remote_copy_file(entry, dest_path.as_path()); @@ -110,8 +111,8 @@ impl FileTransferActivity { } } - fn remote_copy_file(&mut self, entry: &FsEntry, dest: &Path) { - match self.client.as_mut().copy(entry, dest) { + fn remote_copy_file(&mut self, entry: FsEntry, dest: &Path) { + match self.client.as_mut().copy(&entry, dest) { Ok(_) => { self.log( LogLevel::Info, @@ -143,7 +144,7 @@ impl FileTransferActivity { /// ### tricky_copy /// /// Tricky copy will be used whenever copy command is not available on remote host - fn tricky_copy(&mut self, entry: &FsEntry, dest: &Path) { + fn tricky_copy(&mut self, entry: FsEntry, dest: &Path) { // match entry match entry { FsEntry::File(entry) => { @@ -159,8 +160,10 @@ impl FileTransferActivity { } }; // Download file + let name = entry.name.clone(); + let entry_path = entry.abs_path.clone(); if let Err(err) = - self.filetransfer_recv_one(entry, tmpfile.path(), entry.name.clone()) + self.filetransfer_recv(TransferPayload::File(entry), tmpfile.path(), Some(name)) { self.log_and_alert( LogLevel::Error, @@ -169,8 +172,8 @@ impl FileTransferActivity { return; } // Get local fs entry - let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) { - Ok(e) => e, + let tmpfile_entry: FsFile = match self.host.stat(tmpfile.path()) { + Ok(e) => e.unwrap_file(), Err(err) => { self.log_and_alert( LogLevel::Error, @@ -183,14 +186,10 @@ impl FileTransferActivity { return; } }; - let tmpfile_entry = match &tmpfile_entry { - FsEntry::Directory(_) => panic!("tempfile is a directory for some reason"), - FsEntry::File(f) => f, - }; // Upload file to destination let wrkdir = self.remote().wrkdir.clone(); - if let Err(err) = self.filetransfer_send_one( - tmpfile_entry, + if let Err(err) = self.filetransfer_send( + TransferPayload::File(tmpfile_entry), wrkdir.as_path(), Some(String::from(dest.to_string_lossy())), ) { @@ -198,7 +197,7 @@ impl FileTransferActivity { LogLevel::Error, format!( "Copy failed: could not write file {}: {}", - entry.abs_path.display(), + entry_path.display(), err ), ); @@ -216,11 +215,19 @@ impl FileTransferActivity { return; } }; - // Download file - self.filetransfer_recv(entry, tempdir.path(), None); // Get path of dest let mut tempdir_path: PathBuf = tempdir.path().to_path_buf(); tempdir_path.push(entry.get_name()); + // Download file + if let Err(err) = + self.filetransfer_recv(TransferPayload::Any(entry), tempdir.path(), None) + { + self.log_and_alert( + LogLevel::Error, + format!("Copy failed: failed to download file: {}", err), + ); + return; + } // Stat dir let tempdir_entry: FsEntry = match self.host.stat(tempdir_path.as_path()) { Ok(e) => e, @@ -238,11 +245,17 @@ impl FileTransferActivity { }; // Upload to destination let wrkdir: PathBuf = self.remote().wrkdir.clone(); - self.filetransfer_send( - &tempdir_entry, + if let Err(err) = self.filetransfer_send( + TransferPayload::Any(tempdir_entry), wrkdir.as_path(), Some(String::from(dest.to_string_lossy())), - ); + ) { + self.log_and_alert( + LogLevel::Error, + format!("Copy failed: failed to send file: {}", err), + ); + return; + } } } } diff --git a/src/ui/activities/filetransfer/actions/edit.rs b/src/ui/activities/filetransfer/actions/edit.rs index e7bb49d..42de105 100644 --- a/src/ui/activities/filetransfer/actions/edit.rs +++ b/src/ui/activities/filetransfer/actions/edit.rs @@ -26,7 +26,7 @@ * SOFTWARE. */ // locals -use super::{FileTransferActivity, FsEntry, LogLevel, SelectedEntry}; +use super::{FileTransferActivity, FsEntry, LogLevel, SelectedEntry, TransferPayload}; use crate::fs::FsFile; // ext use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; @@ -67,15 +67,15 @@ impl FileTransferActivity { SelectedEntry::None => vec![], }; // Edit all entries - for entry in entries.iter() { + for entry in entries.into_iter() { // Check if file if let FsEntry::File(file) = entry { self.log( LogLevel::Info, - format!("Opening file \"{}\"...", entry.get_abs_path().display()), + format!("Opening file \"{}\"...", file.abs_path.display()), ); // Edit file - if let Err(err) = self.edit_remote_file(&file) { + if let Err(err) = self.edit_remote_file(file) { self.log_and_alert(LogLevel::Error, err); } } @@ -141,7 +141,7 @@ impl FileTransferActivity { /// ### edit_remote_file /// /// Edit file on remote host - fn edit_remote_file(&mut self, file: &FsFile) -> Result<(), String> { + fn edit_remote_file(&mut self, file: FsFile) -> Result<(), String> { // Create temp file let tmpfile: tempfile::NamedTempFile = match tempfile::NamedTempFile::new() { Ok(f) => f, @@ -150,8 +150,14 @@ impl FileTransferActivity { } }; // Download file - if let Err(err) = self.filetransfer_recv_one(file, tmpfile.path(), file.name.clone()) { - return Err(format!("Could not open file {}: {}", file.name, err)); + let file_name = file.name.clone(); + let file_path = file.abs_path.clone(); + if let Err(err) = self.filetransfer_recv( + TransferPayload::File(file), + tmpfile.path(), + Some(file_name.clone()), + ) { + return Err(format!("Could not open file {}: {}", file_name, err)); } // Get current file modification time let prev_mtime: SystemTime = match self.host.stat(tmpfile.path()) { @@ -186,12 +192,12 @@ impl FileTransferActivity { LogLevel::Info, format!( "File \"{}\" has changed; writing changes to remote", - file.abs_path.display() + file_path.display() ), ); // Get local fs entry - let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) { - Ok(e) => e, + let tmpfile_entry: FsFile = match self.host.stat(tmpfile.path()) { + Ok(e) => e.unwrap_file(), Err(err) => { return Err(format!( "Could not stat \"{}\": {}", @@ -200,21 +206,16 @@ impl FileTransferActivity { )) } }; - // Write file - let tmpfile_entry: &FsFile = match &tmpfile_entry { - FsEntry::Directory(_) => panic!("tempfile is a directory for some reason"), - FsEntry::File(f) => f, - }; // Send file let wrkdir = self.remote().wrkdir.clone(); - if let Err(err) = self.filetransfer_send_one( - tmpfile_entry, + if let Err(err) = self.filetransfer_send( + TransferPayload::File(tmpfile_entry), wrkdir.as_path(), - Some(file.name.clone()), + Some(file_name), ) { return Err(format!( "Could not write file {}: {}", - file.abs_path.display(), + file_path.display(), err )); } @@ -222,7 +223,7 @@ impl FileTransferActivity { false => { self.log( LogLevel::Info, - format!("File \"{}\" hasn't changed", file.abs_path.display()), + format!("File \"{}\" hasn't changed", file_path.display()), ); } } diff --git a/src/ui/activities/filetransfer/actions/find.rs b/src/ui/activities/filetransfer/actions/find.rs index 7e0a97d..171c4eb 100644 --- a/src/ui/activities/filetransfer/actions/find.rs +++ b/src/ui/activities/filetransfer/actions/find.rs @@ -27,7 +27,7 @@ */ // locals use super::super::browser::FileExplorerTab; -use super::{FileTransferActivity, FsEntry, SelectedEntry}; +use super::{FileTransferActivity, FsEntry, LogLevel, SelectedEntry, TransferPayload}; use std::path::PathBuf; @@ -77,10 +77,30 @@ impl FileTransferActivity { match self.get_found_selected_entries() { SelectedEntry::One(entry) => match self.browser.tab() { FileExplorerTab::FindLocal | FileExplorerTab::Local => { - self.filetransfer_send(&entry.get_realfile(), wrkdir.as_path(), save_as); + if let Err(err) = self.filetransfer_send( + TransferPayload::Any(entry.get_realfile()), + wrkdir.as_path(), + save_as, + ) { + self.log_and_alert( + LogLevel::Error, + format!("Could not upload file: {}", err), + ); + return; + } } FileExplorerTab::FindRemote | FileExplorerTab::Remote => { - self.filetransfer_recv(&entry.get_realfile(), wrkdir.as_path(), save_as); + if let Err(err) = self.filetransfer_recv( + TransferPayload::Any(entry.get_realfile()), + wrkdir.as_path(), + save_as, + ) { + self.log_and_alert( + LogLevel::Error, + format!("Could not download file: {}", err), + ); + return; + } } }, SelectedEntry::Many(entries) => { @@ -90,21 +110,34 @@ impl FileTransferActivity { dest_path.push(save_as); } // Iter files - for entry in entries.iter() { - match self.browser.tab() { - FileExplorerTab::FindLocal | FileExplorerTab::Local => { - self.filetransfer_send( - &entry.get_realfile(), - dest_path.as_path(), - None, - ); + let entries = entries.iter().map(|x| x.get_realfile()).collect(); + match self.browser.tab() { + FileExplorerTab::FindLocal | FileExplorerTab::Local => { + if let Err(err) = self.filetransfer_send( + TransferPayload::Many(entries), + dest_path.as_path(), + None, + ) { + { + self.log_and_alert( + LogLevel::Error, + format!("Could not upload file: {}", err), + ); + return; + } } - FileExplorerTab::FindRemote | FileExplorerTab::Remote => { - self.filetransfer_recv( - &entry.get_realfile(), - dest_path.as_path(), - None, + } + FileExplorerTab::FindRemote | FileExplorerTab::Remote => { + if let Err(err) = self.filetransfer_recv( + TransferPayload::Many(entries), + dest_path.as_path(), + None, + ) { + self.log_and_alert( + LogLevel::Error, + format!("Could not download file: {}", err), ); + return; } } } diff --git a/src/ui/activities/filetransfer/actions/mod.rs b/src/ui/activities/filetransfer/actions/mod.rs index 2e13003..dcd33d9 100644 --- a/src/ui/activities/filetransfer/actions/mod.rs +++ b/src/ui/activities/filetransfer/actions/mod.rs @@ -25,7 +25,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -pub(self) use super::{FileTransferActivity, FsEntry, LogLevel}; +pub(self) use super::{FileTransferActivity, FsEntry, LogLevel, TransferPayload}; use tuirealm::{Payload, Value}; // actions diff --git a/src/ui/activities/filetransfer/actions/save.rs b/src/ui/activities/filetransfer/actions/save.rs index 508d99c..4a5c238 100644 --- a/src/ui/activities/filetransfer/actions/save.rs +++ b/src/ui/activities/filetransfer/actions/save.rs @@ -26,7 +26,7 @@ * SOFTWARE. */ // locals -use super::{FileTransferActivity, SelectedEntry}; +use super::{FileTransferActivity, LogLevel, SelectedEntry, TransferPayload}; use std::path::PathBuf; impl FileTransferActivity { @@ -50,7 +50,19 @@ impl FileTransferActivity { let wrkdir: PathBuf = self.remote().wrkdir.clone(); match self.get_local_selected_entries() { SelectedEntry::One(entry) => { - self.filetransfer_send(&entry.get_realfile(), wrkdir.as_path(), save_as); + if let Err(err) = self.filetransfer_send( + TransferPayload::Any(entry.get_realfile()), + wrkdir.as_path(), + save_as, + ) { + { + self.log_and_alert( + LogLevel::Error, + format!("Could not upload file: {}", err), + ); + return; + } + } } SelectedEntry::Many(entries) => { // In case of selection: save multiple files in wrkdir/input @@ -59,8 +71,19 @@ impl FileTransferActivity { dest_path.push(save_as); } // Iter files - for entry in entries.iter() { - self.filetransfer_send(&entry.get_realfile(), dest_path.as_path(), None); + let entries = entries.iter().map(|x| x.get_realfile()).collect(); + if let Err(err) = self.filetransfer_send( + TransferPayload::Many(entries), + dest_path.as_path(), + None, + ) { + { + self.log_and_alert( + LogLevel::Error, + format!("Could not upload file: {}", err), + ); + return; + } } } SelectedEntry::None => {} @@ -71,7 +94,19 @@ impl FileTransferActivity { let wrkdir: PathBuf = self.local().wrkdir.clone(); match self.get_remote_selected_entries() { SelectedEntry::One(entry) => { - self.filetransfer_recv(&entry.get_realfile(), wrkdir.as_path(), save_as); + if let Err(err) = self.filetransfer_recv( + TransferPayload::Any(entry.get_realfile()), + wrkdir.as_path(), + save_as, + ) { + { + self.log_and_alert( + LogLevel::Error, + format!("Could not download file: {}", err), + ); + return; + } + } } SelectedEntry::Many(entries) => { // In case of selection: save multiple files in wrkdir/input @@ -80,8 +115,19 @@ impl FileTransferActivity { dest_path.push(save_as); } // Iter files - for entry in entries.iter() { - self.filetransfer_recv(&entry.get_realfile(), dest_path.as_path(), None); + let entries = entries.iter().map(|x| x.get_realfile()).collect(); + if let Err(err) = self.filetransfer_recv( + TransferPayload::Many(entries), + dest_path.as_path(), + None, + ) { + { + self.log_and_alert( + LogLevel::Error, + format!("Could not download file: {}", err), + ); + return; + } } } SelectedEntry::None => {} diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index ee71995..6a0f25c 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -49,9 +49,10 @@ use crate::fs::explorer::FileExplorer; use crate::fs::FsEntry; use crate::host::Localhost; use crate::system::config_client::ConfigClient; -pub(crate) use lib::browser; +pub(self) use lib::browser; use lib::browser::Browser; use lib::transfer::TransferStates; +pub(self) use session::TransferPayload; // Includes use chrono::{DateTime, Local}; diff --git a/src/ui/activities/filetransfer/session.rs b/src/ui/activities/filetransfer/session.rs index ccaf6fa..bb3ef26 100644 --- a/src/ui/activities/filetransfer/session.rs +++ b/src/ui/activities/filetransfer/session.rs @@ -64,6 +64,19 @@ enum TransferErrorReason { FileTransferError(FileTransferError), } +/// ## TransferPayload +/// +/// Represents the entity to send or receive during a transfer. +/// - File: describes an individual `FsFile` to send +/// - Any: Can be any kind of `FsEntry`, but just one +/// - Many: a list of `FsEntry` +#[derive(Debug)] +pub(super) enum TransferPayload { + File(FsFile), + Any(FsEntry), + Many(Vec), +} + impl FileTransferActivity { /// ### connect /// @@ -155,27 +168,28 @@ impl FileTransferActivity { /// If entry is a directory, this applies to directory only pub(super) fn filetransfer_send( &mut self, - entry: &FsEntry, + payload: TransferPayload, curr_remote_path: &Path, dst_name: Option, - ) { - // Reset states - self.transfer.reset(); - // Calculate total size of transfer - let total_transfer_size: usize = self.get_total_transfer_size_local(entry); - self.transfer.full.init(total_transfer_size); - // Mount progress bar - self.mount_progress_bar(format!("Uploading {}...", entry.get_abs_path().display())); - // Send recurse - self.filetransfer_send_recurse(entry, curr_remote_path, dst_name); - // Umount progress bar - self.umount_progress_bar(); + ) -> Result<(), String> { + // Use different method based on payload + match payload { + TransferPayload::Any(entry) => { + self.filetransfer_send_any(&entry, curr_remote_path, dst_name) + } + TransferPayload::File(file) => { + self.filetransfer_send_file(&file, curr_remote_path, dst_name) + } + TransferPayload::Many(entries) => { + self.filetransfer_send_many(entries, curr_remote_path) + } + } } - /// ### filetransfer_send_one + /// ### filetransfer_send_file /// /// Send one file to remote at specified path. - pub(super) fn filetransfer_send_one( + fn filetransfer_send_file( &mut self, file: &FsFile, curr_remote_path: &Path, @@ -197,13 +211,64 @@ impl FileTransferActivity { }; remote_path.push(remote_file_name); // Send - let result = self.filetransfer_send_file(file, remote_path.as_path(), file_name); + let result = self.filetransfer_send_one(file, remote_path.as_path(), file_name); // Umount progress bar self.umount_progress_bar(); // Return result result.map_err(|x| x.to_string()) } + /// ### filetransfer_send_any + /// + /// Send a `TransferPayload` of type `Any` + fn filetransfer_send_any( + &mut self, + entry: &FsEntry, + curr_remote_path: &Path, + dst_name: Option, + ) -> Result<(), String> { + // Reset states + self.transfer.reset(); + // Calculate total size of transfer + let total_transfer_size: usize = self.get_total_transfer_size_local(entry); + self.transfer.full.init(total_transfer_size); + // Mount progress bar + self.mount_progress_bar(format!("Uploading {}...", entry.get_abs_path().display())); + // Send recurse + self.filetransfer_send_recurse(entry, curr_remote_path, dst_name); + // Umount progress bar + self.umount_progress_bar(); + Ok(()) + } + + /// ### filetransfer_send_many + /// + /// Send many entries to remote + fn filetransfer_send_many( + &mut self, + entries: Vec, + curr_remote_path: &Path, + ) -> Result<(), String> { + // Reset states + self.transfer.reset(); + // Calculate total size of transfer + let mut total_transfer_size: usize = 0; + for entry in entries.iter() { + total_transfer_size += self.get_total_transfer_size_local(entry); + } + self.transfer.full.init(total_transfer_size); + // Mount progress bar + self.mount_progress_bar(format!("Uploading {} entries...", entries.len())); + // Send recurse + for entry in entries.iter() { + // Send + self.filetransfer_send_recurse(entry, curr_remote_path, None); + } + // Umount progress bar + self.umount_progress_bar(); + Ok(()) + } + fn filetransfer_send_recurse( &mut self, entry: &FsEntry, @@ -225,8 +290,7 @@ impl FileTransferActivity { // Match entry match entry { FsEntry::File(file) => { - if let Err(err) = - self.filetransfer_send_file(file, remote_path.as_path(), file_name) + if let Err(err) = self.filetransfer_send_one(file, remote_path.as_path(), file_name) { // Log error self.log_and_alert( @@ -329,7 +393,7 @@ impl FileTransferActivity { /// ### filetransfer_send_file /// /// Send local file and write it to remote path - fn filetransfer_send_file( + fn filetransfer_send_one( &mut self, local: &FsFile, remote: &Path, @@ -438,11 +502,29 @@ impl FileTransferActivity { /// If dst_name is Some, entry will be saved with a different name. /// If entry is a directory, this applies to directory only pub(super) fn filetransfer_recv( + &mut self, + payload: TransferPayload, + local_path: &Path, + dst_name: Option, + ) -> Result<(), String> { + match payload { + TransferPayload::Any(entry) => self.filetransfer_recv_any(&entry, local_path, dst_name), + TransferPayload::File(file) => self.filetransfer_recv_file(&file, local_path), + TransferPayload::Many(entries) => self.filetransfer_recv_many(entries, local_path), + } + } + + /// ### filetransfer_recv_any + /// + /// Recv fs entry from remote. + /// If dst_name is Some, entry will be saved with a different name. + /// If entry is a directory, this applies to directory only + fn filetransfer_recv_any( &mut self, entry: &FsEntry, local_path: &Path, dst_name: Option, - ) { + ) -> Result<(), String> { // Reset states self.transfer.reset(); // Calculate total transfer size @@ -454,18 +536,13 @@ impl FileTransferActivity { self.filetransfer_recv_recurse(entry, local_path, dst_name); // Umount progress bar self.umount_progress_bar(); + Ok(()) } - /// ### filetransfer_recv_one + /// ### filetransfer_recv_file /// /// Receive a single file from remote. - /// Use this function instead of `filetransfer_recv_file` from external files - pub(super) fn filetransfer_recv_one( - &mut self, - entry: &FsFile, - local_path: &Path, - dst_name: String, - ) -> Result<(), String> { + fn filetransfer_recv_file(&mut self, entry: &FsFile, local_path: &Path) -> Result<(), String> { // Reset states self.transfer.reset(); // Calculate total transfer size @@ -474,13 +551,41 @@ impl FileTransferActivity { // Mount progress bar self.mount_progress_bar(format!("Downloading {}...", entry.abs_path.display())); // Receive - let result = self.filetransfer_recv_file(local_path, entry, dst_name); + let result = self.filetransfer_recv_one(local_path, entry, entry.name.clone()); // Umount progress bar self.umount_progress_bar(); // Return result result.map_err(|x| x.to_string()) } + /// ### filetransfer_send_many + /// + /// Send many entries to remote + fn filetransfer_recv_many( + &mut self, + entries: Vec, + curr_remote_path: &Path, + ) -> Result<(), String> { + // Reset states + self.transfer.reset(); + // Calculate total size of transfer + let mut total_transfer_size: usize = 0; + for entry in entries.iter() { + total_transfer_size += self.get_total_transfer_size_remote(entry); + } + self.transfer.full.init(total_transfer_size); + // Mount progress bar + self.mount_progress_bar(format!("Uploading {} entries...", entries.len())); + // Send recurse + for entry in entries.iter() { + // Send + self.filetransfer_recv_recurse(entry, curr_remote_path, None); + } + // Umount progress bar + self.umount_progress_bar(); + Ok(()) + } + fn filetransfer_recv_recurse( &mut self, entry: &FsEntry, @@ -504,7 +609,7 @@ impl FileTransferActivity { local_file_path.push(local_file_name.as_str()); // Download file if let Err(err) = - self.filetransfer_recv_file(local_file_path.as_path(), file, file_name) + self.filetransfer_recv_one(local_file_path.as_path(), file, file_name) { self.log_and_alert( LogLevel::Error, @@ -628,10 +733,10 @@ impl FileTransferActivity { } } - /// ### filetransfer_recv_file + /// ### filetransfer_recv_one /// /// Receive file from remote and write it to local path - fn filetransfer_recv_file( + fn filetransfer_recv_one( &mut self, local: &Path, remote: &FsFile,