Skip to content

Commit 8229c7b

Browse files
committed
refactor(output): apply generics to output mod
1 parent de1fc98 commit 8229c7b

8 files changed

Lines changed: 101 additions & 91 deletions

File tree

src/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::handlers::{
3434
))]
3535
use crate::{
3636
client::ClientType,
37-
online::{
37+
handlers::online::{
3838
BroadcastCommand, FullScanCommand, ReceivePayjoinCommand, SendPayjoinCommand, SyncCommand,
3939
},
4040
};

src/handlers/key.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use clap::Parser;
1717
impl KeySubCommand {
1818
pub fn execute(&self, ctx: &mut AppContext) -> Result<(), Error> {
1919
match self {
20-
KeySubCommand::Generate(generate_key_command) => {
21-
generate_key_command.execute(ctx)?.print()
22-
}
23-
KeySubCommand::Restore(restore_key_command) => {
24-
restore_key_command.execute(ctx)?.print()
25-
}
26-
KeySubCommand::Derive(derive_key_command) => derive_key_command.execute(ctx)?.print(),
20+
KeySubCommand::Generate(generate_key_command) => generate_key_command
21+
.execute(ctx)?
22+
.write_out(std::io::stdout()),
23+
KeySubCommand::Restore(restore_key_command) => restore_key_command
24+
.execute(ctx)?
25+
.write_out(std::io::stdout()),
26+
KeySubCommand::Derive(derive_key_command) => derive_key_command
27+
.execute(ctx)?
28+
.write_out(std::io::stdout()),
2729
}
2830
}
2931
}

src/handlers/offline.rs

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::commands::OfflineWalletSubCommand;
22
use crate::error::BDKCliError as Error;
33
use crate::handlers::{AppCommand, AppContext};
4-
use crate::utils::output::FormatOutput;
4+
use crate::utils::output::{FormatOutput, ListResult};
55
use crate::utils::parse_address;
66
use crate::utils::types::{
77
AddressResult, BalanceResult, KeychainPair, PsbtResult, RawPsbt, TransactionDetails,
8-
TransactionListResult, UnspentDetails, UnspentListResult,
8+
UnspentDetails,
99
};
1010
use crate::utils::{parse_outpoint, parse_recipient};
1111
use bdk_wallet::bitcoin::base64::Engine;
@@ -27,31 +27,47 @@ use {
2727
impl OfflineWalletSubCommand {
2828
pub fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> {
2929
match self {
30-
Self::NewAddress(new_address) => new_address.execute(ctx)?.print(),
31-
Self::Balance(balance) => balance.execute(ctx)?.print(),
32-
Self::UnusedAddress(unused_address_command) => {
33-
unused_address_command.execute(ctx)?.print()
30+
Self::NewAddress(new_address) => new_address.execute(ctx)?.write_out(std::io::stdout()),
31+
Self::Balance(balance) => balance.execute(ctx)?.write_out(std::io::stdout()),
32+
Self::UnusedAddress(unused_address_command) => unused_address_command
33+
.execute(ctx)?
34+
.write_out(std::io::stdout()),
35+
Self::Unspent(unspent_command) => {
36+
unspent_command.execute(ctx)?.write_out(std::io::stdout())
3437
}
35-
Self::Unspent(unspent_command) => unspent_command.execute(ctx)?.print(),
36-
Self::Transactions(transactions_command) => transactions_command.execute(ctx)?.print(),
37-
Self::CreateTx(createtx_command) => createtx_command.execute(ctx)?.print(),
38-
Self::BumpFee(bumpfee_command) => bumpfee_command.execute(ctx)?.print(),
39-
Self::Policies(policies_command) => policies_command.execute(ctx)?.print(),
40-
Self::PublicDescriptor(public_descriptor_command) => {
41-
public_descriptor_command.execute(ctx)?.print()
38+
Self::Transactions(transactions_command) => transactions_command
39+
.execute(ctx)?
40+
.write_out(std::io::stdout()),
41+
Self::CreateTx(createtx_command) => {
42+
createtx_command.execute(ctx)?.write_out(std::io::stdout())
4243
}
43-
Self::Sign(sign_command) => sign_command.execute(ctx)?.print(),
44-
Self::ExtractPsbt(extract_psbt_command) => extract_psbt_command.execute(ctx)?.print(),
45-
Self::FinalizePsbt(finalize_psbt_command) => {
46-
finalize_psbt_command.execute(ctx)?.print()
44+
Self::BumpFee(bumpfee_command) => {
45+
bumpfee_command.execute(ctx)?.write_out(std::io::stdout())
4746
}
48-
Self::CombinePsbt(combine_psbt_command) => combine_psbt_command.execute(ctx)?.print(),
47+
Self::Policies(policies_command) => {
48+
policies_command.execute(ctx)?.write_out(std::io::stdout())
49+
}
50+
Self::PublicDescriptor(public_descriptor_command) => public_descriptor_command
51+
.execute(ctx)?
52+
.write_out(std::io::stdout()),
53+
Self::Sign(sign_command) => sign_command.execute(ctx)?.write_out(std::io::stdout()),
54+
Self::ExtractPsbt(extract_psbt_command) => extract_psbt_command
55+
.execute(ctx)?
56+
.write_out(std::io::stdout()),
57+
Self::FinalizePsbt(finalize_psbt_command) => finalize_psbt_command
58+
.execute(ctx)?
59+
.write_out(std::io::stdout()),
60+
Self::CombinePsbt(combine_psbt_command) => combine_psbt_command
61+
.execute(ctx)?
62+
.write_out(std::io::stdout()),
4963
#[cfg(feature = "bip322")]
50-
Self::SignMessage(sign_message_command) => sign_message_command.execute(ctx)?.print(),
64+
Self::SignMessage(sign_message_command) => sign_message_command
65+
.execute(ctx)?
66+
.write_out(std::io::stdout()),
5167
#[cfg(feature = "bip322")]
52-
Self::VerifyMessage(verify_message_command) => {
53-
verify_message_command.execute(ctx)?.print()
54-
}
68+
Self::VerifyMessage(verify_message_command) => verify_message_command
69+
.execute(ctx)?
70+
.write_out(std::io::stdout()),
5571
}
5672
}
5773
}
@@ -92,7 +108,7 @@ impl AppCommand for UnusedAddressCommand {
92108
pub struct UnspentCommand {}
93109

94110
impl AppCommand for UnspentCommand {
95-
type Output = UnspentListResult;
111+
type Output = ListResult<UnspentDetails>;
96112

97113
fn execute(&self, ctx: &mut AppContext) -> Result<Self::Output, Error> {
98114
let wallet = ctx
@@ -104,15 +120,15 @@ impl AppCommand for UnspentCommand {
104120
.map(|utxo| UnspentDetails::from_local_output(&utxo, ctx.network))
105121
.collect();
106122

107-
Ok(UnspentListResult(utxos))
123+
Ok(ListResult::new(utxos))
108124
}
109125
}
110126

111127
#[derive(Parser, Debug, PartialEq, Clone)]
112128
pub struct TransactionsCommand {}
113129

114130
impl AppCommand for TransactionsCommand {
115-
type Output = TransactionListResult;
131+
type Output = ListResult<TransactionDetails>;
116132

117133
fn execute(&self, ctx: &mut AppContext) -> Result<Self::Output, Error> {
118134
let wallet = ctx
@@ -147,7 +163,7 @@ impl AppCommand for TransactionsCommand {
147163
})
148164
.collect();
149165

150-
Ok(TransactionListResult(txns))
166+
Ok(ListResult::new(txns))
151167
}
152168
}
153169

src/handlers/online.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,24 @@ impl OnlineWalletSubCommand {
4646
pub async fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> {
4747
match self {
4848
OnlineWalletSubCommand::FullScan(full_scan_command) => {
49-
full_scan_command.execute(ctx).await?.print()
49+
let response: StatusResult = full_scan_command.execute(ctx).await?;
50+
response.write_out(std::io::stdout())
51+
}
52+
OnlineWalletSubCommand::Sync(sync_command) => {
53+
let response: StatusResult = sync_command.execute(ctx).await?;
54+
response.write_out(std::io::stdout())
5055
}
51-
OnlineWalletSubCommand::Sync(sync_command) => sync_command.execute(ctx).await?.print(),
5256
OnlineWalletSubCommand::Broadcast(broadcast_command) => {
53-
broadcast_command.execute(ctx).await?.print()
57+
let response: TransactionResult = broadcast_command.execute(ctx).await?;
58+
response.write_out(std::io::stdout())
5459
}
5560
OnlineWalletSubCommand::ReceivePayjoin(receive_payjoin_command) => {
56-
receive_payjoin_command.execute(ctx).await?.print()
61+
let response: StatusResult = receive_payjoin_command.execute(ctx).await?;
62+
response.write_out(std::io::stdout())
5763
}
5864
OnlineWalletSubCommand::SendPayjoin(send_payjoin_command) => {
59-
send_payjoin_command.execute(ctx).await?.print()
65+
let response: StatusResult = send_payjoin_command.execute(ctx).await?;
66+
response.write_out(std::io::stdout())
6067
}
6168
}
6269
}
@@ -299,7 +306,6 @@ pub struct BroadcastCommand {
299306
feature = "cbf",
300307
feature = "rpc"
301308
))]
302-
303309
impl AsyncCommand for BroadcastCommand {
304310
type Output = TransactionResult;
305311

src/handlers/repl.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bdk_wallet::{Wallet, bitcoin::Network};
22

3-
// #[cfg(feature = "repl")]
3+
#[cfg(feature = "repl")]
44
use crate::handlers::{AppCommand, AppContext};
55
use crate::utils::output::FormatOutput;
66

@@ -56,17 +56,20 @@ pub(crate) async fn respond(
5656
}
5757
WalletSubCommand::Config(config_cmd) => {
5858
let mut ctx = AppContext::new(network, datadir);
59-
let res = config_cmd
59+
let _ = config_cmd
6060
.execute(&mut ctx)
6161
.map_err(|e| e.to_string())?
62-
.print();
62+
.write_out(std::io::stdout());
6363
Some(())
6464
}
6565
},
6666

6767
// Assuming your REPL Descriptor command is an inline struct based on commands.rs
6868
ReplSubCommand::Descriptor(cmd) => {
69-
let value = cmd.execute(&mut ctx).map_err(|e| e.to_string())?.print();
69+
let value = cmd
70+
.execute(&mut ctx)
71+
.map_err(|e| e.to_string())?
72+
.write_out(std::io::stdout());
7073
Some(())
7174
}
7275

src/main.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
151151

152152
let mut ctx = AppContext::new(cli_opts.network, home_dir);
153153

154-
config_cmd.execute(&mut ctx)?.print()?;
154+
config_cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
155155
}
156156
},
157157

@@ -161,11 +161,13 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
161161
}
162162
CliSubCommand::Descriptor(descriptor_command) => {
163163
let mut ctx = AppContext::new(cli_opts.network, home_dir);
164-
descriptor_command.execute(&mut ctx)?.print()?;
164+
descriptor_command
165+
.execute(&mut ctx)?
166+
.write_out(std::io::stdout())?;
165167
}
166168
CliSubCommand::Wallets(cmd) => {
167169
let mut ctx = AppContext::new(cli_opts.network, home_dir);
168-
cmd.execute(&mut ctx)?.print()?;
170+
cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
169171
}
170172
CliSubCommand::Repl { wallet: _ } => todo!(),
171173
CliSubCommand::Completions { shell } => {
@@ -174,7 +176,7 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
174176
#[cfg(feature = "compiler")]
175177
CliSubCommand::Compile(cmd) => {
176178
let mut ctx = AppContext::new(cli_opts.network, home_dir);
177-
cmd.execute(&mut ctx)?.print()?;
179+
cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
178180
}
179181
};
180182

src/utils/output.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::io::Write;
2+
13
use crate::error::BDKCliError as Error;
24
use serde::Serialize;
35

@@ -8,9 +10,28 @@ pub trait FormatOutput: Serialize {
810
.map_err(|e| Error::Generic(format!("JSON serialization failed: {e}")))
911
}
1012

11-
fn print(&self) -> Result<(), Error> {
13+
fn write_out<W: Write>(&self, mut writer: W) -> Result<(), Error> {
1214
let output = self.format()?;
13-
println!("{}", output);
14-
Ok(())
15+
16+
writeln!(writer, "{}", output)
17+
.map_err(|e| Error::Generic(format!("Failed to write output: {e}")))
18+
}
19+
}
20+
21+
impl<T: Serialize> FormatOutput for T {}
22+
23+
/// A generic wrapper for commands that return a list of items.
24+
#[derive(Serialize)]
25+
pub struct ListResult<T> {
26+
pub count: usize,
27+
pub items: Vec<T>,
28+
}
29+
30+
impl<T> ListResult<T> {
31+
pub fn new(items: Vec<T>) -> Self {
32+
Self {
33+
count: items.len(),
34+
items,
35+
}
1536
}
1637
}

0 commit comments

Comments
 (0)