]> Untitled Git - bdk-cli/commitdiff
ref(main): add run to handle routing
authorVihiga Tyonum <withtvpeter@gmail.com>
Thu, 21 May 2026 15:20:00 +0000 (16:20 +0100)
committerVihiga Tyonum <withtvpeter@gmail.com>
Fri, 5 Jun 2026 16:32:14 +0000 (17:32 +0100)
- add run fn in main to handle routing

src/client.rs
src/config.rs
src/main.rs

index 6c024411fc2702a3678dee7e84e96cfa90fe4a9e..db31bf69a7d184a4cfc29a21dae4edca3d407a29 100644 (file)
@@ -1,10 +1,7 @@
-use crate::error::BDKCliError as Error;
+#[cfg(feature = "rpc")]
+use bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi};
 #[cfg(feature = "esplora")]
 use bdk_esplora::EsploraAsyncExt;
-use bdk_wallet::{
-    bitcoin::{Transaction, Txid},
-    chain::CanonicalizationParams,
-};
 #[cfg(any(
     feature = "electrum",
     feature = "esplora",
@@ -12,14 +9,16 @@ use bdk_wallet::{
     feature = "cbf"
 ))]
 use {
-    crate::commands::{ClientType, WalletOpts},
-  
-    bdk_wallet::Wallet,
+    crate::commands::WalletOpts,
+    crate::error::BDKCliError as Error,
+    bdk_wallet::{
+        Wallet,
+        bitcoin::{Transaction, Txid},
+        chain::CanonicalizationParams,
+    },
+    clap::ValueEnum,
     std::path::PathBuf,
 };
-#[cfg(feature = "rpc")]
-use bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi};
-
 
 #[cfg(feature = "cbf")]
 use {
@@ -27,6 +26,24 @@ use {
     bdk_kyoto::{BuilderExt, LightClient},
 };
 
+#[cfg(any(
+    feature = "electrum",
+    feature = "esplora",
+    feature = "rpc",
+    feature = "cbf"
+))]
+#[derive(Clone, ValueEnum, Debug, Eq, PartialEq)]
+pub enum ClientType {
+    #[cfg(feature = "electrum")]
+    Electrum,
+    #[cfg(feature = "esplora")]
+    Esplora,
+    #[cfg(feature = "rpc")]
+    Rpc,
+    #[cfg(feature = "cbf")]
+    Cbf,
+}
+
 #[cfg(any(
     feature = "electrum",
     feature = "esplora",
@@ -50,9 +67,7 @@ pub(crate) enum BlockchainClient {
     },
 
     #[cfg(feature = "cbf")]
-    KyotoClient {
-        client: Box<KyotoClientHandle>,
-    },
+    KyotoClient { client: Box<KyotoClientHandle> },
 }
 
 #[cfg(any(
