lightspeed_sdk/config.rs
1// src/config.rs
2use crate::{Priority, LightspeedClient, LightspeedError};
3use std::time::Duration;
4use url::Url;
5
6/// Configuration settings for the Lightspeed client
7///
8/// Contains all configurable parameters for connecting to and interacting
9/// with the Lightspeed service.
10#[derive(Debug, Clone)]
11pub struct LightspeedConfig {
12 /// API key for authentication
13 ///
14 /// Obtain your API key from the Solana Vibe Station cloud portal.
15 pub api_key: String,
16
17 /// SVS RPC URL
18 ///
19 /// Your Solana Vibe Station RPC endpoint URL
20 /// Example: "https://basic.rpc.solanavibestation.com"
21 pub svs_rpc_url: String,
22
23 /// Default priority level for transactions
24 ///
25 /// Used when sending transactions without explicitly specifying priority.
26 pub default_priority: Priority,
27
28 /// HTTP request timeout duration
29 pub timeout: Duration,
30
31 /// Interval between keep-alive requests
32 ///
33 /// Only applies when automatic keep-alive is enabled via `start_keep_alive()`.
34 pub keep_alive_interval: Duration,
35
36 /// Use HTTPS for secure connections
37 ///
38 /// Recommended for production environments.
39 pub use_https: bool,
40
41 /// Enable debug logging
42 ///
43 /// When enabled, additional diagnostic information will be logged.
44 pub debug: bool,
45
46 /// Custom endpoint URL (optional)
47 ///
48 /// Primarily used for testing or connecting to alternative endpoints.
49 pub custom_endpoint: Option<String>,
50
51 /// Solana RPC URL for balance checks
52 ///
53 /// Used when `check_balance_before_send` is enabled to verify sufficient
54 /// balance before sending transactions. Defaults to the public SVS endpoint.
55 pub balance_check_rpc_url: String,
56
57 /// Check balance before sending transactions
58 ///
59 /// When enabled, prevents wasting transaction fees on transactions that
60 /// will fail due to insufficient balance.
61 pub check_balance_before_send: bool,
62}
63
64
65impl LightspeedConfig {
66 /// Process the configuration and return the final endpoint URL
67 ///
68 /// If a custom endpoint is set, it uses that directly.
69 /// Otherwise, it processes the SVS RPC URL into the Lightspeed format.
70 pub fn get_endpoint(&self) -> Result<Url, LightspeedError> {
71 if let Some(custom) = &self.custom_endpoint {
72 // Use custom endpoint directly for testing
73 Url::parse(custom)
74 .map_err(|_| LightspeedError::InvalidUrl(custom.clone()))
75 } else {
76 // Process SVS RPC URL
77 if self.svs_rpc_url.is_empty() {
78 return Err(LightspeedError::InvalidUrl("SVS RPC URL is required".to_string()));
79 }
80 Self::process_svs_url(&self.svs_rpc_url)
81 }
82 }
83
84 /// Process SVS RPC URL into Lightspeed endpoint format
85 ///
86 /// Transforms URLs like:
87 /// - `https://basic.rpc.solanavibestation.com/?api_key=xxx`
88 /// - `https://ultra.swqos.rpc.solanavibestation.com`
89 ///
90 /// Into:
91 /// - `https://basic.rpc.solanavibestation.com/lightspeed`
92 /// - `https://ultra.swqos.rpc.solanavibestation.com/lightspeed`
93 fn process_svs_url(svs_url: &str) -> Result<Url, LightspeedError> {
94 // Parse the URL
95 let mut url = Url::parse(svs_url)
96 .map_err(|_| LightspeedError::InvalidUrl(svs_url.to_string()))?;
97
98 // Remove any query parameters (like ?api_key=)
99 url.set_query(None);
100
101 // Ensure it's using a valid scheme
102 if url.scheme() != "https" && url.scheme() != "http" {
103 return Err(LightspeedError::InvalidUrl(
104 format!("URL must use http or https scheme: {}", svs_url)
105 ));
106 }
107
108 // Validate host
109 let host = url.host_str()
110 .ok_or_else(|| LightspeedError::InvalidUrl("URL missing host".to_string()))?;
111
112 // Validate it's a solanavibestation.com domain
113 if !host.ends_with("solanavibestation.com") {
114 return Err(LightspeedError::InvalidUrl(
115 format!("URL must be a solanavibestation.com domain: {}", host)
116 ));
117 }
118
119 // Set the path to /lightspeed
120 url.set_path("/lightspeed");
121
122 Ok(url)
123 }
124}
125
126impl Default for LightspeedConfig {
127 fn default() -> Self {
128 Self {
129 api_key: String::new(),
130 svs_rpc_url: String::new(),
131 default_priority: Priority::Standard,
132 timeout: Duration::from_secs(30),
133 keep_alive_interval: Duration::from_secs(20),
134 use_https: true,
135 debug: false,
136 custom_endpoint: None,
137 balance_check_rpc_url: "https://public.rpc.solanavibestation.com".to_string(),
138 check_balance_before_send: false,
139 }
140 }
141}
142
143/// Builder for creating Lightspeed client instances
144///
145/// Provides a fluent interface for configuring the client before initialization.
146///
147/// ## Example
148///
149/// ```rust
150/// use lightspeed_sdk::{LightspeedClientBuilder, Priority};
151/// use std::time::Duration;
152///
153/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
154/// let client = LightspeedClientBuilder::new("your-api-key")
155/// .svs_rpc_url("https://basic.rpc.solanavibestation.com")
156/// .default_priority(Priority::Standard)
157/// .timeout(Duration::from_secs(60))
158/// .debug(true)
159/// .build()?;
160/// # Ok(())
161/// # }
162/// ```
163pub struct LightspeedClientBuilder {
164 config: LightspeedConfig,
165}
166
167impl LightspeedClientBuilder {
168 /// Creates a new builder with the required API key
169 ///
170 /// ## Arguments
171 ///
172 /// * `api_key` - Your Lightspeed API key from Solana Vibe Station
173 pub fn new(api_key: impl Into<String>) -> Self {
174 let mut config = LightspeedConfig::default();
175 config.api_key = api_key.into();
176 Self { config }
177 }
178
179 /// Sets the SVS RPC URL
180 ///
181 /// ## Arguments
182 ///
183 /// * `url` - Your SVS RPC endpoint URL (e.g., "https://basic.rpc.solanavibestation.com")
184 ///
185 /// The URL will be automatically converted to the Lightspeed endpoint format.
186 pub fn svs_rpc_url(mut self, url: impl Into<String>) -> Self {
187 self.config.svs_rpc_url = url.into();
188 self
189 }
190
191 /// Sets the default priority for transactions
192 ///
193 /// Transactions sent without specifying priority will use this setting.
194 ///
195 /// ## Arguments
196 ///
197 /// * `priority` - Default priority level
198 pub fn default_priority(mut self, priority: Priority) -> Self {
199 self.config.default_priority = priority;
200 self
201 }
202
203 /// Sets the HTTP request timeout
204 ///
205 /// ## Arguments
206 ///
207 /// * `timeout` - Maximum duration for HTTP requests
208 pub fn timeout(mut self, timeout: Duration) -> Self {
209 self.config.timeout = timeout;
210 self
211 }
212
213 /// Sets the keep-alive interval
214 ///
215 /// Determines how frequently keep-alive requests are sent when
216 /// automatic keep-alive is enabled.
217 ///
218 /// ## Arguments
219 ///
220 /// * `interval` - Duration between keep-alive requests
221 pub fn keep_alive_interval(mut self, interval: Duration) -> Self {
222 self.config.keep_alive_interval = interval;
223 self
224 }
225
226 /// Enables or disables HTTPS
227 ///
228 /// ## Arguments
229 ///
230 /// * `enabled` - Whether to use HTTPS (recommended for production)
231 pub fn use_https(mut self, enabled: bool) -> Self {
232 self.config.use_https = enabled;
233 self
234 }
235
236 /// Enables or disables debug logging
237 ///
238 /// ## Arguments
239 ///
240 /// * `enabled` - Whether to enable debug output
241 pub fn debug(mut self, enabled: bool) -> Self {
242 self.config.debug = enabled;
243 self
244 }
245
246 /// Sets a custom endpoint URL
247 ///
248 /// This is primarily intended for testing or connecting to
249 /// alternative Lightspeed deployments. When set, this overrides
250 /// the SVS RPC URL processing.
251 ///
252 /// ## Arguments
253 ///
254 /// * `endpoint` - Custom endpoint URL
255 pub fn custom_endpoint(mut self, endpoint: impl Into<String>) -> Self {
256 self.config.custom_endpoint = Some(endpoint.into());
257 self
258 }
259
260 /// Sets the Solana RPC URL for balance checks
261 ///
262 /// This RPC endpoint is used to query account balances before
263 /// sending transactions (when balance checking is enabled).
264 /// Defaults to the public SVS endpoint.
265 ///
266 /// ## Arguments
267 ///
268 /// * `url` - Solana RPC endpoint URL
269 pub fn balance_check_rpc_url(mut self, url: impl Into<String>) -> Self {
270 self.config.balance_check_rpc_url = url.into();
271 self
272 }
273
274 /// Enables or disables balance checking before sending transactions
275 ///
276 /// When enabled, the client will verify sufficient balance via RPC
277 /// before submitting transactions. This prevents wasting transaction
278 /// fees on transactions that will fail due to insufficient funds.
279 ///
280 /// ## Arguments
281 ///
282 /// * `enabled` - Whether to check balance before sending
283 pub fn check_balance_before_send(mut self, enabled: bool) -> Self {
284 self.config.check_balance_before_send = enabled;
285 self
286 }
287
288 /// Builds and returns the configured Lightspeed client
289 ///
290 /// ## Errors
291 ///
292 /// Returns an error if client initialization fails due to invalid
293 /// configuration or network issues.
294 pub fn build(self) -> Result<LightspeedClient, LightspeedError> {
295 LightspeedClient::new(self.config)
296 }
297}