Skip to main content

hinge_rs/
storage.rs

1use std::fs;
2use std::path::Path;
3
4pub trait Storage {
5    fn exists(&self, path: &str) -> bool;
6    fn read_to_string(&self, path: &str) -> anyhow::Result<String>;
7    fn write_string(&self, path: &str, data: &str) -> anyhow::Result<()>;
8}
9
10pub trait SecretStore: Send + Sync {
11    fn set_secret(&self, key: &str, secret: &str) -> anyhow::Result<()>;
12    fn get_secret(&self, key: &str) -> anyhow::Result<Option<String>>;
13}
14
15#[derive(Clone, Default)]
16pub struct FsStorage;
17
18impl Storage for FsStorage {
19    fn exists(&self, path: &str) -> bool {
20        Path::new(path).exists()
21    }
22    fn read_to_string(&self, path: &str) -> anyhow::Result<String> {
23        Ok(fs::read_to_string(path)?)
24    }
25    fn write_string(&self, path: &str, data: &str) -> anyhow::Result<()> {
26        if let Some(parent) = Path::new(path).parent()
27            && !parent.as_os_str().is_empty()
28        {
29            fs::create_dir_all(parent)?;
30        }
31        Ok(fs::write(path, data)?)
32    }
33}
34
35#[derive(Default)]
36pub struct InMemorySecretStore(std::sync::Mutex<std::collections::HashMap<String, String>>);
37
38impl InMemorySecretStore {
39    pub fn new() -> Self {
40        Self::default()
41    }
42}
43
44impl SecretStore for InMemorySecretStore {
45    fn set_secret(&self, key: &str, secret: &str) -> anyhow::Result<()> {
46        let mut g = self
47            .0
48            .lock()
49            .map_err(|e| anyhow::anyhow!("Lock poisoned: {}", e))?;
50        g.insert(key.to_string(), secret.to_string());
51        Ok(())
52    }
53    fn get_secret(&self, key: &str) -> anyhow::Result<Option<String>> {
54        let g = self
55            .0
56            .lock()
57            .map_err(|e| anyhow::anyhow!("Lock poisoned: {}", e))?;
58        Ok(g.get(key).cloned())
59    }
60}