Skip to content

Commit 389bf5c

Browse files
committed
ref(main): add run to handle routing
- add run fn in main to handle routing
1 parent 1d476d4 commit 389bf5c

3 files changed

Lines changed: 186 additions & 35 deletions

File tree

src/client.rs

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,49 @@
1-
use crate::error::BDKCliError as Error;
1+
#[cfg(feature = "rpc")]
2+
use bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi};
23
#[cfg(feature = "esplora")]
34
use bdk_esplora::EsploraAsyncExt;
4-
use bdk_wallet::{
5-
bitcoin::{Transaction, Txid},
6-
chain::CanonicalizationParams,
7-
};
85
#[cfg(any(
96
feature = "electrum",
107
feature = "esplora",
118
feature = "rpc",
129
feature = "cbf"
1310
))]
1411
use {
15-
crate::commands::{ClientType, WalletOpts},
16-
17-
bdk_wallet::Wallet,
12+
crate::commands::WalletOpts,
13+
crate::error::BDKCliError as Error,
14+
bdk_wallet::{
15+
Wallet,
16+
bitcoin::{Transaction, Txid},
17+
chain::CanonicalizationParams,
18+
},
19+
clap::ValueEnum,
1820
std::path::PathBuf,
1921
};
20-
#[cfg(feature = "rpc")]
21-
use bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi};
22-
2322

2423
#[cfg(feature = "cbf")]
2524
use {
2625
crate::utils::trace_logger,
2726
bdk_kyoto::{BuilderExt, LightClient},
2827
};
2928

29+
#[cfg(any(
30+
feature = "electrum",
31+
feature = "esplora",
32+
feature = "rpc",
33+
feature = "cbf"
34+
))]
35+
#[derive(Clone, ValueEnum, Debug, Eq, PartialEq)]
36+
pub enum ClientType {
37+
#[cfg(feature = "electrum")]
38+
Electrum,
39+
#[cfg(feature = "esplora")]
40+
Esplora,
41+
#[cfg(feature = "rpc")]
42+
Rpc,
43+
#[cfg(feature = "cbf")]
44+
Cbf,
45+
}
46+
3047
#[cfg(any(
3148
feature = "electrum",
3249
feature = "esplora",
@@ -50,9 +67,7 @@ pub(crate) enum BlockchainClient {
5067
},
5168

5269
#[cfg(feature = "cbf")]
53-
KyotoClient {
54-
client: Box<KyotoClientHandle>,
55-
},
70+
KyotoClient { client: Box<KyotoClientHandle> },
5671
}
5772

5873
#[cfg(any(
@@ -83,22 +98,31 @@ impl BlockchainClient {
8398

8499
#[cfg(feature = "cbf")]
85100
Self::KyotoClient { client } => {
86-
// ... (Kyoto broadcast logic from your online.rs) ...
87-
Ok(tx.compute_txid())
101+
let txid = tx.compute_txid();
102+
let wtxid = client
103+
.requester
104+
.broadcast_random(tx.clone())
105+
.await
106+
.map_err(|_| {
107+
tracing::warn!("Broadcast was unsuccessful");
108+
Error::Generic("Transaction broadcast timed out after 30 seconds".into())
109+
})?;
110+
tracing::info!("Successfully broadcast WTXID: {wtxid}");
111+
Ok(txid)
88112
}
89113
}
90114
}
91115

