1use super::error::LunoErr;
2use crate::luno::client_builder::LunoClientBuilder;
3use crate::luno::error::ErrKind;
4use crate::luno::structs::{Account, Balance, OrderBook, Tickers};
5use reqwest::{Method, Url};
6use serde_json::from_str;
7use std::collections::HashMap;
8
9const DEFAULT_BASE_URL: &str = "https://api.luno.com";
10const GET_ACCOUNTS: &str = "/api/1/accounts";
11const GET_BALANCE: &str = "/api/1/balance";
12const GET_TICKER: &str = "/api/1/ticker";
13const GET_TICKERS: &str = "/api/1/tickers";
14const GET_ORDERBOOK: &str = "/api/1/orderbook";
15const GET_ORDERBOOK_TOP: &str = "/api/1/orderbook_top";
16
17pub type LunoResult<T> = Result<T, LunoErr>;
18
19#[derive(Debug, Clone)]
20pub struct Luno {
21 client: LunoClientBuilder,
22 pub base_url: String,
23 pub path: Option<Url>,
24 pub method: Method,
25 username: String,
26 password: String,
27}
28
29#[allow(unused)]
30impl Luno {
31 pub async fn init(api_key_id: String, api_key_secret: String) -> Self {
32 Self {
33 client: LunoClientBuilder::new().await,
34 base_url: DEFAULT_BASE_URL.to_string(), username: api_key_id, password: api_key_secret, path: None,
38 method: Method::GET,
39 }
40 }
41
42 pub async fn create_account(
43 &self,
44 account_name: String,
45 currency_name: String,
46 ) -> LunoResult<Account> {
47 let path = Url::parse(format! {"{}{}", self.base_url, GET_ACCOUNTS}.as_str())?;
48 let result = self
49 .client
50 .create_account_post(
51 path,
52 currency_name,
53 account_name,
54 &self.username,
55 Some(&self.password),
56 )
57 .await;
58
59 match result {
60 Ok(res) => {
61 let res = res.text().await;
62 match res {
63 Ok(e) => {
64 let e: Account = from_str(&e).unwrap();
65 Ok(e)
66 }
67 Err(err) => Err(LunoErr {
68 kind: ErrKind::ErrInvalidArguments,
69 message: err.to_string(),
70 }),
71 }
72 }
73 Err(err) => Err(LunoErr {
74 kind: ErrKind::ErrInvalidArguments,
75 message: err.message,
76 }),
77 }
78 }
79
80 pub async fn get_all_balance(&self) -> LunoResult<Vec<Balance>> {
81 let path = Url::parse(format! {"{}{}", self.base_url, GET_BALANCE}.as_str()).unwrap();
82 let result = self
83 .client
84 .get_request(path, &self.username, Some(&self.password))
85 .await;
86 match result {
87 Ok(res) => {
88 let res = res.text().await;
89 match res {
90 Ok(e) => {
91 let e: HashMap<String, Vec<_>> = from_str(&e).unwrap();
92 Ok(e.get("balance").unwrap().to_vec())
93 }
94 Err(err) => Err(LunoErr {
95 kind: ErrKind::ErrInvalidArguments,
96 message: err.to_string(),
97 }),
98 }
99 }
100 Err(err) => Err(LunoErr {
101 kind: ErrKind::ErrInvalidArguments,
102 message: err.message,
103 }),
104 }
105 }
106
107 pub async fn get_ticker(&self, pair: &String) -> LunoResult<Tickers> {
108 let path = Url::parse(format! {"{}{}", self.base_url, GET_TICKER}.as_str())?;
109 let result = self
110 .client
111 .get_request_with_params(
112 path,
113 (&"pair".to_string(), pair),
114 &self.username,
115 Some(&self.password),
116 )
117 .await;
118
119 match result {
120 Ok(res) => {
121 let res = res.text().await;
122 match res {
123 Ok(e) => {
124 let e: Tickers = from_str(&e).unwrap();
125 Ok(e)
126 }
127 Err(err) => Err(LunoErr {
128 kind: ErrKind::ErrInvalidArguments,
129 message: err.to_string(),
130 }),
131 }
132 }
133 Err(err) => Err(err),
134 }
135 }
136
137 pub async fn get_all_tickers(&self) -> LunoResult<Vec<Tickers>> {
138 let path = Url::parse(format! {"{}{}", self.base_url, GET_TICKERS}.as_str())?;
139 let result = self
140 .client
141 .get_request(path, &self.username, Some(&self.password))
142 .await;
143
144 match result {
145 Ok(res) => {
146 let res = res.text().await;
147 match res {
148 Ok(res) => {
149 let res: HashMap<String, Vec<Tickers>> = from_str(&res)?;
150 Ok(res.get("tickers").unwrap().to_vec())
151 }
152 Err(err) => Err(LunoErr {
153 kind: ErrKind::ErrInvalidArguments,
154 message: err.to_string(),
155 }),
156 }
157 }
158 Err(err) => Err(err),
159 }
160 }
161
162 pub async fn get_full_order_book(&self, pair: &String) -> LunoResult<OrderBook> {
163 let path = Url::parse(format! {"{}{}", self.base_url, GET_ORDERBOOK}.as_str())?;
164 let result = self
165 .client
166 .get_request_with_params(
167 path,
168 (&"pair".to_string(), pair),
169 &self.username,
170 Some(&self.password),
171 )
172 .await;
173
174 match result {
175 Ok(res) => {
176 let res = res.text().await;
177 match res {
178 Ok(e) => {
179 let e: OrderBook = from_str(&e).unwrap();
180 Ok(e)
181 }
182 Err(err) => Err(LunoErr {
183 kind: ErrKind::ErrInvalidArguments,
184 message: err.to_string(),
185 }),
186 }
187 }
188 Err(err) => Err(err),
189 }
190 }
191
192 pub async fn get_top_order_book(&self, pair: &String) -> LunoResult<OrderBook> {
193 let path = Url::parse(format! {"{}{}", self.base_url, GET_ORDERBOOK_TOP}.as_str())?;
194 let result = self
195 .client
196 .get_request_with_params(
197 path,
198 (&"pair".to_string(), pair),
199 &self.username,
200 Some(&self.password),
201 )
202 .await;
203
204 match result {
205 Ok(res) => {
206 let res = res.text().await;
207 match res {
208 Ok(e) => {
209 let e: OrderBook = from_str(&e).unwrap();
210 Ok(e)
211 }
212 Err(err) => Err(LunoErr {
213 kind: ErrKind::ErrInvalidArguments,
214 message: err.to_string(),
215 }),
216 }
217 }
218 Err(err) => Err(err),
219 }
220 }
221
222 pub async fn get_recent_trades(&self, timestamp: String, pair: String) {
223 todo!()
224 }
225}