use std::{ ffi::OsStr, fs, io, path::{Path, PathBuf}, }; use log::debug; use serde::{Deserialize, Serialize}; use ureq::http::StatusCode; use super::{Alias, FileUploading, Share, SharryAlias, SharryFile}; #[derive(Debug, Clone, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct FileChecked { path: PathBuf, } impl FileChecked { pub fn new(value: impl AsRef) -> io::Result { let meta = fs::metadata(&value)?; if meta.is_file() { Ok(Self { path: fs::canonicalize(&value)?, }) } else { Err(io::Error::new( io::ErrorKind::InvalidInput, "Not a regular file", )) } } pub fn start_upload( self, http: &ureq::Agent, alias: &Alias, share: &Share, ) -> io::Result { 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.name()) .header("Upload-Length", size) .send_empty() .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}"); 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 { ::extract_file_name(&self.path) } fn offset(&self) -> T where T: TryFrom, >::Error: std::fmt::Debug + std::fmt::Display, { ::from_usize(0) } fn size(&self) -> T where T: TryFrom, >::Error: std::fmt::Debug + std::fmt::Display, { let val = ::to_usize(fs::metadata(&self.path).unwrap().len()); ::from_usize(val) } }