use std::{ collections::VecDeque, fs, io::{self, Write}, path::{Path, PathBuf}, }; use log::trace; use serde::{Deserialize, Serialize}; use super::{ file::{self, FileTrait}, sharry::{self, Client, Uri}, }; #[derive(Serialize, Deserialize, Debug)] enum FileState { C(file::Checked), U(file::Uploading), } impl FileState { fn file_name(&self) -> &str { match self { FileState::C(c) => c.get_name(), FileState::U(u) => u.get_name(), } } fn start_upload( self, http: &impl Client, uri: &Uri, alias_id: &str, share_id: &str, ) -> sharry::Result { match self { FileState::C(checked) => { let endpoint = &uri.endpoint(format!("alias/upload/{share_id}/files/tus")); checked.start_upload(http, endpoint, alias_id) } FileState::U(uploading) => Ok(uploading), } } } #[derive(Serialize, Deserialize, Debug)] pub struct SavedState { #[serde(skip)] file_name: PathBuf, uri: Uri, alias_id: String, share_id: String, files: VecDeque, } impl SavedState { pub fn new( file_name: PathBuf, uri: Uri, alias_id: String, share_id: String, files: &Vec, ) -> Self { Self { file_name, uri, alias_id, share_id, files: files.clone().into_iter().map(FileState::C).collect(), } } pub fn load(file_name: &Path) -> io::Result { let file = fs::File::open(file_name)?; let state: Self = serde_json::from_reader(io::BufReader::new(file)).map_err(io::Error::other)?; Ok(Self { file_name: file_name.to_owned(), uri: state.uri, alias_id: state.alias_id, share_id: state.share_id, files: state.files, }) } pub fn file_names(&self) -> Vec<&str> { self.files.iter().map(FileState::file_name).collect() } pub fn has_file(&self) -> bool { !self.files.is_empty() } pub fn pop_file(&mut self, http: &impl Client) -> Option { if let Some(state) = self.files.pop_front() { Some( state .start_upload(http, &self.uri, &self.alias_id, &self.share_id) .unwrap(), ) // HACK unwrap } else { None } } pub fn push_file(&mut self, file: file::Uploading) { self.files.push_front(FileState::U(file)); } pub fn save(&self) -> io::Result<()> { let cache_dir = self.file_name.parent().ok_or_else(|| { io::Error::other(format!("orphan file {:?}", self.file_name.display())) })?; fs::create_dir_all(cache_dir)?; let json = serde_json::to_string_pretty(self).map_err(io::Error::other)?; let mut file = fs::File::create(&self.file_name)?; file.write_all(json.as_bytes())?; trace!("updated {:?}", self.file_name.display()); Ok(()) } pub fn clear(self) -> io::Result<()> { fs::remove_file(&self.file_name)?; trace!("removed {:?}", self.file_name.display()); Ok(()) } }