Implement progress bar both for upload and download

This commit is contained in:
timvisee 2018-03-21 00:08:53 +01:00
parent 2d1c669cef
commit d382a015c5
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
5 changed files with 178 additions and 20 deletions

View file

@ -304,9 +304,8 @@ impl<R: Read> Read for ProgressReader<R> {
// Report
if let Some(reporter) = self.reporter.as_mut() {
reporter.lock()
.expect("failed to update progress, unable to lock reproter")
.progress(self.progress);
let progress = self.progress;
let _ = reporter.lock().map(|mut r| r.progress(progress));
}
Ok(len)
@ -333,12 +332,12 @@ pub trait ProgressReporter: Send {
}
/// A trait for readers, to get the exact length of a reader.
pub trait ExactLengthReader: Read {
pub trait ExactLengthReader {
/// Get the exact length of the reader in bytes.
fn len(&self) -> Result<u64, io::Error>;
}
impl<R: ExactLengthReader> ExactLengthReader for BufReader<R> {
impl<R: ExactLengthReader + Read> ExactLengthReader for BufReader<R> {
fn len(&self) -> Result<u64, io::Error> {
self.get_ref().len()
}
@ -444,6 +443,12 @@ impl EncryptedFileWriter {
}
}
impl ExactLengthReader for EncryptedFileWriter {
fn len(&self) -> Result<u64, IoError> {
Ok(self.len as u64)
}
}
/// The writer trait implementation.
impl Write for EncryptedFileWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
@ -508,3 +513,115 @@ impl Write for EncryptedFileWriter {
self.file.flush()
}
}
/// A writer wrapper, that measures the reading process for a writer with a
/// known length.
///
/// If the writer exceeds the initially specified length,
/// the writer will continue to allow reads.
/// The length property will grow accordingly.
///
/// The writer will only start producing `None` if the wrapped writer is doing
/// so.
pub struct ProgressWriter<W> {
/// The wrapped writer.
inner: W,
/// The total length of the writer.
len: u64,
/// The current reading progress.
progress: u64,
/// A reporter, to report the progress status to.
reporter: Option<Arc<Mutex<ProgressReporter>>>,
}
impl<W: Write> ProgressWriter<W> {
/// Wrap the given writer with an exact length, in a progress writer.
pub fn new(inner: W) -> Result<Self, IoError>
where
W: ExactLengthReader
{
Ok(
Self {
len: inner.len()?,
inner,
progress: 0,
reporter: None,
}
)
}
/// Wrap the given writer with the given length in a progress writer.
pub fn from(inner: W, 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: Arc<Mutex<ProgressReporter>>) {
self.reporter = Some(reporter);
}
/// Get the current progress.
pub fn progress(&self) -> u64 {
self.progress
}
/// Unwrap the inner from the progress writer.
pub fn unwrap(self) -> W {
self.inner
}
}
impl<W: Write> Write for ProgressWriter<W> {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
// Write from the wrapped writer, increase the progress
let len = self.inner.write(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() {
let progress = self.progress;
let _ = reporter.lock().map(|mut r| r.progress(progress));
}
Ok(len)
}
fn flush(&mut self) -> Result<(), IoError> {
self.inner.flush()
}
}
impl<W: Write> ExactLengthReader for ProgressWriter<W> {
// Return the specified length.
fn len(&self) -> Result<u64, io::Error> {
Ok(self.len)
}
}