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
52
53impl LightspeedConfig {
54 /// Process the configuration and return the final endpoint URL
55 ///
56 /// If a custom endpoint is set, it uses that directly.
57 /// Otherwise, it processes the SVS RPC URL into the Lightspeed format.
58 pub fn get_endpoint(&self) -> Result<Url, LightspeedError> {
59 if let Some(custom) = &self.custom_endpoint {
60 // Use custom endpoint directly for testing
61 Url::parse(custom)
62 .map_err(|_| LightspeedError::InvalidUrl(custom.clone()))
63 } else {
64 // Process SVS RPC URL
65 if self.svs_rpc_url.is_empty() {
66 return Err(LightspeedError::InvalidUrl("SVS RPC URL is required".to_string()));
67 }
68 Self::process_svs_url(&self.svs_rpc_url)
69 }
70 }
71
72 /// Process SVS RPC URL into Lightspeed endpoint format
73 ///
74 /// Transforms URLs like:
75 /// - `https://basic.rpc.solanavibestation.com/?api_key=xxx`
76 /// - `https://ultra.swqos.rpc.solanavibestation.com`
77 ///
78 /// Into:
79 /// - `https://basic.rpc.solanavibestation.com/lightspeed`
80 /// - `https://ultra.swqos.rpc.solanavibestation.com/lightspeed`
81 fn process_svs_url(svs_url: &str) -> Result<Url, LightspeedError> {
82 // Parse the URL
83 let mut url = Url::parse(svs_url)
84 .map_err(|_| LightspeedError::InvalidUrl(svs_url.to_string()))?;
85
86 // Remove any query parameters (like ?api_key=)
87 url.set_query(None);
88
89 // Ensure it's using a valid scheme
90 if url.scheme() != "https" && url.scheme() != "http" {
91 return Err(LightspeedError::InvalidUrl(
92 format!("URL must use http or https scheme: {}", svs_url)
93 ));
94 }
95
96 // Validate host
97 let host = url.host_str()
98 .ok_or_else(|| LightspeedError::InvalidUrl("URL missing host".to_string()))?;
99
100 // Validate it's a solanavibestation.com domain
101 if !host.ends_with("solanavibestation.com") {
102 return Err(LightspeedError::InvalidUrl(
103 format!("URL must be a solanavibestation.com domain: {}", host)
104 ));
105 }
106
107 // Set the path to /lightspeed
108 url.set_path("/lightspeed");
109
110 Ok(url)
111 }
112}
113
114impl Default for LightspeedConfig {
115 fn default() -> Self {
116 Self {
117 api_key: String::new(),
118 svs_rpc_url: String::new(),
119 default_priority: Priority::Standard,
120 timeout: Duration::from_secs(30),
121 keep_alive_interval: Duration::from_secs(20),
122 use_https: true,
123 debug: false,
124 custom_endpoint: None,
125 }
126 }
127}
128
129/// Builder for creating Lightspeed client instances
130///
131/// Provides a fluent interface for configuring the client before initialization.
132///
133/// ## Example
134///
135/// ```rust
136/// use lightspeed_sdk::{LightspeedClientBuilder, Priority};
137/// use std::time::Duration;
138///
139/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
140/// let client = LightspeedClientBuilder::new("your-api-key")
141/// .svs_rpc_url("https://basic.rpc.solanavibestation.com")
142/// .default_priority(Priority::Standard)
143/// .timeout(Duration::from_secs(60))
144/// .debug(true)
145/// .build()?;
146/// # Ok(())
147/// # }
148/// ```
149pub struct LightspeedClientBuilder {
150 config: LightspeedConfig,
151}
152
153impl LightspeedClientBuilder {
154 /// Creates a new builder with the required API key
155 ///
156 /// ## Arguments
157 ///
158 /// * `api_key` - Your Lightspeed API key from Solana Vibe Station
159 pub fn new(api_key: impl Into<String>) -> Self {
160 let mut config = LightspeedConfig::default();
161 config.api_key = api_key.into();
162 Self { config }
163 }
164
165 /// Sets the SVS RPC URL
166 ///
167 /// ## Arguments
168 ///
169 /// * `url` - Your SVS RPC endpoint URL (e.g., "https://basic.rpc.solanavibestation.com")
170 ///
171 /// The URL will be automatically converted to the Lightspeed endpoint format.
172 pub fn svs_rpc_url(mut self, url: impl Into<String>) -> Self {
173 self.config.svs_rpc_url = url.into();
174 self
175 }
176
177 /// Sets the default priority for transactions
178 ///
179 /// Transactions sent without specifying priority will use this setting.
180 ///
181 /// ## Arguments
182 ///
183 /// * `priority` - Default priority level
184 pub fn default_priority(mut self, priority: Priority) -> Self {
185 self.config.default_priority = priority;
186 self
187 }
188
189 /// Sets the HTTP request timeout
190 ///
191 /// ## Arguments
192 ///
193 /// * `timeout` - Maximum duration for HTTP requests
194 pub fn timeout(mut self, timeout: Duration) -> Self {
195 self.config.timeout = timeout;
196 self
197 }
198
199 /// Sets the keep-alive interval
200 ///
201 /// Determines how frequently keep-alive requests are sent when
202 /// automatic keep-alive is enabled.
203 ///
204 /// ## Arguments
205 ///
206 /// * `interval` - Duration between keep-alive requests
207 pub fn keep_alive_interval(mut self, interval: Duration) -> Self {
208 self.config.keep_alive_interval = interval;
209 self
210 }
211
212 /// Enables or disables HTTPS
213 ///
214 /// ## Arguments
215 ///
216 /// * `enabled` - Whether to use HTTPS (recommended for production)
217 pub fn use_https(mut self, enabled: bool) -> Self {
218 self.config.use_https = enabled;
219 self
220 }
221
222 /// Enables or disables debug logging
223 ///
224 /// ## Arguments
225 ///
226 /// * `enabled` - Whether to enable debug output
227 pub fn debug(mut self, enabled: bool) -> Self {
228 self.config.debug = enabled;
229 self
230 }
231
232 /// Sets a custom endpoint URL
233 ///
234 /// This is primarily intended for testing or connecting to
235 /// alternative Lightspeed deployments. When set, this overrides
236 /// the SVS RPC URL processing.
237 ///
238 /// ## Arguments
239 ///
240 /// * `endpoint` - Custom endpoint URL
241 pub fn custom_endpoint(mut self, endpoint: impl Into<String>) -> Self {
242 self.config.custom_endpoint = Some(endpoint.into());
243 self
244 }
245
246 /// Builds and returns the configured Lightspeed client
247 ///
248 /// ## Errors
249 ///
250 /// Returns an error if client initialization fails due to invalid
251 /// configuration or network issues.
252 pub fn build(self) -> Result<LightspeedClient, LightspeedError> {
253 LightspeedClient::new(self.config)
254 }
255}