From: Steve Myers Date: Wed, 3 Feb 2021 07:04:37 +0000 (-0800) Subject: Create online and offline wallets, use regex to split and filter repl commands X-Git-Tag: v0.2.0~21 X-Git-Url: http://internal-gitweb-vhost/script/%22https:/enum.HexToArrayError.html?a=commitdiff_plain;h=0d3e641bbbf2ad08152eff59a952684ebe761c37;p=bdk-cli Create online and offline wallets, use regex to split and filter repl commands --- diff --git a/src/bdk_cli.rs b/src/bdk_cli.rs index 439c420..e8c20b7 100644 --- a/src/bdk_cli.rs +++ b/src/bdk_cli.rs @@ -86,30 +86,26 @@ fn prepare_home_dir() -> PathBuf { dir } -fn main() { - env_logger::init(); - - let cli_opt: WalletOpt = WalletOpt::from_args(); - - let network = cli_opt.network; - 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 descriptor = cli_opt.descriptor.as_str(); - let change_descriptor = cli_opt.change_descriptor.as_deref(); - debug!("descriptors: {:?} {:?}", descriptor, change_descriptor); - +fn open_database(wallet_opts: &WalletOpts) -> Tree { let database = sled::open(prepare_home_dir().to_str().unwrap()).unwrap(); - let tree = database.open_tree(cli_opt.wallet).unwrap(); + let tree = database.open_tree(&wallet_opts.wallet).unwrap(); debug!("database opened successfully"); + tree +} +fn new_online_wallet( + network: Network, + wallet_opts: &WalletOpts, + database: D, +) -> Result, Error> +where + D: BatchDatabase, +{ // Try to use Esplora config if "esplora" feature is enabled #[cfg(feature = "esplora")] let config_esplora: Option = { - let esplora_concurrency = cli_opt.esplora_concurrency; - cli_opt.esplora.map(|base_url| { + let esplora_concurrency = wallet_opts.esplora_concurrency; + wallet_opts.esplora.clone().map(|base_url| { AnyBlockchainConfig::Esplora(EsploraBlockchainConfig { base_url, concurrency: Some(esplora_concurrency), @@ -119,34 +115,97 @@ fn main() { #[cfg(not(feature = "esplora"))] let config_esplora = None; + let config_electrum = AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { + url: wallet_opts.electrum.clone(), + socks5: wallet_opts.proxy.clone(), + retry: wallet_opts.retries, + timeout: wallet_opts.timeout, + }); + // Fall back to Electrum config if Esplora config isn't provided - let config = - config_esplora.unwrap_or(AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { - url: cli_opt.electrum, - socks5: cli_opt.proxy, - retry: 10, - timeout: None, - })); + let config = config_esplora.unwrap_or(config_electrum); + let descriptor = wallet_opts.descriptor.as_str(); + let change_descriptor = wallet_opts.change_descriptor.as_deref(); let wallet = Wallet::new( descriptor, change_descriptor, network, - tree, - AnyBlockchain::from_config(&config).unwrap(), - ) - .unwrap(); + database, + AnyBlockchain::from_config(&config)?, + )?; + Ok(wallet) +} + +fn new_offline_wallet( + network: Network, + wallet_opts: &WalletOpts, + database: D, +) -> Result, Error> +where + D: BatchDatabase, +{ + let descriptor = wallet_opts.descriptor.as_str(); + let change_descriptor = wallet_opts.change_descriptor.as_deref(); + let wallet = Wallet::new_offline(descriptor, change_descriptor, network, database)?; + Ok(wallet) +} + +fn main() { + env_logger::init(); + + let cli_opts: CliOpts = CliOpts::from_args(); - let wallet = Arc::new(wallet); + let network = cli_opts.network; + debug!("network: {:?}", network); + if network == Network::Bitcoin { + warn!("This is experimental software and not currently recommended for use on Bitcoin mainnet, proceed with caution.") + } + + //println!("cli_opts = {:?}", cli_opts); + + let result = match cli_opts.subcommand { + CliSubCommand::Wallet { + wallet_opts, + subcommand: WalletSubCommand::OnlineWalletSubCommand(online_subcommand), + } => { + let database = open_database(&wallet_opts); + let wallet = new_online_wallet(network, &wallet_opts, database).unwrap(); + let result = bdk_cli::handle_online_wallet_subcommand(&wallet, online_subcommand); + serde_json::to_string_pretty(&result.unwrap()).unwrap() + } + CliSubCommand::Wallet { + wallet_opts, + subcommand: WalletSubCommand::OfflineWalletSubCommand(offline_subcommand), + } => { + let database = open_database(&wallet_opts); + let wallet = new_offline_wallet(network, &wallet_opts, database).unwrap(); + let result = bdk_cli::handle_offline_wallet_subcommand(&wallet, offline_subcommand); + serde_json::to_string_pretty(&result.unwrap()).unwrap() + } + CliSubCommand::Key { + subcommand: key_subcommand, + } => { + let result = bdk_cli::handle_key_subcommand(network, key_subcommand); + serde_json::to_string_pretty(&result.unwrap()).unwrap() + } + CliSubCommand::Repl { wallet_opts } => { + let database = open_database(&wallet_opts); + let online_wallet = new_online_wallet(network, &wallet_opts, database.clone()).unwrap(); + let online_wallet = Arc::new(online_wallet); + + let offline_wallet = new_offline_wallet(network, &wallet_opts, database).unwrap(); + let offline_wallet = Arc::new(offline_wallet); - match cli_opt.subcommand { - WalletSubCommand::Repl => { let mut rl = Editor::<()>::new(); // if rl.load_history("history.txt").is_err() { // println!("No previous history."); // } + let split_regex = Regex::new(r#"[\w\-]+|"[\w\s]*""#).unwrap(); + let filter_regex = Regex::new(r#"[\w\s\-]+"#).unwrap(); + loop { let readline = rl.readline(">> "); match readline { @@ -155,22 +214,46 @@ fn main() { continue; } rl.add_history_entry(line.as_str()); - let split_line: Vec<&str> = line.split(' ').collect(); - let repl_subcommand: Result = - ReplOpt::from_iter_safe(split_line); - debug!("repl_subcommand = {:?}", repl_subcommand); + let split_line: Vec<&str> = + split_regex.find_iter(&line).map(|m| m.as_str()).collect(); + let filtered_line: Vec<&str> = split_line + .iter() + .flat_map(|s| filter_regex.find_iter(s).map(|m| m.as_str())) + .collect(); + let repl_opt: Result = + ReplOpt::from_iter_safe(filtered_line); + debug!("repl_opt = {:?}", repl_opt); - if let Err(err) = repl_subcommand { + if let Err(err) = repl_opt { println!("{}", err.message); continue; } - let result = bdk_cli::handle_wallet_subcommand( - &Arc::clone(&wallet), - repl_subcommand.unwrap().subcommand, - ) - .unwrap(); - println!("{}", serde_json::to_string_pretty(&result).unwrap()); + let repl_subcommand = repl_opt.unwrap().subcommand; + + let result = match repl_subcommand { + ReplSubCommand::OnlineWalletSubCommand(online_subcommand) => { + bdk_cli::handle_online_wallet_subcommand( + &Arc::clone(&online_wallet), + online_subcommand, + ) + } + ReplSubCommand::OfflineWalletSubCommand(offline_subcommand) => { + bdk_cli::handle_offline_wallet_subcommand( + &Arc::clone(&offline_wallet), + offline_subcommand, + ) + } + ReplSubCommand::KeySubCommand(key_subcommand) => { + bdk_cli::handle_key_subcommand(network, key_subcommand) + } + ReplSubCommand::Exit => break, + }; + + println!( + "{}", + serde_json::to_string_pretty(&result.unwrap()).unwrap() + ); } Err(ReadlineError::Interrupted) => continue, Err(ReadlineError::Eof) => break, @@ -182,10 +265,34 @@ fn main() { } // rl.save_history("history.txt").unwrap(); + "Exiting REPL".to_string() } - _ => { - let result = bdk_cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap(); - println!("{}", serde_json::to_string_pretty(&result).unwrap()); - } + }; + + println!("{}", result); +} + +#[cfg(test)] +mod test { + use regex::Regex; + + #[test] + fn test_regex() { + let split_regex = Regex::new(r#"[\w\-]+|"[\w\s]*""#).unwrap(); + //println!("split_regex = {:?}", &split_regex); + let filter_regex = Regex::new(r#"[\w\s\-]+"#).unwrap(); + //println!("filter_regex = {:?}", &filter_regex); + let line = r#"restore -m "word1 word2 word3" -p test"#; + let split_line: Vec<&str> = split_regex.find_iter(&line).map(|m| m.as_str()).collect(); + //println!("split_line({}) = {:?}", &line, &split_line); + let filtered_line: Vec<&str> = split_line + .iter() + .flat_map(|s| filter_regex.find_iter(s).map(|m| m.as_str())) + .collect(); + //println!("filtered_line({:?}) = {:?}", &split_line, &filtered_line); + assert_eq!( + vec!("restore", "-m", "word1 word2 word3", "-p", "test"), + filtered_line + ); } }