cli.rs (4102B)
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 axum::{Router, middleware}; 18 use taler_api::api::TalerRouter as _; 19 use taler_build::long_version; 20 use taler_common::{CommonArgs, cli::ConfigCmd, config::Config}; 21 use tracing::info; 22 23 use crate::{ 24 api::{ServerState, status_middleware}, 25 config::{ServeCfg, WorkerCfg}, 26 db::{dbinit, pool}, 27 loops::{ 28 watcher::watcher, 29 worker::{worker_loop, worker_transient}, 30 }, 31 setup::setup, 32 }; 33 34 /// Taler adapter for bitcoincore 35 #[derive(clap::Parser, Debug)] 36 #[command(long_version = long_version(), about, long_about = None)] 37 pub struct Args { 38 #[clap(flatten)] 39 pub common: CommonArgs, 40 #[clap(subcommand)] 41 pub cmd: Command, 42 } 43 44 #[derive(clap::Subcommand, Debug)] 45 pub enum Command { 46 /// Initialize btc-wire database 47 Dbinit { 48 /// Reset database (DANGEROUS: All existing data is lost) 49 #[clap(long, short)] 50 reset: bool, 51 }, 52 /// Check worker configuration and setup worker state 53 Setup { 54 #[clap(long, short)] 55 reset: bool, 56 }, 57 /// Run btc-wire worker 58 Worker { 59 /// Execute once and return 60 #[clap(long, short)] 61 transient: bool, 62 }, 63 /// Run btc-wire HTTP server 64 Serve { 65 /// Check whether an API is in use (if it's useful to start the HTTP 66 /// server). Exit with 0 if at least one API is enabled, otherwise 1 67 #[clap(long)] 68 check: bool, 69 }, 70 #[command(subcommand)] 71 Config(ConfigCmd), 72 } 73 74 /// TODO support external signer https://github.com/bitcoin/bitcoin/blob/master/doc/external-signer.md 75 76 pub async fn run(cmd: Command, cfg: &Config) -> anyhow::Result<()> { 77 match cmd { 78 Command::Dbinit { reset } => { 79 dbinit(cfg, reset).await?; 80 } 81 Command::Setup { reset } => { 82 setup(cfg, reset).await?; 83 } 84 Command::Worker { transient } => { 85 let state = WorkerCfg::parse(cfg)?; 86 let pool = pool(cfg).await?; 87 88 if transient { 89 worker_transient(state, pool).await?; 90 } else { 91 tokio::spawn(watcher(state.rpc_cfg.clone(), pool.clone())); 92 worker_loop(state, pool.clone()).await; 93 94 info!("btc-wire stopped"); 95 } 96 } 97 Command::Serve { check } => { 98 if check { 99 let cfg = ServeCfg::parse(cfg)?; 100 if cfg.wire_gateway.is_none() { 101 std::process::exit(1); 102 } 103 } else { 104 let pool = pool(cfg).await?; 105 let cfg = ServeCfg::parse(cfg)?; 106 let api = ServerState::start(pool, cfg.payto, cfg.currency).await; 107 let mut router = Router::new(); 108 if let Some(cfg) = cfg.wire_gateway { 109 router = router 110 .wire_gateway(api.clone(), cfg.auth.method()) 111 .prepared_transfer(api.clone()) 112 } 113 if let Some(cfg) = cfg.revenue { 114 router = router.revenue(api.clone(), cfg.auth.method()); 115 } 116 117 router 118 .layer(middleware::from_fn_with_state(api, status_middleware)) 119 .serve(&cfg.serve, cfg.lifetime) 120 .await?; 121 } 122 } 123 Command::Config(cfg_cmd) => cfg_cmd.run(cfg)?, 124 } 125 Ok(()) 126 }