gl_plugin/
storage.rs

1//! A backend to store the signer state in.
2
3pub use gl_client::persist::State;
4use log::debug;
5use thiserror::Error;
6use tonic::async_trait;
7
8#[derive(Debug, Error)]
9pub enum Error {
10    /// underlying database error
11    #[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
25/// A StateStore that uses `sled` as its storage backend
26pub 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}