fedimint_lnv2_client/
cli.rs
1use 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}
52
53#[derive(Clone, Subcommand, Serialize)]
54enum GatewaysOpts {
55 Map,
59 Select {
61 #[arg(long)]
62 invoice: Option<Bolt11Invoice>,
63 },
64 List {
66 #[arg(long)]
67 peer: Option<PeerId>,
68 },
69 Add { gateway: SafeUrl },
71 Remove { gateway: SafeUrl },
73}
74
75pub(crate) async fn handle_cli_command(
76 lightning: &LightningClientModule,
77 args: &[ffi::OsString],
78) -> anyhow::Result<serde_json::Value> {
79 let opts = Opts::parse_from(iter::once(&ffi::OsString::from("lnv2")).chain(args.iter()));
80
81 let value = match opts {
82 Opts::Send { gateway, invoice } => {
83 json(lightning.send(invoice, gateway, Value::Null).await?)
84 }
85 Opts::AwaitSend { operation_id } => json(
86 lightning
87 .await_final_send_operation_state(operation_id)
88 .await?,
89 ),
90 Opts::Receive { amount, gateway } => json(
91 lightning
92 .receive(
93 amount,
94 3600,
95 Bolt11InvoiceDescription::Direct(String::new()),
96 gateway,
97 Value::Null,
98 )
99 .await?,
100 ),
101 Opts::AwaitReceive { operation_id } => json(
102 lightning
103 .await_final_receive_operation_state(operation_id)
104 .await?,
105 ),
106 Opts::Lnurl(lnurl_opts) => match lnurl_opts {
107 LnurlOpts::Generate {
108 recurringd,
109 gateway,
110 } => json(lightning.generate_lnurl(recurringd, gateway).await?),
111 },
112 Opts::Gateways(gateway_opts) => match gateway_opts {
113 #[allow(clippy::unit_arg)]
114 GatewaysOpts::Map => json(lightning.update_gateway_map().await),
115 GatewaysOpts::Select { invoice } => json(lightning.select_gateway(invoice).await?.0),
116 GatewaysOpts::List { peer } => match peer {
117 Some(peer) => json(lightning.module_api.gateways_from_peer(peer).await?),
118 None => json(lightning.module_api.gateways().await?),
119 },
120 GatewaysOpts::Add { gateway } => {
121 let auth = lightning
122 .admin_auth
123 .clone()
124 .ok_or(anyhow::anyhow!("Admin auth not set"))?;
125
126 json(lightning.module_api.add_gateway(auth, gateway).await?)
127 }
128 GatewaysOpts::Remove { gateway } => {
129 let auth = lightning
130 .admin_auth
131 .clone()
132 .ok_or(anyhow::anyhow!("Admin auth not set"))?;
133
134 json(lightning.module_api.remove_gateway(auth, gateway).await?)
135 }
136 },
137 };
138
139 Ok(value)
140}
141
142fn json<T: Serialize>(value: T) -> Value {
143 serde_json::to_value(value).expect("JSON serialization failed")
144}