shrupl/src/appstate.rs

139 lines
3.7 KiB
Rust
Raw Normal View History

2025-06-02 23:57:17 +00:00
use std::{
2025-06-05 01:13:54 +00:00
collections::VecDeque,
2025-06-02 23:57:17 +00:00
fs,
io::{self, Write},
path::{Path, PathBuf},
2025-06-02 23:57:17 +00:00
};
2025-06-05 01:44:39 +00:00
use log::{debug, trace};
2025-06-02 23:57:17 +00:00
use serde::{Deserialize, Serialize};
use super::{
cli::Cli,
2025-06-05 01:13:54 +00:00
sharry::{Alias, ChunkState, FileChecked, FileUploading, Share, UploadError},
2025-06-02 23:57:17 +00:00
};
#[derive(Serialize, Deserialize, Debug)]
pub struct AppState {
2025-06-04 21:02:35 +00:00
#[serde(skip)]
file_name: PathBuf,
2025-06-02 23:57:17 +00:00
alias: Alias,
share: Share,
2025-06-05 01:13:54 +00:00
files: VecDeque<FileState>,
}
2025-06-04 21:02:35 +00:00
#[derive(Serialize, Deserialize, Debug)]
enum FileState {
C(FileChecked),
U(FileUploading),
2025-06-02 23:57:17 +00:00
}
impl AppState {
2025-06-04 21:23:21 +00:00
fn cache_dir() -> PathBuf {
let dir_name = dirs_next::cache_dir()
.expect("could not determine cache directory")
.join("shrupl");
2025-06-04 21:02:35 +00:00
2025-06-05 01:45:25 +00:00
trace!("cachedir: {:?}", dir_name.display());
2025-06-04 21:23:21 +00:00
dir_name
2025-06-04 21:02:35 +00:00
}
2025-06-04 21:23:21 +00:00
fn cache_file(args: &Cli) -> PathBuf {
let file_name = Self::cache_dir().join(format!("{}.json", args.get_hash()));
2025-06-04 21:02:35 +00:00
2025-06-05 01:45:25 +00:00
trace!("cachefile: {:?}", file_name.display());
2025-06-04 21:23:21 +00:00
file_name
2025-06-04 21:02:35 +00:00
}
2025-06-02 23:57:17 +00:00
fn load(file_name: impl AsRef<Path>) -> io::Result<Self> {
let content = fs::read_to_string(file_name)?;
serde_json::from_str(&content).map_err(io::Error::other)
2025-06-02 23:57:17 +00:00
}
2025-06-04 21:02:35 +00:00
pub fn try_resume(args: &Cli) -> Option<Self> {
2025-06-04 21:23:21 +00:00
let file_name = Self::cache_file(args);
2025-06-04 21:02:35 +00:00
Self::load(&file_name)
2025-06-05 01:45:25 +00:00
.inspect_err(|e| debug!("could not resume from {:?}: {e}", file_name.display()))
2025-06-04 21:02:35 +00:00
.map(|state| {
debug!("successfully loaded AppState");
Self {
file_name,
alias: state.alias,
share: state.share,
files: state.files,
}
})
.ok()
}
pub fn from_args(args: &Cli, http: &ureq::Agent) -> Result<Self, ureq::Error> {
2025-06-04 21:23:21 +00:00
let file_name = Self::cache_file(args);
2025-06-04 21:02:35 +00:00
let alias = args.get_alias();
let share = Share::create(http, &alias, args.get_share_request())?;
2025-06-04 21:02:35 +00:00
2025-06-05 01:13:54 +00:00
let files: VecDeque<_> = args.files.clone().into_iter().map(FileState::C).collect();
2025-06-04 21:02:35 +00:00
2025-06-05 01:55:30 +00:00
Ok(Self {
2025-06-04 21:02:35 +00:00
file_name,
alias,
share,
files,
})
}
2025-06-05 01:13:54 +00:00
pub fn upload_chunk(
&mut self,
http: &ureq::Agent,
chunk_size: usize,
) -> Result<Option<()>, UploadError> {
let uploading = match self.files.pop_front() {
Some(FileState::C(checked)) => checked
.start_upload(http, &self.alias, &self.share)
.unwrap(),
Some(FileState::U(uploading)) => uploading,
2025-06-05 11:20:27 +00:00
None => return Ok(None),
2025-06-05 01:13:54 +00:00
};
debug!("{uploading} chunk {chunk_size}");
match uploading.upload_chunk(http, &self.alias, chunk_size) {
ChunkState::Ok(upl) => {
self.files.push_front(FileState::U(upl));
Ok(Some(()))
}
ChunkState::Err(upl, e) => {
self.files.push_front(FileState::U(upl));
Err(e)
}
ChunkState::Finished(path) => {
debug!("Finished {:?}!", path.display());
2025-06-05 11:20:27 +00:00
self.share.notify(http, &self.alias).unwrap();
Ok(self.files.front().map(drop))
2025-06-05 01:13:54 +00:00
}
}
}
2025-06-04 21:02:35 +00:00
pub fn save(&self) -> io::Result<()> {
2025-06-04 21:23:21 +00:00
fs::create_dir_all(Self::cache_dir())?;
2025-06-04 21:02:35 +00:00
2025-06-02 23:57:17 +00:00
let json = serde_json::to_string_pretty(self).map_err(io::Error::other)?;
2025-06-04 21:02:35 +00:00
let mut file = fs::File::create(&self.file_name)?;
2025-06-02 23:57:17 +00:00
file.write_all(json.as_bytes())?;
2025-06-05 11:20:27 +00:00
trace!("updated {:?}", self.file_name.display());
2025-06-02 23:57:17 +00:00
Ok(())
}
2025-06-04 21:23:21 +00:00
pub fn clear(self) -> io::Result<()> {
2025-06-05 11:20:27 +00:00
fs::remove_file(&self.file_name)?;
2025-06-02 23:57:17 +00:00
2025-06-05 11:20:27 +00:00
trace!("removed {:?}", self.file_name.display());
2025-06-04 21:02:35 +00:00
Ok(())
2025-06-02 23:57:17 +00:00
}
}