@@ -83,14 +98,23 @@ impl BlockchainClient {
 
             #[cfg(feature = "cbf")]
             Self::KyotoClient { client } => {
-                // ... (Kyoto broadcast logic from your online.rs) ...
-                Ok(tx.compute_txid())
+                let txid = tx.compute_txid();
+                let wtxid = client
+                    .requester
+                    .broadcast_random(tx.clone())
+                    .await
+                    .map_err(|_| {
+                        tracing::warn!("Broadcast was unsuccessful");
+                        Error::Generic("Transaction broadcast timed out after 30 seconds".into())
+                    })?;
+                tracing::info!("Successfully broadcast WTXID: {wtxid}");
+                Ok(txid)
             }
         }
     }
 
     pub async fn sync_wallet(&self, wallet: &mut Wallet) -> Result<(), Error> {
-        // #[cfg(any(feature = "electrum", feature = "esplora"))]
+        #[cfg(any(feature = "electrum", feature = "esplora"))]
         let request = wallet
             .start_sync_with_revealed_spks()
             .inspect(|item, progress| {
@@ -98,7 +122,7 @@ impl BlockchainClient {
                 eprintln!("[ SCANNING {pc:03.0}% ] {item}");
             });
         match self {
-            // #[cfg(feature = "electrum")]
+            #[cfg(feature = "electrum")]
             Self::Electrum { client, batch_size } => {
                 // Populate the electrum client's transaction cache so it doesn't re-download transaction we
                 // already have.
@@ -109,7 +133,7 @@ impl BlockchainClient {
                     .apply_update(update)
                     .map_err(|e| Error::Generic(e.to_string()))
             }
-            // #[cfg(feature = "esplora")]
+            #[cfg(feature = "esplora")]
             Self::Esplora {
                 client,
                 parallel_requests,
@@ -122,7 +146,7 @@ impl BlockchainClient {
                     .apply_update(update)
                     .map_err(|e| Error::Generic(e.to_string()))
             }
-            // #[cfg(feature = "rpc")]
+            #[cfg(feature = "rpc")]
             Self::RpcClient { client } => {
                 let blockchain_info = client.get_blockchain_info()?;
                 let wallet_cp = wallet.latest_checkpoint();
@@ -166,7 +190,7 @@ impl BlockchainClient {
                 wallet.apply_unconfirmed_txs(mempool_txs.update);
                 Ok(())
             }
-            // #[cfg(feature = "cbf")]
+            #[cfg(feature = "cbf")]
             Self::KyotoClient { client } => sync_kyoto_client(wallet, client)
                 .await
                 .map_err(|e| Error::Generic(e.to_string())),
index 197dc07ce651bd6d64e816f5094f3561b26fcbe7..ec6adfaa237cc6a1222e6a7ec469d89fb8d0ce4c 100644 (file)
@@ -4,11 +4,11 @@
     feature = "rpc",
     feature = "cbf"
 ))]
-use crate::commands::ClientType;
-#[cfg(feature = "sqlite")]
-use crate::commands::DatabaseType;
+use crate::client::ClientType;
 use crate::commands::WalletOpts;
 use crate::error::BDKCliError as Error;
+#[cfg(feature = "sqlite")]
+use crate::persister::DatabaseType;
 use bdk_wallet::bitcoin::Network;
 #[cfg(any(feature = "sqlite", feature = "redb"))]
 use clap::ValueEnum;
index 64600befb037d4992c10c20267ab5d568d4be10c..df5cfc4c49eaed3ed1a2665db7c47fd976bd90ec 100644 (file)
@@ -10,7 +10,7 @@
 #![doc(html_logo_url = "https://github.com/bitcoindevkit/bdk/raw/master/static/bdk.png")]
 #![warn(missing_docs)]
 
-mod backend;
+mod client;
 mod commands;
 mod config;
 mod error;
@@ -22,14 +22,29 @@ mod handlers;
     feature = "rpc"
 ))]
 mod payjoin;
+mod persister;
 mod utils;
-mod wallet;
 
+#[cfg(feature = "redb")]
+use bdk_redb::Store as RedbStore;
 use bdk_wallet::bitcoin::Network;
-use log::{debug, error, warn};
+use log::{debug, warn};
 
-use crate::commands::CliOpts;
-use crate::handlers::handle_command;
+#[cfg(any(
+    feature = "electrum",
+    feature = "esplora",
+    feature = "rpc",
+    feature = "cbf"
+))]
+use crate::client::new_blockchain_client;
+use crate::commands::{CliOpts, CliSubCommand, WalletSubCommand};
+use crate::error::BDKCliError as Error;
+use crate::handlers::{AppCommand, AppContext};
+#[cfg(any(feature = "sqlite", feature = "redb"))]
+use crate::persister::{Persister, new_persisted_wallet};
+use crate::utils::output::FormatOutput;
+use crate::utils::prepare_wallet_db_dir;
+use crate::utils::{load_wallet_config, prepare_home_dir};
 use clap::Parser;
 
 #[tokio::main]
@@ -45,11 +60,123 @@ async fn main() {
         )
     }
 
-    match handle_command(cli_opts).await {
-        Ok(result) => println!("{result}"),
-        Err(e) => {
-            error!("{e}");
-            std::process::exit(1);
-        }
+    if let Err(e) = run(cli_opts).await {
+        eprintln!("Error: {}", e);
+        std::process::exit(1);
     }
 }
