From b9a0e1eeb0873158269b90aabf6886ed50a25ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Thu, 12 Jun 2025 22:26:48 +0000 Subject: [PATCH] [wip] impl `Client` for `ureq::Agent` - progress bar handling - share notify timing --- src/appstate.rs | 73 ++++++++++++++++++++++++++++--------------- src/file/uploading.rs | 7 +++++ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index d9b90d2..dae340e 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -1,4 +1,8 @@ -use std::{fmt, io, time::Duration}; +use std::{ + cell::{Ref, RefCell}, + fmt, io, + time::Duration, +}; use console::style; use indicatif::{ProgressBar, ProgressStyle}; @@ -7,12 +11,12 @@ use log::debug; use super::{ cachefile::CacheFile, cli::Cli, - file::FileTrait, + file::{self, FileTrait}, sharry::{self, Client, ClientError}, }; pub struct AppState { - progress: Option, + current_bar: RefCell>, buffer: Vec, inner: CacheFile, @@ -29,7 +33,7 @@ impl fmt::Debug for AppState { impl AppState { fn new(chunk_size: usize, inner: CacheFile) -> Self { Self { - progress: None, + current_bar: None.into(), buffer: vec![0; chunk_size * 1024 * 1024], inner, } @@ -56,16 +60,9 @@ impl AppState { )) } - pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result> { - let Some(mut uploading) = self.inner.pop_file(http) else { - return Ok(None); - }; - - debug!("{uploading} chunk {}", self.buffer.len()); - - // Initialize or fetch the existing ProgressBar - let bar = &*self.progress.get_or_insert_with(|| { - // Create a new bar with style + fn get_or_create_progressbar(&self, uploading: &file::Uploading) -> Ref<'_, ProgressBar> { + let mut slot = self.current_bar.borrow_mut(); + if slot.is_none() { let bar = ProgressBar::new(uploading.get_size()) .with_style( ProgressStyle::with_template(&format!( @@ -76,21 +73,42 @@ impl AppState { ), style("/").magenta(), )) - .unwrap(), + .unwrap(), // safe as long as the style template is valid ) - .with_message(uploading.get_name().to_owned()) - .with_position(uploading.get_offset()); + .with_position(uploading.get_offset()) + .with_message(uploading.get_name().to_owned()); bar.enable_steady_tick(Duration::from_millis(100)); - bar - }); + *slot = Some(bar); + } + drop(slot); + + // unwrap is safe: We just made sure it's `Some`. + Ref::map(self.current_bar.borrow(), |opt| opt.as_ref().unwrap()) + } + + fn finish_bar(&self) { + let mut slot = self.current_bar.borrow_mut(); + if let Some(bar) = &*slot { + bar.finish(); + *slot = None; + } + } + + pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result> { + let Some(mut uploading) = self.inner.pop_file(http) else { + self.inner.share_notify(http).unwrap(); // HACK unwrap + + return Ok(None); + }; + + self.get_or_create_progressbar(&uploading); + + debug!("{uploading} chunk {}", self.buffer.len()); let chunk = uploading .read(&mut self.buffer) .map_err(ClientError::from)?; - if chunk.get_length() == 0 { - return Err(ClientError::req_err("wtf")); - } http.file_patch( chunk.get_patch_uri(), @@ -101,16 +119,19 @@ impl AppState { match uploading.check_eof() { Ok(uploading) => { + let bar = self.get_or_create_progressbar(&uploading); bar.set_position(uploading.get_offset()); + // BUG in `indicatif` crate? + // `set_position` does not force immediate redraw, so we also call `inc_length` here + bar.inc_length(0); + drop(bar); + self.inner.push_file(uploading); Ok(Some(())) } Err(path) => { debug!("Finished {:?}!", path.display()); - bar.finish(); - self.progress = None; - - self.inner.share_notify(http).unwrap(); // HACK unwrap + self.finish_bar(); Ok(self.inner.has_file().then_some(())) } diff --git a/src/file/uploading.rs b/src/file/uploading.rs index 6ce0480..962c2c6 100644 --- a/src/file/uploading.rs +++ b/src/file/uploading.rs @@ -48,6 +48,13 @@ impl Uploading { f.seek(SeekFrom::Start(self.offset))?; let read_len = f.read(buf)?; + if read_len == 0 { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + format!("could not read from file {:?}", self.path.display()), + )); + } + let chunk = Chunk::new(&buf[..read_len], &self.patch_uri, self.offset); self.offset += chunk.get_length();