depolymerization

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

config.rs (5182B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::net::SocketAddr;
     18 
     19 use bitcoin::Amount;
     20 use sqlx::postgres::PgConnectOptions;
     21 use taler_api::{
     22     Serve,
     23     config::{ApiCfg, DbCfg},
     24 };
     25 use taler_common::{
     26     config::{Config, ValueErr},
     27     map_config,
     28     types::amount::Currency,
     29 };
     30 
     31 use crate::{
     32     payto::{BtcWallet, FullBtcPayto},
     33     taler_utils::taler_to_btc,
     34 };
     35 
     36 pub fn parse_db_cfg(cfg: &Config) -> Result<DbCfg, ValueErr> {
     37     DbCfg::parse(cfg.section("depolymerizer-bitcoindb-postgres"))
     38 }
     39 
     40 pub fn parse_account_payto(cfg: &Config) -> Result<FullBtcPayto, ValueErr> {
     41     let sect = cfg.section("depolymerizer-bitcoin");
     42     let wallet: BtcWallet = sect.parse("bitcoin wallet address", "WALLET").require()?;
     43     let name = sect.cstr("NAME").require()?;
     44 
     45     Ok(FullBtcPayto::new(wallet, &name))
     46 }
     47 
     48 #[derive(Debug, Clone)]
     49 pub enum RpcAuth {
     50     Cookie(String),
     51     Basic(String),
     52 }
     53 
     54 pub struct ServeCfg {
     55     pub payto: FullBtcPayto,
     56     pub serve: Serve,
     57     pub wire_gateway: Option<ApiCfg>,
     58     pub revenue: Option<ApiCfg>,
     59     pub currency: Currency,
     60     pub lifetime: Option<u32>,
     61 }
     62 
     63 impl ServeCfg {
     64     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
     65         let payto = parse_account_payto(cfg)?;
     66 
     67         let s = cfg.section("depolymerizer-bitcoin-httpd");
     68 
     69         let lifetime = s.number("LIFETIME").opt()?.filter(|it| *it != 0);
     70 
     71         let serve = Serve::parse(&s)?;
     72 
     73         let wire_gateway =
     74             ApiCfg::parse(cfg.section("depolymerizer-bitcoin-httpd-wire-gateway-api"))?;
     75         let revenue = ApiCfg::parse(cfg.section("depolymerizer-bitcoin-httpd-revenue-api"))?;
     76 
     77         let sect = cfg.section("depolymerizer-bitcoin");
     78         Ok(Self {
     79             currency: sect.parse("currency", "CURRENCY").require()?,
     80             lifetime,
     81             payto,
     82             serve,
     83             wire_gateway,
     84             revenue,
     85         })
     86     }
     87 }
     88 
     89 #[derive(Debug, Clone)]
     90 
     91 pub struct WorkerCfg {
     92     pub conf: u32,
     93     pub max_conf: u32,
     94     pub bounce_fee: Amount,
     95     pub lifetime: Option<u32>,
     96     pub bump_delay: Option<u32>,
     97     pub db_config: PgConnectOptions,
     98     pub currency: Currency,
     99     pub rpc_cfg: RpcCfg,
    100     pub wallet_cfg: WalletCfg,
    101 }
    102 
    103 impl WorkerCfg {
    104     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    105         let currency: Currency = cfg
    106             .section("depolymerizer-bitcoin")
    107             .parse("currency", "CURRENCY")
    108             .require()?;
    109 
    110         let sect = cfg.section("depolymerizer-bitcoin-worker");
    111         let confirmation = sect.number("CONFIRMATION").require()?;
    112 
    113         Ok(Self {
    114             conf: confirmation,
    115             max_conf: confirmation * 2,
    116             bounce_fee: sect
    117                 .amount("BOUNCE_FEE", &currency)
    118                 .opt()?
    119                 .map(|it| taler_to_btc(&it))
    120                 .unwrap_or_default(),
    121             lifetime: sect.number("LIFETIME").opt()?.filter(|it| *it != 0),
    122             bump_delay: sect.number("BUMP_DELAY").opt()?.filter(|it| *it != 0),
    123             db_config: cfg
    124                 .section("depolymerizer-bitcoindb-postgres")
    125                 .parse("Postgres", "CONFIG")
    126                 .require()
    127                 .unwrap(),
    128             currency,
    129             rpc_cfg: RpcCfg::parse(cfg)?,
    130             wallet_cfg: WalletCfg::parse(cfg)?,
    131         })
    132     }
    133 }
    134 
    135 #[derive(Debug, Clone)]
    136 pub struct WalletCfg {
    137     pub name: String,
    138     pub password: Option<String>,
    139 }
    140 
    141 impl WalletCfg {
    142     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    143         let sect = cfg.section("depolymerizer-bitcoin-worker");
    144         let password = sect.str("PASSWORD").opt()?;
    145         let name = sect.str("WALLET_NAME").require()?;
    146 
    147         Ok(Self { name, password })
    148     }
    149 }
    150 
    151 #[derive(Debug, Clone)]
    152 pub struct RpcCfg {
    153     pub addr: SocketAddr,
    154     pub auth: RpcAuth,
    155 }
    156 
    157 impl RpcCfg {
    158     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    159         let sect = cfg.section("depolymerizer-bitcoin-worker");
    160 
    161         let addr = sect.parse("RPC server address", "RPC_BIND").require()?;
    162 
    163         let auth = map_config!(sect, "auth_method", "RPC_AUTH_METHOD",
    164             "basic" => {
    165                 let username = sect.str("RPC_USERNAME").require()?;
    166                 let password = sect.str("RPC_PASSWORD").require()?;
    167                 RpcAuth::Basic(format!("{username}:{password}"))
    168             },
    169             "cookie" => {
    170                 RpcAuth::Cookie(sect.path("RPC_COOKIE_FILE").require()?)
    171             }
    172         )
    173         .require()?;
    174 
    175         Ok(Self { addr, auth })
    176     }
    177 }