depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

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 }