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