create Error::Mismatch variant
This commit is contained in:
parent
9de8f948dc
commit
b17f239801
8 changed files with 43 additions and 44 deletions
|
|
@ -63,15 +63,7 @@ impl CacheFile {
|
||||||
bar: &ProgressBar,
|
bar: &ProgressBar,
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
bar.set_message(format!("checking {:?}", file.get_name()));
|
bar.set_message(format!("checking {:?}", file.get_name()));
|
||||||
|
file.check_hash(|bytes| bar.inc(bytes))
|
||||||
match file.check_hash(|bytes| bar.inc(bytes)) {
|
|
||||||
Ok(true) => Ok(()),
|
|
||||||
Ok(false) => Err(error::Error::unknown(format!(
|
|
||||||
"Hash mismatch for file {:?}!",
|
|
||||||
file.get_name()
|
|
||||||
))),
|
|
||||||
Err(e) => Err(e.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("checking files in {state:?}");
|
info!("checking files in {state:?}");
|
||||||
|
|
|
||||||
13
src/error.rs
13
src/error.rs
|
|
@ -26,12 +26,15 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
StdIo(#[from] std::io::Error),
|
StdIo(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("response error: {0}")]
|
#[error("Response error: {0}")]
|
||||||
Response(String),
|
Response(String),
|
||||||
|
|
||||||
#[error("Invalid {0}")]
|
#[error("Invalid {0}")]
|
||||||
InvalidParameter(Parameter),
|
InvalidParameter(Parameter),
|
||||||
|
|
||||||
|
#[error("Mismatch, expected {expected:?} but got {actual:?}")]
|
||||||
|
Mismatch { expected: String, actual: String },
|
||||||
|
|
||||||
#[error("Unknown error: {0}")]
|
#[error("Unknown error: {0}")]
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
@ -59,14 +62,18 @@ impl Error {
|
||||||
Self::Response(into_string(e))
|
Self::Response(into_string(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unknown(e: impl ToString) -> Self {
|
pub fn mismatch(expected: impl ToString, actual: impl ToString) -> Self {
|
||||||
Self::Unknown(into_string(e))
|
Self::Mismatch {
|
||||||
|
expected: into_string(expected),
|
||||||
|
actual: into_string(actual),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_fatal(&self) -> bool {
|
pub fn is_fatal(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::InvalidParameter(p) => p.is_fatal(),
|
Self::InvalidParameter(p) => p.is_fatal(),
|
||||||
|
Self::Mismatch { .. } => true,
|
||||||
Self::Unknown(_) => true,
|
Self::Unknown(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,9 @@ impl Checked {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(&mut self, f: impl Fn(u64)) -> io::Result<()> {
|
pub fn hash(&mut self, f: impl Fn(u64)) -> error::Result<()> {
|
||||||
if self.hash.is_some() {
|
if self.hash.is_some() {
|
||||||
return Err(io::Error::other(format!(
|
return Err(error::Error::mismatch("unhashed file", self.path.display()));
|
||||||
"file {:?} is already hashed!",
|
|
||||||
self.path.display()
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.hash = Some(super::compute_file_hash(&self.path, self.size, f)?);
|
self.hash = Some(super::compute_file_hash(&self.path, self.size, f)?);
|
||||||
|
|
@ -101,7 +98,7 @@ impl<'t> FileTrait<'t> for Checked {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> io::Result<bool> {
|
fn check_hash(&self, on_progress: impl Fn(u64)) -> error::Result<()> {
|
||||||
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,19 @@ mod checked;
|
||||||
mod chunk;
|
mod chunk;
|
||||||
mod uploading;
|
mod uploading;
|
||||||
|
|
||||||
use std::{
|
use std::{ffi::OsStr, fs, io::Read, path::Path};
|
||||||
ffi::OsStr,
|
|
||||||
fs,
|
|
||||||
io::{self, Read},
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use base64ct::{Base64, Encoding};
|
use base64ct::{Base64, Encoding};
|
||||||
use blake2b_simd::Params as Blake2b;
|
use blake2b_simd::Params as Blake2b;
|
||||||
|
|
||||||
pub use checked::Checked;
|
pub use checked::Checked;
|
||||||
pub use chunk::Chunk;
|
pub use chunk::Chunk;
|
||||||
use log::debug;
|
use log::{debug, warn};
|
||||||
pub use uploading::Uploading;
|
pub use uploading::Uploading;
|
||||||
|
|
||||||
fn compute_file_hash(path: &Path, size: u64, on_progress: impl Fn(u64)) -> io::Result<String> {
|
use crate::error;
|
||||||
|
|
||||||
|
fn compute_file_hash(path: &Path, size: u64, on_progress: impl Fn(u64)) -> error::Result<String> {
|
||||||
let mut file = fs::File::open(path)?;
|
let mut file = fs::File::open(path)?;
|
||||||
let mut hasher = Blake2b::new().hash_length(64).to_state();
|
let mut hasher = Blake2b::new().hash_length(64).to_state();
|
||||||
|
|
||||||
|
|
@ -36,9 +33,7 @@ fn compute_file_hash(path: &Path, size: u64, on_progress: impl Fn(u64)) -> io::R
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes_read != size {
|
if bytes_read != size {
|
||||||
return Err(io::Error::other(format!(
|
return Err(error::Error::mismatch(size, bytes_read));
|
||||||
"Hashed {bytes_read:?} bytes, known file size {size:?}!"
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = Base64::encode_string(hasher.finalize().as_bytes());
|
let result = Base64::encode_string(hasher.finalize().as_bytes());
|
||||||
|
|
@ -51,15 +46,20 @@ fn check_file_hash(
|
||||||
size: u64,
|
size: u64,
|
||||||
hash: Option<&String>,
|
hash: Option<&String>,
|
||||||
on_progress: impl Fn(u64),
|
on_progress: impl Fn(u64),
|
||||||
) -> io::Result<bool> {
|
) -> error::Result<()> {
|
||||||
let Some(hash) = hash else {
|
let Some(expected) = hash else {
|
||||||
debug!("no hash to check for {:?}!", path.display());
|
return Err(error::Error::mismatch("hash", path.display()));
|
||||||
return Ok(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = *hash == compute_file_hash(path, size, on_progress)?;
|
let actual = &compute_file_hash(path, size, on_progress)?;
|
||||||
debug!("matches {:?}: {result:?}", *hash);
|
|
||||||
Ok(result)
|
if expected == actual {
|
||||||
|
debug!("hash matches {expected:?}");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
warn!("hash mismatch for file {:?}", path.display());
|
||||||
|
Err(error::Error::mismatch(expected, actual))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FileTrait<'t> {
|
pub trait FileTrait<'t> {
|
||||||
|
|
@ -80,5 +80,5 @@ pub trait FileTrait<'t> {
|
||||||
/// get the file's size
|
/// get the file's size
|
||||||
fn get_size(&self) -> u64;
|
fn get_size(&self) -> u64;
|
||||||
|
|
||||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> io::Result<bool>;
|
fn check_hash(&self, on_progress: impl Fn(u64)) -> error::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use std::{
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error;
|
||||||
|
|
||||||
use super::{Checked, Chunk, FileTrait};
|
use super::{Checked, Chunk, FileTrait};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
@ -101,7 +103,7 @@ impl<'t> FileTrait<'t> for Uploading {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_hash(&self, on_progress: impl Fn(u64)) -> io::Result<bool> {
|
fn check_hash(&self, on_progress: impl Fn(u64)) -> error::Result<()> {
|
||||||
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ fn find_cause(
|
||||||
error.into()
|
error.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error => error::Error::unknown(error),
|
error => error::Error::Unknown(error.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{fmt, process, sync::LazyLock};
|
||||||
use console::{StyledObject, style};
|
use console::{StyledObject, style};
|
||||||
use dialoguer::{Confirm, Select, theme::ColorfulTheme};
|
use dialoguer::{Confirm, Select, theme::ColorfulTheme};
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::{error, info};
|
use log::{info, warn};
|
||||||
|
|
||||||
type StaticStyled<'t> = LazyLock<StyledObject<&'t str>>;
|
type StaticStyled<'t> = LazyLock<StyledObject<&'t str>>;
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ impl Log {
|
||||||
pub fn handle(e: &crate::error::Error) {
|
pub fn handle(e: &crate::error::Error) {
|
||||||
if e.is_fatal() {
|
if e.is_fatal() {
|
||||||
// react to fatal error
|
// react to fatal error
|
||||||
error!("fatal error: {e:?}");
|
warn!("fatal error: {e:?}");
|
||||||
Self::error(e);
|
Self::error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,10 @@ pub trait Client {
|
||||||
{
|
{
|
||||||
Ok(fid)
|
Ok(fid)
|
||||||
} else {
|
} else {
|
||||||
Err(error::Error::unknown(format!(
|
Err(error::Error::mismatch(
|
||||||
"Could not extract File ID from {uri:?}"
|
"<proto>://<base>/api/v2/alias/upload/<share>/files/tus/<file>",
|
||||||
)))
|
uri,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue