From c40d68b26206136bca18d65291b62f727e3e2542 Mon Sep 17 00:00:00 2001 From: Cesar Rodas Date: Mon, 20 Jan 2025 23:06:05 -0500 Subject: [PATCH] Introduce `cdk-database` This is a crate that makes it easier to create a database instance based on an enum that can be constructed from a CLI or an env variable. --- .github/workflows/ci.yml | 1 + crates/cdk-database/Cargo.toml | 16 +++++++++ crates/cdk-database/src/lib.rs | 59 ++++++++++++++++++++++++++++++++ crates/cdk-mintd/Cargo.toml | 7 +--- crates/cdk-mintd/src/config.rs | 21 +----------- crates/cdk-mintd/src/env_vars.rs | 15 ++++---- crates/cdk-mintd/src/main.rs | 24 ++----------- 7 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 crates/cdk-database/Cargo.toml create mode 100644 crates/cdk-database/src/lib.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ae7e9401..2a8d8395e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,7 @@ jobs: -p cdk --no-default-features --features mint, -p cdk --no-default-features --features "mint swagger", -p cdk-redb, + -p cdk-database, -p cdk-sqlite, -p cdk-axum --no-default-features, -p cdk-axum --no-default-features --features swagger, diff --git a/crates/cdk-database/Cargo.toml b/crates/cdk-database/Cargo.toml new file mode 100644 index 000000000..c76862f77 --- /dev/null +++ b/crates/cdk-database/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "cdk-database" +version = "0.6.1" +edition = "2021" +description = "CDK database engine selection crate" + +[features] +mint = ["cdk-sqlite/mint", "cdk-redb/mint"] +wallet = ["cdk-sqlite/wallet", "cdk-redb/wallet"] +default = ["mint", "wallet"] + +[dependencies] +cdk-common = { path = "../cdk-common" } +cdk-sqlite = { path = "../cdk-sqlite", default-features = false } +cdk-redb = { path = "../cdk-redb", default-features = false } +serde = { version = "1.0.217", features = ["derive"] } diff --git a/crates/cdk-database/src/lib.rs b/crates/cdk-database/src/lib.rs new file mode 100644 index 000000000..1c18e3670 --- /dev/null +++ b/crates/cdk-database/src/lib.rs @@ -0,0 +1,59 @@ +//! CDK-Database instance +//! +//! This crate will create a database instance based on the provided engine. +use std::path::PathBuf; +use std::sync::Arc; + +use cdk_redb::MintRedbDatabase; +use cdk_sqlite::MintSqliteDatabase; +use serde::{Deserialize, Serialize}; + +/// Database engine definition +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] +#[serde(rename_all = "lowercase")] +pub enum DatabaseEngine { + #[default] + Sqlite, + Redb, +} + +impl std::str::FromStr for DatabaseEngine { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "sqlite" => Ok(DatabaseEngine::Sqlite), + "redb" => Ok(DatabaseEngine::Redb), + _ => Err(format!("Unknown database engine: {}", s)), + } + } +} + +impl DatabaseEngine { + /// Convert the database instance into a mint database + pub async fn mint>( + self, + work_dir: P, + ) -> Result< + Arc< + dyn cdk_common::database::MintDatabase + + Sync + + Send + + 'static, + >, + cdk_common::database::Error, + > { + match self { + DatabaseEngine::Sqlite => { + let sql_db_path = work_dir.into().join("cdk-mintd.sqlite"); + let db = MintSqliteDatabase::new(&sql_db_path).await?; + db.migrate().await; + Ok(Arc::new(db)) + } + DatabaseEngine::Redb => { + let redb_path = work_dir.into().join("cdk-mintd.redb"); + Ok(Arc::new(MintRedbDatabase::new(&redb_path)?)) + } + } + } +} diff --git a/crates/cdk-mintd/Cargo.toml b/crates/cdk-mintd/Cargo.toml index dea4905a6..ac192fcbb 100644 --- a/crates/cdk-mintd/Cargo.toml +++ b/crates/cdk-mintd/Cargo.toml @@ -15,14 +15,9 @@ axum = "0.6.20" cdk = { path = "../cdk", version = "0.6.0", default-features = false, features = [ "mint", ] } -cdk-redb = { path = "../cdk-redb", version = "0.6.0", default-features = false, features = [ - "mint", -] } -cdk-sqlite = { path = "../cdk-sqlite", version = "0.6.0", default-features = false, features = [ - "mint", -] } cdk-cln = { path = "../cdk-cln", version = "0.6.0", default-features = false } cdk-lnbits = { path = "../cdk-lnbits", version = "0.6.0", default-features = false } +cdk-database = { path = "../cdk-database" } cdk-phoenixd = { path = "../cdk-phoenixd", version = "0.6.0", default-features = false } cdk-lnd = { path = "../cdk-lnd", version = "0.6.0", default-features = false } cdk-fake-wallet = { path = "../cdk-fake-wallet", version = "0.6.0", default-features = false } diff --git a/crates/cdk-mintd/src/config.rs b/crates/cdk-mintd/src/config.rs index df46c279b..3e17fd26c 100644 --- a/crates/cdk-mintd/src/config.rs +++ b/crates/cdk-mintd/src/config.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use cdk::nuts::{CurrencyUnit, PublicKey}; use cdk::Amount; use cdk_axum::cache; +use cdk_database::DatabaseEngine; use config::{Config, ConfigError, File}; use serde::{Deserialize, Serialize}; @@ -149,26 +150,6 @@ fn default_max_delay_time() -> u64 { 3 } -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] -#[serde(rename_all = "lowercase")] -pub enum DatabaseEngine { - #[default] - Sqlite, - Redb, -} - -impl std::str::FromStr for DatabaseEngine { - type Err = String; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "sqlite" => Ok(DatabaseEngine::Sqlite), - "redb" => Ok(DatabaseEngine::Redb), - _ => Err(format!("Unknown database engine: {}", s)), - } - } -} - #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Database { pub engine: DatabaseEngine, diff --git a/crates/cdk-mintd/src/env_vars.rs b/crates/cdk-mintd/src/env_vars.rs index 27b815b01..67e31e699 100644 --- a/crates/cdk-mintd/src/env_vars.rs +++ b/crates/cdk-mintd/src/env_vars.rs @@ -4,10 +4,11 @@ use std::str::FromStr; use anyhow::{anyhow, bail, Result}; use cdk::nuts::CurrencyUnit; +use cdk_database::DatabaseEngine; use crate::config::{ - Cln, Database, DatabaseEngine, FakeWallet, Info, LNbits, Ln, LnBackend, Lnd, MintInfo, - Phoenixd, Settings, Strike, + Cln, Database, FakeWallet, Info, LNbits, Ln, LnBackend, Lnd, MintInfo, Phoenixd, Settings, + Strike, }; pub const ENV_WORK_DIR: &str = "CDK_MINTD_WORK_DIR"; @@ -72,15 +73,15 @@ pub const ENV_FAKE_WALLET_MIN_DELAY: &str = "CDK_MINTD_FAKE_WALLET_MIN_DELAY"; pub const ENV_FAKE_WALLET_MAX_DELAY: &str = "CDK_MINTD_FAKE_WALLET_MAX_DELAY"; impl Settings { - pub fn from_env(&mut self) -> Result { + pub fn from_env(mut self) -> Result { if let Ok(database) = env::var(DATABASE_ENV_VAR) { let engine = DatabaseEngine::from_str(&database).map_err(|err| anyhow!(err))?; self.database = Database { engine }; } - self.info = self.info.clone().from_env(); - self.mint_info = self.mint_info.clone().from_env(); - self.ln = self.ln.clone().from_env(); + self.info = self.info.from_env(); + self.mint_info = self.mint_info.from_env(); + self.ln = self.ln.from_env(); match self.ln.ln_backend { LnBackend::Cln => { @@ -104,7 +105,7 @@ impl Settings { LnBackend::None => bail!("Ln backend must be set"), } - Ok(self.clone()) + Ok(self) } } diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index ca2d3f7df..c9ea2e876 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -15,7 +15,6 @@ use axum::middleware::Next; use axum::response::Response; use axum::{middleware, Router}; use bip39::Mnemonic; -use cdk::cdk_database::{self, MintDatabase}; use cdk::cdk_lightning; use cdk::cdk_lightning::MintLightning; use cdk::mint::{MintBuilder, MintMeltLimits}; @@ -25,11 +24,9 @@ use cdk::nuts::{ContactInfo, CurrencyUnit, MintVersion, PaymentMethod}; use cdk::types::LnKey; use cdk_axum::cache::HttpCache; use cdk_mintd::cli::CLIArgs; -use cdk_mintd::config::{self, DatabaseEngine, LnBackend}; +use cdk_mintd::config::{self, LnBackend}; use cdk_mintd::env_vars::ENV_WORK_DIR; use cdk_mintd::setup::LnBackendSetup; -use cdk_redb::MintRedbDatabase; -use cdk_sqlite::MintSqliteDatabase; use clap::Parser; use tokio::sync::Notify; use tower_http::compression::CompressionLayer; @@ -76,7 +73,7 @@ async fn main() -> anyhow::Result<()> { let mut mint_builder = MintBuilder::new(); - let mut settings = if config_file_arg.exists() { + let settings = if config_file_arg.exists() { config::Settings::new(Some(config_file_arg)) } else { tracing::info!("Config file does not exist. Attempting to read env vars"); @@ -86,22 +83,7 @@ async fn main() -> anyhow::Result<()> { // This check for any settings defined in ENV VARs // ENV VARS will take **priority** over those in the config let settings = settings.from_env()?; - - let localstore: Arc + Send + Sync> = - match settings.database.engine { - DatabaseEngine::Sqlite => { - let sql_db_path = work_dir.join("cdk-mintd.sqlite"); - let sqlite_db = MintSqliteDatabase::new(&sql_db_path).await?; - - sqlite_db.migrate().await; - - Arc::new(sqlite_db) - } - DatabaseEngine::Redb => { - let redb_path = work_dir.join("cdk-mintd.redb"); - Arc::new(MintRedbDatabase::new(&redb_path)?) - } - }; + let localstore = settings.database.engine.clone().mint(&work_dir).await?; mint_builder = mint_builder.with_localstore(localstore);