setup.rs (4978B)
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 taler_common::config::Config; 18 use tracing::{debug, error, info, warn}; 19 20 use crate::{ 21 config::{SetupCfg, WiseBalance}, 22 wise_api::client::Client, 23 }; 24 25 pub async fn setup(cfg: &Config, client: &http_client::Client) -> anyhow::Result<()> { 26 let cfg = SetupCfg::parse(cfg)?; 27 let client = Client::new(client, &cfg.token); 28 29 info!(target: "setup", "Check API access and configuration"); 30 let mut ready = true; 31 32 // Check profile 33 let profiles = client.profiles().await?; 34 let profiles_fmt = std::fmt::from_fn(|w| { 35 for p in &profiles { 36 write!(w, "\n{} {:?} '{}'", p.id, p.ty, p.full_name)?; 37 } 38 Ok(()) 39 }); 40 if let Some(id) = cfg.profile_id { 41 if let Some(profile) = profiles.iter().find(|it| it.id == id) { 42 debug!(target: "setup", "PROFILE_ID {id} in config is one of:{profiles_fmt}"); 43 match cfg.name { 44 Some(name) => { 45 if name != profile.full_name { 46 warn!( 47 target: "setup", 48 "Expected NAME '{name}' from config got '{}' from server", 49 profile.full_name 50 ) 51 } else { 52 debug!(target: "setup", "NAME {name} from config match server") 53 } 54 } 55 None => { 56 error!(target: "setup", "Missing NAME got '{}' from server", profile.full_name); 57 ready = false; 58 } 59 } 60 } else { 61 error!(target: "setup", "Unknown PROFILE_ID {id} in config, must be one of:{profiles_fmt}"); 62 ready = false; 63 } 64 } else { 65 error!(target: "setup", "Missing PROFILE_ID in config, must be one of:{profiles_fmt}"); 66 ready = false; 67 } 68 69 if let Some(profile_id) = cfg.profile_id { 70 // Check accounts 71 let accounts = client.borderless_accounts(profile_id).await?; 72 let account = accounts 73 .iter() 74 .find(|it| it.profile_id == profile_id) 75 .unwrap(); 76 77 let mapped: Vec<_> = account 78 .balances 79 .iter() 80 .map(|it| (it.id, it.currency, it.bank_details.account())) 81 .collect(); 82 83 let balances_fmt = std::fmt::from_fn(|w| { 84 for (id, currency, account) in &mapped { 85 if let Some(account) = account { 86 write!(w, "\n{id} {currency} ({account})")?; 87 } 88 } 89 Ok(()) 90 }); 91 info!(target: "setup", "Supported balances are: {balances_fmt}"); 92 93 if cfg.balances.is_empty() { 94 error!(target: "setup", "No balances are configured"); 95 ready = false 96 } else { 97 for WiseBalance { 98 id, 99 currency, 100 payto, 101 } in &cfg.balances 102 { 103 match mapped.iter().find(|it| it.0 == *id as u64) { 104 Some((_, curr, acc)) => { 105 if curr != currency { 106 error!(target: "setup", "Balance {id} in config use currency {currency} expected {curr}"); 107 ready = false; 108 } 109 if let Some(acc) = acc { 110 if acc != payto { 111 error!(target: "setup", "Balance {id} in config use payto ({payto}) expected ({acc})"); 112 ready = false 113 } 114 } else { 115 error!(target: "setup", "Balance {id} in config use payto ({payto}) but it's not supported"); 116 ready = false 117 } 118 } 119 None => { 120 error!(target: "setup", "Unknown balance {id} {currency}"); 121 ready = false 122 } 123 } 124 } 125 } 126 } 127 128 if ready { 129 info!(target: "setup", "Setup finished"); 130 Ok(()) 131 } else { 132 error!(target: "setup", "Setup failed, config need editing"); 133 std::process::exit(0); 134 } 135 }