shrupl/src/file/uploading.rs
Jörn-Michael Miehe 30855ed8ff [wip] retry chunks
- `AppState::rewind` impl
- error handling in `main`
2025-06-13 23:00:36 +00:00

102 lines
2.3 KiB
Rust

use std::{
fmt, fs,
io::{self, Read, Seek, SeekFrom},
path::PathBuf,
};
use log::warn;
use serde::{Deserialize, Serialize};
use super::{Chunk, FileTrait};
#[derive(Serialize, Deserialize)]
pub struct Uploading {
path: PathBuf,
size: u64,
patch_uri: String,
last_offset: Option<u64>,
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> {
match self.last_offset {
Some(last_offset) => Some(Self {
last_offset: None,
offset: last_offset,
..self
}),
None => {
warn!("attempted to rewind twice");
None
}
}
}
pub fn read<'t>(&mut self, buf: &'t mut [u8]) -> io::Result<Chunk<'t>> {
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<Self, PathBuf> {
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 {
<Self as FileTrait>::extract_file_name(&self.path)
}
fn get_size(&self) -> u64 {
self.size
}
}