binance_sdk/common/
config.rs

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
20#[derive(Clone)]
21pub struct HttpAgent(pub Arc<dyn Fn(ClientBuilder) -> ClientBuilder + Send + Sync>);
22
23impl fmt::Debug for HttpAgent {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "HttpAgent(<custom agent fn>)")
26    }
27}
28
29#[derive(Debug, Clone)]
30pub struct ProxyAuth {
31    pub username: String,
32    pub password: String,
33}
34
35#[derive(Debug, Clone)]
36pub struct ProxyConfig {
37    pub host: String,
38    pub port: u16,
39    pub protocol: Option<String>,
40    pub auth: Option<ProxyAuth>,
41}
42
43#[derive(Debug, Clone)]
44pub enum PrivateKey {
45    File(String),
46    Raw(Vec<u8>),
47}
48
49#[derive(Debug, Clone, Builder)]
50#[builder(
51    pattern = "owned",
52    build_fn(name = "try_build", error = "ConfigBuildError")
53)]
54pub struct ConfigurationRestApi {
55    #[builder(setter(into, strip_option), default)]
56    pub api_key: Option<String>,
57
58    #[builder(setter(into, strip_option), default)]
59    pub api_secret: Option<String>,
60
61    #[builder(setter(into, strip_option), default)]
62    pub base_path: Option<String>,
63
64    #[builder(default = "1000")]
65    pub timeout: u64,
66
67    #[builder(default = "true")]
68    pub keep_alive: bool,
69
70    #[builder(default = "true")]
71    pub compression: bool,
72
73    #[builder(default = "3")]
74    pub retries: u32,
75
76    #[builder(default = "1000")]
77    pub backoff: u64,
78
79    #[builder(setter(strip_option), default)]
80    pub proxy: Option<ProxyConfig>,
81
82    #[builder(setter(strip_option, into), default)]
83    pub custom_headers: Option<HashMap<String, String>>,
84
85    #[builder(setter(strip_option), default)]
86    pub agent: Option<HttpAgent>,
87
88    #[builder(setter(strip_option), default)]
89    pub private_key: Option<PrivateKey>,
90
91    #[builder(setter(strip_option), default)]
92    pub private_key_passphrase: Option<String>,
93
94    #[builder(setter(strip_option), default)]
95    pub time_unit: Option<TimeUnit>,
96
97    #[builder(setter(skip))]
98    pub(crate) client: Client,
99
100    #[builder(setter(skip))]
101    pub(crate) user_agent: String,
102
103    #[builder(setter(skip))]
104    pub(crate) signature_gen: SignatureGenerator,
105}
106
107impl ConfigurationRestApi {
108    #[must_use]
109    pub fn builder() -> ConfigurationRestApiBuilder {
110        ConfigurationRestApiBuilder::default()
111    }
112}
113
114impl ConfigurationRestApiBuilder {
115    /// Builds a `ConfigurationRestApi` instance with configured HTTP client and signature generator.
116    ///
117    /// # Returns
118    ///
119    /// A `Result` containing the fully configured `ConfigurationRestApi` or a `ConfigBuildError` if configuration fails.
120    ///
121    /// # Errors
122    ///
123    /// Returns a `ConfigBuildError` if the initial configuration build fails or if client setup encounters issues.
124    pub fn build(self) -> Result<ConfigurationRestApi, ConfigBuildError> {
125        let mut cfg = self.try_build()?;
126        cfg.client = build_client(
127            cfg.timeout,
128            cfg.keep_alive,
129            cfg.proxy.as_ref(),
130            cfg.agent.clone(),
131        );
132        cfg.signature_gen = SignatureGenerator::new(
133            cfg.api_secret.clone(),
134            cfg.private_key.clone(),
135            cfg.private_key_passphrase.clone(),
136        );
137
138        Ok(cfg)
139    }
140}
141
142#[derive(Debug, Clone, Builder)]
143#[builder(
144    pattern = "owned",
145    build_fn(name = "try_build", error = "ConfigBuildError")
146)]
147pub struct ConfigurationWebsocketApi {
148    #[builder(setter(into, strip_option), default)]
149    pub api_key: Option<String>,
150
151    #[builder(setter(into, strip_option), default)]
152    pub api_secret: Option<String>,
153
154    #[builder(setter(into, strip_option), default)]
155    pub ws_url: Option<String>,
156
157    #[builder(default = "5000")]
158    pub timeout: u64,
159
160    #[builder(default = "5000")]
161    pub reconnect_delay: u64,
162
163    #[builder(default = "WebsocketMode::Single")]
164    pub mode: WebsocketMode,
165
166    #[builder(setter(strip_option), default)]
167    pub agent: Option<AgentConnector>,
168
169    #[builder(setter(strip_option), default)]
170    pub private_key: Option<PrivateKey>,
171
172    #[builder(setter(strip_option), default)]
173    pub private_key_passphrase: Option<String>,
174
175    #[builder(setter(strip_option), default)]
176    pub time_unit: Option<TimeUnit>,
177
178    #[builder(default = "true")]
179    pub auto_session_relogon: bool,
180
181    #[builder(setter(skip))]
182    pub(crate) user_agent: String,
183
184    #[builder(setter(skip))]
185    pub(crate) signature_gen: SignatureGenerator,
186}
187
188impl ConfigurationWebsocketApi {
189    /// Creates a builder for `ConfigurationWebsocketApi` with the specified API key.
190    ///
191    /// # Arguments
192    ///
193    /// * `api_key` - The API key to be used for the WebSocket API configuration
194    ///
195    /// # Returns
196    ///
197    /// A `ConfigurationWebsocketApiBuilder` initialized with the provided API key
198    #[must_use]
199    pub fn builder() -> ConfigurationWebsocketApiBuilder {
200        ConfigurationWebsocketApiBuilder::default()
201    }
202}
203
204impl ConfigurationWebsocketApiBuilder {
205    /// Builds the `ConfigurationWebsocketApi` with a generated signature generator.
206    ///
207    /// This method attempts to build the configuration using the builder's settings
208    /// and then initializes the signature generator with the API secret, private key,
209    /// and private key passphrase.
210    ///
211    /// # Returns
212    ///
213    /// A `Result` containing the fully configured `ConfigurationWebsocketApi` or a
214    /// `ConfigBuildError` if the build process fails.
215    ///
216    /// # Errors
217    ///
218    /// Returns a `ConfigBuildError` if the initial configuration build fails or if signature generation fails.
219    ///
220    pub fn build(self) -> Result<ConfigurationWebsocketApi, ConfigBuildError> {
221        let mut cfg = self.try_build()?;
222        cfg.signature_gen = SignatureGenerator::new(
223            cfg.api_secret.clone(),
224            cfg.private_key.clone(),
225            cfg.private_key_passphrase.clone(),
226        );
227
228        Ok(cfg)
229    }
230}
231
232#[derive(Debug, Clone, Builder)]
233#[builder(pattern = "owned", build_fn(error = "ConfigBuildError"))]
234pub struct ConfigurationWebsocketStreams {
235    #[builder(setter(into, strip_option), default)]
236    pub ws_url: Option<String>,
237
238    #[builder(default = "5000")]
239    pub reconnect_delay: u64,
240
241    #[builder(default = "WebsocketMode::Single")]
242    pub mode: WebsocketMode,
243
244    #[builder(setter(strip_option), default)]
245    pub agent: Option<AgentConnector>,
246
247    #[builder(setter(strip_option), default)]
248    pub time_unit: Option<TimeUnit>,
249
250    #[builder(setter(skip))]
251    pub(crate) user_agent: String,
252}
253
254impl ConfigurationWebsocketStreams {
255    #[must_use]
256    /// Creates a builder for `ConfigurationWebsocketStreams` with default settings.
257    ///
258    /// # Returns
259    ///
260    /// A `ConfigurationWebsocketStreamsBuilder` initialized with default values
261    pub fn builder() -> ConfigurationWebsocketStreamsBuilder {
262        ConfigurationWebsocketStreamsBuilder::default()
263    }
264}