diff --git a/src/appstate.rs b/src/appstate.rs index 1a585ab..8cbc2e5 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -1,25 +1,21 @@ -use std::{fmt, io, path::PathBuf, time::Duration}; +use std::{fmt, io, time::Duration}; use console::style; use indicatif::{ProgressBar, ProgressStyle}; -use log::{debug, trace}; -use serde::{Deserialize, Serialize}; +use log::debug; use super::{ + cachefile::CacheFile, cli::Cli, file::FileTrait, - savedstate::SavedState, sharry::{self, Client, ClientError}, }; -#[derive(Serialize, Deserialize)] pub struct AppState { - #[serde(skip)] progress: Option, - #[serde(skip)] buffer: Vec, - inner: SavedState, + inner: CacheFile, } impl fmt::Debug for AppState { @@ -31,23 +27,7 @@ impl fmt::Debug for AppState { } impl AppState { - fn cache_dir() -> PathBuf { - let dir_name = dirs_next::cache_dir() - .expect("could not determine cache directory") - .join("shrupl"); - - trace!("cachedir: {:?}", dir_name.display()); - dir_name - } - - fn cache_file(args: &Cli) -> PathBuf { - let file_name = Self::cache_dir().join(format!("{}.json", args.get_hash())); - - trace!("cachefile: {:?}", file_name.display()); - file_name - } - - fn new(chunk_size: usize, inner: SavedState) -> Self { + fn new(chunk_size: usize, inner: CacheFile) -> Self { Self { progress: None, buffer: vec![0; chunk_size * 1024 * 1024], @@ -56,38 +36,26 @@ impl AppState { } pub fn try_resume(args: &Cli) -> Option { - let file_name = Self::cache_file(args); - let inner = SavedState::load(&file_name) - .inspect_err(|e| debug!("could not resume from {:?}: {e}", file_name.display())) + let inner = CacheFile::try_resume(args) + .inspect_err(|e| debug!("could not resume from hash {:?}: {e}", args.get_hash())) .ok()?; Some(Self::new(args.chunk_size, inner)) } pub fn from_args(args: &Cli, http: &impl Client) -> sharry::Result { - let uri = args.get_uri(); let share_id = http.share_create( - &uri.endpoint("alias/upload/new"), + &args.get_uri().endpoint("alias/upload/new"), &args.alias, args.get_share_request(), )?; Ok(Self::new( args.chunk_size, - SavedState::new( - Self::cache_file(&args), - uri, - args.alias.clone(), - share_id, - &args.files, - ), + CacheFile::from_args(args, share_id), )) } - pub fn file_names(&self) -> Vec<&str> { - self.inner.file_names() - } - pub fn upload_chunk(&mut self, http: &impl Client) -> sharry::Result> { let Some(mut uploading) = self.inner.pop_file(http) else { return Ok(None); @@ -126,7 +94,7 @@ impl AppState { http.file_patch( chunk.get_patch_uri(), - &self.alias_id, + self.inner.alias_id(), chunk.get_offset(), chunk.get_data(), )?; @@ -142,16 +110,17 @@ impl AppState { bar.finish(); self.progress = None; - let endpoint = self - .uri - .endpoint(format!("alias/mail/notify/{}", self.share_id)); - http.share_notify(&endpoint, &self.alias_id).unwrap(); // HACK unwrap + self.inner.share_notify(http).unwrap(); // HACK unwrap Ok(self.inner.has_file().then_some(())) } } } + pub fn file_names(&self) -> Vec<&str> { + self.inner.file_names() + } + pub fn save(&self) -> io::Result<()> { self.inner.save() } diff --git a/src/savedstate.rs b/src/cachefile.rs similarity index 54% rename from src/savedstate.rs rename to src/cachefile.rs index cb392c1..07bf647 100644 --- a/src/savedstate.rs +++ b/src/cachefile.rs @@ -2,13 +2,14 @@ use std::{ collections::VecDeque, fs, io::{self, Write}, - path::{Path, PathBuf}, + path::PathBuf, }; use log::trace; use serde::{Deserialize, Serialize}; use super::{ + cli::Cli, file::{self, FileTrait}, sharry::{self, Client, Uri}, }; @@ -30,22 +31,18 @@ impl FileState { fn start_upload( self, http: &impl Client, - uri: &Uri, + endpoint: &str, 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::C(checked) => checked.start_upload(http, endpoint, alias_id), FileState::U(uploading) => Ok(uploading), } } } #[derive(Serialize, Deserialize, Debug)] -pub struct SavedState { +pub struct CacheFile { #[serde(skip)] file_name: PathBuf, @@ -55,35 +52,47 @@ pub struct SavedState { files: VecDeque, } -impl SavedState { - pub fn new( - file_name: PathBuf, - uri: Uri, - alias_id: String, - share_id: String, - files: &Vec, - ) -> Self { +impl CacheFile { + fn cache_dir() -> PathBuf { + let dir_name = dirs_next::cache_dir() + .expect("could not determine cache directory") + .join("shrupl"); + + trace!("cachedir: {:?}", dir_name.display()); + dir_name + } + + fn cache_file(args: &Cli) -> PathBuf { + let file_name = Self::cache_dir().join(format!("{}.json", args.get_hash())); + + trace!("cachefile: {:?}", file_name.display()); + file_name + } + + pub fn try_resume(args: &Cli) -> io::Result { + let file_name = Self::cache_file(args); + + let state: Self = { + let file = fs::File::open(&file_name)?; + let reader = io::BufReader::new(file); + serde_json::from_reader(reader).map_err(io::Error::other)? + }; + + Ok(Self { file_name, ..state }) + } + + pub fn from_args(args: &Cli, share_id: String) -> Self { Self { - file_name, - uri, - alias_id, + file_name: Self::cache_file(&args), + uri: args.get_uri(), + alias_id: args.alias.clone(), share_id, - files: files.clone().into_iter().map(FileState::C).collect(), + files: args.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 alias_id(&self) -> &str { + &self.alias_id } pub fn file_names(&self) -> Vec<&str> { @@ -96,11 +105,10 @@ impl SavedState { 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 + let endpoint = self + .uri + .endpoint(format!("alias/upload/{}/files/tus", self.share_id)); + Some(state.start_upload(http, &endpoint, &self.alias_id).unwrap()) // HACK unwrap } else { None } @@ -110,6 +118,14 @@ impl SavedState { self.files.push_front(FileState::U(file)); } + pub fn share_notify(&self, http: &impl Client) -> sharry::Result<()> { + let endpoint = self + .uri + .endpoint(format!("alias/mail/notify/{}", self.share_id)); + + http.share_notify(&endpoint, &self.alias_id) + } + 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())) diff --git a/src/main.rs b/src/main.rs index 7b5e8a5..8db94fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod appstate; +mod cachefile; mod cli; mod file; -mod savedstate; mod sharry; use std::{