diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c3b2379..a584fe01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,12 +122,20 @@ jobs: --bin cdk-mintd, --bin cdk-mintd --features redis, --bin cdk-mintd --features sqlcipher, - --bin cdk-mintd --no-default-features --features lnd, - --bin cdk-mintd --no-default-features --features cln, - --bin cdk-mintd --no-default-features --features lnbits, - --bin cdk-mintd --no-default-features --features fakewallet, - --bin cdk-mintd --no-default-features --features grpc-processor, - --bin cdk-mintd --no-default-features --features "management-rpc lnd", + --bin cdk-mintd --no-default-features --features lnd --features sqlite, + --bin cdk-mintd --no-default-features --features cln --features postgres, + --bin cdk-mintd --no-default-features --features lnbits --features sqlite, + --bin cdk-mintd --no-default-features --features fakewallet --features sqlite, + --bin cdk-mintd --no-default-features --features grpc-processor --features sqlite, + --bin cdk-mintd --no-default-features --features "management-rpc lnd sqlite", + --bin cdk-mintd --no-default-features --features cln --features sqlite, + --bin cdk-mintd --no-default-features --features lnd --features postgres, + --bin cdk-mintd --no-default-features --features lnbits --features postgres, + --bin cdk-mintd --no-default-features --features fakewallet --features postgres, + --bin cdk-mintd --no-default-features --features grpc-processor --features postgres, + --bin cdk-mintd --no-default-features --features "management-rpc cln postgres", + --bin cdk-mintd --no-default-features --features "auth sqlite fakewallet", + --bin cdk-mintd --no-default-features --features "auth postgres lnd", --bin cdk-mint-cli, ] steps: diff --git a/crates/cdk-integration-tests/Cargo.toml b/crates/cdk-integration-tests/Cargo.toml index 9de43f58..febe40ca 100644 --- a/crates/cdk-integration-tests/Cargo.toml +++ b/crates/cdk-integration-tests/Cargo.toml @@ -28,7 +28,7 @@ cdk-sqlite = { workspace = true } cdk-redb = { workspace = true } cdk-fake-wallet = { workspace = true } cdk-common = { workspace = true, features = ["mint", "wallet", "auth"] } -cdk-mintd = { workspace = true, features = ["cln", "lnd", "fakewallet", "grpc-processor", "auth", "lnbits", "management-rpc"] } +cdk-mintd = { workspace = true, features = ["cln", "lnd", "fakewallet", "grpc-processor", "auth", "lnbits", "management-rpc", "sqlite", "postgres"] } futures = { workspace = true, default-features = false, features = [ "executor", ] } diff --git a/crates/cdk-mintd/Cargo.toml b/crates/cdk-mintd/Cargo.toml index d9fb63f4..c55882d1 100644 --- a/crates/cdk-mintd/Cargo.toml +++ b/crates/cdk-mintd/Cargo.toml @@ -11,7 +11,10 @@ rust-version.workspace = true readme = "README.md" [features] -default = ["management-rpc", "cln", "lnd", "lnbits", "fakewallet", "grpc-processor", "auth"] +default = ["management-rpc", "cln", "lnd", "lnbits", "fakewallet", "grpc-processor", "sqlite"] +# Database features - at least one must be enabled +sqlite = ["dep:cdk-sqlite"] +postgres = ["dep:cdk-postgres"] # Ensure at least one lightning backend is enabled management-rpc = ["cdk-mint-rpc"] cln = ["dep:cdk-cln"] @@ -19,11 +22,11 @@ lnd = ["dep:cdk-lnd"] lnbits = ["dep:cdk-lnbits"] fakewallet = ["dep:cdk-fake-wallet"] grpc-processor = ["dep:cdk-payment-processor", "cdk-signatory/grpc"] -sqlcipher = ["cdk-sqlite/sqlcipher"] +sqlcipher = ["sqlite", "cdk-sqlite/sqlcipher"] # MSRV is not committed to with swagger enabled swagger = ["cdk-axum/swagger", "dep:utoipa", "dep:utoipa-swagger-ui"] redis = ["cdk-axum/redis"] -auth = ["cdk/auth", "cdk-sqlite/auth", "cdk-axum/auth"] +auth = ["cdk/auth", "cdk-axum/auth", "cdk-sqlite?/auth", "cdk-postgres?/auth"] [dependencies] anyhow.workspace = true @@ -33,9 +36,9 @@ cdk = { workspace = true, features = [ "mint", ] } cdk-sqlite = { workspace = true, features = [ - "mint", -] } -cdk-postgres = { workspace = true, features = ["mint"]} + "mint" +], optional = true } +cdk-postgres = { workspace = true, features = ["mint"], optional = true } cdk-cln = { workspace = true, optional = true } cdk-lnbits = { workspace = true, optional = true } cdk-lnd = { workspace = true, optional = true } diff --git a/crates/cdk-mintd/build.rs b/crates/cdk-mintd/build.rs new file mode 100644 index 00000000..3f833b77 --- /dev/null +++ b/crates/cdk-mintd/build.rs @@ -0,0 +1,29 @@ +fn main() { + // Check that at least one database feature is enabled + let has_database = cfg!(feature = "sqlite") || cfg!(feature = "postgres"); + + if !has_database { + panic!( + "cdk-mintd requires at least one database backend to be enabled.\n\ + Available database features: sqlite, postgres\n\ + Example: cargo build --features sqlite" + ); + } + + // Check that at least one Lightning backend is enabled + let has_lightning_backend = cfg!(feature = "cln") + || cfg!(feature = "lnd") + || cfg!(feature = "lnbits") + || cfg!(feature = "fakewallet") + || cfg!(feature = "grpc-processor"); + + if !has_lightning_backend { + panic!( + "cdk-mintd requires at least one Lightning backend to be enabled.\n\ + Available Lightning backends: cln, lnd, lnbits, fakewallet, grpc-processor\n\ + Example: cargo build --features \"sqlite fakewallet\"" + ); + } + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/crates/cdk-mintd/src/lib.rs b/crates/cdk-mintd/src/lib.rs index 05b6966c..78d0ea97 100644 --- a/crates/cdk-mintd/src/lib.rs +++ b/crates/cdk-mintd/src/lib.rs @@ -39,9 +39,11 @@ use cdk::nuts::{AuthRequired, Method, ProtectedEndpoint, RoutePath}; use cdk::nuts::{ContactInfo, MintVersion, PaymentMethod}; use cdk::types::QuoteTTL; use cdk_axum::cache::HttpCache; +#[cfg(feature = "postgres")] use cdk_postgres::{MintPgAuthDatabase, MintPgDatabase}; -#[cfg(feature = "auth")] +#[cfg(all(feature = "auth", feature = "sqlite"))] use cdk_sqlite::mint::MintSqliteAuthDatabase; +#[cfg(feature = "sqlite")] use cdk_sqlite::MintSqliteDatabase; use cli::CLIArgs; use config::{AuthType, DatabaseEngine, LnBackend}; @@ -243,19 +245,21 @@ pub fn load_settings(work_dir: &Path, config_path: Option) -> Result, + _work_dir: &Path, + _db_password: Option, ) -> Result<( Arc + Send + Sync>, Arc + Send + Sync>, )> { match settings.database.engine { + #[cfg(feature = "sqlite")] DatabaseEngine::Sqlite => { - let db = setup_sqlite_database(work_dir, db_password).await?; + let db = setup_sqlite_database(_work_dir, _db_password).await?; let localstore: Arc + Send + Sync> = db.clone(); let keystore: Arc + Send + Sync> = db; Ok((localstore, keystore)) } + #[cfg(feature = "postgres")] DatabaseEngine::Postgres => { // Get the PostgreSQL configuration, ensuring it exists let pg_config = settings.database.postgres.as_ref().ok_or_else(|| { @@ -266,16 +270,33 @@ async fn setup_database( bail!("PostgreSQL URL is required. Set it in config file [database.postgres] section or via CDK_MINTD_POSTGRES_URL/CDK_MINTD_DATABASE_URL environment variable"); } + #[cfg(feature = "postgres")] let pg_db = Arc::new(MintPgDatabase::new(pg_config.url.as_str()).await?); + #[cfg(feature = "postgres")] let localstore: Arc + Send + Sync> = pg_db.clone(); - let keystore: Arc + Send + Sync> = - pg_db; - Ok((localstore, keystore)) + #[cfg(feature = "postgres")] + let keystore: Arc< + dyn MintKeysDatabase + Send + Sync, + > = pg_db; + #[cfg(feature = "postgres")] + return Ok((localstore, keystore)); + + #[cfg(not(feature = "postgres"))] + bail!("PostgreSQL support not compiled in. Enable the 'postgres' feature to use PostgreSQL database.") + } + #[cfg(not(feature = "sqlite"))] + DatabaseEngine::Sqlite => { + bail!("SQLite support not compiled in. Enable the 'sqlite' feature to use SQLite database.") + } + #[cfg(not(feature = "postgres"))] + DatabaseEngine::Postgres => { + bail!("PostgreSQL support not compiled in. Enable the 'postgres' feature to use PostgreSQL database.") } } } +#[cfg(feature = "sqlite")] async fn setup_sqlite_database( work_dir: &Path, _password: Option, @@ -529,8 +550,17 @@ async fn configure_backend_for_unit( mint_builder.set_unit_fee(&unit, input_fee)?; } - let nut17_supported = SupportedMethods::default_bolt11(unit); - mint_builder = mint_builder.with_supported_websockets(nut17_supported); + #[cfg(any( + feature = "cln", + feature = "lnbits", + feature = "lnd", + feature = "fakewallet", + feature = "grpc-processor" + ))] + { + let nut17_supported = SupportedMethods::default_bolt11(unit); + mint_builder = mint_builder.with_supported_websockets(nut17_supported); + } Ok(mint_builder) } @@ -550,7 +580,7 @@ fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> Mi #[cfg(feature = "auth")] async fn setup_authentication( settings: &config::Settings, - work_dir: &Path, + _work_dir: &Path, mut mint_builder: MintBuilder, _password: Option, ) -> Result { @@ -559,29 +589,53 @@ async fn setup_authentication( let auth_localstore: Arc< dyn cdk_database::MintAuthDatabase + Send + Sync, > = match settings.database.engine { + #[cfg(feature = "sqlite")] DatabaseEngine::Sqlite => { - let sql_db_path = work_dir.join("cdk-mintd-auth.sqlite"); - #[cfg(not(feature = "sqlcipher"))] - let sqlite_db = MintSqliteAuthDatabase::new(&sql_db_path).await?; - #[cfg(feature = "sqlcipher")] - let sqlite_db = { - // Get password from command line arguments for sqlcipher - MintSqliteAuthDatabase::new((sql_db_path, _password.unwrap())).await? - }; + #[cfg(feature = "sqlite")] + { + let sql_db_path = _work_dir.join("cdk-mintd-auth.sqlite"); + #[cfg(not(feature = "sqlcipher"))] + let sqlite_db = MintSqliteAuthDatabase::new(&sql_db_path).await?; + #[cfg(feature = "sqlcipher")] + let sqlite_db = { + // Get password from command line arguments for sqlcipher + MintSqliteAuthDatabase::new((sql_db_path, _password.unwrap())).await? + }; - Arc::new(sqlite_db) - } - DatabaseEngine::Postgres => { - // Get the PostgreSQL configuration, ensuring it exists - let pg_config = settings.database.postgres.as_ref().ok_or_else(|| { - anyhow!("PostgreSQL configuration is required when using PostgreSQL engine") - })?; - - if pg_config.url.is_empty() { - bail!("PostgreSQL URL is required for auth database. Set it in config file [database.postgres] section or via CDK_MINTD_POSTGRES_URL/CDK_MINTD_DATABASE_URL environment variable"); + Arc::new(sqlite_db) } + #[cfg(not(feature = "sqlite"))] + { + bail!("SQLite support not compiled in. Enable the 'sqlite' feature to use SQLite database.") + } + } + #[cfg(feature = "postgres")] + DatabaseEngine::Postgres => { + #[cfg(feature = "postgres")] + { + // Get the PostgreSQL configuration, ensuring it exists + let pg_config = settings.database.postgres.as_ref().ok_or_else(|| { + anyhow!("PostgreSQL configuration is required when using PostgreSQL engine") + })?; - Arc::new(MintPgAuthDatabase::new(pg_config.url.as_str()).await?) + if pg_config.url.is_empty() { + bail!("PostgreSQL URL is required for auth database. Set it in config file [database.postgres] section or via CDK_MINTD_POSTGRES_URL/CDK_MINTD_DATABASE_URL environment variable"); + } + + Arc::new(MintPgAuthDatabase::new(pg_config.url.as_str()).await?) + } + #[cfg(not(feature = "postgres"))] + { + bail!("PostgreSQL support not compiled in. Enable the 'postgres' feature to use PostgreSQL database.") + } + } + #[cfg(not(feature = "sqlite"))] + DatabaseEngine::Sqlite => { + bail!("SQLite support not compiled in. Enable the 'sqlite' feature to use SQLite database.") + } + #[cfg(not(feature = "postgres"))] + DatabaseEngine::Postgres => { + bail!("PostgreSQL support not compiled in. Enable the 'postgres' feature to use PostgreSQL database.") } }; diff --git a/crates/cdk-mintd/src/main.rs b/crates/cdk-mintd/src/main.rs index 468d0e23..1d3dd64f 100644 --- a/crates/cdk-mintd/src/main.rs +++ b/crates/cdk-mintd/src/main.rs @@ -14,6 +14,10 @@ compile_error!( "At least one lightning backend feature must be enabled: cln, lnbits, lnd, fakewallet, or grpc-processor" ); +// Ensure at least one database backend is enabled at compile time +#[cfg(not(any(feature = "sqlite", feature = "postgres")))] +compile_error!("At least one database backend feature must be enabled: sqlite or postgres"); + use anyhow::Result; use cdk_mintd::cli::CLIArgs; use cdk_mintd::{get_work_directory, load_settings};