restructure + refactor sharry::file
This commit is contained in:
parent
c5809d8faf
commit
28039fd286
4 changed files with 128 additions and 109 deletions
|
|
@ -22,12 +22,15 @@ fn main() {
|
|||
let share = Share::create(&agent, &alias, share).unwrap();
|
||||
info!("share: {share:?}");
|
||||
|
||||
let file = File::create(&agent, &share, "/lib/x86_64-linux-gnu/liblldb-14.so.1").unwrap();
|
||||
let file = File::new("/lib/x86_64-linux-gnu/liblldb-14.so.1")
|
||||
.unwrap()
|
||||
.create(&agent, &share)
|
||||
.unwrap();
|
||||
info!("file: {file:?}");
|
||||
|
||||
for chunk in file.chunked(10 * 1024 * 1024) {
|
||||
println!("chunk len: {}", chunk.bytes.len());
|
||||
file.upload_chunk(&agent, &chunk)
|
||||
file.upload_chunk(&agent, &alias, &chunk)
|
||||
.inspect_err(|e| error!("error: {e}"))
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ use std::{
|
|||
|
||||
use log::error;
|
||||
|
||||
pub struct ChunkedFile<'t> {
|
||||
pub struct FileChunks<'t> {
|
||||
path: &'t PathBuf,
|
||||
cnum: u64,
|
||||
csize: usize,
|
||||
}
|
||||
|
||||
impl<'t> ChunkedFile<'t> {
|
||||
impl<'t> FileChunks<'t> {
|
||||
pub(super) fn new(path: &'t PathBuf, chunk_size: usize) -> Self {
|
||||
Self {
|
||||
path,
|
||||
|
|
@ -22,7 +22,7 @@ impl<'t> ChunkedFile<'t> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Iterator for ChunkedFile<'_> {
|
||||
impl Iterator for FileChunks<'_> {
|
||||
type Item = Chunk;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
use std::{
|
||||
ffi::OsStr,
|
||||
fs::metadata,
|
||||
io::{Read, Seek},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use ureq::{Error::Other, http::StatusCode};
|
||||
|
||||
use super::super::{
|
||||
alias::{Alias, SharryAlias},
|
||||
share::Share,
|
||||
};
|
||||
use super::chunkedfile::{Chunk, ChunkedFile};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File<'t> {
|
||||
alias: &'t Alias,
|
||||
path: PathBuf,
|
||||
patch_uri: String,
|
||||
}
|
||||
|
||||
impl<'t> File<'t> {
|
||||
pub fn create(
|
||||
http: &ureq::Agent,
|
||||
share: &'t Share,
|
||||
path: impl Into<PathBuf>,
|
||||
) -> Result<Self, ureq::Error> {
|
||||
let path: PathBuf = path.into();
|
||||
let filename = path
|
||||
.file_name()
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("file.bin");
|
||||
|
||||
let endpoint = share
|
||||
.alias
|
||||
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
||||
|
||||
let res = http
|
||||
.post(endpoint)
|
||||
.sharry_header(share.alias)
|
||||
.header("Sharry-File-Name", filename)
|
||||
.header("Upload-Length", metadata(&path)?.len())
|
||||
.send_empty()?;
|
||||
|
||||
if res.status() != StatusCode::CREATED {
|
||||
return Err(Other("unexpected response status".into()));
|
||||
}
|
||||
|
||||
let location = res
|
||||
.headers()
|
||||
.get("Location")
|
||||
.ok_or_else(|| Other("Location header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| Other("Location header invalid".into()))?;
|
||||
|
||||
debug!("location: {location}");
|
||||
|
||||
Ok(Self {
|
||||
alias: share.alias,
|
||||
path,
|
||||
patch_uri: location.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chunked(&self, chunk_size: usize) -> ChunkedFile {
|
||||
ChunkedFile::new(&self.path, chunk_size)
|
||||
}
|
||||
|
||||
pub fn upload_chunk(&self, http: &ureq::Agent, chunk: &Chunk) -> Result<(), ureq::Error> {
|
||||
debug!("upload uri: {:?}", self.patch_uri);
|
||||
|
||||
let res = http
|
||||
.patch(&self.patch_uri)
|
||||
.sharry_header(self.alias)
|
||||
.header("Upload-Offset", chunk.offset)
|
||||
.send(&chunk.bytes)?;
|
||||
|
||||
if res.status() != StatusCode::NO_CONTENT {
|
||||
return Err(Other("unexpected response status".into()));
|
||||
}
|
||||
|
||||
let offset = res
|
||||
.headers()
|
||||
.get("Upload-Offset")
|
||||
.ok_or_else(|| Other("Upload-Offset header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| Other("Upload-Offset header invalid".into()))?
|
||||
.parse::<u64>()
|
||||
.map_err(|_| Other("Upload-Offset header not an integer".into()))?;
|
||||
|
||||
if chunk.after() != offset {
|
||||
return Err(Other("unexpected offset response".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,122 @@
|
|||
#![allow(unused_imports)]
|
||||
mod chunks;
|
||||
|
||||
mod chunkedfile;
|
||||
mod file;
|
||||
use std::{ffi::OsStr, fs::metadata, io, path::PathBuf};
|
||||
|
||||
pub use chunkedfile::{Chunk, ChunkedFile};
|
||||
pub use file::File;
|
||||
use log::{debug, error};
|
||||
use ureq::{Error::Other, http::StatusCode};
|
||||
|
||||
use super::{
|
||||
alias::{Alias, SharryAlias},
|
||||
share::Share,
|
||||
};
|
||||
pub use chunks::{Chunk, FileChunks};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
path: PathBuf,
|
||||
name: String,
|
||||
size: u64,
|
||||
patch_uri: Option<String>,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn new(path: impl Into<PathBuf>) -> io::Result<Self> {
|
||||
let path: PathBuf = path.into();
|
||||
|
||||
let name = path
|
||||
.file_name()
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("file.bin")
|
||||
.to_string();
|
||||
|
||||
let size = metadata(&path)?.len();
|
||||
|
||||
Ok(Self {
|
||||
path,
|
||||
name,
|
||||
size,
|
||||
patch_uri: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(self, http: &ureq::Agent, share: &Share) -> Result<Self, ureq::Error> {
|
||||
if self.patch_uri.is_some() {
|
||||
return Err(Other("patch_uri already set".into()));
|
||||
}
|
||||
|
||||
let endpoint = share
|
||||
.alias
|
||||
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
||||
|
||||
let res = http
|
||||
.post(endpoint)
|
||||
.sharry_header(share.alias)
|
||||
.header("Sharry-File-Name", &self.name)
|
||||
.header("Upload-Length", self.size)
|
||||
.send_empty()?;
|
||||
|
||||
if res.status() != StatusCode::CREATED {
|
||||
return Err(Other("unexpected response status".into()));
|
||||
}
|
||||
|
||||
let location = res
|
||||
.headers()
|
||||
.get("Location")
|
||||
.ok_or_else(|| Other("Location header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| Other("Location header invalid".into()))?
|
||||
.to_string();
|
||||
|
||||
debug!("received uri: {location}");
|
||||
|
||||
Ok(Self {
|
||||
path: self.path,
|
||||
name: self.name,
|
||||
size: self.size,
|
||||
patch_uri: Some(location),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn chunked(&self, chunk_size: usize) -> FileChunks {
|
||||
FileChunks::new(&self.path, chunk_size)
|
||||
}
|
||||
|
||||
pub fn upload_chunk(
|
||||
&self,
|
||||
http: &ureq::Agent,
|
||||
alias: &Alias,
|
||||
chunk: &Chunk,
|
||||
) -> Result<(), ureq::Error> {
|
||||
let patch_uri = self
|
||||
.patch_uri
|
||||
.as_ref()
|
||||
.ok_or_else(|| Other("unset patch_uri".into()))?;
|
||||
|
||||
debug!("upload uri: {patch_uri:?}");
|
||||
|
||||
let res = http
|
||||
.patch(patch_uri)
|
||||
.sharry_header(alias)
|
||||
.header("Upload-Offset", chunk.offset)
|
||||
.send(&chunk.bytes)?;
|
||||
|
||||
if res.status() != StatusCode::NO_CONTENT {
|
||||
return Err(Other("unexpected response status".into()));
|
||||
}
|
||||
|
||||
let offset = res
|
||||
.headers()
|
||||
.get("Upload-Offset")
|
||||
.ok_or_else(|| Other("Upload-Offset header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| Other("Upload-Offset header invalid".into()))?
|
||||
.parse::<u64>()
|
||||
.map_err(|_| Other("Upload-Offset header not an integer".into()))?;
|
||||
|
||||
if chunk.after() != offset {
|
||||
return Err(Other("unexpected offset response".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue