use crate::{common::temp_file, server::Stream}; use log::error; use std::{ fs::{self, File}, io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write}, ops::Index, path::PathBuf, slice::SliceIndex, }; pub struct FileHandle { buffer: Vec, size: usize, tmp: Option<(PathBuf, BufWriter)>, reader: Option>, dirty: bool, } impl FileHandle { pub fn empty() -> std::io::Result { let (temp_path, temp_file) = temp_file()?; Ok(Self { buffer: Vec::new(), size: 0, tmp: Some((temp_path, BufWriter::new(temp_file))), reader: None, dirty: false, }) } pub fn new_rw(reader: BufReader) -> std::io::Result { // TODO: Copy read to tmp let (temp_path, temp_file) = temp_file()?; Ok(Self { buffer: Vec::new(), size: 0, tmp: Some((temp_path, BufWriter::new(temp_file))), reader: Some(reader), dirty: false, }) } pub fn new_ro(reader: BufReader) -> Self { Self { buffer: Vec::new(), size: 0, tmp: None, reader: Some(reader), dirty: false, } } pub fn is_dirty(&self) -> bool { self.dirty } pub fn write(&mut self, data: &[u8], offset: usize) -> Option { let Some((_, ref mut tmp)) = self.tmp else { error!("Tried to write to a RO file handle"); return None; }; tmp.seek(SeekFrom::Start(offset as u64)) .inspect_err(|e| error!("Seek error: {e}")) .ok()?; let written = tmp .write(data) .inspect_err(|e| error!("Write error: {e}")) .ok()?; self.dirty = true; Some(written) } pub fn read(&mut self, offset: usize, size: usize) -> Vec { let Some(mut reader) = self.reader else { error!("Tried to read from an empty file handle"); return Vec::new(); }; let mut buf = Vec::with_capacity(size); // TODO: error handling... reader.seek(SeekFrom::Start(offset as u64)).unwrap(); reader.read_exact(&mut buf).unwrap(); buf } pub fn clear(&mut self) { self.tmp.as_mut().map(|b| b.1.flush()); self.buffer.clear(); self.dirty = false; } } impl Drop for FileHandle { fn drop(&mut self) { let Some((ref temp_path, _)) = self.tmp else { return; }; if let Err(e) = fs::remove_file(temp_path) { error!("Couldn't delete temp file {temp_path:?}: {e}"); } } }