Compare commits

..

2 commits

4 changed files with 112 additions and 40 deletions

View file

@ -1,6 +1,6 @@
mod sharry; mod sharry;
use log::info; use log::{error, info};
use sharry::{Alias, File, NewShareRequest, Share}; use sharry::{Alias, File, NewShareRequest, Share};
use std::time::Duration; use std::time::Duration;
use ureq::Agent; use ureq::Agent;
@ -22,13 +22,15 @@ fn main() {
let share = Share::create(&agent, &alias, share).unwrap(); let share = Share::create(&agent, &alias, share).unwrap();
info!("share: {:?}", share); info!("share: {:?}", share);
let file = File::create( let file = File::create(&agent, &share, "/lib/x86_64-linux-gnu/liblldb-14.so.1").unwrap();
&agent,
&share,
"/lib/x86_64-linux-gnu/liblldb-14.so.1".into(),
)
.unwrap();
info!("file: {:?}", file); info!("file: {:?}", file);
for chunk in file.chunked(10 * 1024 * 1024) {
println!("chunk len: {}", chunk.bytes.len());
file.upload_chunk(&agent, chunk)
.inspect_err(|e| error!("error: {}", e))
.unwrap();
}
share.notify(&agent).unwrap(); share.notify(&agent).unwrap();
} }

60
src/sharry/chunkedfile.rs Normal file
View file

@ -0,0 +1,60 @@
use std::{
fs,
io::{self, Read, Seek},
mem,
path::PathBuf,
};
use log::error;
pub struct ChunkedFile<'t> {
path: &'t PathBuf,
cnum: u64,
csize: usize,
}
impl<'t> ChunkedFile<'t> {
pub(super) fn new(path: &'t PathBuf, chunk_size: usize) -> Self {
Self {
path,
cnum: 0,
csize: chunk_size,
}
}
}
impl<'t> Iterator for ChunkedFile<'t> {
type Item = Chunk;
fn next(&mut self) -> Option<Self::Item> {
let offset = {
let csize: u64 = self.csize.try_into().unwrap();
self.cnum * csize
};
let mut f = fs::File::open(&self.path)
.inspect_err(|e| error!("Error opening file: {}", e))
.ok()?;
f.seek(io::SeekFrom::Start(offset)).ok()?;
let mut buffer = vec![0; self.csize];
let read_len = f
.read(&mut buffer)
.inspect_err(|e| error!("Error reading file: {}", e))
.ok()?;
buffer.truncate(read_len);
self.cnum += 1;
Some(Self::Item {
offset: offset.try_into().unwrap(),
bytes: buffer,
})
.filter(|c| c.bytes.len() > 0)
}
}
pub struct Chunk {
pub offset: usize,
pub bytes: Vec<u8>,
}

View file

@ -1,15 +1,18 @@
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fs, fs,
io::{self, Read}, io::{self, Read, Seek},
os::unix::fs::FileExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr,
}; };
use log::debug; use log::{debug, error};
use ureq::http::StatusCode; use ureq::http::StatusCode;
use super::{ use super::{
alias::{Alias, SharryAlias}, alias::{Alias, SharryAlias},
chunkedfile::{Chunk, ChunkedFile},
share::Share, share::Share,
}; };
@ -24,17 +27,18 @@ impl<'t> File<'t> {
pub fn create( pub fn create(
http: &ureq::Agent, http: &ureq::Agent,
share: &'t Share, share: &'t Share,
file_path: PathBuf, file_path: impl Into<PathBuf>,
) -> Result<Self, ureq::Error> { ) -> Result<Self, ureq::Error> {
let endpoint = share let file_path: PathBuf = file_path.into();
.alias
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
let filename = file_path let filename = file_path
.file_name() .file_name()
.and_then(OsStr::to_str) .and_then(OsStr::to_str)
.unwrap_or("file.bin"); .unwrap_or("file.bin");
let endpoint = share
.alias
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
let res = http let res = http
.post(endpoint) .post(endpoint)
.sharry_header(share.alias) .sharry_header(share.alias)
@ -55,14 +59,6 @@ impl<'t> File<'t> {
debug!("location: {}", location); 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 { Ok(Self {
alias: share.alias, alias: share.alias,
file_path, file_path,
@ -70,23 +66,36 @@ impl<'t> File<'t> {
}) })
} }
pub fn upload(&self, chunk_size: usize) -> UploadChunk { pub fn chunked(&self, chunk_size: usize) -> ChunkedFile {
UploadChunk::new(&self.file_path, chunk_size).unwrap() ChunkedFile::new(&self.file_path, chunk_size)
} }
}
pub fn upload_chunk(&self, http: &ureq::Agent, chunk: Chunk) -> Result<(), ureq::Error> {
pub struct UploadChunk { debug!("upload uri: {:?}", self.patch_uri);
num: u64,
f: fs::File, let res = http
buffer: Vec<u8>, .patch(&self.patch_uri)
} .sharry_header(self.alias)
.header("Upload-Offset", chunk.offset)
impl UploadChunk { .send(&chunk.bytes)?;
fn new(path: impl AsRef<Path>, chunk_size: usize) -> io::Result<Self> {
Ok(Self { if res.status() != StatusCode::NO_CONTENT {
num: 0, return Err(ureq::Error::Other("unexpected response status".into()));
f: fs::File::open(path)?, }
buffer: vec![0; chunk_size],
}) let offset = res
.headers()
.get("Upload-Offset")
.ok_or_else(|| ureq::Error::Other("Upload-Offset header not found".into()))?
.to_str()
.map_err(|_| ureq::Error::Other("Upload-Offset header invalid".into()))?
.parse::<usize>()
.map_err(|_| ureq::Error::Other("Upload-Offset header not an integer".into()))?;
if chunk.offset + chunk.bytes.len() != offset {
return Err(ureq::Error::Other("unexpected offset response".into()));
}
Ok(())
} }
} }

View file

@ -2,6 +2,7 @@
mod alias; mod alias;
mod api; mod api;
mod chunkedfile;
mod file; mod file;
mod share; mod share;