From b57e85a8ec0d4dbaebb60084a262ded8a744bf89 Mon Sep 17 00:00:00 2001 From: timvisee Date: Mon, 19 Mar 2018 21:52:20 +0100 Subject: [PATCH] Complete upload progress bar implementation, simplify with arc/mutex --- api/src/action/upload.rs | 25 ++++++++++++++++--------- api/src/reader.rs | 17 ++++++++++------- cli/src/action/upload.rs | 4 ++-- cli/src/progress.rs | 3 +-- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/api/src/action/upload.rs b/api/src/action/upload.rs index 3b73243..fc02d00 100644 --- a/api/src/action/upload.rs +++ b/api/src/action/upload.rs @@ -1,6 +1,7 @@ use std::fs::File; use std::io::BufReader; use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; use mime_guess::{get_mime_type, Mime}; use openssl::symm::encrypt_aead; @@ -24,8 +25,7 @@ use reader::{ use file::file::File as SendFile; use file::metadata::{Metadata, XFileMetadata}; -type EncryptedReader = - ProgressReader<'static, BufReader>; +type EncryptedReader = ProgressReader>; pub type Result = ::std::result::Result; /// A file upload action to a Send server. @@ -50,7 +50,7 @@ impl Upload { pub fn invoke( self, client: &Client, - reporter: Box, + reporter: Arc>, ) -> Result { // Create file data, generate a key let file = FileData::from(Box::new(&self.path))?; @@ -58,8 +58,8 @@ impl Upload { // Crpate metadata and a file reader let metadata = self.create_metadata(&key, &file)?; - // TODO: do not use leak, as it might cause memory leaks - let reader = self.create_reader(&key, Box::leak(reporter))?; + let reader = self.create_reader(&key, reporter.clone())?; + let reader_len = reader.len().unwrap(); // Create the request to send let req = self.create_request( @@ -69,10 +69,18 @@ impl Upload { reader, ); + // Start the reporter + reporter.lock() + .expect("unable to start progress, failed to get lock") + .start(reader_len); + // Execute the request let result = self.execute_request(req, client, &key); - // TODO: finish the progress bar + // Mark the reporter as finished + reporter.lock() + .expect("unable to finish progress, failed to get lock") + .finish(); result } @@ -112,7 +120,7 @@ impl Upload { fn create_reader( &self, key: &KeySet, - reporter: &'static mut ProgressReporter, + reporter: Arc>, ) -> Result { // Open the file let file = match File::open(self.path.as_path()) { @@ -139,8 +147,7 @@ impl Upload { .expect("failed to create progress reader"); // Initialize and attach the reporter - reporter.start(reader.len().unwrap()); - reader.set_reporter(&mut *reporter); + reader.set_reporter(reporter); Ok(reader) } diff --git a/api/src/reader.rs b/api/src/reader.rs index d0e1930..5273d4f 100644 --- a/api/src/reader.rs +++ b/api/src/reader.rs @@ -7,6 +7,7 @@ use std::io::{ Error as IoError, Read, }; +use std::sync::{Arc, Mutex}; use openssl::symm::{ Cipher, @@ -236,7 +237,7 @@ unsafe impl Send for EncryptedFileReaderTagged {} /// /// The reader will only start producing `None` if the wrapped reader is doing /// so. -pub struct ProgressReader<'a, R> { +pub struct ProgressReader { /// The wrapped reader. inner: R, @@ -247,10 +248,10 @@ pub struct ProgressReader<'a, R> { progress: u64, /// A reporter, to report the progress status to. - reporter: Option<&'a mut ProgressReporter>, + reporter: Option>>, } -impl<'a, R: Read> ProgressReader<'a, R> { +impl ProgressReader { /// Wrap the given reader with an exact length, in a progress reader. pub fn new(inner: R) -> Result where @@ -277,7 +278,7 @@ impl<'a, R: Read> ProgressReader<'a, R> { } /// Set the reporter to report the status to. - pub fn set_reporter(&mut self, reporter: &'a mut ProgressReporter) { + pub fn set_reporter(&mut self, reporter: Arc>) { self.reporter = Some(reporter); } @@ -287,7 +288,7 @@ impl<'a, R: Read> ProgressReader<'a, R> { } } -impl<'a, R: Read> Read for ProgressReader<'a, R> { +impl Read for ProgressReader { /// Read from the encrypted file, and then the encryption tag. fn read(&mut self, buf: &mut [u8]) -> Result { // Read from the wrapped reader, increase the progress @@ -301,14 +302,16 @@ impl<'a, R: Read> Read for ProgressReader<'a, R> { // Report if let Some(reporter) = self.reporter.as_mut() { - reporter.progress(self.progress); + reporter.lock() + .expect("failed to update progress, unable to lock reproter") + .progress(self.progress); } Ok(len) } } -impl<'a, R: Read> ExactLengthReader for ProgressReader<'a, R> { +impl ExactLengthReader for ProgressReader { // Return the specified length. fn len(&self) -> Result { Ok(self.len) diff --git a/cli/src/action/upload.rs b/cli/src/action/upload.rs index d13a56a..e497ac4 100644 --- a/cli/src/action/upload.rs +++ b/cli/src/action/upload.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use ffsend_api::action::upload::Upload as ApiUpload; use ffsend_api::reqwest::Client; @@ -34,7 +34,7 @@ impl<'a> Upload<'a> { let client = Client::new(); // Create a progress bar reporter - let bar = Box::new(ProgressBar::new()); + let bar = Arc::new(Mutex::new(ProgressBar::new())); // Execute an upload action // TODO: do not unwrap, but return an error diff --git a/cli/src/progress.rs b/cli/src/progress.rs index ce10745..3bc4986 100644 --- a/cli/src/progress.rs +++ b/cli/src/progress.rs @@ -42,7 +42,6 @@ impl ProgressReporter for ProgressBar { fn finish(&mut self) { self.bar.as_mut() .expect("progress bar not yet instantiated") - // TODO: print a proper message here - .finish_print("DONE"); + .finish_print("File uploaded"); } }