depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

commit 96ade12275de36f3ea9f771c9fe6ba6eb4a8f52c
parent 8880a7d5254601bff6ff52aee96a174bb503759d
Author: Antoine A <>
Date:   Wed,  2 Mar 2022 21:09:03 +0100

Better config format error msg

Diffstat:
Mbtc-wire/src/bin/btc-wire-utils.rs | 4++--
Mbtc-wire/src/config.rs | 9+++++----
Mbtc-wire/src/main.rs | 13++++++++-----
Mcommon/src/config.rs | 39+++++++++++++++++++++++++++------------
Mcommon/src/log.rs | 16++++++++--------
Mcommon/src/reconnect.rs | 7++++---
Meth-wire/src/bin/eth-wire-utils.rs | 4++--
Meth-wire/src/main.rs | 13++++++++-----
8 files changed, 64 insertions(+), 41 deletions(-)

diff --git a/btc-wire/src/bin/btc-wire-utils.rs b/btc-wire/src/bin/btc-wire-utils.rs @@ -24,7 +24,7 @@ use btc_wire::{ use clap::StructOpt; use common::{ config::{Config, CoreConfig}, - postgres::{Client, NoTls}, + postgres::NoTls, rand_slice, }; @@ -128,7 +128,7 @@ fn main() { } Cmd::Resetdb => { let hash: BlockHash = rpc.get_genesis().unwrap(); - let mut db = Client::connect(&config.unwrap().db_url, NoTls).unwrap(); + let mut db = config.unwrap().db_config.connect(NoTls).unwrap(); let mut tx = db.transaction().unwrap(); // Clear transaction tables and reset state tx.execute("DELETE FROM tx_in", &[]).unwrap(); diff --git a/btc-wire/src/config.rs b/btc-wire/src/config.rs @@ -20,7 +20,7 @@ use std::{ }; use bitcoin::Network; -use common::log::{fail, ExpectFail}; +use common::log::{fail, OrFail}; pub const WIRE_WALLET_NAME: &str = "wire"; @@ -94,14 +94,15 @@ impl BitcoinConfig { let port = if let Some(addr) = section.and_then(|s| s.get("rpcport")) { addr.parse() - .expect_fail("bitcoin config value 'rpcport' is not a valid port number") + .or_fail(|_| "bitcoin config value 'rpcport' is not a valid port number".into()) } else { rpc_port(network) }; let addr = if let Some(addr) = section.and_then(|s| s.get("rpcbind")) { - SocketAddr::from_str(addr) - .expect_fail("bitcoin config value 'rpcbind' is not a valid socket address") + SocketAddr::from_str(addr).or_fail(|_| { + "bitcoin config value 'rpcbind' is not a valid socket address".into() + }) } else { ([127, 0, 0, 1], port).into() }; diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs @@ -25,7 +25,7 @@ use common::{ config::{load_btc_config, Config, CoreConfig}, log::log::info, named_spawn, password, - postgres::{Client, NoTls}, + postgres::NoTls, reconnect::auto_reconnect_db, }; use std::path::PathBuf; @@ -70,7 +70,10 @@ fn init(config: Option<PathBuf>, init: Init) { // Parse taler config let config = CoreConfig::load_taler_config(config.as_deref(), Some("BTC")); // Connect to database - let mut db = Client::connect(&config.db_url, NoTls).expect("Failed to connect to database"); + let mut db = config + .db_config + .connect(NoTls) + .expect("Failed to connect to database"); // Parse bitcoin config let btc_conf = BitcoinConfig::load(config.data_dir.unwrap_or_else(default_data_dir)) .expect("Failed to load bitcoin configuration"); @@ -181,9 +184,9 @@ fn run(config: Option<PathBuf>) { let rpc_analysis = auto_rpc_common(state.btc_config.clone()); let rpc_worker = auto_rpc_wallet(state.btc_config.clone(), WIRE_WALLET_NAME); - let db_watcher = auto_reconnect_db(state.config.core.db_url.clone()); - let db_analysis = auto_reconnect_db(state.config.core.db_url.clone()); - let db_worker = auto_reconnect_db(state.config.core.db_url.clone()); + let db_watcher = auto_reconnect_db(state.config.core.db_config.clone()); + let db_analysis = auto_reconnect_db(state.config.core.db_config.clone()); + let db_worker = auto_reconnect_db(state.config.core.db_config.clone()); named_spawn("watcher", move || watcher(rpc_watcher, db_watcher)); named_spawn("analysis", move || { analysis(rpc_analysis, db_analysis, state) diff --git a/common/src/config.rs b/common/src/config.rs @@ -21,7 +21,7 @@ use std::{ }; use url::Url; -use crate::log::{fail, ExpectFail}; +use crate::log::{fail, OrFail}; pub trait Config: Sized { /// Load using taler-config @@ -32,7 +32,9 @@ pub trait Config: Sized { cmd.arg("-c"); cmd.arg(path); } - let output = cmd.output().expect_fail("Failed to execute taler-config"); + let output = cmd + .output() + .or_fail(|e| format!("Failed to execute taler-config: {}", e)); if !output.status.success() { panic!( "taler-config failure:\n{}", @@ -64,9 +66,9 @@ pub trait Config: Sized { fn load_from_ini(ini: &Ini, currency: &str, dep: &Properties) -> Self; } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct CoreConfig { - pub db_url: String, + pub db_config: postgres::Config, pub data_dir: Option<PathBuf>, pub currency: String, } @@ -74,14 +76,14 @@ pub struct CoreConfig { impl Config for CoreConfig { fn load_from_ini(_: &Ini, currency: &str, dep: &Properties) -> Self { Self { - db_url: require(dep, "DB_URL", string), + db_config: require(dep, "DB_URL", postgres), data_dir: path(dep, "DATA_DIR"), currency: currency.to_string(), } } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct GatewayConfig { pub http_lifetime: Option<u32>, pub port: u16, @@ -104,7 +106,7 @@ impl Config for GatewayConfig { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct WireConfig { pub base_url: Url, pub confirmation: Option<u16>, @@ -150,7 +152,7 @@ pub fn load_eth_config(path: Option<&Path>) -> EthConfig { fn section<'a>(ini: &'a Ini, name: &str) -> &'a Properties { ini.section(Some(name)) - .expect_fail(format_args!("missing config section {}", name)) + .or_fail(|_| format!("missing config section {}", name)) } fn require<T>( @@ -159,7 +161,7 @@ fn require<T>( lambda: fn(properties: &Properties, name: &str) -> Option<T>, ) -> T { let result = lambda(properties, name); - result.expect_fail(format_args!("missing config {}", name)) + result.or_fail(|_| format!("missing config value {}", name)) } fn string(properties: &Properties, name: &str) -> Option<String> { @@ -168,19 +170,32 @@ fn string(properties: &Properties, name: &str) -> Option<String> { fn path(properties: &Properties, name: &str) -> Option<PathBuf> { properties.get(name).map(|s| { - PathBuf::from_str(s).expect_fail(format_args!("config value {} is not a valid path", name)) + PathBuf::from_str(s) + .or_fail(|_| format!("config value {}={} is not a valid path", name, s)) }) } fn nb<T: FromStr>(properties: &Properties, name: &str) -> Option<T> { properties.get(name).map(|s| { s.parse() - .expect_fail(format_args!("config value {} is not a number", name)) + .or_fail(|_| format!("config value {}={} is not a number", name, s)) }) } fn url(properties: &Properties, name: &str) -> Option<Url> { properties.get(name).map(|s| { - Url::parse(s).expect_fail(format_args!("config value {} is not a valid url", name)) + Url::parse(s) + .or_fail(|e| format!("config value {}={} is not a valid url: {}", name, s, e)) + }) +} + +fn postgres(properties: &Properties, name: &str) -> Option<postgres::Config> { + properties.get(name).map(|s| { + postgres::Config::from_str(s).or_fail(|e| { + format!( + "config value {}={} is not a valid postgres url: {}", + name, s, e + ) + }) }) } diff --git a/common/src/log.rs b/common/src/log.rs @@ -47,19 +47,19 @@ pub fn init() { .unwrap(); } -pub trait ExpectFail<T> { - fn expect_fail(self, msg: impl Display) -> T; +pub trait OrFail<T, E> { + fn or_fail<F: FnOnce(E) -> String>(self, lambda: F) -> T; } -impl<T, E> ExpectFail<T> for Result<T, E> { - fn expect_fail(self, msg: impl Display) -> T { - self.unwrap_or_else(|_| fail(msg)) +impl<T, E> OrFail<T, E> for Result<T, E> { + fn or_fail<F: FnOnce(E) -> String>(self, lambda: F) -> T { + self.unwrap_or_else(|e| fail(lambda(e))) } } -impl<T> ExpectFail<T> for Option<T> { - fn expect_fail(self, msg: impl Display) -> T { - self.unwrap_or_else(|| fail(msg)) +impl<T> OrFail<T, ()> for Option<T> { + fn or_fail<F: FnOnce(()) -> String>(self, lambda: F) -> T { + self.unwrap_or_else(|| fail(lambda(()))) } } diff --git a/common/src/reconnect.rs b/common/src/reconnect.rs @@ -56,13 +56,14 @@ impl<S, C> AutoReconnect<S, C> { } } -pub type AutoReconnectDb = AutoReconnect<String, Client>; +pub type AutoReconnectDb = AutoReconnect<postgres::Config, Client>; -pub fn auto_reconnect_db(config: String) -> AutoReconnectDb { +pub fn auto_reconnect_db(config: postgres::Config) -> AutoReconnectDb { AutoReconnect::new( config, |config| { - Client::connect(config, NoTls) + config + .connect(NoTls) .map_err(|err| error!("connect DB: {}", err)) .ok() }, diff --git a/eth-wire/src/bin/eth-wire-utils.rs b/eth-wire/src/bin/eth-wire-utils.rs @@ -26,7 +26,7 @@ use common::{ config::{Config, CoreConfig}, log::init, password, - postgres::{Client, NoTls}, + postgres::NoTls, rand_slice, }; use eth_wire::{ @@ -175,7 +175,7 @@ fn main() { } Cmd::Resetdb => { let block = rpc.earliest_block().unwrap(); - let mut db = Client::connect(&config.unwrap().db_url, NoTls).unwrap(); + let mut db = config.unwrap().db_config.connect(NoTls).unwrap(); let mut tx = db.transaction().unwrap(); // Clear transaction tables and reset state tx.execute("DELETE FROM tx_in", &[]).unwrap(); diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs @@ -20,7 +20,7 @@ use clap::StructOpt; use common::{ config::{load_eth_config, Config, CoreConfig}, named_spawn, password, - postgres::{Client, NoTls}, + postgres::NoTls, reconnect::auto_reconnect_db, }; use eth_wire::{ @@ -66,7 +66,10 @@ fn init(config: Option<PathBuf>, init: Init) { // Parse taler config let config = CoreConfig::load_taler_config(config.as_deref(), Some("ETH")); // Connect to database - let mut db = Client::connect(&config.db_url, NoTls).expect("Failed to connect to database"); + let mut db = config + .db_config + .connect(NoTls) + .expect("Failed to connect to database"); // Connect to ethereum node let mut rpc = Rpc::new( config @@ -183,9 +186,9 @@ fn run(config: Option<PathBuf>) { .unwrap_or(PathBuf::from("/tmp/")), ); - let db_watcher = auto_reconnect_db(state.config.core.db_url.clone()); - let db_analysis = auto_reconnect_db(state.config.core.db_url.clone()); - let db_worker = auto_reconnect_db(state.config.core.db_url.clone()); + let db_watcher = auto_reconnect_db(state.config.core.db_config.clone()); + let db_analysis = auto_reconnect_db(state.config.core.db_config.clone()); + let db_worker = auto_reconnect_db(state.config.core.db_config.clone()); named_spawn("watcher", move || watcher(rpc_watcher, db_watcher)); named_spawn("analysis", move || {