Complete upload progress bar implementation, simplify with arc/mutex

This commit is contained in:
timvisee 2018-03-19 21:52:20 +01:00
parent 030454cc10
commit b57e85a8ec
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
4 changed files with 29 additions and 20 deletions

View file

@ -1,6 +1,7 @@
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use mime_guess::{get_mime_type, Mime}; use mime_guess::{get_mime_type, Mime};
use openssl::symm::encrypt_aead; use openssl::symm::encrypt_aead;
@ -24,8 +25,7 @@ use reader::{
use file::file::File as SendFile; use file::file::File as SendFile;
use file::metadata::{Metadata, XFileMetadata}; use file::metadata::{Metadata, XFileMetadata};
type EncryptedReader = type EncryptedReader = ProgressReader<BufReader<EncryptedFileReaderTagged>>;
ProgressReader<'static, BufReader<EncryptedFileReaderTagged>>;
pub type Result<T> = ::std::result::Result<T, UploadError>; pub type Result<T> = ::std::result::Result<T, UploadError>;
/// A file upload action to a Send server. /// A file upload action to a Send server.
@ -50,7 +50,7 @@ impl Upload {
pub fn invoke( pub fn invoke(
self, self,
client: &Client, client: &Client,
reporter: Box<ProgressReporter + 'static>, reporter: Arc<Mutex<ProgressReporter>>,
) -> Result<SendFile> { ) -> Result<SendFile> {
// Create file data, generate a key // Create file data, generate a key
let file = FileData::from(Box::new(&self.path))?; let file = FileData::from(Box::new(&self.path))?;
@ -58,8 +58,8 @@ impl Upload {
// Crpate metadata and a file reader // Crpate metadata and a file reader
let metadata = self.create_metadata(&key, &file)?; let metadata = self.create_metadata(&key, &file)?;
// TODO: do not use leak, as it might cause memory leaks let reader = self.create_reader(&key, reporter.clone())?;
let reader = self.create_reader(&key, Box::leak(reporter))?; let reader_len = reader.len().unwrap();
// Create the request to send // Create the request to send
let req = self.create_request( let req = self.create_request(
@ -69,10 +69,18 @@ impl Upload {
reader, reader,
); );
// Start the reporter
reporter.lock()
.expect("unable to start progress, failed to get lock")
.start(reader_len);
// Execute the request // Execute the request
let result = self.execute_request(req, client, &key); 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 result
} }
@ -112,7 +120,7 @@ impl Upload {
fn create_reader( fn create_reader(
&self, &self,
key: &KeySet, key: &KeySet,
reporter: &'static mut ProgressReporter, reporter: Arc<Mutex<ProgressReporter>>,
) -> Result<EncryptedReader> { ) -> Result<EncryptedReader> {
// Open the file // Open the file
let file = match File::open(self.path.as_path()) { let file = match File::open(self.path.as_path()) {
@ -139,8 +147,7 @@ impl Upload {
.expect("failed to create progress reader"); .expect("failed to create progress reader");
// Initialize and attach the reporter // Initialize and attach the reporter
reporter.start(reader.len().unwrap()); reader.set_reporter(reporter);
reader.set_reporter(&mut *reporter);
Ok(reader) Ok(reader)
} }

View file

@ -7,6 +7,7 @@ use std::io::{
Error as IoError, Error as IoError,
Read, Read,
}; };
use std::sync::{Arc, Mutex};
use openssl::symm::{ use openssl::symm::{
Cipher, Cipher,
@ -236,7 +237,7 @@ unsafe impl Send for EncryptedFileReaderTagged {}
/// ///
/// The reader will only start producing `None` if the wrapped reader is doing /// The reader will only start producing `None` if the wrapped reader is doing
/// so. /// so.
pub struct ProgressReader<'a, R> { pub struct ProgressReader<R> {
/// The wrapped reader. /// The wrapped reader.
inner: R, inner: R,
@ -247,10 +248,10 @@ pub struct ProgressReader<'a, R> {
progress: u64, progress: u64,
/// A reporter, to report the progress status to. /// A reporter, to report the progress status to.
reporter: Option<&'a mut ProgressReporter>, reporter: Option<Arc<Mutex<ProgressReporter>>>,
} }
impl<'a, R: Read> ProgressReader<'a, R> { impl<R: Read> ProgressReader<R> {
/// Wrap the given reader with an exact length, in a progress reader. /// Wrap the given reader with an exact length, in a progress reader.
pub fn new(inner: R) -> Result<Self, IoError> pub fn new(inner: R) -> Result<Self, IoError>
where where
@ -277,7 +278,7 @@ impl<'a, R: Read> ProgressReader<'a, R> {
} }
/// Set the reporter to report the status to. /// 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<Mutex<ProgressReporter>>) {
self.reporter = Some(reporter); 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<R: Read> Read for ProgressReader<R> {
/// Read from the encrypted file, and then the encryption tag. /// Read from the encrypted file, and then the encryption tag.
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
// Read from the wrapped reader, increase the progress // Read from the wrapped reader, increase the progress
@ -301,14 +302,16 @@ impl<'a, R: Read> Read for ProgressReader<'a, R> {
// Report // Report
if let Some(reporter) = self.reporter.as_mut() { 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) Ok(len)
} }
} }
impl<'a, R: Read> ExactLengthReader for ProgressReader<'a, R> { impl<R: Read> ExactLengthReader for ProgressReader<R> {
// Return the specified length. // Return the specified length.
fn len(&self) -> Result<u64, io::Error> { fn len(&self) -> Result<u64, io::Error> {
Ok(self.len) Ok(self.len)

View file

@ -1,5 +1,5 @@
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::{Arc, Mutex};
use ffsend_api::action::upload::Upload as ApiUpload; use ffsend_api::action::upload::Upload as ApiUpload;
use ffsend_api::reqwest::Client; use ffsend_api::reqwest::Client;
@ -34,7 +34,7 @@ impl<'a> Upload<'a> {
let client = Client::new(); let client = Client::new();
// Create a progress bar reporter // Create a progress bar reporter
let bar = Box::new(ProgressBar::new()); let bar = Arc::new(Mutex::new(ProgressBar::new()));
// Execute an upload action // Execute an upload action
// TODO: do not unwrap, but return an error // TODO: do not unwrap, but return an error

View file

@ -42,7 +42,6 @@ impl ProgressReporter for ProgressBar {
fn finish(&mut self) { fn finish(&mut self) {
self.bar.as_mut() self.bar.as_mut()
.expect("progress bar not yet instantiated") .expect("progress bar not yet instantiated")
// TODO: print a proper message here .finish_print("File uploaded");
.finish_print("DONE");
} }
} }