shrupl/src/sharry/file/checked.rs

93 lines
2.5 KiB
Rust
Raw Normal View History

use std::{
ffi::OsStr,
2025-06-05 22:08:24 +00:00
fs, io,
path::{Path, PathBuf},
};
use log::debug;
use serde::{Deserialize, Serialize};
use ureq::http::StatusCode;
2025-06-06 15:21:49 +00:00
use super::{Alias, FileUploading, Share, SharryAlias, SharryFile};
2025-06-04 16:44:24 +00:00
#[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileChecked {
path: PathBuf,
}
impl FileChecked {
pub fn new(value: impl AsRef<Path>) -> io::Result<Self> {
let meta = fs::metadata(&value)?;
if meta.is_file() {
Ok(Self {
path: fs::canonicalize(&value)?,
})
} else {
Err(io::Error::new(
2025-06-05 22:08:24 +00:00
io::ErrorKind::InvalidInput,
"Not a regular file",
))
}
}
pub fn start_upload(
self,
http: &ureq::Agent,
alias: &Alias,
share: &Share,
) -> io::Result<FileUploading> {
2025-06-06 15:21:49 +00:00
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)
2025-06-06 15:21:49 +00:00
.header("Sharry-File-Name", self.name())
.header("Upload-Length", size)
.send_empty()
2025-06-06 15:21:49 +00:00
.map_err(ureq::Error::into_io)?
};
if res.status() != StatusCode::CREATED {
return Err(io::Error::other("unexpected response status"));
}
let location = (res.headers().get("Location"))
.ok_or_else(|| io::Error::other("Location header not found"))?
.to_str()
.map_err(|_| io::Error::other("Location header invalid"))?
.to_string();
debug!("patch uri: {location}");
2025-06-04 16:58:18 +00:00
Ok(FileUploading::new(self.path, size, location))
}
}
2025-06-06 15:21:49 +00:00
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)
}
}