Ver código fonte

Update ln-bits to support v1 api (#802)

* feat: v1 websockets

* chore: update lnbits dep
thesimplekid 1 semana atrás
pai
commit
a335b269b7

+ 1 - 1
crates/cdk-lnbits/Cargo.toml

@@ -21,5 +21,5 @@ tokio.workspace = true
 tokio-util.workspace = true
 tracing.workspace = true
 thiserror.workspace = true
-lnbits-rs = "0.5.0"
+lnbits-rs = "0.6.0"
 serde_json.workspace = true

+ 60 - 61
crates/cdk-lnbits/src/lib.rs

@@ -23,12 +23,10 @@ use cdk_common::payment::{
 use cdk_common::util::unix_time;
 use cdk_common::{mint, Bolt11Invoice};
 use error::Error;
-use futures::stream::StreamExt;
 use futures::Stream;
 use lnbits_rs::api::invoice::CreateInvoiceRequest;
 use lnbits_rs::LNBitsClient;
 use serde_json::Value;
-use tokio::sync::Mutex;
 use tokio_util::sync::CancellationToken;
 
 pub mod error;
@@ -38,8 +36,7 @@ pub mod error;
 pub struct LNbits {
     lnbits_api: LNBitsClient,
     fee_reserve: FeeReserve,
-    receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
-    webhook_url: String,
+    webhook_url: Option<String>,
     wait_invoice_cancel_token: CancellationToken,
     wait_invoice_is_active: Arc<AtomicBool>,
     settings: Bolt11Settings,
@@ -53,14 +50,12 @@ impl LNbits {
         invoice_api_key: String,
         api_url: String,
         fee_reserve: FeeReserve,
-        receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
-        webhook_url: String,
+        webhook_url: Option<String>,
     ) -> Result<Self, Error> {
         let lnbits_api = LNBitsClient::new("", &admin_api_key, &invoice_api_key, &api_url, None)?;
 
         Ok(Self {
             lnbits_api,
-            receiver,
             fee_reserve,
             webhook_url,
             wait_invoice_cancel_token: CancellationToken::new(),
@@ -73,6 +68,17 @@ impl LNbits {
             },
         })
     }
+
+    /// Subscribe to lnbits ws
+    pub async fn subscribe_ws(&self) -> Result<(), Error> {
+        self.lnbits_api
+            .subscribe_to_websocket()
+            .await
+            .map_err(|err| {
+                tracing::error!("Could not subscribe to lnbits ws");
+                Error::Anyhow(err)
+            })
+    }
 }
 
 #[async_trait]
@@ -94,61 +100,50 @@ impl MintPayment for LNbits {
     async fn wait_any_incoming_payment(
         &self,
     ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> {
-        let receiver = self
-            .receiver
-            .lock()
-            .await
-            .take()
-            .ok_or(anyhow!("No receiver"))?;
-
-        let lnbits_api = self.lnbits_api.clone();
-
+        let api = self.lnbits_api.clone();
         let cancel_token = self.wait_invoice_cancel_token.clone();
+        let is_active = Arc::clone(&self.wait_invoice_is_active);
 
-        Ok(futures::stream::unfold(
-            (
-                receiver,
-                lnbits_api,
-                cancel_token,
-                Arc::clone(&self.wait_invoice_is_active),
-            ),
-            |(mut receiver, lnbits_api, cancel_token, is_active)| async move {
+        Ok(Box::pin(futures::stream::unfold(
+            (api, cancel_token, is_active),
+            |(api, cancel_token, is_active)| async move {
                 is_active.store(true, Ordering::SeqCst);
 
+                let receiver = api.receiver();
+                let mut receiver = receiver.lock().await;
+
                 tokio::select! {
                     _ = cancel_token.cancelled() => {
                         // Stream is cancelled
                         is_active.store(false, Ordering::SeqCst);
-                        tracing::info!("Waiting for phonixd invoice ending");
+                        tracing::info!("Waiting for lnbits invoice ending");
                         None
                     }
                     msg_option = receiver.recv() => {
-                    match msg_option {
-                        Some(msg) => {
-                            let check = lnbits_api.is_invoice_paid(&msg).await;
-
-                            match check {
-                                Ok(state) => {
-                                    if state {
-                                        Some((msg, (receiver, lnbits_api, cancel_token, is_active)))
-                                    } else {
-                                        None
+                        match msg_option {
+                            Some(msg) => {
+                                let check = api.is_invoice_paid(&msg).await;
+
+                                match check {
+                                    Ok(state) => {
+                                        if state {
+                                            Some((msg, (api, cancel_token, is_active)))
+                                        } else {
+                                            Some(("".to_string(), (api, cancel_token, is_active)))
+                                        }
                                     }
+                                    _ => Some(("".to_string(), (api, cancel_token, is_active))),
                                 }
-                                _ => None,
                             }
+                            None => {
+                                is_active.store(false, Ordering::SeqCst);
+                                None
+                            },
                         }
-                        None => {
-                            is_active.store(true, Ordering::SeqCst);
-                            None
-                        },
-                    }
-
                     }
                 }
             },
-        )
-        .boxed())
+        )))
     }
 
     async fn get_payment_quote(
@@ -211,7 +206,7 @@ impl MintPayment for LNbits {
 
         let invoice_info = self
             .lnbits_api
-            .find_invoice(&pay_response.payment_hash)
+            .get_payment_info(&pay_response.payment_hash)
             .await
             .map_err(|err| {
                 tracing::error!("Could not find invoice");
@@ -219,22 +214,23 @@ impl MintPayment for LNbits {
                 Self::Err::Anyhow(anyhow!("Could not find invoice"))
             })?;
 
-        let status = match invoice_info.pending {
-            true => MeltQuoteState::Unpaid,
-            false => MeltQuoteState::Paid,
+        let status = match invoice_info.paid {
+            true => MeltQuoteState::Paid,
+            false => MeltQuoteState::Unpaid,
         };
 
         let total_spent = Amount::from(
             (invoice_info
+                .details
                 .amount
-                .checked_add(invoice_info.fee)
+                .checked_add(invoice_info.details.fee)
                 .ok_or(Error::AmountOverflow)?)
             .unsigned_abs(),
         );
 
         Ok(MakePaymentResponse {
             payment_lookup_id: pay_response.payment_hash,
-            payment_proof: Some(invoice_info.payment_hash),
+            payment_proof: invoice_info.details.preimage,
             status,
             total_spent,
             unit: CurrencyUnit::Sat,
@@ -261,7 +257,7 @@ impl MintPayment for LNbits {
             memo: Some(description),
             unit: unit.to_string(),
             expiry,
-            webhook: Some(self.webhook_url.clone()),
+            webhook: self.webhook_url.clone(),
             internal: None,
             out: false,
         };
@@ -283,7 +279,7 @@ impl MintPayment for LNbits {
         let expiry = request.expires_at().map(|t| t.as_secs());
 
         Ok(CreateIncomingPaymentResponse {
-            request_lookup_id: create_invoice_response.payment_hash,
+            request_lookup_id: create_invoice_response.payment_hash().to_string(),
             request: request.to_string(),
             expiry,
         })
@@ -327,7 +323,7 @@ impl MintPayment for LNbits {
 
         let pay_response = MakePaymentResponse {
             payment_lookup_id: payment.details.payment_hash,
-            payment_proof: Some(payment.preimage),
+            payment_proof: payment.preimage,
             status: lnbits_to_melt_status(&payment.details.status, payment.details.pending),
             total_spent: Amount::from(
                 payment.details.amount.unsigned_abs()
@@ -340,12 +336,16 @@ impl MintPayment for LNbits {
     }
 }
 
-fn lnbits_to_melt_status(status: &str, pending: bool) -> MeltQuoteState {
-    match (status, pending) {
-        ("success", false) => MeltQuoteState::Paid,
-        ("failed", false) => MeltQuoteState::Unpaid,
-        (_, false) => MeltQuoteState::Unknown,
-        (_, true) => MeltQuoteState::Pending,
+fn lnbits_to_melt_status(status: &str, pending: Option<bool>) -> MeltQuoteState {
+    if pending.unwrap_or_default() {
+        return MeltQuoteState::Pending;
+    }
+
+    match status {
+        "success" => MeltQuoteState::Paid,
+        "failed" => MeltQuoteState::Unpaid,
+        "pending" => MeltQuoteState::Pending,
+        _ => MeltQuoteState::Unknown,
     }
 }
 
@@ -354,10 +354,9 @@ impl LNbits {
     pub async fn create_invoice_webhook_router(
         &self,
         webhook_endpoint: &str,
-        sender: tokio::sync::mpsc::Sender<String>,
     ) -> anyhow::Result<Router> {
         self.lnbits_api
-            .create_invoice_webhook_router(webhook_endpoint, sender)
+            .create_invoice_webhook_router(webhook_endpoint)
             .await
     }
 }

+ 2 - 2
crates/cdk-mintd/example.config.toml

@@ -58,8 +58,8 @@ reserve_fee_min = 4
 # admin_api_key = ""
 # invoice_api_key = ""
 # lnbits_api = ""
-# fee_percent=0.04
-# reserve_fee_min=4
+# To be set true to support pre v1 lnbits api
+# retro_api=false
 
 # [lnd]
 # address = "https://domain:port"

+ 1 - 0
crates/cdk-mintd/src/config.rs

@@ -118,6 +118,7 @@ pub struct LNbits {
     pub lnbits_api: String,
     pub fee_percent: f32,
     pub reserve_fee_min: Amount,
+    pub retro_api: bool,
 }
 
 #[cfg(feature = "cln")]

+ 29 - 15
crates/cdk-mintd/src/setup.rs

@@ -2,8 +2,6 @@
 use std::collections::HashMap;
 #[cfg(feature = "fakewallet")]
 use std::collections::HashSet;
-#[cfg(feature = "lnbits")]
-use std::sync::Arc;
 
 #[cfg(feature = "cln")]
 use anyhow::anyhow;
@@ -22,8 +20,6 @@ use cdk::nuts::CurrencyUnit;
     feature = "fakewallet"
 ))]
 use cdk::types::FeeReserve;
-#[cfg(feature = "lnbits")]
-use tokio::sync::Mutex;
 
 use crate::config::{self, Settings};
 #[cfg(feature = "cln")]
@@ -79,32 +75,50 @@ impl LnBackendSetup for config::LNbits {
         let invoice_api_key = &self.invoice_api_key;
 
         // Channel used for lnbits web hook
-        let (sender, receiver) = tokio::sync::mpsc::channel(8);
         let webhook_endpoint = "/webhook/lnbits/sat/invoice";
 
-        let mint_url: MintUrl = settings.info.url.parse()?;
-        let webhook_url = mint_url.join(webhook_endpoint)?;
-
         let fee_reserve = FeeReserve {
             min_fee_reserve: self.reserve_fee_min,
             percent_fee_reserve: self.fee_percent,
         };
 
+        let webhook_url = if settings
+            .lnbits
+            .as_ref()
+            .expect("Lnbits must be defined")
+            .retro_api
+        {
+            let mint_url: MintUrl = settings.info.url.parse()?;
+            let webhook_url = mint_url.join(webhook_endpoint)?;
+
+            Some(webhook_url.to_string())
+        } else {
+            None
+        };
+
         let lnbits = cdk_lnbits::LNbits::new(
             admin_api_key.clone(),
             invoice_api_key.clone(),
             self.lnbits_api.clone(),
             fee_reserve,
-            Arc::new(Mutex::new(Some(receiver))),
-            webhook_url.to_string(),
+            webhook_url,
         )
         .await?;
 
-        let router = lnbits
-            .create_invoice_webhook_router(webhook_endpoint, sender)
-            .await?;
-
-        routers.push(router);
+        if settings
+            .lnbits
+            .as_ref()
+            .expect("Lnbits must be defined")
+            .retro_api
+        {
+            let router = lnbits
+                .create_invoice_webhook_router(webhook_endpoint)
+                .await?;
+
+            routers.push(router);
+        } else {
+            lnbits.subscribe_ws().await?;
+        };
 
         Ok(lnbits)
     }