config.rs (4665B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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::time::Duration; 18 19 use compact_str::CompactString; 20 use taler_api::{ 21 Serve, 22 config::{ApiCfg, DbCfg}, 23 }; 24 use taler_common::{ 25 config::{CfgErr, Config}, 26 config_bail, map_config, 27 types::{ 28 amount::Currency, 29 payto::{ACH, BankID}, 30 }, 31 }; 32 33 use crate::payto::WiseAccount; 34 35 #[derive(Debug, Clone, Copy)] 36 pub enum AccountType { 37 Exchange, 38 Normal, 39 } 40 41 pub fn parse_db_cfg(cfg: &Config) -> Result<DbCfg, CfgErr> { 42 DbCfg::parse(cfg.section("wisedb-postgres")) 43 } 44 45 pub struct WiseBalance { 46 pub id: u32, 47 pub currency: Currency, 48 pub payto: WiseAccount, 49 } 50 51 fn balances(cfg: &Config) -> Result<Vec<WiseBalance>, CfgErr> { 52 cfg.sections() 53 .filter_map(|s| { 54 (|| { 55 Ok(if s.name.starts_with("wise-balance-") { 56 Some(WiseBalance { 57 id: s.number("id").require()?, 58 currency: s.currency("currency").require()?, 59 payto: map_config!(s, "payto type", "PAYTO_TYPE", 60 "iban" => { 61 WiseAccount::IBAN(BankID { 62 iban: s.parse("IBAN", "iban").require()?, 63 bic: s.parse("BIC", "bic").opt()? 64 }) 65 }, 66 "ach" => { 67 WiseAccount::ACH(ACH { 68 routing_number: s.parse("ACH routing number", "routing_number").require()?, 69 account_number: s.parse("ACH account_number", "account_number").require()? 70 }) 71 }, 72 ) 73 .require()?, 74 }) 75 } else { 76 None 77 }) 78 })() 79 .transpose() 80 }) 81 .collect() 82 } 83 84 /// taler-wise setup config 85 pub struct SetupCfg { 86 pub token: String, 87 pub profile_id: Option<u64>, 88 pub name: Option<CompactString>, 89 pub balances: Vec<WiseBalance>, 90 } 91 92 impl SetupCfg { 93 pub fn parse(cfg: &Config) -> Result<Self, CfgErr> { 94 let s = cfg.section("wise-worker"); 95 Ok(Self { 96 profile_id: s.number("PROFILE_ID").opt()?, 97 token: s.str("TOKEN").require()?, 98 name: cfg.section("wise").cstr("NAME").opt()?, 99 balances: balances(cfg)?, 100 }) 101 } 102 } 103 104 /// taler-wise httpd config 105 pub struct ServeCfg { 106 pub name: CompactString, 107 pub serve: Serve, 108 pub balances: Vec<WiseBalance>, 109 pub wire_gateway: Option<ApiCfg>, 110 pub revenue: Option<ApiCfg>, 111 pub observability: Option<ApiCfg>, 112 } 113 114 impl ServeCfg { 115 pub fn parse(cfg: &Config) -> Result<Self, CfgErr> { 116 let s = cfg.section("wise"); 117 Ok(Self { 118 name: s.cstr("NAME").require()?, 119 serve: Serve::parse(&cfg.section("wise-httpd"))?, 120 wire_gateway: ApiCfg::parse(cfg.section("wise-httpd-wire-gateway-api"))?, 121 revenue: ApiCfg::parse(cfg.section("wise-httpd-revenue-api"))?, 122 observability: ApiCfg::parse(cfg.section("wise-httpd-observability-api"))?, 123 balances: balances(cfg)?, 124 }) 125 } 126 } 127 128 /// taler-wise worker config 129 pub struct WorkerCfg { 130 pub profile_id: u64, 131 pub token: String, 132 pub frequency: Duration, 133 pub balances: Vec<WiseBalance>, 134 } 135 136 impl WorkerCfg { 137 pub fn parse(cfg: &Config) -> Result<Self, CfgErr> { 138 let s = cfg.section("wise-worker"); 139 let cfg = Self { 140 profile_id: s.number("PROFILE_ID").require()?, 141 token: s.str("TOKEN").require()?, 142 frequency: s.duration("FREQUENCY").require()?, 143 balances: balances(cfg)?, 144 }; 145 if cfg.balances.is_empty() { 146 config_bail!("Missing configured balance in a section [wise-balance-*]"); 147 } 148 Ok(cfg) 149 } 150 }