fedimint_lnv2_client/
cli.rs1use std::{ffi, iter};
2
3use clap::{Parser, Subcommand};
4use fedimint_core::core::OperationId;
5use fedimint_core::util::SafeUrl;
6use fedimint_core::{Amount, PeerId};
7use lightning_invoice::Bolt11Invoice;
8use serde::Serialize;
9use serde_json::Value;
10
11use crate::api::LightningFederationApi;
12use crate::{Bolt11InvoiceDescription, LightningClientModule};
13
14#[derive(Parser, Serialize)]
15enum Opts {
16 Send {
19 invoice: Bolt11Invoice,
20 #[arg(long)]
21 gateway: Option<SafeUrl>,
22 },
23 AwaitSend { operation_id: OperationId },
25 Receive {
29 amount: Amount,
30 #[arg(long)]
31 gateway: Option<SafeUrl>,
32 },
33 AwaitReceive { operation_id: OperationId },
35 #[command(subcommand)]
37 Lnurl(LnurlOpts),
38 #[command(subcommand)]
40 Gateways(GatewaysOpts),
41}
42
43#[derive(Clone, Subcommand, Serialize)]
44enum LnurlOpts {
45 Generate {
47 recurringd: SafeUrl,
48 #[arg(long)]
49 gateway: Option<SafeUrl>,
50 },
51 Receive {
53 #[arg(long)]
54 batch_size: Option<usize>,
55 },
56}
57
58#[derive(Clone, Subcommand, Serialize)]
59enum GatewaysOpts {
60 Map,
64 Select {
66 #[arg(long)]
67 invoice: Option<Bolt11Invoice>,
68 },
69 List {
71 #[arg(long)]
72 peer: Option<PeerId>,
73 },
74 Add { gateway: SafeUrl },
76 Remove { gateway: SafeUrl },
78}
79
80pub(crate) async fn handle_cli_command(
81 lightning: &LightningClientModule,
82 args: &[ffi::OsString],
83) -> anyhow::Result<serde_json::Value> {
84 let opts = Opts::parse_from(iter::once(&ffi::OsString::from("lnv2")).chain(args.iter()));
85
86 let value = match opts {
87 Opts::Send { gateway, invoice } => {
88 json(lightning.send(invoice, gateway, Value::Null).await?)
89 }
90 Opts::AwaitSend { operation_id } => json(
91 lightning
92 .await_final_send_operation_state(operation_id)
93 .await?,
94 ),
95 Opts::Receive { amount, gateway } => json(
96 lightning
97 .receive(
98 amount,
99 3600,
100 Bolt11InvoiceDescription::Direct(String::new()),
101 gateway,
102 Value::Null,
103 )
104 .await?,
105 ),
106 Opts::AwaitReceive { operation_id } => json(
107 lightning
108 .await_final_receive_operation_state(operation_id)
109 .await?,
110 ),
111 Opts::Lnurl(lnurl_opts) => match lnurl_opts {
112 LnurlOpts::Generate {
113 recurringd,
114 gateway,
115 } => json(lightning.generate_lnurl(recurringd, gateway).await?),
116 LnurlOpts::Receive { batch_size } => {
117 json(lightning.receive_lnurl(batch_size, Value::Null).await)
118 }
119 },
120 Opts::Gateways(gateway_opts) => match gateway_opts {
121 #[allow(clippy::unit_arg)]
122 GatewaysOpts::Map => json(
123 LightningClientModule::update_gateway_map(
124 &lightning.federation_id,
125 &lightning.client_ctx,
126 &lightning.module_api,
127 &lightning.gateway_conn,
128 )
129 .await,
130 ),
131 GatewaysOpts::Select { invoice } => json(lightning.select_gateway(invoice).await?.0),
132 GatewaysOpts::List { peer } => match peer {
133 Some(peer) => json(lightning.module_api.gateways_from_peer(peer).await?),
134 None => json(lightning.module_api.gateways().await?),
135 },
136 GatewaysOpts::Add { gateway } => {
137 let auth = lightning
138 .admin_auth
139 .clone()
140 .ok_or(anyhow::anyhow!("Admin auth not set"))?;
141
142 json(lightning.module_api.add_gateway(auth, gateway).await?)
143 }
144 GatewaysOpts::Remove { gateway } => {
145 let auth = lightning
146 .admin_auth
147 .clone()
148 .ok_or(anyhow::anyhow!("Admin auth not set"))?;
149
150 json(lightning.module_api.remove_gateway(auth, gateway).await?)
151 }
152 },
153 };
154
155 Ok(value)
156}
157
158fn json<T: Serialize>(value: T) -> Value {
159 serde_json::to_value(value).expect("JSON serialization failed")
160}