[wip] impl Client for ureq::Agent

- progress bar handling
- share notify timing
This commit is contained in:
Jörn-Michael Miehe 2025-06-12 22:26:48 +00:00
parent 2edc690331
commit b9a0e1eeb0
2 changed files with 54 additions and 26 deletions

View file

@ -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<ProgressBar>,
current_bar: RefCell<Option<ProgressBar>>,
buffer: Vec<u8>,
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<Option<()>> {
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<Option<()>> {
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(()))
}

View file

@ -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();