1use crate::channel::ChannelResponse;
2use crate::pay::PayResponse;
3use crate::withdraw::WithdrawalResponse;
4use crate::Error as LnUrlError;
5use serde::de::Error;
6use serde::{Deserialize, Serialize};
7use std::fmt::Display;
8use std::str::FromStr;
9
10pub fn decode_ln_url_response(string: &str) -> Result<LnUrlResponse, LnUrlError> {
11 let json: serde_json::Value = serde_json::from_str(string)?;
12 decode_ln_url_response_from_json(json)
13}
14
15pub fn decode_ln_url_response_from_json(
16 json: serde_json::Value,
17) -> Result<LnUrlResponse, LnUrlError> {
18 let obj = json.as_object().ok_or(LnUrlError::InvalidResponse)?;
19 let tag_str = obj
20 .get("tag")
21 .and_then(|v| v.as_str())
22 .ok_or(LnUrlError::InvalidResponse)?;
23
24 let tag = Tag::from_str(tag_str)?;
25 match tag {
26 Tag::PayRequest => {
27 let pay_response: PayResponse = serde_json::from_value(json)?;
28 Ok(LnUrlResponse::LnUrlPayResponse(pay_response))
29 }
30 Tag::WithdrawRequest => {
31 let resp: WithdrawalResponse = serde_json::from_value(json)?;
32 Ok(LnUrlResponse::LnUrlWithdrawResponse(resp))
33 }
34 Tag::ChannelRequest => {
35 let resp: ChannelResponse = serde_json::from_value(json)?;
36 Ok(LnUrlResponse::LnUrlChannelResponse(resp))
37 }
38 }
39}
40
41#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
42pub enum LnUrlResponse {
43 LnUrlPayResponse(PayResponse),
44 LnUrlWithdrawResponse(WithdrawalResponse),
45 LnUrlChannelResponse(ChannelResponse),
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
49pub enum Tag {
50 #[serde(rename = "payRequest")]
51 PayRequest,
52 #[serde(rename = "withdrawRequest")]
53 WithdrawRequest,
54 #[serde(rename = "channelRequest")]
55 ChannelRequest,
56}
57
58impl Display for Tag {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 match self {
61 Tag::PayRequest => write!(f, "payRequest"),
62 Tag::WithdrawRequest => write!(f, "withdrawRequest"),
63 Tag::ChannelRequest => write!(f, "channelRequest"),
64 }
65 }
66}
67
68impl FromStr for Tag {
69 type Err = serde_json::Error;
70
71 fn from_str(s: &str) -> Result<Self, Self::Err> {
72 match s {
73 "payRequest" => Ok(Tag::PayRequest),
74 "withdrawRequest" => Ok(Tag::WithdrawRequest),
75 "channelRequest" => Ok(Tag::ChannelRequest),
76 _ => Err(serde_json::Error::custom("Unknown tag")),
77 }
78 }
79}
80
81#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
84#[serde(tag = "status")]
85pub enum Response<T> {
86 #[serde(rename = "ERROR")]
87 Error { reason: String },
88 #[serde(rename = "OK")]
89 Ok(T),
90}
91
92#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
93pub struct EventResponse {
94 pub event: Option<String>,
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn response_from_str() {
103 let tests = vec![
104 (
105 r#"{"status":"ERROR","reason":"error detail..."}"#,
106 Response::Error {
107 reason: "error detail...".to_string(),
108 },
109 ),
110 (
111 r#"{"status":"OK","event":"LOGGEDIN"}"#,
112 Response::<EventResponse>::Ok(EventResponse {
113 event: Some("LOGGEDIN".to_string()),
114 }),
115 ),
116 ];
117
118 for test in tests {
119 let resp: Response<_> = serde_json::from_str(test.0).unwrap();
120 assert_eq!(resp, test.1);
121 }
122 }
123 #[test]
124 fn response_to_str() {
125 let tests = vec![
126 (
127 r#"{"status":"ERROR","reason":"error detail..."}"#,
128 Response::Error {
129 reason: "error detail...".to_string(),
130 },
131 ),
132 (
133 r#"{"status":"OK","event":"LOGGEDIN"}"#,
134 Response::<EventResponse>::Ok(EventResponse {
135 event: Some("LOGGEDIN".to_string()),
136 }),
137 ),
138 ];
139
140 for test in tests {
141 let json = serde_json::to_string(&test.1).unwrap();
142 assert_eq!(json, test.0);
143 }
144 }
145}