From: Vihiga Tyonum Date: Fri, 29 May 2026 03:24:41 +0000 (+0100) Subject: refactor(handlers): Apply app context X-Git-Url: http://internal-gitweb-vhost/blockdata/script/encode/-script/display/struct.ScriptHash.html?a=commitdiff_plain;h=63162bed1ba9804486048a401b2c927a66060ce2;p=bdk-cli refactor(handlers): Apply app context - apply app context with state to all the modules - cover case for commands when db is not required --- diff --git a/src/handlers/config.rs b/src/handlers/config.rs index fe64132..3bd302c 100644 --- a/src/handlers/config.rs +++ b/src/handlers/config.rs @@ -10,6 +10,7 @@ use crate::client::ClientType; use crate::commands::WalletOpts; use crate::config::{WalletConfig, WalletConfigInner}; use crate::error::BDKCliError as Error; +use crate::handlers::Init; use crate::handlers::{AppCommand, AppContext}; #[cfg(feature = "sqlite")] use crate::persister::DatabaseType; @@ -27,10 +28,10 @@ pub struct SaveConfigCommand { pub(crate) wallet_opts: WalletOpts, } -impl AppCommand for SaveConfigCommand { +impl AppCommand> for SaveConfigCommand { type Output = StatusResult; - fn execute(&self, ctx: &mut AppContext<'_>) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { if ctx.network == Network::Bitcoin { eprintln!("WARNING: Configuring for Bitcoin MAINNET. Experimental software!"); } @@ -144,10 +145,10 @@ impl AppCommand for SaveConfigCommand { #[derive(Args, Debug, Clone, PartialEq)] pub struct ListWalletsCommand {} -impl AppCommand for ListWalletsCommand { +impl AppCommand> for ListWalletsCommand { type Output = WalletsListResult; - fn execute(&self, ctx: &mut AppContext) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { let config = match WalletConfig::load(&ctx.datadir)? { Some(cfg) => cfg, None => return Err(Error::Generic("No wallets configured yet.".into())), diff --git a/src/handlers/descriptor.rs b/src/handlers/descriptor.rs index 188abd8..c0bec73 100644 --- a/src/handlers/descriptor.rs +++ b/src/handlers/descriptor.rs @@ -1,3 +1,4 @@ +use crate::handlers::Init; use crate::utils::types::DescriptorResult; use crate::{ error::BDKCliError as Error, @@ -38,10 +39,10 @@ pub struct DescriptorCommand { /// Optional key: xprv, xpub, or mnemonic phrase key: Option, } -impl AppCommand for DescriptorCommand { +impl AppCommand> for DescriptorCommand { type Output = DescriptorResult; - fn execute(&self, ctx: &mut AppContext) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { match &self.key { Some(key) => { if is_mnemonic(key) { @@ -68,10 +69,10 @@ pub struct CompileCommand { } #[cfg(feature = "compiler")] -impl AppCommand for CompileCommand { +impl AppCommand> for CompileCommand { type Output = DescriptorResult; - fn execute(&self, _ctx: &mut AppContext) -> Result { + fn execute(&self, _ctx: &mut AppContext) -> Result { let policy: Concrete = Concrete::from_str(&self.policy) .map_err(|e| Error::Generic(format!("Invalid policy: {e}")))?; diff --git a/src/handlers/key.rs b/src/handlers/key.rs index b9dbe34..ce8c844 100644 --- a/src/handlers/key.rs +++ b/src/handlers/key.rs @@ -1,5 +1,6 @@ use crate::commands::KeySubCommand; use crate::error::BDKCliError as Error; +use crate::handlers::Init; use crate::handlers::{AppCommand, AppContext}; use crate::utils::output::FormatOutput; use crate::utils::types::KeyResult; @@ -15,7 +16,7 @@ use bdk_wallet::miniscript::{self, Segwitv0}; use clap::Parser; impl KeySubCommand { - pub fn execute(&self, ctx: &mut AppContext) -> Result<(), Error> { + pub fn execute(&self, ctx: &mut AppContext) -> Result<(), Error> { match self { KeySubCommand::Generate(generate_key_command) => generate_key_command .execute(ctx)? @@ -44,10 +45,10 @@ pub struct GenerateKeyCommand { password: Option, } -impl AppCommand for GenerateKeyCommand { +impl AppCommand> for GenerateKeyCommand { type Output = KeyResult; - fn execute(&self, ctx: &mut AppContext) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { let secp = Secp256k1::new(); let mnemonic_type = match self.word_count { 12 => WordCount::Words12, @@ -88,10 +89,10 @@ pub struct DeriveKeyCommand { path: DerivationPath, } -impl AppCommand for DeriveKeyCommand { +impl AppCommand> for DeriveKeyCommand { type Output = KeyResult; - fn execute(&self, ctx: &mut AppContext) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { let secp = Secp256k1::new(); let derived_xprv = &self.xprv.derive_priv(&secp, &self.path)?; @@ -134,10 +135,10 @@ pub struct RestoreKeyCommand { password: Option, } -impl AppCommand for RestoreKeyCommand { +impl AppCommand> for RestoreKeyCommand { type Output = KeyResult; - fn execute(&self, ctx: &mut AppContext) -> Result { + fn execute(&self, ctx: &mut AppContext) -> Result { let secp = Secp256k1::new(); let mnemonic = Mnemonic::parse_in(Language::English, &self.mnemonic)?; diff --git a/src/handlers/offline.rs b/src/handlers/offline.rs index f541f74..c8bb18f 100644 --- a/src/handlers/offline.rs +++ b/src/handlers/offline.rs @@ -1,6 +1,6 @@ use crate::commands::OfflineWalletSubCommand; use crate::error::BDKCliError as Error; -use crate::handlers::{AppCommand, AppContext}; +use crate::handlers::{AppCommand, AppContext, OfflineOperations}; use crate::utils::output::{FormatOutput, ListResult}; use crate::utils::parse_address; use crate::utils::types::{ @@ -25,7 +25,7 @@ use { }; impl OfflineWalletSubCommand { - pub fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> { + pub fn execute(&self, ctx: &mut AppContext>) -> Result<(), Error> { match self { Self::NewAddress(new_address) => new_address.execute(ctx)?.write_out(std::io::stdout()), Self::Balance(balance) => balance.execute(ctx)?.write_out(std::io::stdout()), @@ -75,14 +75,11 @@ impl OfflineWalletSubCommand { #[derive(Parser, Debug, Clone, PartialEq)] pub struct NewAddressCommand {} -impl AppCommand for NewAddressCommand { +impl AppCommand>> for NewAddressCommand { type Output = AddressResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".to_string()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let address_info = wallet.reveal_next_address(KeychainKind::External); Ok(AddressResult::from(address_info)) } @@ -91,14 +88,11 @@ impl AppCommand for NewAddressCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct UnusedAddressCommand {} -impl AppCommand for UnusedAddressCommand { +impl AppCommand>> for UnusedAddressCommand { type Output = AddressResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("wallet is required".to_string()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let address_info = wallet.next_unused_address(KeychainKind::External); Ok(AddressResult::from(address_info)) } @@ -107,14 +101,11 @@ impl AppCommand for UnusedAddressCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct UnspentCommand {} -impl AppCommand for UnspentCommand { +impl AppCommand>> for UnspentCommand { type Output = ListResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet is required".to_string()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let utxos = wallet .list_unspent() .map(|utxo| UnspentDetails::from_local_output(&utxo, ctx.network)) @@ -127,16 +118,11 @@ impl AppCommand for UnspentCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct TransactionsCommand {} -impl AppCommand for TransactionsCommand { +impl AppCommand>> for TransactionsCommand { type Output = ListResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("wallet required".to_string()))?; - - let transactions = wallet.transactions(); + fn execute(&self, ctx: &mut AppContext>) -> Result { + let transactions = &mut ctx.state.wallet.transactions(); let txns: Vec = transactions .map(|tx| { @@ -170,15 +156,11 @@ impl AppCommand for TransactionsCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct BalanceCommand {} -impl AppCommand for BalanceCommand { +impl AppCommand>> for BalanceCommand { type Output = BalanceResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or_else(|| Error::Generic("Wallet required".into()))?; - let balance = wallet.balance(); + fn execute(&self, ctx: &mut AppContext>) -> Result { + let balance = ctx.state.wallet.balance(); Ok(BalanceResult::from(balance)) } } @@ -239,16 +221,11 @@ pub struct CreateTxCommand { pub add_data: Option, } -impl AppCommand for CreateTxCommand { +impl AppCommand>> for CreateTxCommand { type Output = PsbtResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or_else(|| Error::Generic("Wallet required".into()))?; - - let mut tx_builder = wallet.build_tx(); + fn execute(&self, ctx: &mut AppContext>) -> Result { + let mut tx_builder = ctx.state.wallet.build_tx(); if self.send_all { tx_builder @@ -348,14 +325,11 @@ pub struct BumpFeeCommand { pub fee_rate: f32, } -impl AppCommand for BumpFeeCommand { +impl AppCommand>> for BumpFeeCommand { type Output = PsbtResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or_else(|| Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let txid = Txid::from_str(self.txid.as_str())?; @@ -392,14 +366,11 @@ impl AppCommand for BumpFeeCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct PoliciesCommand {} -impl AppCommand for PoliciesCommand { +impl AppCommand>> for PoliciesCommand { type Output = KeychainPair; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let external_policy = wallet.policies(KeychainKind::External)?; let internal_policy = wallet.policies(KeychainKind::Internal)?; @@ -413,14 +384,11 @@ impl AppCommand for PoliciesCommand { #[derive(Parser, Debug, PartialEq, Clone)] pub struct PublicDescriptorCommand {} -impl AppCommand for PublicDescriptorCommand { +impl AppCommand>> for PublicDescriptorCommand { type Output = KeychainPair; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; Ok(KeychainPair { external: wallet.public_descriptor(KeychainKind::External).to_string(), internal: wallet.public_descriptor(KeychainKind::Internal).to_string(), @@ -443,14 +411,11 @@ pub struct SignCommand { pub trust_witness_utxo: Option, } -impl AppCommand for SignCommand { +impl AppCommand>> for SignCommand { type Output = PsbtResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let psbt_bytes = BASE64_STANDARD .decode(&self.psbt) .map_err(|e| Error::Generic(e.to_string()))?; @@ -473,10 +438,10 @@ pub struct ExtractPsbtCommand { pub psbt: String, } -impl AppCommand for ExtractPsbtCommand { +impl AppCommand>> for ExtractPsbtCommand { type Output = RawPsbt; - fn execute(&self, _ctx: &mut AppContext) -> Result { + fn execute(&self, _ctx: &mut AppContext>) -> Result { let psbt_serialized = BASE64_STANDARD.decode(self.psbt.clone())?; let psbt = Psbt::deserialize(&psbt_serialized)?; let raw_tx = psbt.extract_tx()?; @@ -500,14 +465,11 @@ pub struct FinalizePsbtCommand { pub trust_witness_utxo: Option, } -impl AppCommand for FinalizePsbtCommand { +impl AppCommand>> for FinalizePsbtCommand { type Output = PsbtResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let psbt_bytes = BASE64_STANDARD .decode(&self.psbt) .map_err(|e| Error::Generic(e.to_string()))?; @@ -532,10 +494,10 @@ pub struct CombinePsbtCommand { pub psbt: Vec, } -impl AppCommand for CombinePsbtCommand { +impl AppCommand>> for CombinePsbtCommand { type Output = PsbtResult; - fn execute(&self, _ctx: &mut AppContext) -> Result { + fn execute(&self, _ctx: &mut AppContext>) -> Result { let mut psbts = self .psbt .iter() @@ -560,7 +522,7 @@ impl AppCommand for CombinePsbtCommand { } } -#[cfg(feature = "bip322")] +// #[cfg(feature = "bip322")] #[derive(Debug, Parser, Clone, PartialEq)] pub struct SignMessageCommand { /// The message to sign @@ -581,14 +543,11 @@ pub struct SignMessageCommand { } #[cfg(feature = "bip322")] -impl AppCommand for SignMessageCommand { +impl AppCommand>> for SignMessageCommand { type Output = MessageResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &mut ctx.state.wallet; let address: Address = parse_address(&self.address)?; let signature_format = parse_signature_format(&self.signature_type)?; @@ -630,14 +589,11 @@ pub struct VerifyMessageCommand { } #[cfg(feature = "bip322")] -impl AppCommand for VerifyMessageCommand { +impl AppCommand>> for VerifyMessageCommand { type Output = MessageResult; - fn execute(&self, ctx: &mut AppContext) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; + fn execute(&self, ctx: &mut AppContext>) -> Result { + let wallet = &ctx.state.wallet; let address: Address = parse_address(&self.address)?; diff --git a/src/handlers/online.rs b/src/handlers/online.rs index 866f6f9..0c44c34 100644 --- a/src/handlers/online.rs +++ b/src/handlers/online.rs @@ -25,14 +25,14 @@ use {bdk_wallet::KeychainKind, std::collections::HashSet, std::io::Write}; use { crate::commands::OnlineWalletSubCommand, crate::error::BDKCliError as Error, - crate::handlers::{AppContext, AsyncCommand}, + crate::handlers::{AppContext, AsyncAppCommand, OnlineOperations}, crate::payjoin::{PayjoinManager, ohttp::RelayManager}, crate::utils::is_final, crate::utils::output::FormatOutput, crate::utils::types::{StatusResult, TransactionResult}, bdk_wallet::bitcoin::{ - Psbt, Transaction, base64::Engine, base64::prelude::BASE64_STANDARD, consensus::Decodable, - hex::FromHex, + Psbt, Transaction, Txid, base64::Engine, base64::prelude::BASE64_STANDARD, + consensus::Decodable, hex::FromHex, }, std::sync::{Arc, Mutex}, }; @@ -43,7 +43,7 @@ use { feature = "rpc" ))] impl OnlineWalletSubCommand { - pub async fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> { + pub async fn execute(&self, ctx: &mut AppContext>) -> Result<(), Error> { match self { OnlineWalletSubCommand::FullScan(full_scan_command) => { let response: StatusResult = full_scan_command.execute(ctx).await?; @@ -84,17 +84,15 @@ pub struct FullScanCommand { feature = "cbf", feature = "rpc" ))] -impl AsyncCommand for FullScanCommand { +impl AsyncAppCommand>> for FullScanCommand { type Output = StatusResult; - async fn execute(&self, ctx: &mut AppContext<'_>) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; - let client = ctx - .client - .ok_or(Error::Generic("Online client required".into()))?; + async fn execute( + &self, + ctx: &mut AppContext>, + ) -> Result { + let wallet = &mut ctx.state.wallet; + let client = ctx.state.client; #[cfg(any(feature = "electrum", feature = "esplora"))] let request = wallet.start_full_scan().inspect({ @@ -185,17 +183,15 @@ pub struct SyncCommand {} feature = "cbf", feature = "rpc" ))] -impl AsyncCommand for SyncCommand { +impl AsyncAppCommand>> for SyncCommand { type Output = StatusResult; - async fn execute(&self, ctx: &mut AppContext<'_>) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".to_string()))?; - let client = ctx - .client - .ok_or(Error::Generic("Client is required".to_string()))?; + async fn execute( + &self, + ctx: &mut AppContext>, + ) -> Result { + let mut wallet = &mut ctx.state.wallet; + let client = ctx.state.client; #[cfg(any(feature = "electrum", feature = "esplora"))] let request = wallet .start_sync_with_revealed_spks() @@ -271,8 +267,8 @@ impl AsyncCommand for SyncCommand { let mempool_txs = emitter.mempool()?; wallet.apply_unconfirmed_txs(mempool_txs.update); } - #[cfg(feature = "cbf")] - KyotoClient { client } => sync_kyoto_client(wallet, client) + // #[cfg(feature = "cbf")] + KyotoClient { client } => sync_kyoto_client(&mut wallet, client) .await .map_err(|e| Error::Generic(e.to_string()))?, } @@ -306,13 +302,14 @@ pub struct BroadcastCommand { feature = "cbf", feature = "rpc" ))] -impl AsyncCommand for BroadcastCommand { +impl AsyncAppCommand>> for BroadcastCommand { type Output = TransactionResult; - async fn execute(&self, ctx: &mut AppContext<'_>) -> Result { - let client = ctx - .client - .ok_or(Error::Generic("Online client required".into()))?; + async fn execute( + &self, + ctx: &mut AppContext>, + ) -> Result { + let client = ctx.state.client; let tx = match (&self.psbt, &self.tx) { (Some(psbt), None) => { @@ -339,7 +336,7 @@ impl AsyncCommand for BroadcastCommand { } }; - let txid = client.broadcast(tx).await?; + let txid: Txid = client.broadcast(tx).await?; Ok(TransactionResult { txid: txid.to_string(), @@ -349,20 +346,6 @@ impl AsyncCommand for BroadcastCommand { #[derive(Parser, Debug, Clone, PartialEq, Eq)] pub struct ReceivePayjoinCommand { - // /// The amount to receive in satoshis. - // pub amount: u64, - - // /// The payjoin directory URL. - // #[clap(long)] - // pub directory: String, - - // /// Optional OHTTP relay URLs for privacy. - // #[clap(long)] - // pub ohttp_relays: Vec, - - // /// Maximum fee rate in sat/vB to pay for the payjoin transaction. - // #[clap(long)] - // pub max_fee_rate: u64, /// Amount to be received in sats. #[arg(env = "PAYJOIN_AMOUNT", long = "amount", required = true)] amount: u64, @@ -385,17 +368,15 @@ pub struct ReceivePayjoinCommand { feature = "cbf", feature = "rpc" ))] -impl AsyncCommand for ReceivePayjoinCommand { +impl AsyncAppCommand>> for ReceivePayjoinCommand { type Output = StatusResult; - async fn execute(&self, ctx: &mut AppContext<'_>) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; - let client = ctx - .client - .ok_or(Error::Generic("Online client required".into()))?; + async fn execute( + &self, + ctx: &mut AppContext>, + ) -> Result { + let wallet = &mut ctx.state.wallet; + let client = ctx.state.client; let relay_manager = Arc::new(Mutex::new(RelayManager::new())); let mut payjoin_manager = PayjoinManager::new(wallet, relay_manager); @@ -415,16 +396,6 @@ impl AsyncCommand for ReceivePayjoinCommand { #[derive(Parser, Debug, Clone, PartialEq, Eq)] pub struct SendPayjoinCommand { - // /// The Payjoin URI string to send to. - // pub uri: String, - - // /// Optional OHTTP relay URLs for privacy. - // #[clap(long)] - // pub ohttp_relays: Vec, - - // /// Fee rate in sat/vB for the transaction. - // #[clap(long, short)] - // pub fee_rate: u64, /// BIP 21 URI for the Payjoin. #[arg(env = "PAYJOIN_URI", long = "uri", required = true)] uri: String, @@ -447,15 +418,15 @@ pub struct SendPayjoinCommand { feature = "cbf", feature = "rpc" ))] -impl AsyncCommand for SendPayjoinCommand { +impl AsyncAppCommand>> for SendPayjoinCommand { type Output = StatusResult; - async fn execute(&self, ctx: &mut AppContext<'_>) -> Result { - let wallet = ctx - .wallet - .as_deref_mut() - .ok_or(Error::Generic("Wallet required".into()))?; - let client = ctx.client.ok_or(Error::Generic("client required".into()))?; + async fn execute( + &self, + ctx: &mut AppContext>, + ) -> Result { + let wallet = &mut ctx.state.wallet; + let client = ctx.state.client; let relay_manager = Arc::new(Mutex::new(RelayManager::new())); let mut payjoin_manager = PayjoinManager::new(wallet, relay_manager); diff --git a/src/handlers/repl.rs b/src/handlers/repl.rs index 19206b2..802e735 100644 --- a/src/handlers/repl.rs +++ b/src/handlers/repl.rs @@ -1,12 +1,21 @@ use bdk_wallet::{Wallet, bitcoin::Network}; #[cfg(feature = "repl")] -use crate::handlers::{AppCommand, AppContext}; -use crate::utils::output::FormatOutput; +use crate::handlers::AppCommand; +#[cfg(feature = "repl")] +use crate::{handlers::AppContext, utils::output::FormatOutput}; -#[cfg(feature = "sqlite")] +#[cfg(feature = "repl")] use crate::commands::ReplSubCommand; use clap::Parser; + +#[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "rpc", + feature = "cbf" +))] +use crate::client::BlockchainClient; #[cfg(feature = "repl")] use std::io::Write; use { @@ -18,9 +27,16 @@ use { pub(crate) async fn respond( network: Network, wallet: &mut Wallet, + #[cfg(any( + feature = "electrum", + feature = "esplora", + feature = "rpc", + feature = "cbf" + ))] + client: Option<&BlockchainClient>, line: &str, datadir: std::path::PathBuf, - cli_opts: &CliOpts, + _cli_opts: &CliOpts, ) -> Result { let args = shlex::split(line).ok_or("error: Invalid quoting".to_string())?; @@ -35,12 +51,14 @@ pub(crate) async fn respond( } }; - let mut ctx = AppContext::new(network, datadir.clone()).with_wallet(&mut *wallet); - let response = match repl_subcommand { ReplSubCommand::Wallet { subcommand } => match subcommand { WalletSubCommand::OfflineWalletSubCommand(cmd) => { - cmd.execute(&mut ctx).map_err(|e| e.to_string())?; + let mut ctx = AppContext::new_offline_wallet(network, datadir, wallet); + cmd.execute(&mut ctx) + .map_err(|e| e.to_string())? + .write_out(std::io::stdout()) + .map_err(|e| e.to_string())?; Some(()) } #[cfg(any( @@ -50,35 +68,47 @@ pub(crate) async fn respond( feature = "rpc" ))] WalletSubCommand::OnlineWalletSubCommand(cmd) => { - let value = cmd.execute(&mut ctx).await.map_err(|e| e.to_string())?; + let client_ref = client.ok_or("Online commands require a client.".to_string())?; + let mut ctx = AppContext::new_online_wallet(network, datadir, wallet, client_ref); + + cmd.execute(&mut ctx) + .await + .map_err(|e| e.to_string())? + .write_out(std::io::stdout()) + .map_err(|e| e.to_string())?; Some(()) - // Some(value) } WalletSubCommand::Config(config_cmd) => { let mut ctx = AppContext::new(network, datadir); - let _ = config_cmd + config_cmd .execute(&mut ctx) .map_err(|e| e.to_string())? - .write_out(std::io::stdout()); + .write_out(std::io::stdout()) + .map_err(|e| e.to_string())?; Some(()) } }, - // Assuming your REPL Descriptor command is an inline struct based on commands.rs ReplSubCommand::Descriptor(cmd) => { - let value = cmd - .execute(&mut ctx) + let mut ctx = AppContext::new(network, datadir); + cmd.execute(&mut ctx) .map_err(|e| e.to_string())? - .write_out(std::io::stdout()); + .write_out(std::io::stdout()) + .map_err(|e| e.to_string())?; + Some(()) + } + + ReplSubCommand::Key { subcommand } => { + let mut ctx = AppContext::new(network, datadir); + subcommand.execute(&mut ctx).map_err(|e| e.to_string())?; Some(()) } ReplSubCommand::Exit => None, - _ => todo!(), + // _ => todo!(), // Handled specifically depending on your ReplSubCommand definitions }; - if let Some(value) = response { - // writeln!(std::io::stdout(), "{value}").map_err(|e| e.to_string())?; + if response.is_some() { std::io::stdout().flush().map_err(|e| e.to_string())?; Ok(false) } else {