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