Skip to main content

fyers_rs/
config.rs

1//! Client configuration and secret handling.
2
3use std::fmt;
4use std::time::Duration;
5
6use url::Url;
7
8const DEFAULT_API_BASE_URL: &str = "https://api-t1.fyers.in/api/v3";
9const DEFAULT_API_V2_BASE_URL: &str = "https://api.fyers.in/api/v2";
10const DEFAULT_DATA_BASE_URL: &str = "https://api-t1.fyers.in/data";
11const DEFAULT_SYMBOLS_BASE_URL: &str = "https://public.fyers.in/sym_details";
12const DEFAULT_DATA_SOCKET_URL: &str = "wss://socket.fyers.in/hsm/v1-5/prod";
13const DEFAULT_ORDER_SOCKET_URL: &str = "wss://socket.fyers.in/trade/v3";
14const DEFAULT_TBT_SOCKET_URL: &str = "wss://rtsocket-api.fyers.in/versova";
15const DEFAULT_TIMEOUT_SECS: u64 = 30;
16
17/// A secret string that redacts its value in debug output.
18#[derive(Clone, PartialEq, Eq)]
19pub struct SecretString(String);
20
21impl SecretString {
22    /// Wrap a secret value.
23    pub fn new(value: impl Into<String>) -> Self {
24        Self(value.into())
25    }
26
27    /// Expose the secret value for transport/authentication code.
28    pub fn expose_secret(&self) -> &str {
29        &self.0
30    }
31}
32
33impl fmt::Debug for SecretString {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        f.write_str("SecretString([redacted])")
36    }
37}
38
39/// Shared configuration for [`crate::FyersClient`].
40#[derive(Clone, Debug)]
41pub struct FyersConfig {
42    client_id: String,
43    secret_key: Option<SecretString>,
44    redirect_uri: Option<Url>,
45    access_token: Option<SecretString>,
46    api_base_url: Url,
47    api_v2_base_url: Url,
48    data_base_url: Url,
49    symbols_base_url: Url,
50    data_socket_url: Url,
51    order_socket_url: Url,
52    tbt_socket_url: Url,
53    timeout: Duration,
54}
55
56impl FyersConfig {
57    /// Create a config from all validated values.
58    #[allow(clippy::too_many_arguments)]
59    pub(crate) fn new(
60        client_id: String,
61        secret_key: Option<SecretString>,
62        redirect_uri: Option<Url>,
63        access_token: Option<SecretString>,
64        api_base_url: Url,
65        api_v2_base_url: Url,
66        data_base_url: Url,
67        symbols_base_url: Url,
68        data_socket_url: Url,
69        order_socket_url: Url,
70        tbt_socket_url: Url,
71        timeout: Duration,
72    ) -> Self {
73        Self {
74            client_id,
75            secret_key,
76            redirect_uri,
77            access_token,
78            api_base_url,
79            api_v2_base_url,
80            data_base_url,
81            symbols_base_url,
82            data_socket_url,
83            order_socket_url,
84            tbt_socket_url,
85            timeout,
86        }
87    }
88
89    /// Fyers app/client ID.
90    pub fn client_id(&self) -> &str {
91        &self.client_id
92    }
93
94    /// Optional app secret key.
95    pub fn secret_key(&self) -> Option<&SecretString> {
96        self.secret_key.as_ref()
97    }
98
99    /// Optional redirect URI for auth flows.
100    pub fn redirect_uri(&self) -> Option<&Url> {
101        self.redirect_uri.as_ref()
102    }
103
104    /// Optional access token.
105    pub fn access_token(&self) -> Option<&SecretString> {
106        self.access_token.as_ref()
107    }
108
109    /// REST API base URL.
110    pub fn api_base_url(&self) -> &Url {
111        &self.api_base_url
112    }
113
114    /// Legacy v2 REST API base URL.
115    pub fn api_v2_base_url(&self) -> &Url {
116        &self.api_v2_base_url
117    }
118
119    /// Market-data REST base URL.
120    pub fn data_base_url(&self) -> &Url {
121        &self.data_base_url
122    }
123
124    /// Public symbol-master file base URL.
125    pub fn symbols_base_url(&self) -> &Url {
126        &self.symbols_base_url
127    }
128
129    /// Market-data WebSocket URL.
130    pub fn data_socket_url(&self) -> &Url {
131        &self.data_socket_url
132    }
133
134    /// Order WebSocket URL.
135    pub fn order_socket_url(&self) -> &Url {
136        &self.order_socket_url
137    }
138
139    /// TBT/depth WebSocket URL.
140    pub fn tbt_socket_url(&self) -> &Url {
141        &self.tbt_socket_url
142    }
143
144    /// HTTP timeout.
145    pub fn timeout(&self) -> Duration {
146        self.timeout
147    }
148}
149
150/// Default Fyers REST API base URL.
151pub fn default_api_base_url() -> Url {
152    Url::parse(DEFAULT_API_BASE_URL).expect("default API base URL is valid")
153}
154
155/// Default Fyers legacy v2 REST API base URL.
156pub fn default_api_v2_base_url() -> Url {
157    Url::parse(DEFAULT_API_V2_BASE_URL).expect("default API v2 base URL is valid")
158}
159
160/// Default Fyers market-data REST base URL.
161pub fn default_data_base_url() -> Url {
162    Url::parse(DEFAULT_DATA_BASE_URL).expect("default data base URL is valid")
163}
164
165/// Default Fyers public symbol-master base URL.
166pub fn default_symbols_base_url() -> Url {
167    Url::parse(DEFAULT_SYMBOLS_BASE_URL).expect("default symbols base URL is valid")
168}
169
170/// Default Fyers market-data WebSocket URL.
171pub fn default_data_socket_url() -> Url {
172    Url::parse(DEFAULT_DATA_SOCKET_URL).expect("default data socket URL is valid")
173}
174
175/// Default Fyers order WebSocket URL.
176pub fn default_order_socket_url() -> Url {
177    Url::parse(DEFAULT_ORDER_SOCKET_URL).expect("default order socket URL is valid")
178}
179
180/// Default Fyers TBT/depth WebSocket URL.
181pub fn default_tbt_socket_url() -> Url {
182    Url::parse(DEFAULT_TBT_SOCKET_URL).expect("default TBT socket URL is valid")
183}
184
185/// Default client timeout.
186pub fn default_timeout() -> Duration {
187    Duration::from_secs(DEFAULT_TIMEOUT_SECS)
188}