+
+async fn run(cli_opts: CliOpts) -> Result<(), Error> {
+    let datadir = cli_opts.datadir.clone();
+    let home_dir = prepare_home_dir(datadir)?;
+
+    match cli_opts.subcommand.clone() {
+        CliSubCommand::Wallet {
+            wallet: wallet_name,
+            subcommand,
+        } => match subcommand {
+            #[cfg(any(
+                feature = "electrum",
+                feature = "esplora",
+                feature = "rpc",
+                feature = "cbf"
+            ))]
+            WalletSubCommand::OnlineWalletSubCommand(online_cmd) => {
+                let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
+
+                let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
+                #[cfg(any(feature = "sqlite", feature = "redb"))]
+                let mut persister: Persister = match &wallet_opts.database_type {
+                    #[cfg(feature = "sqlite")]
+                    crate::persister::DatabaseType::Sqlite => {
+                        let db_file = database_path.join("wallet.sqlite");
+                        let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
+                        Persister::Connection(connection)
+                    }
+                    #[cfg(feature = "redb")]
+                    crate::persister::DatabaseType::Redb => {
+                        use crate::persister::Persister;
+
+                        let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
+                            home_dir.join("wallet.redb"),
+                        )?);
+                        let store = RedbStore::new(db, wallet_name)?;
+                        log::debug!("Redb database opened successfully");
+                        Persister::RedbStore(store)
+                    }
+                };
+
+                let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
+
+                let client = new_blockchain_client(&wallet_opts, &wallet, database_path)?;
+
+                let mut ctx = AppContext::new(network, home_dir)
+                    .with_wallet(&mut wallet)
+                    .with_client(&client);
+
+                online_cmd.execute(&mut ctx).await?;
+            }
+            WalletSubCommand::OfflineWalletSubCommand(offline_cmd) => {
+                let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
+
+                let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
+
+                #[cfg(any(feature = "sqlite", feature = "redb"))]
+                let mut persister: Persister = match &wallet_opts.database_type {
+                    #[cfg(feature = "sqlite")]
+                    crate::persister::DatabaseType::Sqlite => {
+                        let db_file = database_path.join("wallet.sqlite");
+                        let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
+                        Persister::Connection(connection)
+                    }
+                    #[cfg(feature = "redb")]
+                    crate::persister::DatabaseType::Redb => {
+                        use crate::persister::Persister;
+                        let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
+                            home_dir.join("wallet.redb"),
+                        )?);
+                        let store = RedbStore::new(db, wallet_name)?;
+                        Persister::RedbStore(store)
+                    }
+                };
+
+                let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
+
+                let mut ctx = AppContext::new(network, home_dir).with_wallet(&mut wallet);
+
+                offline_cmd.execute(&mut ctx)?;
+            }
+            WalletSubCommand::Config(mut config_cmd) => {
+                config_cmd.wallet_opts.wallet = Some(wallet_name);
+
+                let mut ctx = AppContext::new(cli_opts.network, home_dir);
+
+                config_cmd.execute(&mut ctx)?.print()?;
+            }
+        },
+
+        CliSubCommand::Key { subcommand } => {
+            let mut ctx = AppContext::new(cli_opts.network, home_dir);
+            subcommand.execute(&mut ctx)?;
+        }
+        CliSubCommand::Descriptor(descriptor_command) => {
+            let mut ctx = AppContext::new(cli_opts.network, home_dir);
+            descriptor_command.execute(&mut ctx)?.print()?;
+        }
+        CliSubCommand::Wallets(cmd) => {
+            let mut ctx = AppContext::new(cli_opts.network, home_dir);
+            cmd.execute(&mut ctx)?.print()?;
+        }
+        CliSubCommand::Repl { wallet: _ } => todo!(),
+        CliSubCommand::Completions { shell } => {
+        shell;
+        }
+        #[cfg(feature = "compiler")]
+        CliSubCommand::Compile(cmd) => {
+            let mut ctx = AppContext::new(cli_opts.network, home_dir);
+            cmd.execute(&mut ctx)?.print()?;
+        }
+    };
+
+    Ok(())
+}