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}