1use crate::{Mexc, PROD_API_URL};
2use reqwest::{StatusCode, Response};
3use anyhow::{anyhow, bail};
4use serde::Deserialize;
5use crate::utils::get_timestamp;
6
7use crate::utils::parse_string_to_f64;
8
9#[derive(Deserialize, Debug, Clone)]
10pub struct Account {
11 #[serde(rename = "accountType")]
12 pub account_type: String,
13 #[serde(rename = "canDeposit")]
14 pub can_deposit: bool,
15 #[serde(rename = "canTrade")]
16 pub can_trade: bool,
17 #[serde(rename = "canWithdraw")]
18 pub can_withdraw: bool,
19 pub permissions: Vec<String>,
20 pub balances: Vec<AccountBalance>
21}
22
23#[derive(Deserialize, Debug, Clone)]
24pub struct AccountBalance {
25 pub asset: String,
26 #[serde(deserialize_with = "parse_string_to_f64")]
27 pub free: f64,
28 #[serde(deserialize_with = "parse_string_to_f64")]
29 pub locked: f64
30}
31
32#[derive(Deserialize, Debug, Clone)]
33pub struct ListenKeyReponse {
34 #[serde(rename = "listenKey")]
35 pub listen_key: String
36}
37
38impl Mexc {
39
40 pub async fn get_signed(&self, url: &str) -> anyhow::Result<Response> {
41 let api_key = self.api_key.as_ref().ok_or_else(|| anyhow!("Missing api key"))?;
42
43 let resp = self.client
44 .get(url)
45 .header("X-MEXC-APIKEY", api_key)
46 .send().await?;
47 Ok(resp)
48 }
49
50 pub async fn get_account(&self) -> anyhow::Result<Account> {
51
52 let timestamp = get_timestamp();
53
54 let order_request = format!("timestamp={timestamp}");
55 let signed_order = self.sign_request(order_request)?;
56 let url = format!("{PROD_API_URL}/api/v3/account?{signed_order}");
57 let resp: Response = self.get_signed(&url).await?;
58
59 if resp.status() == StatusCode::OK {
60 let account: Account = resp.json().await?;
61 Ok(account)
62 } else {
63 let err = resp.text().await?;
64 bail!(err);
65 }
66 }
67
68 pub async fn get_listen_key(&self) -> anyhow::Result<String> {
69
70 let timestamp = get_timestamp();
71 let order_request = format!("timestamp={timestamp}");
72 let signed_order = self.sign_request(order_request)?;
73
74 let url = format!("{PROD_API_URL}/api/v3/userDataStream?{signed_order}");
75 let resp: Response = self.post_signed(&url).await?;
76
77 let keyresp: ListenKeyReponse = resp.json().await?;
78 Ok(keyresp.listen_key)
79 }
80
81 pub async fn keep_alive_listen_key(&self, listen_key: &str) -> anyhow::Result<String> {
82
83 let timestamp = get_timestamp();
84 let order_request = format!("listenKey={listen_key}×tamp={timestamp}");
85 let signed_order = self.sign_request(order_request)?;
86
87 let url = format!("{PROD_API_URL}/api/v3/userDataStream?{signed_order}");
88 let resp: Response = self.put_signed(&url).await?;
89
90 let keyresp: ListenKeyReponse = resp.json().await?;
91 Ok(keyresp.listen_key)
92 }
93
94 pub async fn delete_listen_key(&self, listen_key: &str) -> anyhow::Result<String> {
95
96 let timestamp = get_timestamp();
97 let order_request = format!("listenKey={listen_key}×tamp={timestamp}");
98 let signed_order = self.sign_request(order_request)?;
99
100 let url = format!("{PROD_API_URL}/api/v3/userDataStream?{signed_order}");
101 let resp: Response = self.delete_signed(&url).await?;
102
103 let keyresp: ListenKeyReponse = resp.json().await?;
104 Ok(keyresp.listen_key)
105 }
106}
107
108
109#[cfg(test)]
110mod tests {
111
112 use super::*;
113 use crate::utils::unlock_keys;
114
115 #[tokio::test]
116 pub async fn test_get_account() {
117 let (key, secret) = unlock_keys().unwrap();
118 let client = Mexc::new(Some(key),Some(secret),None).unwrap();
119
120 let acc = client.get_account().await.unwrap();
121 dbg!(acc);
122 }
123
124 #[tokio::test]
125 pub async fn test_get_listenkey() {
126 let (key, secret) = unlock_keys().unwrap();
127 let client = Mexc::new(Some(key),Some(secret),None).unwrap();
128
129 let key = client.get_listen_key().await.unwrap();
130 dbg!(key);
131 }
132
133 #[tokio::test]
134 pub async fn test_keep_alive() {
135 let (key, secret) = unlock_keys().unwrap();
136 let client = Mexc::new(Some(key),Some(secret),None).unwrap();
137
138 let listen_key = "enter key here";
139
140 let key = client.keep_alive_listen_key(&listen_key).await.unwrap();
141 dbg!(key);
142 }
143
144 #[tokio::test]
145 pub async fn test_delete_listen_key() {
146 let (key, secret) = unlock_keys().unwrap();
147 let client = Mexc::new(Some(key),Some(secret),None).unwrap();
148
149 let listen_key = "enter key here";
150
151 let key = client.delete_listen_key(&listen_key).await.unwrap();
152 dbg!(key);
153 }
154}