lnbits_rs/api/
webhook.rs

1//! Webhook
2
3use axum::extract::State;
4use axum::http::StatusCode;
5use axum::routing::post;
6use axum::{Json, Router};
7use serde::Deserialize;
8use serde_json::Value;
9
10use crate::LNBitsClient;
11
12/// Webhook state
13#[derive(Debug, Clone)]
14pub struct WebhookState {
15    /// Sender
16    pub sender: tokio::sync::mpsc::Sender<String>,
17}
18
19impl LNBitsClient {
20    /// Create invoice webhook
21    pub async fn create_invoice_webhook_router(
22        &self,
23        webhook_endpoint: &str,
24    ) -> anyhow::Result<Router> {
25        let state = WebhookState {
26            sender: self.sender.clone(),
27        };
28
29        let router = Router::new()
30            .route(webhook_endpoint, post(handle_invoice))
31            .with_state(state);
32
33        Ok(router)
34    }
35}
36
37/// Webhook request
38#[derive(Debug, Clone, PartialEq, Deserialize)]
39pub struct WebhookRequest {
40    /// Checking id
41    pub checking_id: String,
42}
43
44async fn handle_invoice(
45    State(state): State<WebhookState>,
46    Json(payload): Json<Value>,
47) -> Result<StatusCode, StatusCode> {
48    let webhook_response: WebhookRequest =
49        serde_json::from_value(payload.clone()).map_err(|_err| {
50            log::warn!("Got an invalid payload on webhook");
51            log::debug!("Value: {}", payload);
52
53            StatusCode::UNPROCESSABLE_ENTITY
54        })?;
55
56    log::debug!(
57        "Received webhook update for: {}",
58        webhook_response.checking_id
59    );
60
61    if let Err(err) = state.sender.send(webhook_response.checking_id).await {
62        log::warn!("Could not send on channel: {}", err);
63    }
64
65    Ok(StatusCode::OK)
66}