summaryrefslogtreecommitdiff
path: root/src/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/storage.rs')
-rw-r--r--src/storage.rs106
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(),
+ )
}
}