1use 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#[derive(Clone, PartialEq, Eq)]
19pub struct SecretString(String);
20
21impl SecretString {
22 pub fn new(value: impl Into<String>) -> Self {
24 Self(value.into())
25 }
26
27 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#[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 #[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 pub fn client_id(&self) -> &str {
91 &self.client_id
92 }
93
94 pub fn secret_key(&self) -> Option<&SecretString> {
96 self.secret_key.as_ref()
97 }
98
99 pub fn redirect_uri(&self) -> Option<&Url> {
101 self.redirect_uri.as_ref()
102 }
103
104 pub fn access_token(&self) -> Option<&SecretString> {
106 self.access_token.as_ref()
107 }
108
109 pub fn api_base_url(&self) -> &Url {
111 &self.api_base_url
112 }
113
114 pub fn api_v2_base_url(&self) -> &Url {
116 &self.api_v2_base_url
117 }
118
119 pub fn data_base_url(&self) -> &Url {
121 &self.data_base_url
122 }
123
124 pub fn symbols_base_url(&self) -> &Url {
126 &self.symbols_base_url
127 }
128
129 pub fn data_socket_url(&self) -> &Url {
131 &self.data_socket_url
132 }
133
134 pub fn order_socket_url(&self) -> &Url {
136 &self.order_socket_url
137 }
138
139 pub fn tbt_socket_url(&self) -> &Url {
141 &self.tbt_socket_url
142 }
143
144 pub fn timeout(&self) -> Duration {
146 self.timeout
147 }
148}
149
150pub fn default_api_base_url() -> Url {
152 Url::parse(DEFAULT_API_BASE_URL).expect("default API base URL is valid")
153}
154
155pub 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
160pub fn default_data_base_url() -> Url {
162 Url::parse(DEFAULT_DATA_BASE_URL).expect("default data base URL is valid")
163}
164
165pub fn default_symbols_base_url() -> Url {
167 Url::parse(DEFAULT_SYMBOLS_BASE_URL).expect("default symbols base URL is valid")
168}
169
170pub fn default_data_socket_url() -> Url {
172 Url::parse(DEFAULT_DATA_SOCKET_URL).expect("default data socket URL is valid")
173}
174
175pub fn default_order_socket_url() -> Url {
177 Url::parse(DEFAULT_ORDER_SOCKET_URL).expect("default order socket URL is valid")
178}
179
180pub fn default_tbt_socket_url() -> Url {
182 Url::parse(DEFAULT_TBT_SOCKET_URL).expect("default TBT socket URL is valid")
183}
184
185pub fn default_timeout() -> Duration {
187 Duration::from_secs(DEFAULT_TIMEOUT_SECS)
188}