Browse Source

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.
Cesar Rodas 2 months ago
parent
commit
c40d68b262

+ 1 - 0
.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,

+ 16 - 0
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"] }

+ 59 - 0
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<Self, Self::Err> {
+        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<P: Into<PathBuf>>(
+        self,
+        work_dir: P,
+    ) -> Result<
+        Arc<
+            dyn cdk_common::database::MintDatabase<Err = cdk_common::database::Error>
+                + 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)?))
+            }
+        }
+    }
+}

+ 1 - 6
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 }

+ 1 - 20
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<Self, Self::Err> {
-        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,

+ 8 - 7
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<Self> {
+    pub fn from_env(mut self) -> Result<Self> {
         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)
     }
 }
 

+ 3 - 21
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<dyn MintDatabase<Err = cdk_database::Error> + 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);