commit 96ade12275de36f3ea9f771c9fe6ba6eb4a8f52c
parent 8880a7d5254601bff6ff52aee96a174bb503759d
Author: Antoine A <>
Date: Wed, 2 Mar 2022 21:09:03 +0100
Better config format error msg
Diffstat:
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 || {