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 }