use core::net::SocketAddr;
use std::fs;
use base64::{Engine, engine::general_purpose};
use reqwest::{Certificate, Client};
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::error::KoerierError;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct Lnd {
pub(crate) rest_host: SocketAddr,
pub(crate) tls_cert_path: String,
pub(crate) invoice_macaroon_path: String,
pub(crate) min_invoice_amount: u64,
pub(crate) max_invoice_amount: u64,
pub(crate) invoice_expiry_sec: u32,
}
impl Lnd {
pub(crate) fn create_client(&self) -> Result<Client, KoerierError> {
let cert: Vec<u8> = fs::read(&self.tls_cert_path)?;
let cert: Certificate = Certificate::from_pem(&cert)?;
let client: Client = Client::builder().add_root_certificate(cert).build()?;
Ok(client)
}
pub(crate) fn hex_encoded_macaroon(&self) -> Result<String, KoerierError> {
let invoice_macaroon = fs::read(&self.invoice_macaroon_path)?;
let invoice_macaroon = hex::encode(invoice_macaroon);
Ok(invoice_macaroon)
}
pub(crate) async fn fetch_invoice(
&self,
client: Client,
value: usize,
description_hash: Vec<u8>,
) -> Result<String, KoerierError> {
let request_body = json!({
"value": value,
"description_hash": general_purpose::STANDARD.encode(&description_hash),
"expiry": &self.invoice_expiry_sec,
"private": false,
});
let url_invoices = format!("https://{}/v1/invoices", &self.rest_host);
let response = client
.post(url_invoices)
.header("Grpc-Metadata-macaroon", self.hex_encoded_macaroon()?)
.json(&request_body)
.send()
.await?;
let body: serde_json::Value = response.json().await?;
if let Some(payment_request) = body.get("payment_request") {
Ok(payment_request.as_str().unwrap().to_string())
} else {
Err(KoerierError::Lnd(
"No `payment_request` in LND's response".to_string(),
))
}
}
}