Explorar o código

Complete upload progress bar implementation, simplify with arc/mutex

timvisee %!s(int64=7) %!d(string=hai) anos
pai
achega
b57e85a8ec
Modificáronse 4 ficheiros con 29 adicións e 20 borrados
  1. 16 9
      api/src/action/upload.rs
  2. 10 7
      api/src/reader.rs
  3. 2 2
      cli/src/action/upload.rs
  4. 1 2
      cli/src/progress.rs

+ 16 - 9
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<EncryptedFileReaderTagged>>;
+type EncryptedReader = ProgressReader<BufReader<EncryptedFileReaderTagged>>;
 pub type Result<T> = ::std::result::Result<T, UploadError>;
 
 /// A file upload action to a Send server.
@@ -50,7 +50,7 @@ impl Upload {
     pub fn invoke(
         self,
         client: &Client,
-        reporter: Box<ProgressReporter + 'static>,
+        reporter: Arc<Mutex<ProgressReporter>>,
     ) -> Result<SendFile> {
         // 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<Mutex<ProgressReporter>>,
     ) -> Result<EncryptedReader> {
         // 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)
     }

+ 10 - 7
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<R> {
     /// 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<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.
     pub fn new(inner: R) -> Result<Self, IoError>
         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<Mutex<ProgressReporter>>) {
         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.
     fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
         // 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<R: Read> ExactLengthReader for ProgressReader<R> {
     // Return the specified length.
     fn len(&self) -> Result<u64, io::Error> {
         Ok(self.len)

+ 2 - 2
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

+ 1 - 2
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");
     }
 }