1use 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#[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 ) -> 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#[derive(Debug, Clone, PartialEq, Deserialize)]
39pub struct WebhookRequest {
40 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}