diff --git a/src/appstate.rs b/src/appstate.rs index 8fb5252..68eff53 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -9,7 +9,7 @@ use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, warn}; use crate::{ - cachefile::CacheFile, + cachefile::{CacheFile, FileState}, cli::Cli, file::{self, Chunk, FileTrait}, sharry::{self, Client}, @@ -153,14 +153,23 @@ impl AppState { Ok(self.is_done()) } - pub fn rewind(mut self) -> Option { - let Some(uploading) = self.inner.pop_file(&self.http) else { - warn!("rewind called on empty queue"); + pub fn rewind_chunk(mut self) -> Option { + let uploading = if let Some(state) = self.inner.pop_file() { + match state { + FileState::U(s) => s, + FileState::C(s) => {} + } + } else { + warn!("rewind_chunk called on empty queue"); return None; }; - let uploading = uploading.rewind()?; - self.inner.push_file(uploading); + let Some(FileState::U(uploading)) = self.inner.pop_file() else { + warn!("rewind_chunk called in invalid state"); + return None; + }; + + self.inner.push_file(FileState::U(uploading.rewind()?)); Some(self) } @@ -179,6 +188,14 @@ impl AppState { Some(self) } + pub fn rebuild_share(self, args: &Cli) -> sharry::Result { + let share_id = + self.http + .share_create(&args.get_uri(), &args.alias, args.get_share_request())?; + + Ok(Self::new(self.http, CacheFile::from_args(args, share_id))) + } + pub fn file_names(&self) -> Vec<&str> { self.inner.file_names() } diff --git a/src/cachefile.rs b/src/cachefile.rs index 44d07a0..022244e 100644 --- a/src/cachefile.rs +++ b/src/cachefile.rs @@ -14,34 +14,6 @@ use crate::{ sharry::{self, Client, Uri}, }; -#[derive(Serialize, Deserialize, Debug)] -enum FileState { - C(file::Checked), - U(file::Uploading), -} - -impl FileState { - fn file_name(&self) -> &str { - match self { - FileState::C(c) => c.get_name(), - FileState::U(u) => u.get_name(), - } - } - - fn start_upload( - self, - client: &impl sharry::Client, - uri: &sharry::Uri, - alias_id: &str, - share_id: &str, - ) -> sharry::Result { - match self { - FileState::C(checked) => checked.start_upload(client, uri, alias_id, share_id), - FileState::U(uploading) => Ok(uploading), - } - } -} - #[derive(Serialize, Deserialize, Debug)] pub struct CacheFile { #[serde(skip)] @@ -50,7 +22,9 @@ pub struct CacheFile { uri: Uri, alias_id: String, share_id: String, - files: VecDeque, + + uploading: Option, + files: VecDeque, } impl CacheFile { @@ -88,38 +62,47 @@ impl CacheFile { uri: args.get_uri(), alias_id: args.alias.clone(), share_id, - files: args.files.clone().into_iter().map(FileState::C).collect(), + uploading: None, + files: args.files.clone().into(), } } pub fn file_names(&self) -> Vec<&str> { - self.files.iter().map(FileState::file_name).collect() + let mut result = vec![]; + + if let Some(upl) = self.uploading.as_ref() { + result.push(upl.get_name()); + } + self.files.iter().map(|chk| result.push(chk.get_name())); + + result } - pub fn is_empty(&self) -> bool { - self.files.is_empty() - } + pub fn start_upload(&mut self, client: &impl Client) -> sharry::Result { + if self.uploading.is_some() { + return Ok(true); + } - pub fn pop_file(&mut self, client: &impl Client) -> Option { - if let Some(state) = self.files.pop_front() { - // HACK unwrap - // TODO somehow retry - Some( - state - .start_upload(client, &self.uri, &self.alias_id, &self.share_id) - .unwrap(), - ) + if let Some(chk) = self.files.pop_front() { + self.uploading = + Some(chk.start_upload(client, &self.uri, &self.alias_id, &self.share_id)?); + + Ok(true) } else { - None + Ok(false) } } - pub fn push_file(&mut self, file: file::Uploading) { - self.files.push_front(FileState::U(file)); + pub fn uploading(&mut self) -> &mut Option { + &mut self.uploading } - pub fn requeue_file(&mut self, file: file::Checked) { - self.files.push_back(FileState::C(file)); + pub fn abort_upload(&mut self) { + let Some(upl) = self.uploading.take() else { + panic!("abort called while not uploading"); + }; + + self.files.push_front(upl.abort()); } pub fn share_notify(&self, client: &impl Client) -> sharry::Result<()> { diff --git a/src/main.rs b/src/main.rs index de85892..9d3ef63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,7 +88,6 @@ fn main() { match state.upload_chunk(&mut buffer) { Err(e) => { Log::handle(&e); - tries += 1; match e { ClientError::InvalidParameter(p) => match p { @@ -99,22 +98,29 @@ fn main() { Log::error("Failed to requeue file!"); }; - trace!("File {fid:?} requeued (tried: {tries})"); + trace!("File {fid:?} requeued"); state = s; } - // TODO Error 404: Share might have been deleted + // TODO Error 404: Share not found Parameter::ShareID(sid) => { - Log::error(format_args!("404 sid: {sid}")); + // requeue file + let Ok(s) = state.rebuild_share(&args) else { + Log::error("Failed to rebuild share!"); + }; + + trace!("Share {sid:?} rebuilt"); + state = s; } p => Log::error(format_args!("Unexpected {p}!")), }, _ => { // retry chunk - let Some(s) = state.rewind() else { + let Some(s) = state.rewind_chunk() else { Log::error("Failed to retry chunk!"); }; + tries += 1; - trace!("State rewound, retrying last chunk (tried: {tries})"); + trace!("State rewound, retrying last chunk (tries: {tries})"); state = s; } }