implement SharryFile trait

This commit is contained in:
Jörn-Michael Miehe 2025-06-06 15:21:49 +00:00
parent 39560eeeed
commit e98001f4a4
6 changed files with 111 additions and 42 deletions

View file

@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
use super::{
cli::Cli,
sharry::{Alias, ChunkState, FileChecked, FileUploading, Share, UploadError},
sharry::{Alias, ChunkState, FileChecked, FileUploading, Share, SharryFile, UploadError},
};
#[derive(Serialize, Deserialize, Debug)]
@ -37,8 +37,8 @@ enum FileState {
impl FileState {
fn file_name(&self) -> &str {
match self {
FileState::C(checked) => checked.file_name(),
FileState::U(uploading) => uploading.file_name(),
FileState::C(checked) => checked.name(),
FileState::U(uploading) => uploading.name(),
}
}
@ -145,7 +145,7 @@ impl AppState {
))
.unwrap(),
)
.with_message(uploading.file_name().to_owned())
.with_message(uploading.name().to_owned())
.with_position(uploading.offset());
bar.enable_steady_tick(Duration::from_millis(100));

View file

@ -8,7 +8,7 @@ use log::debug;
use serde::{Deserialize, Serialize};
use ureq::http::StatusCode;
use super::{Alias, FileUploading, Share, SharryAlias};
use super::{Alias, FileUploading, Share, SharryAlias, SharryFile};
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileChecked {
@ -30,30 +30,23 @@ impl FileChecked {
}
}
pub fn file_name(&self) -> &str {
self.path
.file_name()
.and_then(OsStr::to_str)
.expect("bad file name")
}
pub fn start_upload(
self,
http: &ureq::Agent,
alias: &Alias,
share: &Share,
) -> io::Result<FileUploading> {
let size = usize::try_from(fs::metadata(&self.path)?.len()).map_err(io::Error::other)?;
let size: usize = self.size();
let res = {
let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
(http.post(endpoint))
.sharry_header(alias)
.header("Sharry-File-Name", self.file_name())
.header("Sharry-File-Name", self.name())
.header("Upload-Length", size)
.send_empty()
.map_err(io::Error::other)?
.map_err(ureq::Error::into_io)?
};
if res.status() != StatusCode::CREATED {
@ -71,3 +64,29 @@ impl FileChecked {
Ok(FileUploading::new(self.path, size, location))
}
}
impl<'t> SharryFile<'t> for FileChecked {
/// get a reference to the file's name
///
/// Uses SharryFile::extract_file_name, which may **panic**!
fn name(&'t self) -> &'t str {
<Self as SharryFile>::extract_file_name(&self.path)
}
fn offset<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: std::fmt::Debug + std::fmt::Display,
{
<Self as SharryFile>::from_usize(0)
}
fn size<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: std::fmt::Debug + std::fmt::Display,
{
let val = <Self as SharryFile>::to_usize(fs::metadata(&self.path).unwrap().len());
<Self as SharryFile>::from_usize(val)
}
}

View file

@ -0,0 +1,50 @@
use std::{
ffi::OsStr,
fmt::{Debug, Display},
path::{Path, PathBuf},
};
pub trait SharryFile<'t> {
/// get a reference to the filename from a PathBuf reference
///
/// # Panics
///
/// Expects `Path::file_name` and `ffi::OsStr::to_str` to succeed on the contained path.
fn extract_file_name(p: &'t PathBuf) -> &'t str {
p.file_name()
.and_then(OsStr::to_str)
.expect("bad file name")
}
fn from_usize<T>(val: usize) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: Debug + Display,
{
val.try_into()
.inspect_err(|e| panic!("usize did not fit into other type: {e}"))
.unwrap()
}
fn to_usize<T>(val: T) -> usize
where
T: TryInto<usize>,
<T as TryInto<usize>>::Error: Debug + Display,
{
val.try_into()
.inspect_err(|e| panic!("usize did not fit into other type: {e}"))
.unwrap()
}
fn name(&'t self) -> &'t str;
fn offset<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: Debug + Display;
fn size<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: Debug + Display;
}

View file

@ -1,7 +1,9 @@
mod checked;
mod filetrait;
mod uploading;
pub use checked::FileChecked;
pub use filetrait::SharryFile;
pub use uploading::{ChunkState, FileUploading, UploadError};
use super::{Alias, Share, alias::SharryAlias};

View file

@ -1,6 +1,5 @@
use std::{
ffi::OsStr,
fmt::{Debug, Display},
fs,
io::{self, Read, Seek, SeekFrom},
path::PathBuf,
@ -10,7 +9,7 @@ use log::debug;
use serde::{Deserialize, Serialize};
use ureq::http::{HeaderValue, StatusCode};
use super::{Alias, SharryAlias};
use super::{Alias, SharryAlias, SharryFile};
#[derive(Serialize, Deserialize, Debug)]
pub struct FileUploading {
@ -34,7 +33,7 @@ pub enum ChunkState {
Finished(PathBuf),
}
impl Display for FileUploading {
impl std::fmt::Display for FileUploading {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
@ -69,29 +68,6 @@ impl FileUploading {
Ok(bytes)
}
pub fn file_name(&self) -> &str {
self.path
.file_name()
.and_then(OsStr::to_str)
.expect("bad file name")
}
pub fn offset<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: Debug,
{
self.offset.try_into().unwrap()
}
pub fn size<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: Debug,
{
self.size.try_into().unwrap()
}
pub fn upload_chunk(
mut self,
http: &ureq::Agent,
@ -135,3 +111,25 @@ impl FileUploading {
ChunkState::Ok(self)
}
}
impl<'t> SharryFile<'t> for FileUploading {
fn name(&'t self) -> &'t str {
<Self as SharryFile>::extract_file_name(&self.path)
}
fn offset<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: std::fmt::Debug + std::fmt::Display,
{
<Self as SharryFile>::from_usize(self.offset)
}
fn size<T>(&self) -> T
where
T: TryFrom<usize>,
<T as TryFrom<usize>>::Error: std::fmt::Debug + std::fmt::Display,
{
<Self as SharryFile>::from_usize(self.size)
}
}

View file

@ -7,5 +7,5 @@ mod share;
pub use alias::Alias;
pub use api::{NewShareRequest, Uri};
pub use file::{ChunkState, FileChecked, FileUploading, UploadError};
pub use file::{ChunkState, FileChecked, FileUploading, SharryFile, UploadError};
pub use share::Share;