Skip to main content

solana_validator_optimizer/
config.rs

1use config::Config;
2use serde::Deserialize;
3use std::path::Path;
4
5#[derive(Debug, Deserialize, Clone)]
6pub struct AppConfig {
7    pub snapshot_url: String,
8    pub snapshot_sha256: Option<String>, // optional hash check
9    pub rpc_url: String,
10    pub metrics_port: u16,
11    pub cache_size: usize,
12}
13
14impl AppConfig {
15    /// Backward-compatible default loader:
16    /// - reads ./Config.toml (base name "Config")
17    /// - allows overrides via OPTIMIZER_* env vars
18    pub fn load() -> Result<Self, config::ConfigError> {
19        let cfg = Config::builder()
20            .add_source(config::File::with_name("Config").required(false))
21            .add_source(config::Environment::with_prefix("OPTIMIZER"))
22            .build()?;
23
24        let mut app: AppConfig = cfg.try_deserialize()?;
25        app.normalize();
26        Ok(app)
27    }
28
29    /// Load config from an explicit path (operator-friendly).
30    /// Example: /etc/svo/Config.toml
31    pub fn load_from_path(path: &str) -> Result<Self, config::ConfigError> {
32        let p = Path::new(path);
33
34        let cfg = Config::builder()
35            .add_source(config::File::from(p).required(true))
36            .add_source(config::Environment::with_prefix("OPTIMIZER"))
37            .build()?;
38
39        let mut app: AppConfig = cfg.try_deserialize()?;
40        app.normalize();
41        Ok(app)
42    }
43
44    /// Normalize config values after deserialization
45    fn normalize(&mut self) {
46        // Treat empty string as "unset"
47        if matches!(self.snapshot_sha256.as_deref(), Some(s) if s.trim().is_empty()) {
48            self.snapshot_sha256 = None;
49        }
50
51        // Trim snapshot_url for safety
52        self.snapshot_url = self.snapshot_url.trim().to_string();
53
54        // Basic safety defaults (prevents operator misconfig)
55        if self.cache_size == 0 {
56            self.cache_size = 128;
57        }
58
59        if self.metrics_port == 0 {
60            self.metrics_port = 9090;
61        }
62    }
63}