Compare commits

...

2 commits

5 changed files with 71 additions and 83 deletions

31
.vscode/settings.json vendored
View file

@ -12,6 +12,37 @@
}, },
}, },
"rust-analyzer.imports.prefix": "plain", "rust-analyzer.imports.prefix": "plain",
"todo-tree.general.tags": [
"BUG",
"HACK",
"FIXME",
"TODO",
"XXX",
"[ ]",
"[x]",
"BOOKMARK"
],
"todo-tree.highlights.backgroundColourScheme": [
"red",
"orange",
"yellow",
"green",
"blue",
"indigo",
"violet",
"yellow"
],
"todo-tree.highlights.foregroundColourScheme": [
"white",
"black",
"black",
"white",
"white",
"white",
"black",
"black"
],
"todo-tree.highlights.useColourScheme": true,
// // override the default setting (`cargo check --all-targets`) which produces the following error // // override the default setting (`cargo check --all-targets`) which produces the following error
// // "can't find crate for `test`" when the default compilation target is a no_std target // // "can't find crate for `test`" when the default compilation target is a no_std target
// "rust-analyzer.checkOnSave.allTargets": false, // "rust-analyzer.checkOnSave.allTargets": false,

View file

@ -37,8 +37,8 @@ enum FileState {
impl FileState { impl FileState {
fn file_name(&self) -> &str { fn file_name(&self) -> &str {
match self { match self {
FileState::C(checked) => checked.name(), FileState::C(checked) => checked.get_name(),
FileState::U(uploading) => uploading.name(), FileState::U(uploading) => uploading.get_name(),
} }
} }
@ -133,7 +133,7 @@ impl AppState {
// Initialize or fetch the existing ProgressBar in one call: // Initialize or fetch the existing ProgressBar in one call:
let bar = &*self.progress.get_or_insert_with(|| { let bar = &*self.progress.get_or_insert_with(|| {
// Create a new bar with style // Create a new bar with style
let bar = ProgressBar::new(uploading.size()) let bar = ProgressBar::new(uploading.get_size())
.with_style( .with_style(
ProgressStyle::with_template(&format!( ProgressStyle::with_template(&format!(
concat!( concat!(
@ -145,8 +145,8 @@ impl AppState {
)) ))
.unwrap(), .unwrap(),
) )
.with_message(uploading.name().to_owned()) .with_message(uploading.get_name().to_owned())
.with_position(uploading.offset()); .with_position(uploading.get_offset());
bar.enable_steady_tick(Duration::from_millis(100)); bar.enable_steady_tick(Duration::from_millis(100));
bar bar
@ -154,7 +154,7 @@ impl AppState {
match uploading.upload_chunk(http, &self.alias, chunk_size) { match uploading.upload_chunk(http, &self.alias, chunk_size) {
ChunkState::Ok(upl) => { ChunkState::Ok(upl) => {
bar.set_position(upl.offset()); bar.set_position(upl.get_offset());
self.files.push_front(FileState::U(upl)); self.files.push_front(FileState::U(upl));
Ok(Some(())) Ok(Some(()))
} }

View file

@ -6,7 +6,7 @@ use std::{
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ureq::http::StatusCode; use ureq::http::{HeaderValue, StatusCode};
use super::{Alias, FileUploading, Share, SharryAlias, SharryFile}; use super::{Alias, FileUploading, Share, SharryAlias, SharryFile};
@ -36,14 +36,14 @@ impl FileChecked {
alias: &Alias, alias: &Alias,
share: &Share, share: &Share,
) -> io::Result<FileUploading> { ) -> io::Result<FileUploading> {
let size: usize = self.size(); let size = self.get_size();
let res = { let res = {
let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id)); let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
(http.post(endpoint)) (http.post(endpoint))
.sharry_header(alias) .sharry_header(alias)
.header("Sharry-File-Name", self.name()) .header("Sharry-File-Name", self.get_name())
.header("Upload-Length", size) .header("Upload-Length", size)
.send_empty() .send_empty()
.map_err(ureq::Error::into_io)? .map_err(ureq::Error::into_io)?
@ -68,25 +68,12 @@ impl FileChecked {
impl<'t> SharryFile<'t> for FileChecked { impl<'t> SharryFile<'t> for FileChecked {
/// get a reference to the file's name /// get a reference to the file's name
/// ///
/// Uses SharryFile::extract_file_name, which may **panic**! /// Uses `SharryFile::extract_file_name`, which may **panic**!
fn name(&'t self) -> &'t str { fn get_name(&'t self) -> &'t str {
<Self as SharryFile>::extract_file_name(&self.path) <Self as SharryFile>::extract_file_name(&self.path)
} }
fn offset<T>(&self) -> T fn get_size(&self) -> u64 {
where fs::metadata(&self.path).unwrap().len()
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

@ -1,50 +1,22 @@
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fmt::{Debug, Display}, fmt::{Debug, Display},
path::{Path, PathBuf}, path::Path,
}; };
pub trait SharryFile<'t> { pub trait SharryFile<'t> {
/// get a reference to the filename from a PathBuf reference /// extract the filename part of a `Path` reference
/// ///
/// # Panics /// # Panics
/// ///
/// Expects `Path::file_name` and `ffi::OsStr::to_str` to succeed on the contained path. /// Expects `path::Path::file_name` and `ffi::OsStr::to_str` to succeed on the given path
fn extract_file_name(p: &'t PathBuf) -> &'t str { fn extract_file_name(p: &'t Path) -> &'t str {
p.file_name() p.file_name()
.and_then(OsStr::to_str) .and_then(OsStr::to_str)
.expect("bad file name") .expect("bad file name")
} }
fn from_usize<T>(val: usize) -> T fn get_name(&'t self) -> &'t str;
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 fn get_size(&self) -> u64;
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

@ -14,9 +14,9 @@ use super::{Alias, SharryAlias, SharryFile};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct FileUploading { pub struct FileUploading {
path: PathBuf, path: PathBuf,
size: usize, size: u64,
uri: String, uri: String,
offset: usize, offset: u64,
} }
#[derive(Debug)] #[derive(Debug)]
@ -46,7 +46,7 @@ impl std::fmt::Display for FileUploading {
} }
impl FileUploading { impl FileUploading {
pub(super) fn new(path: PathBuf, size: usize, uri: String) -> Self { pub(super) fn new(path: PathBuf, size: u64, uri: String) -> Self {
Self { Self {
path, path,
size, size,
@ -55,11 +55,13 @@ impl FileUploading {
} }
} }
fn read_chunk(&self, chunk_size: usize) -> io::Result<Vec<u8>> { pub fn get_offset(&self) -> u64 {
let offset = u64::try_from(self.offset).map_err(io::Error::other)?; self.offset
}
fn read_chunk(&self, chunk_size: usize) -> io::Result<Vec<u8>> {
let mut f = fs::File::open(&self.path)?; let mut f = fs::File::open(&self.path)?;
f.seek(SeekFrom::Start(offset))?; f.seek(SeekFrom::Start(self.offset))?;
let mut bytes = vec![0; chunk_size]; let mut bytes = vec![0; chunk_size];
let read_len = f.read(&mut bytes)?; let read_len = f.read(&mut bytes)?;
@ -93,12 +95,20 @@ impl FileUploading {
let Some(Ok(Ok(res_offset))) = (res.headers().get("Upload-Offset")) let Some(Ok(Ok(res_offset))) = (res.headers().get("Upload-Offset"))
.map(HeaderValue::to_str) .map(HeaderValue::to_str)
.map(|v| v.map(str::parse::<usize>)) .map(|v| v.map(str::parse::<u64>))
else { else {
return ChunkState::Err(self, UploadError::ResponseOffset); return ChunkState::Err(self, UploadError::ResponseOffset);
}; };
if self.offset + chunk.len() != res_offset { // convert chunk.len() into an `u64`
//
// BOOKMARK this might panic on platforms where `usize` > 64 bit.
// Also whoa, you've sent more than 2 EiB ... in ONE chunk.
// Maybe just chill?
let chunk_len = u64::try_from(chunk.len())
.unwrap_or_else(|e| panic!("usize={} did not fit into u64: {}", chunk.len(), e));
if self.offset + chunk_len != res_offset {
return ChunkState::Err(self, UploadError::ResponseOffset); return ChunkState::Err(self, UploadError::ResponseOffset);
} }
@ -113,23 +123,11 @@ impl FileUploading {
} }
impl<'t> SharryFile<'t> for FileUploading { impl<'t> SharryFile<'t> for FileUploading {
fn name(&'t self) -> &'t str { fn get_name(&'t self) -> &'t str {
<Self as SharryFile>::extract_file_name(&self.path) <Self as SharryFile>::extract_file_name(&self.path)
} }
fn offset<T>(&self) -> T fn get_size(&self) -> u64 {
where self.size
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)
} }
} }