2025-05-24 00:48:59 +00:00
|
|
|
use std::{
|
|
|
|
|
ffi::OsStr,
|
|
|
|
|
fs,
|
2025-05-24 01:47:02 +00:00
|
|
|
io::{self, Read},
|
2025-05-24 00:48:59 +00:00
|
|
|
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,
|
2025-05-24 01:47:02 +00:00
|
|
|
file_path: PathBuf,
|
2025-05-24 00:48:59 +00:00
|
|
|
patch_uri: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'t> File<'t> {
|
|
|
|
|
pub fn create(
|
|
|
|
|
http: &ureq::Agent,
|
|
|
|
|
share: &'t Share,
|
2025-05-24 01:47:02 +00:00
|
|
|
file_path: PathBuf,
|
2025-05-24 00:48:59 +00:00
|
|
|
) -> Result<Self, ureq::Error> {
|
|
|
|
|
let endpoint = share
|
|
|
|
|
.alias
|
|
|
|
|
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
|
|
|
|
|
2025-05-24 01:47:02 +00:00
|
|
|
let filename = file_path
|
2025-05-24 00:48:59 +00:00
|
|
|
.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)
|
2025-05-24 01:47:02 +00:00
|
|
|
.header("Upload-Length", fs::metadata(&file_path)?.len())
|
2025-05-24 00:48:59 +00:00
|
|
|
.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,
|
2025-05-24 01:47:02 +00:00
|
|
|
file_path,
|
2025-05-24 00:48:59 +00:00
|
|
|
patch_uri: location.into(),
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-05-24 01:47:02 +00:00
|
|
|
|
|
|
|
|
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<u8>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UploadChunk {
|
|
|
|
|
fn new(path: impl AsRef<Path>, chunk_size: usize) -> io::Result<Self> {
|
|
|
|
|
Ok(Self {
|
|
|
|
|
num: 0,
|
|
|
|
|
f: fs::File::open(path)?,
|
|
|
|
|
buffer: vec![0; chunk_size],
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-05-24 00:48:59 +00:00
|
|
|
}
|