use std::{ ffi::OsStr, fs, io::{self, Read}, path::{Path, PathBuf}, }; use log::debug; use ureq::http::StatusCode; use super::{ alias::{Alias, SharryAlias}, share::Share, }; #[derive(Debug)] pub struct File<'t> { alias: &'t Alias, file_path: PathBuf, patch_uri: String, } impl<'t> File<'t> { pub fn create( http: &ureq::Agent, share: &'t Share, file_path: PathBuf, ) -> Result { let endpoint = share .alias .get_endpoint(format!("alias/upload/{}/files/tus", share.id)); let filename = file_path .file_name() .and_then(OsStr::to_str) .unwrap_or("file.bin"); let res = http .post(endpoint) .sharry_header(share.alias) .header("Sharry-File-Name", filename) .header("Upload-Length", fs::metadata(&file_path)?.len()) .send_empty()?; if res.status() != StatusCode::CREATED { return Err(ureq::Error::Other("unexpected response status".into())); } let location = res .headers() .get("Location") .ok_or_else(|| ureq::Error::Other("Location header not found".into()))? .to_str() .map_err(|_| ureq::Error::Other("Location header invalid".into()))?; debug!("location: {}", location); // let start = 10; // let count = 10; // let mut f = File::open(path)?; // f.seek(SeekFrom::Start(0)); // let mut buf = vec![0; count]; // f.read_exact(&mut buf)?; Ok(Self { alias: share.alias, file_path, patch_uri: location.into(), }) } pub fn upload(&self, chunk_size: usize) -> UploadChunk { UploadChunk::new(&self.file_path, chunk_size).unwrap() } } pub struct UploadChunk { num: u64, f: fs::File, buffer: Vec, } impl UploadChunk { fn new(path: impl AsRef, chunk_size: usize) -> io::Result { Ok(Self { num: 0, f: fs::File::open(path)?, buffer: vec![0; chunk_size], }) } }