use std::{ fmt, fs, io::{self, Read, Seek, SeekFrom}, path::PathBuf, }; use serde::{Deserialize, Serialize}; use super::{Chunk, FileTrait}; #[derive(Serialize, Deserialize)] pub struct Uploading { path: PathBuf, size: u64, patch_uri: String, last_offset: Option, offset: u64, } impl fmt::Debug for Uploading { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Uploading {:?} ({}/{})", self.path.display(), self.offset, self.size ) } } impl Uploading { pub(super) fn new(path: PathBuf, size: u64, patch_uri: String) -> Self { Self { path, size, patch_uri, last_offset: None, offset: 0, } } pub fn get_offset(&self) -> u64 { self.offset } pub fn rewind(self) -> Option { self.last_offset.map(|last_offset| Self { last_offset: None, offset: last_offset, ..self }) } pub fn read<'t>(&mut self, buf: &'t mut [u8]) -> io::Result> { let mut f = fs::File::open(&self.path)?; f.seek(SeekFrom::Start(self.offset))?; let read_len = f.read(buf)?; if read_len == 0 { return Err(io::Error::new( io::ErrorKind::UnexpectedEof, format!("could not read from file {:?}", self.path.display()), )); } let chunk = Chunk::new(&buf[..read_len], self.patch_uri.clone(), self.offset); self.last_offset = Some(self.offset); self.offset += chunk.get_length(); Ok(chunk) } pub fn check_eof(self) -> Result { if self.offset < self.size { Ok(self) } else { Err(self.path) } } } impl<'t> FileTrait<'t> for Uploading { /// get a reference to the file's name /// /// Uses `SharryFile::extract_file_name`, which may **panic**! fn get_name(&'t self) -> &'t str { ::extract_file_name(&self.path) } fn get_size(&self) -> u64 { self.size } }