1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use generic_api_client::{http::{self, *}, websocket::*};
4use serde::Serialize;
5use traits::*;
6
7pub use generic_api_client;
8pub use exchanges::*;
9
10mod exchanges;
11pub mod traits;
12
13macro_rules! request_return_type {
15 ($lt:lifetime, $Response:ty, $Options:ty, $Body:ty) => {
16 Result<
17 <<$Options as HttpOption<$lt, $Response, $Body>>::RequestHandler as RequestHandler<$Body>>::Successful,
18 RequestError<
19 <<$Options as HttpOption<$lt, $Response, $Body>>::RequestHandler as RequestHandler<$Body>>::BuildError,
20 <<$Options as HttpOption<$lt, $Response, $Body>>::RequestHandler as RequestHandler<$Body>>::Unsuccessful,
21 >,
22 >
23 };
24}
25
26#[derive(Default, Debug, Clone)]
27pub struct Client {
28 client: http::Client,
29 #[cfg(feature = "binance")]
30 binance: binance::BinanceOptions,
31 #[cfg(feature = "bitflyer")]
32 bitflyer: bitflyer::BitFlyerOptions,
33 #[cfg(feature = "bybit")]
34 bybit: bybit::BybitOptions,
35 #[cfg(feature = "coincheck")]
36 coincheck: coincheck::CoincheckOptions,
37}
38
39impl Client {
40 pub fn new() -> Self {
42 Self::default()
43 }
44
45 #[inline(always)]
47 pub fn update_default_option<O>(&mut self, option: O)
48 where
49 O: HandlerOption,
50 Self: GetOptions<O::Options>,
51 {
52 self.default_options_mut().update(option);
53 }
54
55 #[inline]
56 fn merged_options<O>(&self, options: impl IntoIterator<Item=O>) -> O::Options
57 where
58 O: HandlerOption,
59 Self:GetOptions<O::Options>,
60 {
61 let mut default_options = self.default_options().clone();
62 for option in options {
63 default_options.update(option);
64 }
65 default_options
66 }
67
68 #[inline(always)]
70 pub async fn request<'a, R, O, Q, B>(&self, method: Method, url: &str, query: Option<&Q>, body: Option<B>, options: impl IntoIterator<Item=O>)
71 -> request_return_type!('a, R, O, B)
72 where
73 O: HttpOption<'a, R, B>,
74 O::RequestHandler: RequestHandler<B>,
75 Self: GetOptions<O::Options>,
76 Q: Serialize + ?Sized,
77 {
78 self.client.request(method, url, query, body, &O::request_handler(self.merged_options(options))).await
79 }
80
81 #[inline(always)]
83 pub async fn get<'a, R, O, Q>(&self, url: &str, query: Option<&Q>, options: impl IntoIterator<Item=O>) -> request_return_type!('a, R, O, ())
84 where
85 O: HttpOption<'a, R, ()>,
86 O::RequestHandler: RequestHandler<()>,
87 Self: GetOptions<O::Options>,
88 Q: Serialize + ?Sized,
89 {
90 self.client.get(url, query, &O::request_handler(self.merged_options(options))).await
91 }
92
93 #[inline(always)]
95 pub async fn get_no_query<'a, R, O>(&self, url: &str, options: impl IntoIterator<Item=O>) -> request_return_type!('a, R, O, ())
96 where
97 O: HttpOption<'a, R, ()>,
98 O::RequestHandler: RequestHandler<()>,
99 Self: GetOptions<O::Options>,
100 {
101 self.client.get_no_query(url, &O::request_handler(self.merged_options(options))).await
102 }
103
104 #[inline(always)]
106 pub async fn post<'a, R, O, B>(&self, url: &str, body: Option<B>, options: impl IntoIterator<Item=O>)
107 -> request_return_type!('a, R, O, B)
108 where
109 O: HttpOption<'a, R, B>,
110 O::RequestHandler: RequestHandler<B>,
111 Self: GetOptions<O::Options>,
112 {
113 self.client.post(url, body, &O::request_handler(self.merged_options(options))).await
114 }
115
116 #[inline(always)]
118 pub async fn post_no_body<'a, R, O>(&self, url: &str, options: impl IntoIterator<Item=O>)
119 -> request_return_type!('a, R, O, ())
120 where
121 O: HttpOption<'a, R, ()>,
122 O::RequestHandler: RequestHandler<()>,
123 Self: GetOptions<O::Options>,
124 {
125 self.client.post_no_body(url, &O::request_handler(self.merged_options(options))).await
126 }
127
128 #[inline(always)]
130 pub async fn put<'a, R, O, B>(&self, url: &str, body: Option<B>, options: impl IntoIterator<Item=O>)
131 -> request_return_type!('a, R, O, B)
132 where
133 O: HttpOption<'a, R, B>,
134 O::RequestHandler: RequestHandler<B>,
135 Self: GetOptions<O::Options>,
136 {
137 self.client.put(url, body, &O::request_handler(self.merged_options(options))).await
138 }
139
140 #[inline(always)]
142 pub async fn put_no_body<'a, R, O>(&self, url: &str, options: impl IntoIterator<Item=O>)
143 -> request_return_type!('a, R, O, ())
144 where
145 O: HttpOption<'a, R, ()>,
146 O::RequestHandler: RequestHandler<()>,
147 Self: GetOptions<O::Options>,
148 {
149 self.client.put_no_body(url, &O::request_handler(self.merged_options(options))).await
150 }
151
152 #[inline(always)]
154 pub async fn delete<'a, R, O, Q>(&self, url: &str, query: Option<&Q>, options: impl IntoIterator<Item=O>) -> request_return_type!('a, R, O, ())
155 where
156 O: HttpOption<'a, R, ()>,
157 O::RequestHandler: RequestHandler<()>,
158 Self: GetOptions<O::Options>,
159 Q: Serialize + ?Sized,
160 {
161 self.client.delete(url, query, &O::request_handler(self.merged_options(options))).await
162 }
163
164 #[inline(always)]
166 pub async fn delete_no_query<'a, R, O>(&self, url: &str, options: impl IntoIterator<Item=O>) -> request_return_type!('a, R, O, ())
167 where
168 O: HttpOption<'a, R, ()>,
169 O::RequestHandler: RequestHandler<()>,
170 Self: GetOptions<O::Options>,
171 {
172 self.client.delete_no_query(url, &O::request_handler(self.merged_options(options))).await
173 }
174
175 #[inline(always)]
176 pub async fn websocket<O, H>(&self, url: &str, handler: H, options: impl IntoIterator<Item=O>) -> Result<WebSocketConnection<O::WebSocketHandler>, TungsteniteError>
177 where
178 O: WebSocketOption<H>,
179 O::WebSocketHandler: WebSocketHandler,
180 Self: GetOptions<O::Options>,
181 {
182 WebSocketConnection::new(url, O::websocket_handler(handler, self.merged_options(options))).await
183 }
184}
185
186pub trait GetOptions<O: HandlerOptions> {
187 fn default_options(&self) -> &O;
188 fn default_options_mut(&mut self) -> &mut O;
189}
190
191#[cfg(feature = "binance")]
192#[cfg_attr(docsrs, doc(cfg(feature = "binance")))]
193impl GetOptions<binance::BinanceOptions> for Client {
194 #[inline(always)]
195 fn default_options(&self) -> &binance::BinanceOptions {
196 &self.binance
197 }
198
199 #[inline(always)]
200 fn default_options_mut(&mut self) -> &mut binance::BinanceOptions {
201 &mut self.binance
202 }
203}
204
205#[cfg(feature = "bitflyer")]
206#[cfg_attr(docsrs, doc(cfg(feature = "bitflyer")))]
207impl GetOptions<bitflyer::BitFlyerOptions> for Client {
208 #[inline(always)]
209 fn default_options(&self) -> &bitflyer::BitFlyerOptions {
210 &self.bitflyer
211 }
212
213 #[inline(always)]
214 fn default_options_mut(&mut self) -> &mut bitflyer::BitFlyerOptions {
215 &mut self.bitflyer
216 }
217}
218
219#[cfg(feature = "bybit")]
220#[cfg_attr(docsrs, doc(cfg(feature = "bybit")))]
221impl GetOptions<bybit::BybitOptions> for Client {
222 #[inline(always)]
223 fn default_options(&self) -> &bybit::BybitOptions {
224 &self.bybit
225 }
226
227 #[inline(always)]
228 fn default_options_mut(&mut self) -> &mut bybit::BybitOptions {
229 &mut self.bybit
230 }
231}
232
233#[cfg(feature = "coincheck")]
234#[cfg_attr(docsrs, doc(cfg(feature = "coincheck")))]
235impl GetOptions<coincheck::CoincheckOptions> for Client {
236 #[inline(always)]
237 fn default_options(&self) -> &coincheck::CoincheckOptions {
238 &self.coincheck
239 }
240
241 #[inline(always)]
242 fn default_options_mut(&mut self) -> &mut coincheck::CoincheckOptions {
243 &mut self.coincheck
244 }
245}