92116
pub async fn sync_wallet(&self, wallet: &mut Wallet) -> Result<(), Error> {
93-
// #[cfg(any(feature = "electrum", feature = "esplora"))]
117+
#[cfg(any(feature = "electrum", feature = "esplora"))]
94118
let request = wallet
95119
.start_sync_with_revealed_spks()
96120
.inspect(|item, progress| {
97121
let pc = (100 * progress.consumed()) as f32 / progress.total() as f32;
98122
eprintln!("[ SCANNING {pc:03.0}% ] {item}");
99123
});
100124
match self {
101-
// #[cfg(feature = "electrum")]
125+
#[cfg(feature = "electrum")]
102126
Self::Electrum { client, batch_size } => {
103127
// Populate the electrum client's transaction cache so it doesn't re-download transaction we
104128
// already have.
@@ -109,7 +133,7 @@ impl BlockchainClient {
109133
.apply_update(update)
110134
.map_err(|e| Error::Generic(e.to_string()))
111135
}
112-
// #[cfg(feature = "esplora")]
136+
#[cfg(feature = "esplora")]
113137
Self::Esplora {
114138
client,
115139
parallel_requests,
@@ -122,7 +146,7 @@ impl BlockchainClient {
122146
.apply_update(update)
123147
.map_err(|e| Error::Generic(e.to_string()))
124148
}
125-
// #[cfg(feature = "rpc")]
149+
#[cfg(feature = "rpc")]
126150
Self::RpcClient { client } => {
127151
let blockchain_info = client.get_blockchain_info()?;
128152
let wallet_cp = wallet.latest_checkpoint();
@@ -166,7 +190,7 @@ impl BlockchainClient {
166190
wallet.apply_unconfirmed_txs(mempool_txs.update);
167191
Ok(())
168192
}
169-
// #[cfg(feature = "cbf")]
193+
#[cfg(feature = "cbf")]
170194
Self::KyotoClient { client } => sync_kyoto_client(wallet, client)
171195
.await
172196
.map_err(|e| Error::Generic(e.to_string())),

src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
feature = "rpc",
55
feature = "cbf"
66
))]
7-
use crate::commands::ClientType;
8-
#[cfg(feature = "sqlite")]
9-
use crate::commands::DatabaseType;
7+
use crate::client::ClientType;
108
use crate::commands::WalletOpts;
119
use crate::error::BDKCliError as Error;
10+
#[cfg(feature = "sqlite")]
11+
use crate::persister::DatabaseType;
1212
use bdk_wallet::bitcoin::Network;
1313
#[cfg(any(feature = "sqlite", feature = "redb"))]
1414
use clap::ValueEnum;

src/main.rs

Lines changed: 138 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#![doc(html_logo_url = "https://github.com/bitcoindevkit/bdk/raw/master/static/bdk.png")]
1111
#![warn(missing_docs)]
1212

13-
mod backend;
13+
mod client;
1414
mod commands;
1515
mod config;
1616
mod error;
@@ -22,14 +22,29 @@ mod handlers;
2222
feature = "rpc"
2323
))]
2424
mod payjoin;
25+
mod persister;
2526
mod utils;
26-
mod wallet;
2727

28+
#[cfg(feature = "redb")]
29+
use bdk_redb::Store as RedbStore;
2830
use bdk_wallet::bitcoin::Network;
29-
use log::{debug, error, warn};
31+
use log::{debug, warn};
3032

31-
use crate::commands::CliOpts;
32-
use crate::handlers::handle_command;
33+
#[cfg(any(
34+
feature = "electrum",
35+
feature = "esplora",
36+
feature = "rpc",
37+
feature = "cbf"
38+
))]
39+
use crate::client::new_blockchain_client;
40+
use crate::commands::{CliOpts, CliSubCommand, WalletSubCommand};
41+
use crate::error::BDKCliError as Error;
42+
use crate::handlers::{AppCommand, AppContext};
43+
#[cfg(any(feature = "sqlite", feature = "redb"))]
44+
use crate::persister::{Persister, new_persisted_wallet};
45+
use crate::utils::output::FormatOutput;
46+
use crate::utils::prepare_wallet_db_dir;
47+
use crate::utils::{load_wallet_config, prepare_home_dir};
3348
use clap::Parser;
3449

3550
#[tokio::main]
@@ -45,11 +60,123 @@ async fn main() {
4560
)
4661
}
4762

