better impl, ChunkedFile with Iterator trait
This commit is contained in:
parent
dcee123194
commit
8ce3acde5e
4 changed files with 92 additions and 62 deletions
|
|
@ -1,6 +1,6 @@
|
|||
mod sharry;
|
||||
|
||||
use log::info;
|
||||
use log::{error, info};
|
||||
use sharry::{Alias, File, NewShareRequest, Share};
|
||||
use std::time::Duration;
|
||||
use ureq::Agent;
|
||||
|
|
@ -25,8 +25,11 @@ fn main() {
|
|||
let file = File::create(&agent, &share, "/lib/x86_64-linux-gnu/liblldb-14.so.1").unwrap();
|
||||
info!("file: {:?}", file);
|
||||
|
||||
for chunk in file.chunks(10_485_760) {
|
||||
println!("chunk len: {}", chunk.len());
|
||||
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();
|
||||
|
|
|
|||
60
src/sharry/chunkedfile.rs
Normal file
60
src/sharry/chunkedfile.rs
Normal 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>,
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ use ureq::http::StatusCode;
|
|||
|
||||
use super::{
|
||||
alias::{Alias, SharryAlias},
|
||||
chunkedfile::{Chunk, ChunkedFile},
|
||||
share::Share,
|
||||
};
|
||||
|
||||
|
|
@ -65,71 +66,36 @@ impl<'t> File<'t> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn chunks(&self, chunk_size: usize) -> FileChunks {
|
||||
FileChunks::new(&self.file_path, chunk_size)
|
||||
pub fn chunked(&self, chunk_size: usize) -> ChunkedFile {
|
||||
ChunkedFile::new(&self.file_path, chunk_size)
|
||||
}
|
||||
|
||||
// pub fn upload(&mut self) -> io::Result<()> {
|
||||
// let mut f = fs::File::open(&self.path)?;
|
||||
// f.seek(io::SeekFrom::Start(0));
|
||||
pub fn upload_chunk(&self, http: &ureq::Agent, chunk: Chunk) -> Result<(), ureq::Error> {
|
||||
debug!("upload uri: {:?}", self.patch_uri);
|
||||
|
||||
// let patch_size = f.read(&mut self.buffer)?;
|
||||
// let patch_data = &self.buffer[0..patch_size];
|
||||
let res = http
|
||||
.patch(&self.patch_uri)
|
||||
.sharry_header(self.alias)
|
||||
.header("Upload-Offset", chunk.offset)
|
||||
.send(&chunk.bytes)?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
}
|
||||
|
||||
pub struct FileChunks<'t> {
|
||||
num: u64,
|
||||
path: &'t PathBuf,
|
||||
buffer: Vec<u8>,
|
||||
data_len: Option<usize>,
|
||||
}
|
||||
|
||||
impl<'t> FileChunks<'t> {
|
||||
fn new(path: &'t PathBuf, chunk_size: usize) -> Self {
|
||||
Self {
|
||||
num: 0,
|
||||
path,
|
||||
buffer: vec![0; chunk_size],
|
||||
data_len: None,
|
||||
if res.status() != StatusCode::NO_CONTENT {
|
||||
return Err(ureq::Error::Other("unexpected response status".into()));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_offset(&self) -> Option<u64> {
|
||||
let buffer_len: u64 = self
|
||||
.buffer
|
||||
.len()
|
||||
.try_into()
|
||||
.inspect_err(|e| error!("Error converting length: {}", e))
|
||||
.ok()?;
|
||||
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()))?;
|
||||
|
||||
Some(self.num * buffer_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Iterator for FileChunks<'t> {
|
||||
type Item = &'t [u8];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut f = fs::File::open(&self.path)
|
||||
.inspect_err(|e| error!("Error opening file: {}", e))
|
||||
.ok()?;
|
||||
|
||||
f.seek(io::SeekFrom::Start(self.get_offset()?)).ok()?;
|
||||
|
||||
self.data_len = {
|
||||
let read_len = f
|
||||
.read(&mut self.buffer)
|
||||
.inspect_err(|e| error!("Error reading file: {}", e))
|
||||
.ok()?;
|
||||
|
||||
Some(read_len).filter(|l| *l > 0)
|
||||
};
|
||||
|
||||
self.num += 1;
|
||||
|
||||
Some(unsafe { std::mem::transmute(&self.buffer[0..self.data_len?]) })
|
||||
if chunk.offset + chunk.bytes.len() != offset {
|
||||
return Err(ureq::Error::Other("unexpected offset response".into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
mod alias;
|
||||
mod api;
|
||||
mod chunkedfile;
|
||||
mod file;
|
||||
mod share;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue