commit 29b5207e9f46e9d91cce0002cb206c7af79ece35
parent bac023df91fa79225f5e622ba074000be812f3ae
Author: Antoine A <>
Date: Thu, 19 Jun 2025 12:02:27 +0200
common: more common config logic
Diffstat:
8 files changed, 116 insertions(+), 73 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -2221,6 +2221,7 @@ name = "taler-api"
version = "0.0.0"
dependencies = [
"axum",
+ "base64",
"criterion",
"dashmap",
"ed25519-dalek",
diff --git a/Cargo.toml b/Cargo.toml
@@ -44,3 +44,4 @@ taler-test-utils = { path = "common/taler-test-utils" }
anyhow = "1"
http-body-util = "0.1.2"
libdeflater = "1.22.0"
+base64 = "0.22"
diff --git a/common/taler-api/Cargo.toml b/common/taler-api/Cargo.toml
@@ -10,6 +10,7 @@ license-file.workspace = true
[dependencies]
listenfd = "1.0.0"
dashmap = "6.1"
+base64.workspace = true
http-body-util.workspace = true
libdeflater.workspace = true
ed25519-dalek = { version = "2.1.1", default-features = false }
diff --git a/common/taler-api/src/config.rs b/common/taler-api/src/config.rs
@@ -0,0 +1,90 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2025 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+
+use std::net::{IpAddr, SocketAddr};
+
+use base64::{Engine, prelude::BASE64_STANDARD};
+use sqlx::postgres::PgConnectOptions;
+use taler_common::{
+ config::{Section, ValueErr},
+ map_config,
+};
+
+use crate::{Serve, auth::AuthMethod};
+
+/// Basic database config
+pub struct DbCfg {
+ pub cfg: PgConnectOptions,
+ pub sql_dir: String,
+}
+
+impl DbCfg {
+ pub fn parse(sect: Section) -> Result<Self, ValueErr> {
+ Ok(Self {
+ cfg: sect.postgres("CONFIG").require()?,
+ sql_dir: sect.path("SQL_DIR").require()?,
+ })
+ }
+}
+
+/// Basic api config
+pub struct ApiCfg {
+ pub auth: AuthMethod,
+}
+
+impl ApiCfg {
+ pub fn parse(sect: Section) -> Result<Option<Self>, ValueErr> {
+ Ok(if sect.boolean("ENABLED").require()? {
+ let auth = map_config!(sect, "auth_method", "AUTH_METHOD",
+ "none" => {
+ Ok(AuthMethod::None)
+ },
+ "basic" => {
+ let username = sect.str("USERNAME").require()?;
+ let password = sect.str("PASSWORD").require()?;
+ Ok(AuthMethod::Basic(
+ BASE64_STANDARD.encode(format!("{username}:{password}")),
+ ))
+ },
+ "bearer" => {
+ Ok(AuthMethod::Bearer(sect.str("AUTH_TOKEN").require()?))
+ }
+ )
+ .require()?;
+ Some(Self { auth })
+ } else {
+ None
+ })
+ }
+}
+
+impl Serve {
+ pub fn parse(sect: Section) -> Result<Self, ValueErr> {
+ map_config!(sect, "serve", "SERVE",
+ "tcp" => {
+ let port = sect.number("PORT").require()?;
+ let ip: IpAddr = sect.parse("IP addr", "BIND_TO").require()?;
+ Ok::<Serve, ValueErr>(Serve::Tcp(SocketAddr::new(ip, port)))
+ },
+ "unix" => {
+ let path = sect.path("UNIXPATH").require()?;
+ let permission = sect.unix_mode("UNIXPATH_MODE").require()?;
+ Ok::<Serve, ValueErr>(Serve::Unix { path, permission })
+ }
+ )
+ .require()
+ }
+}
diff --git a/common/taler-api/src/lib.rs b/common/taler-api/src/lib.rs
@@ -22,6 +22,7 @@ use tracing::info;
pub mod api;
pub mod auth;
+pub mod config;
pub mod constants;
pub mod db;
pub mod error;
diff --git a/taler-magnet-bank/Cargo.toml b/taler-magnet-bank/Cargo.toml
@@ -18,7 +18,6 @@ hmac = "0.12"
sha1 = "0.10"
p256 = { version = "0.13.2", features = ["alloc", "ecdsa"] }
spki = "0.7.3"
-base64 = "0.22"
form_urlencoded = "1.2"
percent-encoding = "2.3"
passterm = "2.0"
@@ -35,6 +34,7 @@ thiserror.workspace = true
tracing.workspace = true
tokio.workspace = true
anyhow.workspace = true
+base64.workspace = true
[dev-dependencies]
taler-test-utils.workspace = true
diff --git a/taler-magnet-bank/src/config.rs b/taler-magnet-bank/src/config.rs
@@ -14,34 +14,21 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-use std::net::{IpAddr, SocketAddr};
-
-use base64::{Engine, prelude::BASE64_STANDARD};
use reqwest::Url;
-use sqlx::postgres::PgConnectOptions;
-use taler_api::{Serve, auth::AuthMethod};
+use taler_api::{
+ Serve,
+ config::{ApiCfg, DbCfg},
+};
use taler_common::{
- config::{Config, Section, ValueErr, map_config},
+ config::{Config, ValueErr},
types::payto::PaytoURI,
};
use crate::{FullHuPayto, HuIban, magnet::Token};
-pub struct DbCfg {
- pub cfg: PgConnectOptions,
- pub sql_dir: String,
-}
-
-impl DbCfg {
- pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
- let sect = cfg.section("magnet-bankdb-postgres");
- Ok(Self {
- cfg: sect.postgres("CONFIG").require()?,
- sql_dir: sect.path("SQL_DIR").require()?,
- })
- }
+pub fn parse_db_cfg(cfg: &Config) -> Result<DbCfg, ValueErr> {
+ DbCfg::parse(cfg.section("magnet-bankdb-postgres"))
}
-
pub fn parse_account_payto(cfg: &Config) -> Result<FullHuPayto, ValueErr> {
let sect = cfg.section("magnet-bank");
let iban: HuIban = sect.parse("iban", "IBAN").require()?;
@@ -50,36 +37,6 @@ pub fn parse_account_payto(cfg: &Config) -> Result<FullHuPayto, ValueErr> {
Ok(FullHuPayto::new(iban, name))
}
-pub struct ApiCfg {
- pub auth: AuthMethod,
-}
-
-impl ApiCfg {
- pub fn parse(sect: Section) -> Result<Option<Self>, ValueErr> {
- Ok(if sect.boolean("ENABLED").require()? {
- let auth = map_config!(sect, "auth_method", "AUTH_METHOD",
- "none" => {
- Ok(AuthMethod::None)
- },
- "basic" => {
- let username = sect.str("USERNAME").require()?;
- let password = sect.str("PASSWORD").require()?;
- Ok(AuthMethod::Basic(
- BASE64_STANDARD.encode(format!("{username}:{password}")),
- ))
- },
- "bearer" => {
- Ok(AuthMethod::Bearer(sect.str("AUTH_TOKEN").require()?))
- }
- )
- .require()?;
- Some(Self { auth })
- } else {
- None
- })
- }
-}
-
pub struct ServeCfg {
pub payto: PaytoURI,
pub serve: Serve,
@@ -93,19 +50,7 @@ impl ServeCfg {
let sect = cfg.section("magnet-bank-httpd");
- let serve = map_config!(sect, "serve", "SERVE",
- "tcp" => {
- let port = sect.number("PORT").require()?;
- let ip: IpAddr = sect.parse("IP addr", "BIND_TO").require()?;
- Ok::<Serve, ValueErr>(Serve::Tcp(SocketAddr::new(ip, port)))
- },
- "unix" => {
- let path = sect.path("UNIXPATH").require()?;
- let permission = sect.unix_mode("UNIXPATH_MODE").require()?;
- Ok::<Serve, ValueErr>(Serve::Unix { path, permission })
- }
- )
- .require()?;
+ let serve = Serve::parse(sect)?;
let wire_gateway = ApiCfg::parse(cfg.section("magnet-bank-httpd-wire-gateway-api"))?;
let revenue = ApiCfg::parse(cfg.section("magnet-bank-httpd-revenue-api"))?;
diff --git a/taler-magnet-bank/src/main.rs b/taler-magnet-bank/src/main.rs
@@ -19,11 +19,15 @@ use std::sync::Arc;
use clap::Parser;
use taler_api::api::{Router, TalerRouter as _};
use taler_common::{
- cli::{long_version, ConfigCmd}, config::{parser::ConfigSource, Config}, db::{dbinit, pool}, taler_main, CommonArgs
+ CommonArgs,
+ cli::{ConfigCmd, long_version},
+ config::{Config, parser::ConfigSource},
+ db::{dbinit, pool},
+ taler_main,
};
use taler_magnet_bank::{
adapter::MagnetApi,
- config::{DbCfg, ServeCfg, WorkerCfg},
+ config::{ServeCfg, WorkerCfg, parse_db_cfg},
dev::{self, DevCmd},
magnet::AuthClient,
setup,
@@ -76,16 +80,16 @@ enum Command {
async fn app(args: Args, cfg: Config) -> anyhow::Result<()> {
match args.cmd {
- Command::Setup { reset } => {
- let cfg = WorkerCfg::parse(&cfg)?;
- setup::setup(cfg, reset).await?
- }
Command::Dbinit { reset } => {
- let cfg = DbCfg::parse(&cfg)?;
+ let cfg = parse_db_cfg(&cfg)?;
let pool = pool(cfg.cfg, "magnet_bank").await?;
let mut conn = pool.acquire().await?;
dbinit(&mut conn, cfg.sql_dir.as_ref(), "magnet-bank", reset).await?;
}
+ Command::Setup { reset } => {
+ let cfg = WorkerCfg::parse(&cfg)?;
+ setup::setup(cfg, reset).await?
+ }
Command::Serve { check } => {
if check {
let cfg = ServeCfg::parse(&cfg)?;
@@ -93,7 +97,7 @@ async fn app(args: Args, cfg: Config) -> anyhow::Result<()> {
std::process::exit(1);
}
} else {
- let db = DbCfg::parse(&cfg)?;
+ let db = parse_db_cfg(&cfg)?;
let pool = pool(db.cfg, "magnet_bank").await?;
let cfg = ServeCfg::parse(&cfg)?;
let api = Arc::new(MagnetApi::start(pool, cfg.payto).await);
@@ -108,7 +112,7 @@ async fn app(args: Args, cfg: Config) -> anyhow::Result<()> {
}
}
Command::Worker { transient: _ } => {
- let db = DbCfg::parse(&cfg)?;
+ let db = parse_db_cfg(&cfg)?;
let pool = pool(db.cfg, "magnet_bank").await?;
let cfg = WorkerCfg::parse(&cfg)?;
let keys = setup::load(&cfg)?;