1pub use gl_client::persist::State;
4use log::debug;
5use thiserror::Error;
6use tonic::async_trait;
7
8#[derive(Debug, Error)]
9pub enum Error {
10 #[error("database error: {0}")]
12 Sled(#[from] ::sled::Error),
13 #[error("state corruption: {0}")]
14 CorruptState(#[from] serde_json::Error),
15 #[error("unhandled error: {0}")]
16 Other(Box<dyn std::error::Error + Send + Sync>),
17}
18
19#[async_trait]
20pub trait StateStore: Send + Sync {
21 async fn write(&self, state: State) -> Result<(), Error>;
22 async fn read(&self) -> Result<State, Error>;
23}
24
25pub struct SledStateStore {
27 db: sled::Db,
28}
29
30impl SledStateStore {
31 pub fn new(path: std::path::PathBuf) -> Result<SledStateStore, sled::Error> {
32 let db = sled::open(path)?;
33 Ok(Self { db })
34 }
35}
36
37use sled::transaction::TransactionError;
38impl From<TransactionError<Error>> for Error {
39 fn from(e: TransactionError<Error>) -> Self {
40 match e {
41 TransactionError::Abort(e) => e,
42 TransactionError::Storage(e) => Error::Sled(e),
43 }
44 }
45}
46
47const SLED_KEY: &str = "signer_state";
48
49#[async_trait]
50impl StateStore for SledStateStore {
51 async fn read(&self) -> Result<State, Error> {
52 match self.db.get(SLED_KEY)? {
53 None => {
54 debug!("Initializing a new signer state");
55 Ok(State::new())
56 }
57 Some(v) => Ok(serde_json::from_slice(&v)?),
58 }
59 }
60
61 async fn write(&self, state: State) -> Result<(), Error> {
62 let raw = serde_json::to_vec(&state)?;
63 self.db
64 .insert(SLED_KEY, raw)
65 .map(|_v| ())
66 .map_err(|e| e.into())
67 }
68}