asimov_server/
persistence.rs

1// This is free and unencumbered software released into the public domain.
2
3use serde::{Deserialize, Serialize};
4use std::{
5    path::PathBuf,
6    sync::{Arc, LazyLock, RwLock},
7};
8use thiserror::Error;
9
10#[derive(Debug, Error)]
11pub enum Error {
12    #[error("failed to read or write")]
13    IoError(#[from] std::io::Error),
14    #[error("failed to serialize or deserialize")]
15    SerdeError(#[from] serde_json::Error),
16}
17pub type Result<T> = std::result::Result<T, Error>;
18
19static STATE: LazyLock<Arc<RwLock<PersistentState>>> =
20    LazyLock::new(|| Arc::new(RwLock::new(read().unwrap_or_default())));
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23#[serde(default)]
24pub struct PersistentState {
25    pub provider: String,
26}
27
28impl Default for PersistentState {
29    fn default() -> Self {
30        Self {
31            provider: "asimov-default-provider".into(),
32        }
33    }
34}
35
36/// Get the path to persistence file.
37fn get_file_path() -> Result<PathBuf> {
38    let current_dir = std::env::current_exe()?;
39    Ok(current_dir.with_file_name("persistence.json"))
40}
41
42/// Read the persistent state from the file.
43fn read() -> Result<PersistentState> {
44    let path = get_file_path()?;
45    let file = std::fs::File::open(path)?;
46    let reader = std::io::BufReader::new(file);
47    Ok(serde_json::from_reader(reader)?)
48}
49
50/// Write the persistent state to the file.
51fn write(state: &PersistentState) -> Result<()> {
52    let path = get_file_path()?;
53    let file = std::fs::File::create(path)?;
54    let writer = std::io::BufWriter::new(file);
55    serde_json::to_writer(writer, state)?;
56    Ok(())
57}
58
59/// Get the reference to persistent state.
60pub(crate) fn get_ref() -> Arc<RwLock<PersistentState>> {
61    STATE.clone()
62}
63
64/// Get the copy of current persistent state.
65pub fn get() -> PersistentState {
66    STATE.read().unwrap().clone()
67}
68
69/// Set the persistent state.
70///
71/// This method updates the persistent state
72/// and writes it to the file _immediately_!
73///
74/// This method is thread-safe.
75pub fn set<F>(x: F) -> Result<()>
76where
77    F: FnOnce(&mut PersistentState),
78{
79    let mut state = STATE.write().unwrap();
80    x(&mut state);
81    write(&state)
82}