1use derive_builder::Builder;
2use reqwest::{Client, ClientBuilder};
3use std::collections::HashMap;
4use std::fmt;
5use std::sync::Arc;
6use tokio_tungstenite::Connector;
7
8use super::models::{ConfigBuildError, TimeUnit, WebsocketMode};
9use super::utils::{SignatureGenerator, build_client};
10
11#[derive(Clone)]
12pub struct AgentConnector(pub Connector);
13
14impl fmt::Debug for AgentConnector {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(f, "Connector(…)")
17 }
18}
19
20pub type WebsocketHandshakeResult = Result<
29 (
30 tokio_tungstenite::WebSocketStream<
31 tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
32 >,
33 tokio_tungstenite::tungstenite::handshake::client::Response,
34 ),
35 tokio_tungstenite::tungstenite::Error,
36>;
37
38pub type WebsocketHandshakeFn = Arc<
72 dyn Fn(
73 tokio_tungstenite::tungstenite::handshake::client::Request,
74 Option<tokio_tungstenite::tungstenite::protocol::WebSocketConfig>,
75 bool,
76 Option<Connector>,
77 ) -> std::pin::Pin<Box<dyn Future<Output = WebsocketHandshakeResult> + Send>>
78 + Send
79 + Sync,
80>;
81
82pub type TimestampProvider = Arc<dyn Fn() -> u64 + Send + Sync>;
118
119#[derive(Clone)]
120pub struct HttpAgent(pub Arc<dyn Fn(ClientBuilder) -> ClientBuilder + Send + Sync>);
121
122impl fmt::Debug for HttpAgent {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "HttpAgent(<custom agent fn>)")
125 }
126}
127
128#[derive(Clone)]
129pub struct ProxyAuth {
130 pub username: String,
131 pub password: String,
132}
133
134#[derive(Debug, Clone)]
135pub struct ProxyConfig {
136 pub host: String,
137 pub port: u16,
138 pub protocol: Option<String>,
139 pub auth: Option<ProxyAuth>,
140}
141
142impl fmt::Debug for ProxyAuth {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 f.debug_struct("ProxyAuth")
145 .field("username", &self.username)
146 .field("password", &"[REDACTED]")
147 .finish()
148 }
149}
150
151#[derive(Clone)]
152pub enum PrivateKey {
153 File(String),
154 Raw(Vec<u8>),
155}
156
157impl fmt::Debug for PrivateKey {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 match self {
160 PrivateKey::File(_) => write!(f, "PrivateKey::File([REDACTED])"),
161 PrivateKey::Raw(_) => write!(f, "PrivateKey::Raw([REDACTED])"),
162 }
163 }
164}
165
166#[derive(Clone, Builder)]
167#[builder(
168 pattern = "owned",
169 build_fn(name = "try_build", error = "ConfigBuildError")
170)]
171pub struct ConfigurationRestApi {
172 #[builder(setter(into, strip_option), default)]
173 pub api_key: Option<String>,
174
175 #[builder(setter(into, strip_option), default)]
176 pub api_secret: Option<String>,
177
178 #[builder(setter(into, strip_option), default)]
179 pub base_path: Option<String>,
180
181 #[builder(default = "1000")]
182 pub timeout: u64,
183
184 #[builder(default = "true")]
185 pub keep_alive: bool,
186
187 #[builder(default = "true")]
188 pub compression: bool,
189
190 #[builder(default = "3")]
191 pub retries: u32,
192
193 #[builder(default = "1000")]
194 pub backoff: u64,
195
196 #[builder(setter(strip_option), default)]
197 pub proxy: Option<ProxyConfig>,
198
199 #[builder(setter(strip_option, into), default)]
200 pub custom_headers: Option<HashMap<String, String>>,
201
202 #[builder(setter(strip_option), default)]
203 pub agent: Option<HttpAgent>,
204
205 #[builder(setter(strip_option), default)]
206 pub private_key: Option<PrivateKey>,
207
208 #[builder(setter(strip_option), default)]
209 pub private_key_passphrase: Option<String>,
210
211 #[builder(setter(strip_option), default)]
212 pub time_unit: Option<TimeUnit>,
213
214 #[builder(setter(strip_option), default)]
217 pub timestamp_provider: Option<TimestampProvider>,
218
219 #[builder(setter(skip))]
220 pub(crate) client: Client,
221
222 #[builder(setter(skip))]
223 pub(crate) user_agent: String,
224
225 #[builder(setter(skip))]
226 pub(crate) signature_gen: SignatureGenerator,
227}
228
229impl fmt::Debug for ConfigurationRestApi {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 f.debug_struct("ConfigurationRestApi")
232 .field("api_key", &self.api_key.as_ref().map(|_| "[REDACTED]"))
233 .field(
234 "api_secret",
235 &self.api_secret.as_ref().map(|_| "[REDACTED]"),
236 )
237 .field("base_path", &self.base_path)
238 .field("timeout", &self.timeout)
239 .field("keep_alive", &self.keep_alive)
240 .field("compression", &self.compression)
241 .field("retries", &self.retries)
242 .field("backoff", &self.backoff)
243 .field("proxy", &self.proxy)
244 .field("custom_headers", &self.custom_headers)
245 .field("agent", &self.agent)
246 .field(
247 "private_key",
248 &self.private_key.as_ref().map(|_| "[REDACTED]"),
249 )
250 .field(
251 "private_key_passphrase",
252 &self.private_key_passphrase.as_ref().map(|_| "[REDACTED]"),
253 )
254 .field("time_unit", &self.time_unit)
255 .field(
256 "timestamp_provider",
257 &self
258 .timestamp_provider
259 .as_ref()
260 .map(|_| "<custom timestamp fn>"),
261 )
262 .field("client", &"<reqwest::Client>")
263 .field("user_agent", &self.user_agent)
264 .field("signature_gen", &self.signature_gen)
265 .finish()
266 }
267}
268
269impl ConfigurationRestApi {
270 #[must_use]
271 pub fn builder() -> ConfigurationRestApiBuilder {
272 ConfigurationRestApiBuilder::default()
273 }
274}
275
276impl ConfigurationRestApiBuilder {
277 pub fn build(self) -> Result<ConfigurationRestApi, ConfigBuildError> {
287 let mut cfg = self.try_build()?;
288 cfg.client = build_client(
289 cfg.timeout,
290 cfg.keep_alive,
291 cfg.proxy.as_ref(),
292 cfg.agent.clone(),
293 );
294 cfg.signature_gen = SignatureGenerator::new(
295 cfg.api_secret.clone(),
296 cfg.private_key.clone(),
297 cfg.private_key_passphrase.clone(),
298 );
299
300 Ok(cfg)
301 }
302}
303
304#[derive(Clone, Builder)]
305#[builder(
306 pattern = "owned",
307 build_fn(name = "try_build", error = "ConfigBuildError")
308)]
309pub struct ConfigurationWebsocketApi {
310 #[builder(setter(into, strip_option), default)]
311 pub api_key: Option<String>,
312
313 #[builder(setter(into, strip_option), default)]
314 pub api_secret: Option<String>,
315
316 #[builder(setter(into, strip_option), default)]
317 pub ws_url: Option<String>,
318
319 #[builder(default = "5000")]
320 pub timeout: u64,
321
322 #[builder(default = "5000")]
323 pub reconnect_delay: u64,
324
325 #[builder(default = "WebsocketMode::Single")]
326 pub mode: WebsocketMode,
327
328 #[builder(setter(strip_option), default)]
329 pub agent: Option<AgentConnector>,
330
331 #[builder(setter(strip_option), default)]
334 pub handshake: Option<WebsocketHandshakeFn>,
335
336 #[builder(setter(strip_option), default)]
337 pub private_key: Option<PrivateKey>,
338
339 #[builder(setter(strip_option), default)]
340 pub private_key_passphrase: Option<String>,
341
342 #[builder(setter(strip_option), default)]
343 pub time_unit: Option<TimeUnit>,
344
345 #[builder(default = "true")]
346 pub auto_session_relogon: bool,
347
348 #[builder(setter(strip_option), default)]
351 pub timestamp_provider: Option<TimestampProvider>,
352
353 #[builder(setter(skip))]
354 pub(crate) user_agent: String,
355
356 #[builder(setter(skip))]
357 pub(crate) signature_gen: SignatureGenerator,
358}
359
360impl fmt::Debug for ConfigurationWebsocketApi {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 f.debug_struct("ConfigurationWebsocketApi")
363 .field("api_key", &self.api_key.as_ref().map(|_| "[REDACTED]"))
364 .field(
365 "api_secret",
366 &self.api_secret.as_ref().map(|_| "[REDACTED]"),
367 )
368 .field("ws_url", &self.ws_url)
369 .field("timeout", &self.timeout)
370 .field("reconnect_delay", &self.reconnect_delay)
371 .field("mode", &self.mode)
372 .field("agent", &self.agent)
373 .field(
374 "handshake",
375 &self.handshake.as_ref().map(|_| "<custom handshake fn>"),
376 )
377 .field(
378 "private_key",
379 &self.private_key.as_ref().map(|_| "[REDACTED]"),
380 )
381 .field(
382 "private_key_passphrase",
383 &self.private_key_passphrase.as_ref().map(|_| "[REDACTED]"),
384 )
385 .field("time_unit", &self.time_unit)
386 .field("auto_session_relogon", &self.auto_session_relogon)
387 .field(
388 "timestamp_provider",
389 &self
390 .timestamp_provider
391 .as_ref()
392 .map(|_| "<custom timestamp fn>"),
393 )
394 .field("user_agent", &self.user_agent)
395 .field("signature_gen", &self.signature_gen)
396 .finish()
397 }
398}
399
400impl ConfigurationWebsocketApi {
401 #[must_use]
411 pub fn builder() -> ConfigurationWebsocketApiBuilder {
412 ConfigurationWebsocketApiBuilder::default()
413 }
414}
415
416impl ConfigurationWebsocketApiBuilder {
417 pub fn build(self) -> Result<ConfigurationWebsocketApi, ConfigBuildError> {
433 let mut cfg = self.try_build()?;
434 cfg.signature_gen = SignatureGenerator::new(
435 cfg.api_secret.clone(),
436 cfg.private_key.clone(),
437 cfg.private_key_passphrase.clone(),
438 );
439
440 Ok(cfg)
441 }
442}
443
444#[derive(Clone, Builder)]
445#[builder(pattern = "owned", build_fn(error = "ConfigBuildError"))]
446pub struct ConfigurationWebsocketStreams {
447 #[builder(setter(into, strip_option), default)]
448 pub ws_url: Option<String>,
449
450 #[builder(setter(into, strip_option), default)]
451 pub api_key: Option<String>,
452
453 #[builder(setter(into, strip_option), default)]
454 pub api_secret: Option<String>,
455
456 #[builder(setter(strip_option), default)]
457 pub private_key: Option<PrivateKey>,
458
459 #[builder(setter(strip_option), default)]
460 pub private_key_passphrase: Option<String>,
461
462 #[builder(default = "5000")]
463 pub reconnect_delay: u64,
464
465 #[builder(default = "WebsocketMode::Single")]
466 pub mode: WebsocketMode,
467
468 #[builder(setter(strip_option), default)]
469 pub agent: Option<AgentConnector>,
470
471 #[builder(setter(strip_option), default)]
474 pub handshake: Option<WebsocketHandshakeFn>,
475
476 #[builder(setter(strip_option), default)]
477 pub time_unit: Option<TimeUnit>,
478
479 #[builder(setter(strip_option), default)]
482 pub timestamp_provider: Option<TimestampProvider>,
483
484 #[builder(setter(skip))]
485 pub(crate) user_agent: String,
486}
487
488impl fmt::Debug for ConfigurationWebsocketStreams {
489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490 f.debug_struct("ConfigurationWebsocketStreams")
491 .field("ws_url", &self.ws_url)
492 .field("reconnect_delay", &self.reconnect_delay)
493 .field("mode", &self.mode)
494 .field("agent", &self.agent)
495 .field(
496 "handshake",
497 &self.handshake.as_ref().map(|_| "<custom handshake fn>"),
498 )
499 .field("time_unit", &self.time_unit)
500 .field(
501 "timestamp_provider",
502 &self
503 .timestamp_provider
504 .as_ref()
505 .map(|_| "<custom timestamp fn>"),
506 )
507 .field("user_agent", &self.user_agent)
508 .field("api_key", &self.api_key.as_ref().map(|_| "[REDACTED]"))
509 .field(
510 "api_secret",
511 &self.api_secret.as_ref().map(|_| "[REDACTED]"),
512 )
513 .field(
514 "private_key",
515 &self.private_key.as_ref().map(|_| "[REDACTED]"),
516 )
517 .field(
518 "private_key_passphrase",
519 &self.private_key_passphrase.as_ref().map(|_| "[REDACTED]"),
520 )
521 .finish()
522 }
523}
524
525impl ConfigurationWebsocketStreams {
526 #[must_use]
527 pub fn builder() -> ConfigurationWebsocketStreamsBuilder {
533 ConfigurationWebsocketStreamsBuilder::default()
534 }
535}