2025-06-12 22:26:48 +00:00
|
|
|
use std::{
|
|
|
|
|
cell::{Ref, RefCell},
|
|
|
|
|
fmt, io,
|
|
|
|
|
time::Duration,
|
|
|
|
|
};
|
2025-06-02 23:57:17 +00:00
|
|
|
|
2025-06-05 17:37:35 +00:00
|
|
|
use console::style;
|
|
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
2025-06-12 16:07:54 +00:00
|
|
|
use log::debug;
|
2025-06-02 23:57:17 +00:00
|
|
|
|
|
|
|
|
use super::{
|
2025-06-12 16:07:54 +00:00
|
|
|
cachefile::CacheFile,
|
2025-06-02 23:57:17 +00:00
|
|
|
cli::Cli,
|
2025-06-12 22:26:48 +00:00
|
|
|
file::{self, FileTrait},
|
2025-06-12 09:26:11 +00:00
|
|
|
sharry::{self, Client, ClientError},
|
2025-06-02 23:57:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct AppState {
|
2025-06-12 22:26:48 +00:00
|
|
|
current_bar: RefCell<Option<ProgressBar>>,
|
2025-06-10 23:39:08 +00:00
|
|
|
buffer: Vec<u8>,
|
2025-06-04 21:02:35 +00:00
|
|
|
|
2025-06-12 16:07:54 +00:00
|
|
|
inner: CacheFile,
|
2025-06-04 13:25:00 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-11 00:28:02 +00:00
|
|
|
impl fmt::Debug for AppState {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("AppState")
|
2025-06-12 09:26:11 +00:00
|
|
|
.field("inner", &self.inner)
|
2025-06-12 16:25:15 +00:00
|
|
|
.finish_non_exhaustive()
|
2025-06-11 00:28:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-02 23:57:17 +00:00
|
|
|
impl AppState {
|
2025-06-12 16:07:54 +00:00
|
|
|
fn new(chunk_size: usize, inner: CacheFile) -> Self {
|
2025-06-11 00:28:02 +00:00
|
|
|
Self {
|
2025-06-12 22:26:48 +00:00
|
|
|
current_bar: None.into(),
|
2025-06-11 00:28:02 +00:00
|
|
|
buffer: vec![0; chunk_size * 1024 * 1024],
|
2025-06-12 09:26:11 +00:00
|
|
|
inner,
|
2025-06-11 00:28:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 21:02:35 +00:00
|
|
|
pub fn try_resume(args: &Cli) -> Option<Self> {
|
2025-06-12 16:07:54 +00:00
|
|
|
let inner = CacheFile::try_resume(args)
|
|
|
|
|
.inspect_err(|e| debug!("could not resume from hash {:?}: {e}", args.get_hash()))
|
2025-06-12 09:26:11 +00:00
|
|
|
.ok()?;
|
|
|
|
|
|
|
|
|
|
Some(Self::new(args.chunk_size, inner))
|
2025-06-04 21:02:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-10 18:20:52 +00:00
|
|
|
pub fn from_args(args: &Cli, http: &impl Client) -> sharry::Result<Self> {
|
|
|
|
|
let share_id = http.share_create(
|
2025-06-12 16:07:54 +00:00
|
|
|
&args.get_uri().endpoint("alias/upload/new"),
|
2025-06-12 09:26:11 +00:00
|
|
|
&args.alias,
|
2025-06-10 18:20:52 +00:00
|
|
|
args.get_share_request(),
|
|
|
|
|
)?;
|
2025-06-04 21:02:35 +00:00
|
|
|
|
2025-06-11 00:28:02 +00:00
|
|
|
Ok(Self::new(
|
|
|
|
|
args.chunk_size,
|
2025-06-12 16:07:54 +00:00
|
|
|
CacheFile::from_args(args, share_id),
|
2025-06-11 00:28:02 +00:00
|
|
|
))
|
2025-06-04 21:02:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-12 22:26:48 +00:00
|
|
|
fn get_or_create_progressbar(&self, uploading: &file::Uploading) -> Ref<'_, ProgressBar> {
|
|
|
|
|
let mut slot = self.current_bar.borrow_mut();
|
|
|
|
|
if slot.is_none() {
|
2025-06-06 23:42:18 +00:00
|
|
|
let bar = ProgressBar::new(uploading.get_size())
|
2025-06-05 21:36:41 +00:00
|
|
|
.with_style(
|
|
|
|
|
ProgressStyle::with_template(&format!(
|
|
|
|
|
concat!(
|
|
|
|
|
"{{msg:.yellow}}: {{bar:50.cyan/blue}} ",
|
|
|
|
|
"{{binary_bytes:.magenta}}{}{{binary_total_bytes:.magenta}} ",
|
|
|
|
|
"({{eta}})",
|
|
|
|
|
),
|
|
|
|
|
style("/").magenta(),
|
|
|
|
|
))
|
2025-06-12 22:26:48 +00:00
|
|
|
.unwrap(), // safe as long as the style template is valid
|
2025-06-05 21:36:41 +00:00
|
|
|
)
|
2025-06-12 22:26:48 +00:00
|
|
|
.with_position(uploading.get_offset())
|
|
|
|
|
.with_message(uploading.get_name().to_owned());
|
2025-06-05 21:36:41 +00:00
|
|
|
|
|
|
|
|
bar.enable_steady_tick(Duration::from_millis(100));
|
2025-06-12 22:26:48 +00:00
|
|
|
*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());
|
2025-06-05 17:37:35 +00:00
|
|
|
|
2025-06-10 23:39:08 +00:00
|
|
|
let chunk = uploading
|
|
|
|
|
.read(&mut self.buffer)
|
2025-06-12 09:26:11 +00:00
|
|
|
.map_err(ClientError::from)?;
|
2025-06-10 23:39:08 +00:00
|
|
|
|
|
|
|
|
http.file_patch(
|
|
|
|
|
chunk.get_patch_uri(),
|
2025-06-12 16:07:54 +00:00
|
|
|
self.inner.alias_id(),
|
2025-06-10 23:39:08 +00:00
|
|
|
chunk.get_offset(),
|
|
|
|
|
chunk.get_data(),
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
match uploading.check_eof() {
|
|
|
|
|
Ok(uploading) => {
|
2025-06-12 22:26:48 +00:00
|
|
|
let bar = self.get_or_create_progressbar(&uploading);
|
2025-06-10 23:39:08 +00:00
|
|
|
bar.set_position(uploading.get_offset());
|
2025-06-12 22:26:48 +00:00
|
|
|
// BUG in `indicatif` crate?
|
|
|
|
|
// `set_position` does not force immediate redraw, so we also call `inc_length` here
|
|
|
|
|
bar.inc_length(0);
|
|
|
|
|
drop(bar);
|
|
|
|
|
|
2025-06-12 09:26:11 +00:00
|
|
|
self.inner.push_file(uploading);
|
2025-06-05 01:13:54 +00:00
|
|
|
Ok(Some(()))
|
|
|
|
|
}
|
2025-06-10 23:39:08 +00:00
|
|
|
Err(path) => {
|
2025-06-05 01:13:54 +00:00
|
|
|
debug!("Finished {:?}!", path.display());
|
2025-06-12 22:26:48 +00:00
|
|
|
self.finish_bar();
|
2025-06-05 11:20:27 +00:00
|
|
|
|
2025-06-12 09:26:11 +00:00
|
|
|
Ok(self.inner.has_file().then_some(()))
|
2025-06-05 01:13:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-12 16:07:54 +00:00
|
|
|
pub fn file_names(&self) -> Vec<&str> {
|
|
|
|
|
self.inner.file_names()
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 21:02:35 +00:00
|
|
|
pub fn save(&self) -> io::Result<()> {
|
2025-06-12 09:26:11 +00:00
|
|
|
self.inner.save()
|
2025-06-02 23:57:17 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-04 21:23:21 +00:00
|
|
|
pub fn clear(self) -> io::Result<()> {
|
2025-06-12 09:26:11 +00:00
|
|
|
self.inner.clear()
|
2025-06-02 23:57:17 +00:00
|
|
|
}
|
|
|
|
|
}
|