use crate::{
MdbxColdBackend, MdbxColdError,
backend::{DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT},
};
use signet_cold::ColdConnect;
use signet_hot::HotConnect;
use signet_hot_mdbx::{DatabaseArguments, DatabaseEnv, MdbxError};
use std::{path::PathBuf, time::Duration};
#[derive(Debug, thiserror::Error)]
pub enum MdbxConnectorError {
#[error("missing environment variable: {0}")]
MissingEnvVar(&'static str),
#[error("hot storage initialization failed: {0}")]
HotInit(#[from] MdbxError),
#[error("cold storage initialization failed: {0}")]
ColdInit(#[from] MdbxColdError),
}
#[derive(Debug, Clone)]
pub struct MdbxConnector {
path: PathBuf,
db_args: DatabaseArguments,
read_timeout: Duration,
write_timeout: Duration,
}
impl MdbxConnector {
pub fn new(path: impl Into<PathBuf>) -> Self {
Self {
path: path.into(),
db_args: DatabaseArguments::new(),
read_timeout: DEFAULT_READ_TIMEOUT,
write_timeout: DEFAULT_WRITE_TIMEOUT,
}
}
#[must_use]
pub const fn with_db_args(mut self, db_args: DatabaseArguments) -> Self {
self.db_args = db_args;
self
}
#[must_use]
pub fn with_read_timeout(mut self, read_timeout: Duration) -> Self {
assert!(!read_timeout.is_zero(), "read_timeout must be non-zero");
self.read_timeout = read_timeout;
self
}
#[must_use]
pub fn with_write_timeout(mut self, write_timeout: Duration) -> Self {
assert!(!write_timeout.is_zero(), "write_timeout must be non-zero");
self.write_timeout = write_timeout;
self
}
pub fn path(&self) -> &std::path::Path {
&self.path
}
pub const fn db_args(&self) -> &DatabaseArguments {
&self.db_args
}
pub fn from_env(env_var: &'static str) -> Result<Self, MdbxConnectorError> {
let path: PathBuf =
std::env::var(env_var).map_err(|_| MdbxConnectorError::MissingEnvVar(env_var))?.into();
Ok(Self::new(path))
}
}
impl HotConnect for MdbxConnector {
type Hot = DatabaseEnv;
type Error = MdbxError;
fn connect(&self) -> Result<Self::Hot, Self::Error> {
self.db_args.clone().open_rw(&self.path)
}
}
impl ColdConnect for MdbxConnector {
type Cold = MdbxColdBackend;
type Error = MdbxColdError;
#[allow(clippy::manual_async_fn)]
fn connect(&self) -> impl std::future::Future<Output = Result<Self::Cold, Self::Error>> + Send {
let path = self.path.clone();
let read_timeout = self.read_timeout;
let write_timeout = self.write_timeout;
async move {
MdbxColdBackend::open_rw(&path)
.map(|b| b.with_read_timeout(read_timeout).with_write_timeout(write_timeout))
}
}
}