binance_sdk/common/
config.rs

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