6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 1 | use std::{fs, io, path::PathBuf}; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 2 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 3 | use serde::{Serialize, de::DeserializeOwned}; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 4 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 5 | use crate::{client::Flock, paths}; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 6 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 7 | fn path(name: &str) -> PathBuf { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 8 | paths::state_dir().join(format!("{name}.json")) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 9 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 10 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 11 | pub fn load<T: DeserializeOwned + Default>(name: &str) -> T { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 12 | fs::read(path(name)) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 13 | .ok() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 14 | .and_then(|b| serde_json::from_slice(&b).ok()) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 15 | .unwrap_or_default() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 16 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 17 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 18 | /// readers skip the lock, the rename keeps them from seeing half a file |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 19 | pub fn update<T, R>(name: &str, f: impl FnOnce(&mut T) -> R) -> io::Result<R> |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 20 | where |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 21 | T: Serialize + DeserializeOwned + Default, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 22 | { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 23 | let lock = fs::OpenOptions::new() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 24 | .create(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 25 | .truncate(false) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 26 | .write(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 27 | .open(paths::state_dir().join(format!("{name}.lock")))?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 28 | let _guard = Flock::exclusive(lock)?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 29 | let mut value = load(name); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 30 | let out = f(&mut value); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 31 | let tmp = path(&format!("{name}.tmp")); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 32 | fs::write(&tmp, serde_json::to_vec(&value)?)?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 33 | fs::rename(tmp, path(name))?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 34 | Ok(out) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 35 | } |