48-
match handle_command(cli_opts).await {
49-
Ok(result) => println!("{result}"),
50-
Err(e) => {
51-
error!("{e}");
52-
std::process::exit(1);
53-
}
63+
if let Err(e) = run(cli_opts).await {
64+
eprintln!("Error: {}", e);
65+
std::process::exit(1);
5466
}
5567
}
68+
69+
async fn run(cli_opts: CliOpts) -> Result<(), Error> {
70+
let datadir = cli_opts.datadir.clone();
71+
let home_dir = prepare_home_dir(datadir)?;
72+
73+
match cli_opts.subcommand.clone() {
74+
CliSubCommand::Wallet {
75+
wallet: wallet_name,
76+
subcommand,
77+
} => match subcommand {
78+
#[cfg(any(
79+
feature = "electrum",
80+
feature = "esplora",
81+
feature = "rpc",
82+
feature = "cbf"
83+
))]
84+
WalletSubCommand::OnlineWalletSubCommand(online_cmd) => {
85+
let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
86+
87+
let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
88+
#[cfg(any(feature = "sqlite", feature = "redb"))]
89+
let mut persister: Persister = match &wallet_opts.database_type {
90+
#[cfg(feature = "sqlite")]
91+
crate::persister::DatabaseType::Sqlite => {
92+
let db_file = database_path.join("wallet.sqlite");
93+
let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
94+
Persister::Connection(connection)
95+
}
96+
#[cfg(feature = "redb")]
97+
crate::persister::DatabaseType::Redb => {
98+
use crate::persister::Persister;
99+
100+
let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
101+
home_dir.join("wallet.redb"),
102+
)?);
103+
let store = RedbStore::new(db, wallet_name)?;
104+
log::debug!("Redb database opened successfully");
105+
Persister::RedbStore(store)
106+
}
107+
};
108+
109+
let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
110+
111+
let client = new_blockchain_client(&wallet_opts, &wallet, database_path)?;
112+
113+
let mut ctx = AppContext::new(network, home_dir)
114+
.with_wallet(&mut wallet)
115+
.with_client(&client);
116+
117+
online_cmd.execute(&mut ctx).await?;
118+
}
119+
WalletSubCommand::OfflineWalletSubCommand(offline_cmd) => {
120+
let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
121+
122+
let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
123+
124+
#[cfg(any(feature = "sqlite", feature = "redb"))]
125+
let mut persister: Persister = match &wallet_opts.database_type {
126+
#[cfg(feature = "sqlite")]
127+
crate::persister::DatabaseType::Sqlite => {
128+
let db_file = database_path.join("wallet.sqlite");
129+
let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
130+
Persister::Connection(connection)
131+
}
132+
#[cfg(feature = "redb")]
133+
crate::persister::DatabaseType::Redb => {
134+
use crate::persister::Persister;
135+
let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
136+
home_dir.join("wallet.redb"),
137+
)?);
138+
let store = RedbStore::new(db, wallet_name)?;
139+
Persister::RedbStore(store)
140+
}
141+
};
142+
143+
let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
144+
145+
let mut ctx = AppContext::new(network, home_dir).with_wallet(&mut wallet);
146+
147+
offline_cmd.execute(&mut ctx)?;
148+
}
149+
WalletSubCommand::Config(mut config_cmd) => {
150+
config_cmd.wallet_opts.wallet = Some(wallet_name);
151+
152+
let mut ctx = AppContext::new(cli_opts.network, home_dir);
153+
154+
config_cmd.execute(&mut ctx)?.print()?;
155+
}
156+
},
157+
158+
CliSubCommand::Key { subcommand } => {
159+
let mut ctx = AppContext::new(cli_opts.network, home_dir);
160+
subcommand.execute(&mut ctx)?;
161+
}
162+
CliSubCommand::Descriptor(descriptor_command) => {
163+
let mut ctx = AppContext::new(cli_opts.network, home_dir);
164+
descriptor_command.execute(&mut ctx)?.print()?;
165+
}
166+
CliSubCommand::Wallets(cmd) => {
167+
let mut ctx = AppContext::new(cli_opts.network, home_dir);
168+
cmd.execute(&mut ctx)?.print()?;
169+
}
170+
CliSubCommand::Repl { wallet: _ } => todo!(),
171+
CliSubCommand::Completions { shell } => {
172+
shell;
173+
}
174+
#[cfg(feature = "compiler")]
175+
CliSubCommand::Compile(cmd) => {
176+
let mut ctx = AppContext::new(cli_opts.network, home_dir);
177+
cmd.execute(&mut ctx)?.print()?;
178+
}
179+
};
180+
181+
Ok(())
182+
}

0 commit comments

Comments
 (0)