mirror of
https://github.com/lndk-org/lndk.git
synced 2026-08-13 12:33:05 +02:00
refactor(cli): extract repeated gRPC client setup and metadata handling
Extracted duplicated gRPC channel creation, client authentication, and metadata handling code into reusable functions to reduce code duplication and improve error handling.
This commit is contained in:
parent
e990a6cde2
commit
efe5688552
1 changed files with 76 additions and 128 deletions
204
src/cli.rs
204
src/cli.rs
|
|
@ -24,6 +24,11 @@ fn get_macaroon_path_default(network: &str) -> PathBuf {
|
|||
.join(format!(".lnd/data/chain/bitcoin/{network}/admin.macaroon"))
|
||||
}
|
||||
|
||||
fn print_and_exit(msg: &str) -> ! {
|
||||
println!("{msg}");
|
||||
exit(1)
|
||||
}
|
||||
|
||||
/// A cli for interacting with lndk.
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "lndk-cli")]
|
||||
|
|
@ -175,13 +180,8 @@ async fn main() {
|
|||
Commands::DecodeOffer { offer_string } => {
|
||||
println!("Decoding offer: {offer_string}.");
|
||||
match decode(offer_string) {
|
||||
Ok(offer) => {
|
||||
println!("Decoded offer: {:?}.", offer)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("ERROR ({}): {}", e.code(), e);
|
||||
exit(1)
|
||||
}
|
||||
Ok(offer) => println!("Decoded offer: {:?}.", offer),
|
||||
Err(e) => print_and_exit(&format!("ERROR ({}): {}", e.code(), e)),
|
||||
}
|
||||
}
|
||||
Commands::DecodeInvoice { invoice_string } => {
|
||||
|
|
@ -192,10 +192,7 @@ async fn main() {
|
|||
Ok(invoice) => {
|
||||
println!("Decoded invoice: {:?}.", invoice);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("ERROR ({}): {}", e.code(), e);
|
||||
exit(1);
|
||||
}
|
||||
Err(e) => print_and_exit(&format!("ERROR ({}): {}", e.code(), e)),
|
||||
}
|
||||
}
|
||||
Commands::PayOffer {
|
||||
|
|
@ -207,37 +204,19 @@ async fn main() {
|
|||
fee_limit_percent,
|
||||
} => {
|
||||
let tls = read_cert_from_args_or_exit(args.cert_pem, args.cert_path);
|
||||
let grpc_host = args.grpc_host;
|
||||
let grpc_port = args.grpc_port;
|
||||
let channel = Channel::from_shared(format!("{grpc_host}:{grpc_port}"))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR creating endpoint: {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.tls_config(tls)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR tls config: {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.connect()
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR connecting: {e:?}");
|
||||
exit(1)
|
||||
});
|
||||
|
||||
let mut client = OffersClient::new(channel);
|
||||
let channel = create_grpc_channel(args.grpc_host, args.grpc_port, tls).await;
|
||||
let (mut client, macaroon) = create_authenticated_client(
|
||||
channel,
|
||||
args.macaroon_path,
|
||||
args.macaroon_hex,
|
||||
&args.network,
|
||||
);
|
||||
|
||||
let offer = match decode(offer_string.to_string()) {
|
||||
Ok(offer) => offer,
|
||||
Err(e) => {
|
||||
println!("ERROR ({}): {}", e.code(), e);
|
||||
exit(1)
|
||||
}
|
||||
Err(e) => print_and_exit(&format!("ERROR ({}): {}", e.code(), e)),
|
||||
};
|
||||
|
||||
let macaroon =
|
||||
read_macaroon_from_args(args.macaroon_path, args.macaroon_hex, &args.network);
|
||||
let mut request = Request::new(PayOfferRequest {
|
||||
offer: offer.to_string(),
|
||||
amount,
|
||||
|
|
@ -246,7 +225,7 @@ async fn main() {
|
|||
fee_limit,
|
||||
fee_limit_percent,
|
||||
});
|
||||
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
|
||||
add_metadata(&mut request, macaroon);
|
||||
|
||||
match client.pay_offer(request).await {
|
||||
Ok(_) => println!("Successfully paid for offer!"),
|
||||
|
|
@ -260,43 +239,26 @@ async fn main() {
|
|||
response_invoice_timeout,
|
||||
} => {
|
||||
let tls = read_cert_from_args_or_exit(args.cert_pem, args.cert_path);
|
||||
let grpc_host = args.grpc_host;
|
||||
let grpc_port = args.grpc_port;
|
||||
let channel = Channel::from_shared(format!("{grpc_host}:{grpc_port}"))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to create endpoint {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.tls_config(tls)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to configure tls {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.connect()
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to connect {e:?}");
|
||||
exit(1)
|
||||
});
|
||||
let channel = create_grpc_channel(args.grpc_host, args.grpc_port, tls).await;
|
||||
let (mut client, macaroon) = create_authenticated_client(
|
||||
channel,
|
||||
args.macaroon_path,
|
||||
args.macaroon_hex,
|
||||
&args.network,
|
||||
);
|
||||
|
||||
let mut client = OffersClient::new(channel);
|
||||
let offer = match decode(offer_string.to_string()) {
|
||||
Ok(offer) => offer,
|
||||
Err(e) => {
|
||||
println!("ERROR ({}): {}", e.code(), e);
|
||||
exit(1)
|
||||
}
|
||||
Err(e) => print_and_exit(&format!("ERROR ({}): {}", e.code(), e)),
|
||||
};
|
||||
|
||||
let macaroon =
|
||||
read_macaroon_from_args(args.macaroon_path, args.macaroon_hex, &args.network);
|
||||
let mut request = Request::new(GetInvoiceRequest {
|
||||
offer: offer.to_string(),
|
||||
amount,
|
||||
payer_note,
|
||||
response_invoice_timeout,
|
||||
});
|
||||
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
|
||||
add_metadata(&mut request, macaroon);
|
||||
match client.get_invoice(request).await {
|
||||
Ok(response) => println!("Invoice: {:?}.", response.get_ref()),
|
||||
Err(err) => print_grpc_error(err),
|
||||
|
|
@ -309,35 +271,21 @@ async fn main() {
|
|||
fee_limit_percent,
|
||||
} => {
|
||||
let tls = read_cert_from_args_or_exit(args.cert_pem, args.cert_path);
|
||||
let grpc_host = args.grpc_host.clone();
|
||||
let grpc_port = args.grpc_port;
|
||||
let channel = Channel::from_shared(format!("{grpc_host}:{grpc_port}"))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to create endpoint {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.tls_config(tls)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to configure tls {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.connect()
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to connect {e:?}");
|
||||
exit(1)
|
||||
});
|
||||
let channel = create_grpc_channel(args.grpc_host, args.grpc_port, tls).await;
|
||||
let (mut client, macaroon) = create_authenticated_client(
|
||||
channel,
|
||||
args.macaroon_path,
|
||||
args.macaroon_hex,
|
||||
&args.network,
|
||||
);
|
||||
|
||||
let mut client = OffersClient::new(channel);
|
||||
let macaroon =
|
||||
read_macaroon_from_args(args.macaroon_path, args.macaroon_hex, &args.network);
|
||||
let mut request = Request::new(PayInvoiceRequest {
|
||||
invoice: invoice_string.to_owned(),
|
||||
amount,
|
||||
fee_limit,
|
||||
fee_limit_percent,
|
||||
});
|
||||
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
|
||||
add_metadata(&mut request, macaroon);
|
||||
match client.pay_invoice(request).await {
|
||||
Ok(_) => println!("Successfully paid for offer!"),
|
||||
Err(err) => print_grpc_error(err),
|
||||
|
|
@ -351,28 +299,14 @@ async fn main() {
|
|||
quantity,
|
||||
} => {
|
||||
let tls = read_cert_from_args_or_exit(args.cert_pem, args.cert_path);
|
||||
let grpc_host = args.grpc_host.clone();
|
||||
let grpc_port = args.grpc_port;
|
||||
let channel = Channel::from_shared(format!("{grpc_host}:{grpc_port}"))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to create endpoint {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.tls_config(tls)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to configure tls {e:?}");
|
||||
exit(1)
|
||||
})
|
||||
.connect()
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to connect {e:?}");
|
||||
exit(1)
|
||||
});
|
||||
let channel = create_grpc_channel(args.grpc_host, args.grpc_port, tls).await;
|
||||
let (mut client, macaroon) = create_authenticated_client(
|
||||
channel,
|
||||
args.macaroon_path,
|
||||
args.macaroon_hex,
|
||||
&args.network,
|
||||
);
|
||||
|
||||
let mut client = OffersClient::new(channel);
|
||||
let macaroon =
|
||||
read_macaroon_from_args(args.macaroon_path, args.macaroon_hex, &args.network);
|
||||
let mut request = Request::new(CreateOfferRequest {
|
||||
amount,
|
||||
quantity,
|
||||
|
|
@ -380,7 +314,7 @@ async fn main() {
|
|||
issuer,
|
||||
expiry,
|
||||
});
|
||||
add_metadata(&mut request, macaroon).unwrap_or_else(|_| exit(1));
|
||||
add_metadata(&mut request, macaroon);
|
||||
match client.create_offer(request).await {
|
||||
Ok(response) => println!("Offer: {:?}.", response.get_ref()),
|
||||
Err(err) => print_grpc_error(err),
|
||||
|
|
@ -389,13 +323,34 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_metadata<R>(request: &mut Request<R>, macaroon: String) -> Result<(), ()> {
|
||||
let macaroon = macaroon.parse().map_err(|e| {
|
||||
println!("ERROR: failed to parse provided macaroon string into tonic metadata {e:?}")
|
||||
})?;
|
||||
request.metadata_mut().insert("macaroon", macaroon);
|
||||
async fn create_grpc_channel(grpc_host: String, grpc_port: u16, tls: ClientTlsConfig) -> Channel {
|
||||
Channel::from_shared(format!("{grpc_host}:{grpc_port}"))
|
||||
.unwrap_or_else(|e| print_and_exit(&format!("ERROR: failed to create endpoint {e:?}")))
|
||||
.tls_config(tls)
|
||||
.unwrap_or_else(|e| print_and_exit(&format!("ERROR: failed to configure tls {e:?}")))
|
||||
.connect()
|
||||
.await
|
||||
.unwrap_or_else(|e| print_and_exit(&format!("ERROR: failed to connect {e:?}")))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
fn create_authenticated_client(
|
||||
channel: Channel,
|
||||
macaroon_path: Option<PathBuf>,
|
||||
macaroon_hex: Option<String>,
|
||||
network: &str,
|
||||
) -> (OffersClient<Channel>, String) {
|
||||
let client = OffersClient::new(channel);
|
||||
let macaroon = read_macaroon_from_args(macaroon_path, macaroon_hex, network);
|
||||
(client, macaroon)
|
||||
}
|
||||
|
||||
fn add_metadata<R>(request: &mut Request<R>, macaroon: String) {
|
||||
let macaroon = macaroon.parse().unwrap_or_else(|e| {
|
||||
print_and_exit(&format!(
|
||||
"ERROR: failed to parse provided macaroon string into tonic metadata {e:?}"
|
||||
))
|
||||
});
|
||||
request.metadata_mut().insert("macaroon", macaroon);
|
||||
}
|
||||
|
||||
fn read_macaroon_from_file(path: PathBuf) -> Result<String, std::io::Error> {
|
||||
|
|
@ -443,10 +398,7 @@ fn read_cert_from_args_or_exit(
|
|||
) -> ClientTlsConfig {
|
||||
match read_cert_from_args(cert_pem, cert_path) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
println!("{}", err);
|
||||
exit(1);
|
||||
}
|
||||
Err(err) => print_and_exit(&format!("ERROR: {}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -457,38 +409,34 @@ fn read_macaroon_from_args(
|
|||
) -> String {
|
||||
// Make sure both macaroon options are not set.
|
||||
if macaroon_path.is_some() && macaroon_hex.is_some() {
|
||||
println!("ERROR: Only one of `macaroon_path` or `macaroon_hex` should be set.");
|
||||
exit(1)
|
||||
print_and_exit("ERROR: Only one of `macaroon_path` or `macaroon_hex` should be set.");
|
||||
}
|
||||
|
||||
// Let's grab the macaroon string now. If neither macaroon_path nor macaroon_hex are
|
||||
// set, use the default macaroon path.
|
||||
match macaroon_path {
|
||||
Some(path) => read_macaroon_from_file(path.clone()).unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to read macaroon from file {e:?}");
|
||||
exit(1)
|
||||
print_and_exit(&format!("ERROR: failed to read macaroon from file {e:?}"))
|
||||
}),
|
||||
None => match &macaroon_hex {
|
||||
Some(macaroon) => macaroon.clone(),
|
||||
None => {
|
||||
let path = get_macaroon_path_default(network);
|
||||
read_macaroon_from_file(path).unwrap_or_else(|e| {
|
||||
println!("ERROR: failed to read macaroon from file {e:?}");
|
||||
exit(1)
|
||||
print_and_exit(&format!("ERROR: failed to read macaroon from file {e:?}"))
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn print_grpc_error(err: tonic::Status) {
|
||||
fn print_grpc_error(err: tonic::Status) -> ! {
|
||||
let details = err.get_error_details();
|
||||
if let Some(error_info) = details.error_info() {
|
||||
println!("ERROR ({}): {}", error_info.reason, err.message());
|
||||
print_and_exit(&format!("ERROR ({}): {}", error_info.reason, err.message()));
|
||||
} else {
|
||||
println!("ERROR: {}", err.message());
|
||||
print_and_exit(&format!("ERROR: {}", err.message()));
|
||||
}
|
||||
exit(1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue