This commit is contained in:
hulthe committed 2022-10-09 22:12:45 +02:00
1 parent 4273640cd3
commit 1f05c6dc3d
6 files changed
+446 -233

No files matched your search

+111
View File
@@ -0,0 +1,111 @@
use std::io;
use std::path::PathBuf;
use std::sync::Arc;
use serde::{de::DeserializeOwned, Serialize};
use tokio::{
fs::{self, File},
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
};
#[derive(Clone)]
pub struct Persistence {
state: Arc<PersistenceState>,
}
pub struct PersistenceFile<S> {
content: S,
file: Option<File>,
}
enum PersistenceState {
NoPersistence,
Persistence { directory: PathBuf },
}
impl Persistence {
pub async fn new() -> Persistence {
Persistence {
state: Arc::new(PersistenceState::NoPersistence),
}
}
pub async fn new_persistence(directory: PathBuf) -> io::Result<Persistence> {
let _ = fs::read_dir(&directory).await?;
Ok(Persistence {
state: Arc::new(PersistenceState::Persistence { directory }),
})
}
pub async fn open<S: Default + Serialize + DeserializeOwned>(
&self,
name: String,
) -> Result<PersistenceFile<S>, io::Error> {
Ok(match &*self.state {
PersistenceState::NoPersistence => PersistenceFile {
content: S::default(),
file: None,
},
PersistenceState::Persistence { directory } => {
let file_path = directory.join(&name);
let mut file = fs::OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(file_path)
.await?;
let mut content = String::new();
file.read_to_string(&mut content).await?;
let content = ron::from_str(&content).unwrap_or_else(|_| {
info!("Failed to load persistence {name}, using default");
S::default()
});
PersistenceFile {
content,
file: Some(file),
}
}
})
}
}
impl<S> PersistenceFile<S>
where
S: Serialize,
{
pub fn get(&self) -> &S {
&self.content
}
pub async fn set(&mut self, s: S) -> anyhow::Result<()> {
self.content = s;
if let Some(file) = &mut self.file {
let serialized = ron::ser::to_string_pretty(&self.content, Default::default())?;
file.rewind().await?;
file.set_len(0).await?;
file.write_all(serialized.as_bytes()).await?;
}
Ok(())
}
pub async fn update(&mut self, f: impl FnOnce(&mut S)) -> anyhow::Result<()>
where
S: Clone + PartialEq,
{
let mut new = self.content.clone();
f(&mut new);
if new != self.content {
self.set(new).await?;
}
Ok(())
}
}