depolymerization

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

config.rs (5101B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025 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, payto::PaytoURI},
     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.str("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: PaytoURI,
     56     pub serve: Serve,
     57     pub wire_gateway: Option<ApiCfg>,
     58     pub currency: Currency,
     59     pub lifetime: Option<u32>,
     60 }
     61 
     62 impl ServeCfg {
     63     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
     64         let payto = parse_account_payto(cfg)?;
     65 
     66         let sect = cfg.section("depolymerizer-bitcoin-httpd");
     67 
     68         let lifetime = sect.number("LIFETIME").opt()?.filter(|it| *it != 0);
     69 
     70         let serve = Serve::parse(sect)?;
     71 
     72         let wire_gateway =
     73             ApiCfg::parse(cfg.section("depolymerizer-bitcoin-httpd-wire-gateway-api"))?;
     74 
     75         let sect = cfg.section("depolymerizer-bitcoin");
     76         Ok(Self {
     77             currency: sect.parse("currency", "CURRENCY").require()?,
     78             lifetime,
     79             payto: payto.as_payto(),
     80             serve,
     81             wire_gateway,
     82         })
     83     }
     84 }
     85 
     86 #[derive(Debug, Clone)]
     87 
     88 pub struct WorkerCfg {
     89     pub confirmation: u32,
     90     pub max_confirmation: u32,
     91     pub bounce_fee: Amount,
     92     pub lifetime: Option<u32>,
     93     pub bump_delay: Option<u32>,
     94     pub db_config: PgConnectOptions,
     95     pub currency: Currency,
     96     pub rpc_cfg: RpcCfg,
     97     pub wallet_cfg: WalletCfg,
     98 }
     99 
    100 impl WorkerCfg {
    101     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    102         let currency: Currency = cfg
    103             .section("depolymerizer-bitcoin")
    104             .parse("currency", "CURRENCY")
    105             .require()?;
    106 
    107         let sect = cfg.section("depolymerizer-bitcoin-worker");
    108         let confirmation = sect.number("CONFIRMATION").require()?;
    109 
    110         Ok(Self {
    111             confirmation,
    112             max_confirmation: confirmation * 2,
    113             bounce_fee: sect
    114                 .amount("BOUNCE_FEE", currency.as_ref())
    115                 .opt()?
    116                 .map(|it| taler_to_btc(&it))
    117                 .unwrap_or_default(),
    118             lifetime: sect.number("LIFETIME").opt()?.filter(|it| *it != 0),
    119             bump_delay: sect.number("BUMP_DELAY").opt()?.filter(|it| *it != 0),
    120             db_config: cfg
    121                 .section("depolymerizer-bitcoindb-postgres")
    122                 .parse("Postgres", "CONFIG")
    123                 .require()
    124                 .unwrap(),
    125             currency,
    126             rpc_cfg: RpcCfg::parse(cfg)?,
    127             wallet_cfg: WalletCfg::parse(cfg)?,
    128         })
    129     }
    130 }
    131 
    132 #[derive(Debug, Clone)]
    133 pub struct WalletCfg {
    134     pub name: String,
    135     pub password: Option<String>,
    136 }
    137 
    138 impl WalletCfg {
    139     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    140         let sect = cfg.section("depolymerizer-bitcoin-worker");
    141         let password = sect.str("PASSWORD").opt()?;
    142         let name = sect.str("WALLET_NAME").require()?;
    143 
    144         Ok(Self { name, password })
    145     }
    146 }
    147 
    148 #[derive(Debug, Clone)]
    149 pub struct RpcCfg {
    150     pub addr: SocketAddr,
    151     pub auth: RpcAuth,
    152 }
    153 
    154 impl RpcCfg {
    155     pub fn parse(cfg: &Config) -> Result<Self, ValueErr> {
    156         let sect = cfg.section("depolymerizer-bitcoin-worker");
    157 
    158         let addr = sect.parse("RPC server address", "RPC_BIND").require()?;
    159 
    160         let auth = map_config!(sect, "auth_method", "RPC_AUTH_METHOD",
    161             "basic" => {
    162                 let username = sect.str("RPC_USERNAME").require()?;
    163                 let password = sect.str("RPC_PASSWORD").require()?;
    164                 Ok(RpcAuth::Basic(format!("{username}:{password}")))
    165             },
    166             "cookie" => {
    167                 Ok(RpcAuth::Cookie(sect.path("RPC_COOKIE_FILE").require()?))
    168             }
    169         )
    170         .require()?;
    171 
    172         Ok(Self { addr, auth })
    173     }
    174 }