[wip] implement handling "missing share"
- rework `CacheFile` API
This commit is contained in:
parent
3b46d228f4
commit
865566ad0c
3 changed files with 66 additions and 60 deletions
|
|
@ -9,7 +9,7 @@ use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cachefile::CacheFile,
|
cachefile::{CacheFile, FileState},
|
||||||
cli::Cli,
|
cli::Cli,
|
||||||
file::{self, Chunk, FileTrait},
|
file::{self, Chunk, FileTrait},
|
||||||
sharry::{self, Client},
|
sharry::{self, Client},
|
||||||
|
|
@ -153,14 +153,23 @@ impl AppState {
|
||||||
Ok(self.is_done())
|
Ok(self.is_done())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rewind(mut self) -> Option<Self> {
|
pub fn rewind_chunk(mut self) -> Option<Self> {
|
||||||
let Some(uploading) = self.inner.pop_file(&self.http) else {
|
let uploading = if let Some(state) = self.inner.pop_file() {
|
||||||
warn!("rewind called on empty queue");
|
match state {
|
||||||
|
FileState::U(s) => s,
|
||||||
|
FileState::C(s) => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("rewind_chunk called on empty queue");
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let uploading = uploading.rewind()?;
|
let Some(FileState::U(uploading)) = self.inner.pop_file() else {
|
||||||
self.inner.push_file(uploading);
|
warn!("rewind_chunk called in invalid state");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.inner.push_file(FileState::U(uploading.rewind()?));
|
||||||
|
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +188,14 @@ impl AppState {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rebuild_share(self, args: &Cli) -> sharry::Result<Self> {
|
||||||
|
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> {
|
pub fn file_names(&self) -> Vec<&str> {
|
||||||
self.inner.file_names()
|
self.inner.file_names()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,34 +14,6 @@ use crate::{
|
||||||
sharry::{self, Client, Uri},
|
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<file::Uploading> {
|
|
||||||
match self {
|
|
||||||
FileState::C(checked) => checked.start_upload(client, uri, alias_id, share_id),
|
|
||||||
FileState::U(uploading) => Ok(uploading),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct CacheFile {
|
pub struct CacheFile {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
|
@ -50,7 +22,9 @@ pub struct CacheFile {
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
alias_id: String,
|
alias_id: String,
|
||||||
share_id: String,
|
share_id: String,
|
||||||
files: VecDeque<FileState>,
|
|
||||||
|
uploading: Option<file::Uploading>,
|
||||||
|
files: VecDeque<file::Checked>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheFile {
|
impl CacheFile {
|
||||||
|
|
@ -88,38 +62,47 @@ impl CacheFile {
|
||||||
uri: args.get_uri(),
|
uri: args.get_uri(),
|
||||||
alias_id: args.alias.clone(),
|
alias_id: args.alias.clone(),
|
||||||
share_id,
|
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> {
|
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 {
|
pub fn start_upload(&mut self, client: &impl Client) -> sharry::Result<bool> {
|
||||||
self.files.is_empty()
|
if self.uploading.is_some() {
|
||||||
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_file(&mut self, client: &impl Client) -> Option<file::Uploading> {
|
if let Some(chk) = self.files.pop_front() {
|
||||||
if let Some(state) = self.files.pop_front() {
|
self.uploading =
|
||||||
// HACK unwrap
|
Some(chk.start_upload(client, &self.uri, &self.alias_id, &self.share_id)?);
|
||||||
// TODO somehow retry
|
|
||||||
Some(
|
Ok(true)
|
||||||
state
|
|
||||||
.start_upload(client, &self.uri, &self.alias_id, &self.share_id)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_file(&mut self, file: file::Uploading) {
|
pub fn uploading(&mut self) -> &mut Option<file::Uploading> {
|
||||||
self.files.push_front(FileState::U(file));
|
&mut self.uploading
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn requeue_file(&mut self, file: file::Checked) {
|
pub fn abort_upload(&mut self) {
|
||||||
self.files.push_back(FileState::C(file));
|
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<()> {
|
pub fn share_notify(&self, client: &impl Client) -> sharry::Result<()> {
|
||||||
|
|
|
||||||
18
src/main.rs
18
src/main.rs
|
|
@ -88,7 +88,6 @@ fn main() {
|
||||||
match state.upload_chunk(&mut buffer) {
|
match state.upload_chunk(&mut buffer) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
Log::handle(&e);
|
Log::handle(&e);
|
||||||
tries += 1;
|
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
ClientError::InvalidParameter(p) => match p {
|
ClientError::InvalidParameter(p) => match p {
|
||||||
|
|
@ -99,22 +98,29 @@ fn main() {
|
||||||
Log::error("Failed to requeue file!");
|
Log::error("Failed to requeue file!");
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!("File {fid:?} requeued (tried: {tries})");
|
trace!("File {fid:?} requeued");
|
||||||
state = s;
|
state = s;
|
||||||
}
|
}
|
||||||
// TODO Error 404: Share might have been deleted
|
// TODO Error 404: Share not found
|
||||||
Parameter::ShareID(sid) => {
|
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}!")),
|
p => Log::error(format_args!("Unexpected {p}!")),
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
// retry chunk
|
// retry chunk
|
||||||
let Some(s) = state.rewind() else {
|
let Some(s) = state.rewind_chunk() else {
|
||||||
Log::error("Failed to retry chunk!");
|
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;
|
state = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue