upbit/api_deposit/
deposit_info.rs

1use reqwest::header::{ACCEPT, AUTHORIZATION};
2use reqwest::{Response, Url};
3
4use crate::request::RequestWithQuery;
5use crate::response::{TransactionInfo, TransactionInfoSource};
6
7use super::{
8    super::constant::{URL_DEPOSIT, URL_SERVER},
9    super::response::ResponseError,
10};
11
12impl TransactionInfo {
13    pub async fn get_deposit_info_by_currency(currency: &str) -> Result<Self, ResponseError> {
14        let res = Self::request_deposit_by_currency(currency).await?;
15        let res_serialized = res
16            .text()
17            .await
18            .map_err(crate::response::response_error_from_reqwest)?;
19
20        if res_serialized.contains("error") {
21            return Err(serde_json::from_str(&res_serialized)
22                .map(crate::response::response_error)
23                .ok()
24                .unwrap());
25        }
26
27        Self::deserialize_order_status_response(&res_serialized)
28    }
29
30    pub async fn get_deposit_info_by_uuid(uuid: &str) -> Result<Self, ResponseError> {
31        let res = Self::request_deposit_by_uuid(uuid).await?;
32        let res_serialized = res
33            .text()
34            .await
35            .map_err(crate::response::response_error_from_reqwest)?;
36
37        if res_serialized.contains("error") {
38            return Err(serde_json::from_str(&res_serialized)
39                .map(crate::response::response_error)
40                .ok()
41                .unwrap());
42        }
43
44        Self::deserialize_order_status_response(&res_serialized)
45    }
46
47    pub async fn get_deposit_info_by_txid(txid: &str) -> Result<Self, ResponseError> {
48        let res = Self::request_deposit_by_txid(txid).await?;
49        let res_serialized = res
50            .text()
51            .await
52            .map_err(crate::response::response_error_from_reqwest)?;
53
54        if res_serialized.contains("error") {
55            return Err(serde_json::from_str(&res_serialized)
56                .map(crate::response::response_error)
57                .ok()
58                .unwrap());
59        }
60
61        Self::deserialize_order_status_response(&res_serialized)
62    }
63
64    async fn request_deposit_by_currency(currency: &str) -> Result<Response, ResponseError> {
65        let mut url = Url::parse(&format!("{URL_SERVER}{URL_DEPOSIT}"))
66            .map_err(crate::response::response_error_internal_url_parse_error)?;
67
68        url.query_pairs_mut().append_pair("currency", currency);
69
70        let token_string = Self::set_token_with_query(url.as_str())?;
71
72        reqwest::Client::new()
73            .get(url.as_str())
74            .header(ACCEPT, "application/json")
75            .header(AUTHORIZATION, &token_string)
76            .send()
77            .await
78            .map_err(crate::response::response_error_from_reqwest)
79    }
80
81    async fn request_deposit_by_uuid(uuid: &str) -> Result<Response, ResponseError> {
82        let mut url = Url::parse(&format!("{URL_SERVER}{URL_DEPOSIT}"))
83            .map_err(crate::response::response_error_internal_url_parse_error)?;
84
85        url.query_pairs_mut().append_pair("uuid", uuid);
86
87        let token_string = Self::set_token_with_query(url.as_str())?;
88
89        reqwest::Client::new()
90            .get(url.as_str())
91            .header(ACCEPT, "application/json")
92            .header(AUTHORIZATION, &token_string)
93            .send()
94            .await
95            .map_err(crate::response::response_error_from_reqwest)
96    }
97
98    async fn request_deposit_by_txid(txid: &str) -> Result<Response, ResponseError> {
99        let mut url = Url::parse(&format!("{URL_SERVER}{URL_DEPOSIT}"))
100            .map_err(crate::response::response_error_internal_url_parse_error)?;
101
102        url.query_pairs_mut().append_pair("txid", txid);
103
104        let token_string = Self::set_token_with_query(url.as_str())?;
105
106        reqwest::Client::new()
107            .get(url.as_str())
108            .header(ACCEPT, "application/json")
109            .header(AUTHORIZATION, &token_string)
110            .send()
111            .await
112            .map_err(crate::response::response_error_from_reqwest)
113    }
114
115    fn deserialize_order_status_response(res_serialized: &str) -> Result<Self, ResponseError> {
116        serde_json::from_str(res_serialized)
117            .map(|x: TransactionInfoSource| Self {
118                r#type: x.r#type(),
119                uuid: x.uuid(),
120                currency: x.currency(),
121                net_type: x.net_type(),
122                txid: x.txid(),
123                state: x.state(),
124                created_at: x.created_at(),
125                done_at: x.done_at(),
126                amount: x.amount(),
127                fee: x.fee(),
128                transaction_type: x.transaction_type(),
129
130                holder: None,
131                bank: None,
132                fiat_amount: None,
133                memo: None,
134                fiat_currency: None,
135                confirmations: None,
136                krw_amount: None,
137                network_name: None,
138                cancelable: None,
139                blockchain_url: None,
140                state_i18n: None,
141                address: None,
142            })
143            .map_err(crate::response::response_error_from_json)
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use std::collections::{HashMap, HashSet};
150
151    use serde_json::Value;
152
153    use crate::response::TransactionInfo;
154
155    #[tokio::test]
156    async fn test_get_deposit_info_by_currency() {
157        crate::test_utils::setup_test_keys();
158
159        let res = TransactionInfo::request_deposit_by_currency("KRW")
160            .await
161            .unwrap();
162        let res_serialized = res
163            .text()
164            .await
165            .map_err(crate::response::response_error_from_reqwest)
166            .unwrap();
167
168        if res_serialized.contains("error") {
169            assert!(false, "Error response: {res_serialized}");
170        }
171
172        let json = serde_json::from_str::<Value>(&res_serialized).unwrap();
173        let expected_structure = serde_json::json!({
174            "type": "",
175            "uuid": "",
176            "currency": "",
177            "net_type": "",
178            "txid": "",
179            "state": "",
180            "created_at": "",
181            "done_at": "",
182            "amount": "",
183            "fee": "",
184            "transaction_type": ""
185        });
186
187        let expected_structure = expected_structure
188            .as_object()
189            .unwrap()
190            .iter()
191            .map(|(k, v)| (k.as_str(), v.clone()))
192            .collect::<HashMap<&str, Value>>();
193
194        let (missing_keys, extra_keys) = compare_keys(&json, &expected_structure, "");
195
196        if !missing_keys.is_empty() {
197            println!("[test_get_deposit_info] Missing keys: {missing_keys:?}");
198            assert!(false);
199        } else {
200            println!("[test_get_deposit_info] No keys are missing");
201        }
202
203        if !extra_keys.is_empty() {
204            println!("[test_get_deposit_info] Extra keys: {extra_keys:?}");
205            assert!(false);
206        } else {
207            println!("[test_get_deposit_info] No extra keys found.");
208        }
209
210        assert!(true);
211    }
212
213    fn compare_keys(
214        json: &Value,
215        expected: &HashMap<&str, Value>,
216        path: &str,
217    ) -> (Vec<String>, Vec<String>) {
218        let mut missing_keys = Vec::new();
219        let mut extra_keys = Vec::new();
220
221        if let Value::Object(map) = json {
222            let json_keys: HashSet<&str> = map.keys().map(|k| k.as_str()).collect();
223            let expected_keys: HashSet<&str> = expected.keys().cloned().collect();
224
225            for key in expected_keys.difference(&json_keys) {
226                missing_keys.push(format!("{path}{key}"));
227            }
228
229            for key in json_keys.difference(&expected_keys) {
230                extra_keys.push(format!("{path}{key}"));
231            }
232
233            for key in expected_keys.intersection(&json_keys) {
234                if let Some(expected_value) = expected.get(*key) {
235                    let new_path = format!("{}{}.", path, key);
236                    if let Value::Object(_) = expected_value {
237                        let expected_map = expected_value
238                            .as_object()
239                            .unwrap()
240                            .iter()
241                            .map(|(k, v)| (k.as_str(), v.clone()))
242                            .collect::<HashMap<&str, Value>>();
243                        let (mut missing, mut extra) =
244                            compare_keys(&map[*key], &expected_map, &new_path);
245                        missing_keys.append(&mut missing);
246                        extra_keys.append(&mut extra);
247                    }
248                }
249            }
250        }
251
252        (missing_keys, extra_keys)
253    }
254}