1use anyhow::Result;
4use chrono::{TimeZone, Utc};
5use serde::{Deserialize, Deserializer};
6
7use super::LNBitsEndpoint;
8
9#[derive(Debug, Deserialize)]
11pub struct PaymentDetails {
12 pub status: String,
14 pub checking_id: String,
16 pub amount: i64,
18 pub fee: i64,
20 pub memo: String,
22 #[serde(deserialize_with = "deserialize_time")]
24 pub time: String,
25 #[serde(deserialize_with = "deserialize_time")]
27 pub created_at: String,
28 #[serde(deserialize_with = "deserialize_time")]
30 pub updated_at: String,
31 pub bolt11: String,
33 pub preimage: Option<String>,
35 pub payment_hash: String,
37 #[serde(deserialize_with = "deserialize_time")]
39 pub expiry: String,
40 pub extra: serde_json::Value,
42 pub wallet_id: String,
44}
45
46fn deserialize_time<'de, D>(deserializer: D) -> Result<String, D::Error>
49where
50 D: Deserializer<'de>,
51{
52 #[derive(Deserialize)]
53 #[serde(untagged)]
54 enum TimeValue {
55 Unix(u64),
56 String(String),
57 }
58
59 let time_value = TimeValue::deserialize(deserializer)?;
60
61 match time_value {
62 TimeValue::Unix(timestamp) => {
63 let datetime = Utc
65 .timestamp_opt(timestamp as i64, 0)
66 .single()
67 .ok_or_else(|| serde::de::Error::custom("Invalid timestamp"))?;
68
69 Ok(datetime.to_rfc3339())
71 }
72 TimeValue::String(s) => Ok(s),
73 }
74}
75
76#[derive(Debug, Deserialize)]
78pub struct Payment {
79 pub paid: bool,
81 pub preimage: Option<String>,
83 pub details: PaymentDetails,
85}
86
87impl crate::LNBitsClient {
88 pub async fn get_payment_info(&self, payment_hash: &str) -> Result<Payment> {
90 let body = self
91 .make_get(
92 LNBitsEndpoint::PaymentHash(payment_hash.to_string()),
93 crate::api::LNBitsRequestKey::Admin,
94 )
95 .await?;
96
97 let payment: Payment = serde_json::from_str(&body)?;
98
99 Ok(payment)
100 }
101}