-
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
340 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//! ## FileTransferActivity | ||
//! | ||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall | ||
|
||
/** | ||
* MIT License | ||
* | ||
* termscp - Copyright (c) 2021 Christian Visintin | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
pub(crate) mod browser; | ||
pub(crate) mod transfer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
//! ## FileTransferActivity | ||
//! | ||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall | ||
|
||
/** | ||
* MIT License | ||
* | ||
* termscp - Copyright (c) 2021 Christian Visintin | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
use bytesize::ByteSize; | ||
use std::fmt; | ||
use std::time::Instant; | ||
|
||
/// ### TransferStates | ||
/// | ||
/// TransferStates contains the states related to the transfer process | ||
pub struct TransferStates { | ||
aborted: bool, // Describes whether the transfer process has been aborted | ||
pub full: ProgressStates, // full transfer states | ||
pub partial: ProgressStates, // Partial transfer states | ||
} | ||
|
||
/// ### ProgressStates | ||
/// | ||
/// Progress states describes the states for the progress of a single transfer part | ||
pub struct ProgressStates { | ||
started: Instant, | ||
total: usize, | ||
written: usize, | ||
} | ||
|
||
impl Default for TransferStates { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl TransferStates { | ||
/// ### new | ||
/// | ||
/// Instantiates a new transfer states | ||
pub fn new() -> TransferStates { | ||
TransferStates { | ||
aborted: false, | ||
full: ProgressStates::default(), | ||
partial: ProgressStates::default(), | ||
} | ||
} | ||
|
||
/// ### reset | ||
/// | ||
/// Re-intiialize transfer states | ||
pub fn reset(&mut self) { | ||
self.aborted = false; | ||
} | ||
|
||
/// ### abort | ||
/// | ||
/// Set aborted to true | ||
pub fn abort(&mut self) { | ||
self.aborted = true; | ||
} | ||
|
||
/// ### aborted | ||
/// | ||
/// Returns whether transfer has been aborted | ||
pub fn aborted(&self) -> bool { | ||
self.aborted | ||
} | ||
} | ||
|
||
impl Default for ProgressStates { | ||
fn default() -> Self { | ||
ProgressStates { | ||
started: Instant::now(), | ||
written: 0, | ||
total: 0, | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for ProgressStates { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
let eta: String = match self.calc_eta() { | ||
0 => String::from("--:--"), | ||
seconds => format!( | ||
"{:0width$}:{:0width$}", | ||
(seconds / 60), | ||
(seconds % 60), | ||
width = 2 | ||
), | ||
}; | ||
write!( | ||
f, | ||
"{:.2}% - ETA {} ({}/s)", | ||
self.calc_progress_percentage(), | ||
eta, | ||
ByteSize(self.calc_bytes_per_second()) | ||
) | ||
} | ||
} | ||
|
||
impl ProgressStates { | ||
/// ### init | ||
/// | ||
/// Initialize a new Progress State | ||
pub fn init(&mut self, sz: usize) { | ||
self.started = Instant::now(); | ||
self.total = sz; | ||
self.written = 0; | ||
} | ||
|
||
/// ### update_progress | ||
/// | ||
/// Update progress state | ||
pub fn update_progress(&mut self, delta: usize) -> f64 { | ||
self.written += delta; | ||
self.calc_progress_percentage() | ||
} | ||
|
||
/// ### calc_progress | ||
/// | ||
/// Calculate progress in a range between 0.0 to 1.0 | ||
pub fn calc_progress(&self) -> f64 { | ||
let prog: f64 = (self.written as f64) / (self.total as f64); | ||
match prog > 1.0 { | ||
true => 1.0, | ||
false => prog, | ||
} | ||
} | ||
|
||
/// ### started | ||
/// | ||
/// Get started | ||
pub fn started(&self) -> Instant { | ||
self.started | ||
} | ||
|
||
/// ### calc_progress_percentage | ||
/// | ||
/// Calculate the current transfer progress as percentage | ||
fn calc_progress_percentage(&self) -> f64 { | ||
self.calc_progress() * 100.0 | ||
} | ||
|
||
/// ### calc_bytes_per_second | ||
/// | ||
/// Generic function to calculate bytes per second using elapsed time since transfer started and the bytes written | ||
/// and the total amount of bytes to write | ||
pub fn calc_bytes_per_second(&self) -> u64 { | ||
// bytes_written : elapsed_secs = x : 1 | ||
let elapsed_secs: u64 = self.started.elapsed().as_secs(); | ||
match elapsed_secs { | ||
0 => match self.written == self.total { | ||
// NOTE: would divide by 0 :D | ||
true => self.total as u64, // Download completed in less than 1 second | ||
false => 0, // 0 B/S | ||
}, | ||
_ => self.written as u64 / elapsed_secs, | ||
} | ||
} | ||
|
||
/// ### calc_eta | ||
/// | ||
/// Calculate ETA for current transfer as seconds | ||
fn calc_eta(&self) -> u64 { | ||
let elapsed_secs: u64 = self.started.elapsed().as_secs(); | ||
let prog: f64 = self.calc_progress_percentage(); | ||
match prog as u64 { | ||
0 => 0, | ||
_ => ((elapsed_secs * 100) / (prog as u64)) - elapsed_secs, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
|
||
use super::*; | ||
|
||
use pretty_assertions::assert_eq; | ||
use std::time::Duration; | ||
|
||
#[test] | ||
fn test_ui_activities_filetransfer_lib_transfer_progress_states() { | ||
let mut states: ProgressStates = ProgressStates::default(); | ||
assert_eq!(states.total, 0); | ||
assert_eq!(states.written, 0); | ||
assert!(states.started().elapsed().as_secs() < 5); | ||
// Init new transfer | ||
states.init(1024); | ||
assert_eq!(states.total, 1024); | ||
assert_eq!(states.written, 0); | ||
assert_eq!(states.calc_bytes_per_second(), 0); | ||
assert_eq!(states.calc_eta(), 0); | ||
assert_eq!(states.calc_progress_percentage(), 0.0); | ||
assert_eq!(states.calc_progress(), 0.0); | ||
assert_eq!(states.to_string().as_str(), "0.00% - ETA --:-- (0 B/s)"); | ||
// Wait 4 second (virtually) | ||
states.started = states.started.checked_sub(Duration::from_secs(4)).unwrap(); | ||
// Update state | ||
states.update_progress(256); | ||
assert_eq!(states.total, 1024); | ||
assert_eq!(states.written, 256); | ||
assert_eq!(states.calc_bytes_per_second(), 64); // 256 bytes in 4 seconds | ||
assert_eq!(states.calc_eta(), 12); // 16 total sub 4 | ||
assert_eq!(states.calc_progress_percentage(), 25.0); | ||
assert_eq!(states.calc_progress(), 0.25); | ||
assert_eq!(states.to_string().as_str(), "25.00% - ETA 00:12 (64 B/s)"); | ||
// 100% | ||
states.started = states.started.checked_sub(Duration::from_secs(12)).unwrap(); | ||
states.update_progress(768); | ||
assert_eq!(states.total, 1024); | ||
assert_eq!(states.written, 1024); | ||
assert_eq!(states.calc_bytes_per_second(), 64); // 256 bytes in 4 seconds | ||
assert_eq!(states.calc_eta(), 0); // 16 total sub 4 | ||
assert_eq!(states.calc_progress_percentage(), 100.0); | ||
assert_eq!(states.calc_progress(), 1.0); | ||
assert_eq!(states.to_string().as_str(), "100.00% - ETA --:-- (64 B/s)"); | ||
// Check if terminated at started | ||
states.started = Instant::now(); | ||
assert_eq!(states.calc_bytes_per_second(), 1024); | ||
} | ||
|
||
#[test] | ||
fn test_ui_activities_filetransfer_lib_transfer_states() { | ||
let mut states: TransferStates = TransferStates::default(); | ||
assert_eq!(states.aborted, false); | ||
assert_eq!(states.full.total, 0); | ||
assert_eq!(states.full.written, 0); | ||
assert!(states.full.started.elapsed().as_secs() < 5); | ||
assert_eq!(states.partial.total, 0); | ||
assert_eq!(states.partial.written, 0); | ||
assert!(states.partial.started.elapsed().as_secs() < 5); | ||
// Aborted | ||
states.abort(); | ||
assert_eq!(states.aborted(), true); | ||
states.reset(); | ||
assert_eq!(states.aborted(), false); | ||
} | ||
} |
Oops, something went wrong.