Start implementing an upload progress bar (WIP)

This commit is contained in:
timvisee 2018-03-19 21:19:09 +01:00
parent c646cf7938
commit 030454cc10
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
7 changed files with 242 additions and 34 deletions

View file

@ -1,6 +1,12 @@
use std::cmp::min;
use std::fs::File;
use std::io::{self, Cursor, Read};
use std::io::{
self,
BufReader,
Cursor,
Error as IoError,
Read,
};
use openssl::symm::{
Cipher,
@ -75,14 +81,6 @@ impl EncryptedFileReaderTagged {
)
}
/// Calculate the total length of the encrypted file with the appended
/// tag.
/// Useful in combination with some progress monitor, to determine how much
/// of the file is read or for example; sent over the network.
pub fn len(&self) -> Result<u64, io::Error> {
Ok(self.file.metadata()?.len() + TAG_LEN as u64)
}
/// Read data from the internal buffer if there is any data in it, into
/// the given `buf`.
///
@ -181,6 +179,16 @@ impl EncryptedFileReaderTagged {
}
}
impl ExactLengthReader for EncryptedFileReaderTagged {
/// Calculate the total length of the encrypted file with the appended
/// tag.
/// Useful in combination with some progress monitor, to determine how much
/// of the file is read or for example; sent over the network.
fn len(&self) -> Result<u64, io::Error> {
Ok(self.file.metadata()?.len() + TAG_LEN as u64)
}
}
/// The reader trait implementation.
impl Read for EncryptedFileReaderTagged {
/// Read from the encrypted file, and then the encryption tag.
@ -218,3 +226,115 @@ impl Read for EncryptedFileReaderTagged {
// TODO: implement this some other way
unsafe impl Send for EncryptedFileReaderTagged {}
/// A reader wrapper, that measures the reading process for a reader with a
/// known length.
///
/// If the reader exceeds the initially specified length,
/// the reader will continue to allow reads.
/// The length property will grow accordingly.
///
/// The reader will only start producing `None` if the wrapped reader is doing
/// so.
pub struct ProgressReader<'a, R> {
/// The wrapped reader.
inner: R,
/// The total length of the reader.
len: u64,
/// The current reading progress.
progress: u64,
/// A reporter, to report the progress status to.
reporter: Option<&'a mut ProgressReporter>,
}
impl<'a, R: Read> ProgressReader<'a, R> {
/// Wrap the given reader with an exact length, in a progress reader.
pub fn new(inner: R) -> Result<Self, IoError>
where
R: ExactLengthReader
{
Ok(
Self {
len: inner.len()?,
inner,
progress: 0,
reporter: None,
}
)
}
/// Wrap the given reader with the given length in a progress reader.
pub fn from(inner: R, len: u64) -> Self {
Self {
inner,
len,
progress: 0,
reporter: None,
}
}
/// Set the reporter to report the status to.
pub fn set_reporter(&mut self, reporter: &'a mut ProgressReporter) {
self.reporter = Some(reporter);
}
/// Get the current progress.
pub fn progress(&self) -> u64 {
self.progress
}
}
impl<'a, R: Read> Read for ProgressReader<'a, 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
let len = self.inner.read(buf)?;
self.progress += len as u64;
// Keep the specified length in-bound
if self.progress > self.len {
self.len = self.progress;
}
// Report
if let Some(reporter) = self.reporter.as_mut() {
reporter.progress(self.progress);
}
Ok(len)
}
}
impl<'a, R: Read> ExactLengthReader for ProgressReader<'a, R> {
// Return the specified length.
fn len(&self) -> Result<u64, io::Error> {
Ok(self.len)
}
}
/// A progress reporter.
pub trait ProgressReporter: Send {
/// Start the progress with the given total.
fn start(&mut self, total: u64);
/// A progress update.
fn progress(&mut self, progress: u64);
/// Finish the progress.
fn finish(&mut self);
}
/// A trait for readers, to get the exact length of a reader.
pub trait ExactLengthReader: Read {
/// Get the exact length of the reader in bytes.
fn len(&self) -> Result<u64, io::Error>;
}
impl<R: ExactLengthReader> ExactLengthReader for BufReader<R> {
fn len(&self) -> Result<u64, io::Error> {
self.get_ref().len()
}
}