diff options
Diffstat (limited to 'src/storage.rs')
| -rw-r--r-- | src/storage.rs | 106 |
1 files changed, 94 insertions, 12 deletions
diff --git a/src/storage.rs b/src/storage.rs index 90abf05..c099481 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,41 +1,123 @@ +use std::{ + path::PathBuf, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, +}; + use etcetera::{AppStrategy, AppStrategyArgs, app_strategy::Xdg}; use smol::unblock; pub struct StorageManager { xdg: Xdg, + config: Option<Box<[u8]>>, data: Option<Box<[u8]>>, + saving_config: Arc<AtomicBool>, + saving_data: Arc<AtomicBool>, + saving_config_failed: Arc<AtomicBool>, + saving_data_failed: Arc<AtomicBool>, } impl StorageManager { pub fn load(app: AppStrategyArgs) -> std::io::Result<Self> { let xdg = etcetera::choose_app_strategy(app).map_err(std::io::Error::other)?; + let config = std::fs::read(xdg.in_config_dir("config")) + .or_else(|_| std::fs::read(xdg.in_config_dir("config.tmp"))) + .map(|config| config.into_boxed_slice()) + .ok(); let data = std::fs::read(xdg.in_data_dir("save")) .or_else(|_| std::fs::read(xdg.in_data_dir("save.tmp"))) .map(|data| data.into_boxed_slice()) .ok(); - Ok(Self { data, xdg }) + Ok(Self { + xdg, + config, + data, + saving_config: Arc::new(AtomicBool::new(false)), + saving_data: Arc::new(AtomicBool::new(false)), + saving_config_failed: Arc::new(AtomicBool::new(false)), + saving_data_failed: Arc::new(AtomicBool::new(false)), + }) + } + + pub fn config(&self) -> Option<&[u8]> { + self.config.as_deref() } - pub fn get(&self) -> Option<&[u8]> { + pub fn data(&self) -> Option<&[u8]> { self.data.as_deref() } - pub fn background_save(&mut self, data: Box<[u8]>) { - let tmp_file = self.xdg.in_data_dir("save.tmp"); - let save_file = self.xdg.in_data_dir("save"); + pub fn is_saving_config(&self) -> bool { + self.saving_config.load(Ordering::Acquire) + } + + pub fn is_saving_data(&self) -> bool { + self.saving_data.load(Ordering::Acquire) + } + + pub fn saving_config_failed(&self) -> bool { + self.saving_config_failed.load(Ordering::Acquire) + } + + pub fn saving_data_failed(&self) -> bool { + self.saving_data_failed.load(Ordering::Acquire) + } + + fn background_save( + &mut self, + file: PathBuf, + data: Box<[u8]>, + state: Arc<AtomicBool>, + failed: Arc<AtomicBool>, + ) { + let tmp_file = file.with_added_extension("tmp"); self.data = Some(data.clone()); unblock(move || { - std::fs::write(&tmp_file, &data)?; + if let Err(e) = { + std::fs::write(&tmp_file, &data)?; - let saved_data = std::fs::read(&tmp_file)?; - if *saved_data != *data { - return Err(std::io::Error::other("Failed to verify file integrity")); + let saved_data = std::fs::read(&tmp_file)?; + if *saved_data != *data { + return Err(std::io::Error::other("Failed to verify file integrity")); + } + + std::fs::rename(tmp_file, &file)?; + state.store(false, Ordering::Release); + Ok(()) + } { + log::error!("{e}"); + failed.store(true, Ordering::Release); + Err(e) + } else { + Ok(()) } + }) + .detach(); + } + + pub fn background_save_config(&mut self, data: Box<[u8]>) { + self.saving_config_failed.store(false, Ordering::Release); + self.saving_config.store(true, Ordering::Release); + self.background_save( + self.xdg.in_data_dir("config"), + data, + self.saving_config.clone(), + self.saving_config_failed.clone(), + ) + } - std::fs::rename(tmp_file, save_file)?; - Ok(()) - }); + pub fn background_save_data(&mut self, data: Box<[u8]>) { + self.saving_data_failed.store(false, Ordering::Release); + self.saving_data.store(true, Ordering::Release); + self.background_save( + self.xdg.in_data_dir("save"), + data, + self.saving_data.clone(), + self.saving_config_failed.clone(), + ) } } |
