shrupl/src/file/uploading.rs

109 lines
2.5 KiB
Rust
Raw Normal View History

use std::{
fs,
io::{self, Read, Seek, SeekFrom},
path::PathBuf,
};
use log::warn;
use serde::{Deserialize, Serialize};
2025-06-26 09:56:29 +00:00
2025-06-18 19:40:34 +00:00
use super::{Checked, Chunk, FileTrait};
#[derive(Serialize, Deserialize, Debug)]
pub struct Uploading {
/// canonical path to a regular file
2025-06-04 16:58:18 +00:00
path: PathBuf,
/// size of that file
2025-06-06 23:42:18 +00:00
size: u64,
/// hash of that file
hash: Option<String>,
file_id: String,
#[serde(skip)]
last_offset: Option<u64>,
2025-06-06 23:42:18 +00:00
offset: u64,
}
impl Uploading {
pub(super) fn new(path: PathBuf, size: u64, hash: Option<String>, file_id: String) -> Self {
2025-06-04 16:58:18 +00:00
Self {
path,
size,
hash,
file_id,
last_offset: None,
2025-06-04 16:58:18 +00:00
offset: 0,
}
}
2025-06-06 23:42:18 +00:00
pub fn get_offset(&self) -> u64 {
self.offset
}
pub fn rewind(self) -> Option<Self> {
if let Some(last_offset) = self.last_offset {
Some(Self {
last_offset: None,
offset: last_offset,
..self
})
} else {
2025-06-13 23:11:40 +00:00
warn!("attempted to rewind twice");
None
}
}
pub fn read<'t>(&mut self, buf: &'t mut [u8]) -> io::Result<Chunk<'t>> {
2025-06-05 22:08:24 +00:00
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(self.file_id.clone(), self.offset, &buf[..read_len]);
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)
}
}
2025-06-18 19:40:34 +00:00
pub fn abort(self) -> Checked {
Checked {
path: self.path,
size: self.size,
hash: self.hash,
2025-06-18 19:40:34 +00:00
}
}
}
2025-06-06 15:21:49 +00:00
impl<'t> FileTrait<'t> for Uploading {
/// get a reference to the file's name
///
/// Uses `SharryFile::extract_file_name`, which may **panic**!
2025-06-06 23:42:18 +00:00
fn get_name(&'t self) -> &'t str {
<Self as FileTrait>::extract_file_name(&self.path)
2025-06-06 15:21:49 +00:00
}
2025-06-06 23:42:18 +00:00
fn get_size(&self) -> u64 {
self.size
2025-06-06 15:21:49 +00:00
}
2025-06-27 01:55:43 +00:00
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()> {
super::check_file_hash(&self.path, self.size, self.hash.as_ref(), on_progress)
}
2025-06-06 15:21:49 +00:00
}