Update cli module to use StructOpt and add docs
This commit is contained in:
parent
2e7f98a371
commit
364b47bfcb
@ -27,6 +27,7 @@ cc = { version = "=1.0.62", optional = true }
|
|||||||
socks = { version = "0.3", optional = true }
|
socks = { version = "0.3", optional = true }
|
||||||
lazy_static = { version = "1.4", optional = true }
|
lazy_static = { version = "1.4", optional = true }
|
||||||
tiny-bip39 = { version = "^0.8", optional = true }
|
tiny-bip39 = { version = "^0.8", optional = true }
|
||||||
|
structopt = { version = "^0.3", optional = true }
|
||||||
|
|
||||||
# Platform-specific dependencies
|
# Platform-specific dependencies
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
@ -45,7 +46,7 @@ electrum = ["electrum-client"]
|
|||||||
esplora = ["reqwest", "futures"]
|
esplora = ["reqwest", "futures"]
|
||||||
compact_filters = ["rocksdb", "socks", "lazy_static", "cc"]
|
compact_filters = ["rocksdb", "socks", "lazy_static", "cc"]
|
||||||
key-value-db = ["sled"]
|
key-value-db = ["sled"]
|
||||||
cli-utils = ["clap", "base64"]
|
cli-utils = ["clap", "base64", "structopt"]
|
||||||
async-interface = ["async-trait"]
|
async-interface = ["async-trait"]
|
||||||
all-keys = ["keys-bip39"]
|
all-keys = ["keys-bip39"]
|
||||||
keys-bip39 = ["tiny-bip39"]
|
keys-bip39 = ["tiny-bip39"]
|
||||||
|
163
examples/repl.rs
163
examples/repl.rs
@ -24,27 +24,34 @@
|
|||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bitcoin::Network;
|
||||||
|
use clap::AppSettings;
|
||||||
|
use log::{debug, error, info, trace, warn, LevelFilter};
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
|
use structopt::StructOpt;
|
||||||
use clap::AppSettings;
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use log::{debug, error, info, trace, LevelFilter};
|
|
||||||
|
|
||||||
use bitcoin::Network;
|
|
||||||
|
|
||||||
use bdk::bitcoin;
|
use bdk::bitcoin;
|
||||||
|
use bdk::blockchain::esplora::EsploraBlockchainConfig;
|
||||||
use bdk::blockchain::{
|
use bdk::blockchain::{
|
||||||
AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig,
|
AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig,
|
||||||
};
|
};
|
||||||
use bdk::cli;
|
use bdk::cli::{self, WalletOpt, WalletSubCommand};
|
||||||
use bdk::sled;
|
use bdk::sled;
|
||||||
use bdk::Wallet;
|
use bdk::Wallet;
|
||||||
|
|
||||||
use bdk::blockchain::esplora::EsploraBlockchainConfig;
|
#[derive(Debug, StructOpt, Clone, PartialEq)]
|
||||||
|
#[structopt(name = "BDK Wallet", setting = AppSettings::NoBinaryName,
|
||||||
|
version = option_env ! ("CARGO_PKG_VERSION").unwrap_or("unknown"),
|
||||||
|
author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""))]
|
||||||
|
struct ReplOpt {
|
||||||
|
/// Wallet sub-command
|
||||||
|
#[structopt(subcommand)]
|
||||||
|
pub subcommand: WalletSubCommand,
|
||||||
|
}
|
||||||
|
|
||||||
fn prepare_home_dir() -> PathBuf {
|
fn prepare_home_dir() -> PathBuf {
|
||||||
let mut dir = PathBuf::new();
|
let mut dir = PathBuf::new();
|
||||||
@ -61,100 +68,96 @@ fn prepare_home_dir() -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init();
|
let cli_opt: WalletOpt = WalletOpt::from_args();
|
||||||
|
|
||||||
let app = cli::make_cli_subcommands();
|
let level = LevelFilter::from_str(cli_opt.log_level.as_str()).unwrap_or(LevelFilter::Info);
|
||||||
let mut repl_app = app.clone().setting(AppSettings::NoBinaryName);
|
env_logger::builder().filter_level(level).init();
|
||||||
|
|
||||||
let app = cli::add_global_flags(app);
|
let network = Network::from_str(cli_opt.network.as_str()).unwrap_or(Network::Testnet);
|
||||||
|
debug!("network: {:?}", network);
|
||||||
|
if network == Network::Bitcoin {
|
||||||
|
warn!("This is experimental software and not currently recommended for use on Bitcoin mainnet, proceed with caution.")
|
||||||
|
}
|
||||||
|
|
||||||
let matches = app.get_matches();
|
let descriptor = cli_opt.descriptor.as_str();
|
||||||
|
let change_descriptor = cli_opt.change_descriptor.as_deref();
|
||||||
// TODO
|
|
||||||
// let level = match matches.occurrences_of("v") {
|
|
||||||
// 0 => LevelFilter::Info,
|
|
||||||
// 1 => LevelFilter::Debug,
|
|
||||||
// _ => LevelFilter::Trace,
|
|
||||||
// };
|
|
||||||
|
|
||||||
let network = match matches.value_of("network") {
|
|
||||||
Some("regtest") => Network::Regtest,
|
|
||||||
Some("testnet") | _ => Network::Testnet,
|
|
||||||
};
|
|
||||||
|
|
||||||
let descriptor = matches.value_of("descriptor").unwrap();
|
|
||||||
let change_descriptor = matches.value_of("change_descriptor");
|
|
||||||
debug!("descriptors: {:?} {:?}", descriptor, change_descriptor);
|
debug!("descriptors: {:?} {:?}", descriptor, change_descriptor);
|
||||||
|
|
||||||
let database = sled::open(prepare_home_dir().to_str().unwrap()).unwrap();
|
let database = sled::open(prepare_home_dir().to_str().unwrap()).unwrap();
|
||||||
let tree = database
|
let tree = database.open_tree(cli_opt.wallet).unwrap();
|
||||||
.open_tree(matches.value_of("wallet").unwrap())
|
|
||||||
.unwrap();
|
|
||||||
debug!("database opened successfully");
|
debug!("database opened successfully");
|
||||||
|
|
||||||
let config = match matches.value_of("esplora") {
|
let config = match cli_opt.esplora {
|
||||||
Some(base_url) => AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
|
Some(base_url) => AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
|
||||||
base_url: base_url.to_string(),
|
base_url: base_url.to_string(),
|
||||||
concurrency: matches
|
concurrency: Some(cli_opt.esplora_concurrency),
|
||||||
.value_of("esplora_concurrency")
|
|
||||||
.and_then(|v| v.parse::<u8>().ok()),
|
|
||||||
}),
|
}),
|
||||||
None => AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
|
None => AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
|
||||||
url: matches.value_of("server").unwrap().to_string(),
|
url: cli_opt.electrum,
|
||||||
socks5: matches.value_of("proxy").map(ToString::to_string),
|
socks5: cli_opt.proxy,
|
||||||
retry: 10,
|
retry: 10,
|
||||||
timeout: 10,
|
timeout: 10,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let wallet = Arc::new(
|
|
||||||
Wallet::new(
|
|
||||||
descriptor,
|
|
||||||
change_descriptor,
|
|
||||||
network,
|
|
||||||
tree,
|
|
||||||
AnyBlockchain::from_config(&config).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(_sub_matches) = matches.subcommand_matches("repl") {
|
let wallet = Wallet::new(
|
||||||
let mut rl = Editor::<()>::new();
|
descriptor,
|
||||||
|
change_descriptor,
|
||||||
|
network,
|
||||||
|
tree,
|
||||||
|
AnyBlockchain::from_config(&config).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// if rl.load_history("history.txt").is_err() {
|
let wallet = Arc::new(wallet);
|
||||||
// println!("No previous history.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
loop {
|
match cli_opt.subcommand {
|
||||||
let readline = rl.readline(">> ");
|
WalletSubCommand::Other(external) if external.contains(&"repl".to_string()) => {
|
||||||
match readline {
|
let mut rl = Editor::<()>::new();
|
||||||
Ok(line) => {
|
|
||||||
if line.trim() == "" {
|
// if rl.load_history("history.txt").is_err() {
|
||||||
continue;
|
// println!("No previous history.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let readline = rl.readline(">> ");
|
||||||
|
match readline {
|
||||||
|
Ok(line) => {
|
||||||
|
if line.trim() == "" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rl.add_history_entry(line.as_str());
|
||||||
|
let split_line: Vec<&str> = line.split(" ").collect();
|
||||||
|
let repl_subcommand: Result<ReplOpt, clap::Error> =
|
||||||
|
ReplOpt::from_iter_safe(split_line);
|
||||||
|
debug!("repl_subcommand = {:?}", repl_subcommand);
|
||||||
|
|
||||||
|
if let Err(err) = repl_subcommand {
|
||||||
|
println!("{}", err.message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = cli::handle_wallet_subcommand(
|
||||||
|
&Arc::clone(&wallet),
|
||||||
|
repl_subcommand.unwrap().subcommand,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
println!("{}", serde_json::to_string_pretty(&result).unwrap());
|
||||||
}
|
}
|
||||||
|
Err(ReadlineError::Interrupted) => continue,
|
||||||
rl.add_history_entry(line.as_str());
|
Err(ReadlineError::Eof) => break,
|
||||||
let matches = repl_app.get_matches_from_safe_borrow(line.split(" "));
|
Err(err) => {
|
||||||
if let Err(err) = matches {
|
println!("{:?}", err);
|
||||||
println!("{}", err.message);
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result =
|
|
||||||
cli::handle_matches(&Arc::clone(&wallet), matches.unwrap()).unwrap();
|
|
||||||
println!("{}", serde_json::to_string_pretty(&result).unwrap());
|
|
||||||
}
|
|
||||||
Err(ReadlineError::Interrupted) => continue,
|
|
||||||
Err(ReadlineError::Eof) => break,
|
|
||||||
Err(err) => {
|
|
||||||
println!("{:?}", err);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// rl.save_history("history.txt").unwrap();
|
// rl.save_history("history.txt").unwrap();
|
||||||
} else {
|
}
|
||||||
let result = cli::handle_matches(&wallet, matches).unwrap();
|
_ => {
|
||||||
println!("{}", serde_json::to_string_pretty(&result).unwrap());
|
let result = cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap();
|
||||||
|
println!("{}", serde_json::to_string_pretty(&result).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1202
src/cli.rs
1202
src/cli.rs
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user