use bdk::bitcoin::Network;
use ini::Ini;
use std::env;
use structopt::StructOpt;
#[derive(Debug, StructOpt, Clone, PartialEq)]
#[structopt(name = "BTC Tip Server",
version = option_env ! ("CARGO_PKG_VERSION").unwrap_or("unknown"),
author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""),
about = "Top level options and command modes")]
pub struct ConfigOpts {
#[structopt(
name = "HOST",
env = "HOST",
short = "h",
long = "host",
default_value = "0.0.0.0"
)]
pub host: String,
#[structopt(
name = "PORT",
env = "PORT",
short = "p",
long = "port",
default_value = "8080"
)]
pub port: u16,
#[structopt(
name = "DATADIR",
env = "BDK_DATADIR",
long = "datadir",
default_value = ".bdk-bitcoin"
)]
pub data_dir: String,
#[structopt(
name = "NETWORK",
env = "NETWORK",
short = "n",
long = "network",
default_value = "testnet",
possible_values = &["bitcoin","testnet", "signet", "regtest"]
)]
pub network: Network,
#[structopt(
name = "DESCRIPTOR",
env = "DESCRIPTOR",
short = "d",
long = "descriptor"
)]
pub descriptor: String,
#[structopt(
name = "WALLET",
env = "WALLET",
short = "w",
long = "wallet",
default_value = "btctipserver"
)]
pub wallet: String,
#[structopt(flatten)]
pub electrum_opts: ElectrumOpts,
}
pub(crate) fn load_ini_to_env(ini: Ini) {
if let Some(section_bdk) = ini.section(Some("BDK")) {
for (k, v) in section_bdk.iter() {
if env::var_os(k).is_none() {
env::set_var(k.to_uppercase(), v);
}
}
}
}
#[cfg_attr(not(doc), allow(missing_docs))]
#[cfg_attr(
doc,
doc = r#"
Electrum options
Electrum blockchain client options.
"#
)]
#[derive(Debug, StructOpt, Clone, PartialEq)]
pub struct ElectrumOpts {
#[structopt(name = "PROXY_IP:PORT", env = "PROXY", long = "proxy")]
pub proxy: Option<String>,
#[structopt(
name = "PROXY_RETRIES",
env = "RETRIES",
long = "retries",
default_value = "5"
)]
pub retries: u8,
#[structopt(name = "PROXY_TIMEOUT", env = "TIMEOUT", long = "timeout")]
pub timeout: Option<u8>,
#[structopt(
name = "ELECTRUM_URL",
env = "ELECTRUM",
short = "s",
long = "server",
default_value = "ssl://electrum.blockstream.info:60002"
)]
pub electrum: String,
}
#[cfg(test)]
mod test {
use super::{ConfigOpts, ElectrumOpts};
use crate::config::load_ini_to_env;
use bdk::bitcoin::Network;
use ini::Ini;
use structopt;
use structopt::StructOpt;
#[test]
fn test_config_from_args() {
let cli_args = vec!["btctipserver", "--network", "bitcoin",
"--descriptor", "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
];
let config_opts: ConfigOpts = ConfigOpts::from_iter(&cli_args);
let expected_config_opts = ConfigOpts {
host: "0.0.0.0".to_string(),
port: 8080,
data_dir: ".bdk-bitcoin".to_string(),
network: Network::Bitcoin,
descriptor: "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)".parse().unwrap(),
wallet: "btctipserver".to_string(),
electrum_opts: ElectrumOpts {
proxy: None,
retries: 5,
timeout: None,
electrum: "ssl://electrum.blockstream.info:60002".to_string()
}
};
assert_eq!(expected_config_opts, config_opts);
}
#[test]
fn test_config_from_ini_env() {
let config = r#"
[BDK]
datadir = .bdk-bitcoin
network = bitcoin
wallet = test
descriptor = 'wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)'
electrum = 'ssl://electrum.blockstream.info:60003'
proxy = 127.0.0.1:9150
retries = 5
timeout = 2
"#;
let ini = Ini::load_from_str(config).unwrap();
load_ini_to_env(ini);
let cli_args = vec!["btctipserver"];
let config_opts: ConfigOpts = ConfigOpts::from_iter(&cli_args);
let expected_config_opts = ConfigOpts {
host: "0.0.0.0".to_string(),
port: 8080,
data_dir: ".bdk-bitcoin".to_string(),
network: Network::Bitcoin,
descriptor: "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)".parse().unwrap(),
wallet: "test".to_string(),
electrum_opts: ElectrumOpts {
proxy: Some("127.0.0.1:9150".to_string()),
retries: 5,
timeout: Some(2),
electrum: "ssl://electrum.blockstream.info:60003".to_string()
}
};
assert_eq!(expected_config_opts, config_opts);
}
}