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<D>(
+ network: Network,
+ wallet_opts: &WalletOpts,
+ database: D,
+) -> Result<Wallet<AnyBlockchain, D>, Error>
+where
+ D: BatchDatabase,
+{
// Try to use Esplora config if "esplora" feature is enabled
#[cfg(feature = "esplora")]
let config_esplora: Option<AnyBlockchainConfig> = {
- 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),
#[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<D>(
+ network: Network,
+ wallet_opts: &WalletOpts,
+ database: D,
+) -> Result<Wallet<(), D>, 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 {
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);
+ 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, clap::Error> =
+ 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,
}
// 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
+ );
}
}