summaryrefslogtreecommitdiff
path: root/src/storage.rs
blob: 90abf059f9a424a02467eb75d2e6a758619d065b (plain)
use etcetera::{AppStrategy, AppStrategyArgs, app_strategy::Xdg};
use smol::unblock;

pub struct StorageManager {
	xdg: Xdg,
	data: Option<Box<[u8]>>,
}

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 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 })
	}

	pub fn get(&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");

		self.data = Some(data.clone());
		unblock(move || {
			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"));
			}

			std::fs::rename(tmp_file, save_file)?;
			Ok(())
		});
	}
}