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 {
86 #[serde(rename = "ERROR")]
87 Error { reason: String },
88 #[serde(rename = "OK")]
89 Ok { event: Option<String> },
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn response_from_str() {
98 let tests = vec![
99 (
100 r#"{"status":"ERROR","reason":"error detail..."}"#,
101 Response::Error {
102 reason: "error detail...".to_string(),
103 },
104 ),
105 (
106 r#"{"status":"OK","event":"LOGGEDIN"}"#,
107 Response::Ok {
108 event: Some("LOGGEDIN".to_string()),
109 },
110 ),
111 ];
112
113 for test in tests {
114 let resp: Response = serde_json::from_str(test.0).unwrap();
115 assert_eq!(resp, test.1);
116 }
117 }
118 #[test]
119 fn response_to_str() {
120 let tests = vec![
121 (
122 r#"{"status":"ERROR","reason":"error detail..."}"#,
123 Response::Error {
124 reason: "error detail...".to_string(),
125 },
126 ),
127 (
128 r#"{"status":"OK","event":"LOGGEDIN"}"#,
129 Response::Ok {
130 event: Some("LOGGEDIN".to_string()),
131 },
132 ),
133 ];
134
135 for test in tests {
136 let json = serde_json::to_string(&test.1).unwrap();
137 assert_eq!(json, test.0);
138 }
139 }
140}