use std::{ fmt, fs, io::{self, Read, Seek, SeekFrom}, path::PathBuf, }; use serde::{Deserialize, Serialize}; use super::{FileChecked, SharryFile}; #[derive(Serialize, Deserialize, Debug)] pub struct FileUploading { path: PathBuf, size: u64, patch_uri: String, offset: u64, } impl fmt::Display for FileUploading { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Uploading {:?} ({}/{})", self.path.display(), self.offset, self.size ) } } impl FileUploading { pub fn new(file: FileChecked, patch_uri: String) -> Self { Self { path: file.path, size: file.size, patch_uri, offset: 0, } } pub fn get_patch_uri(&self) -> &str { &self.patch_uri } pub fn get_offset(&self) -> u64 { self.offset } pub fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut f = fs::File::open(&self.path)?; f.seek(SeekFrom::Start(self.offset))?; let read_len = f.read(buf)?; // convert into `u64` // // BOOKMARK this might **panic** on platforms where `usize` has more than 64 bit. // Also, you're reading more than 2 EiB ... in ONE chunk. // Whoa! Maybe just chill? let read_len = u64::try_from(read_len) .unwrap_or_else(|e| panic!("usize={} did not fit into u64: {}", read_len, e)); self.offset += read_len; Ok(read_len) } pub fn check_eof(self) -> Result { if self.offset < self.size { Ok(self) } else { Err(self.path) } } } impl<'t> SharryFile<'t> for FileUploading { /// 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 } }