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}