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", ¤cy) 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 }