enigma_relay/
config.rs

1use std::fs;
2use std::path::Path;
3
4use serde::Deserialize;
5
6use crate::error::{EnigmaRelayError, Result};
7
8#[derive(Clone, Deserialize, Debug, PartialEq, Eq)]
9#[serde(rename_all = "lowercase")]
10pub enum RelayMode {
11    Http,
12    Tls,
13}
14
15#[derive(Clone, Deserialize, Debug, PartialEq, Eq)]
16#[serde(rename_all = "lowercase")]
17pub enum StorageKind {
18    Sled,
19    Memory,
20}
21
22#[derive(Clone, Deserialize, Debug)]
23pub struct TlsConfig {
24    pub cert_pem_path: String,
25    pub key_pem_path: String,
26    #[serde(default)]
27    pub client_ca_pem_path: Option<String>,
28}
29
30#[derive(Clone, Deserialize, Debug)]
31pub struct StorageConfig {
32    pub kind: StorageKind,
33    pub path: String,
34}
35
36impl Default for StorageConfig {
37    fn default() -> Self {
38        StorageConfig {
39            kind: StorageKind::Sled,
40            path: "./relay_db".to_string(),
41        }
42    }
43}
44
45#[derive(Clone, Deserialize, Debug)]
46pub struct RelayLimits {
47    pub max_message_bytes: u64,
48    pub max_queue_bytes_per_user: u64,
49    pub max_messages_per_user: u64,
50    pub message_ttl_seconds: u64,
51    pub gc_interval_seconds: u64,
52    pub pull_batch_max: u64,
53}
54
55impl Default for RelayLimits {
56    fn default() -> Self {
57        RelayLimits {
58            max_message_bytes: 8_388_608,
59            max_queue_bytes_per_user: 1_073_741_824,
60            max_messages_per_user: 200_000,
61            message_ttl_seconds: 14 * 24 * 3600,
62            gc_interval_seconds: 60,
63            pull_batch_max: 256,
64        }
65    }
66}
67
68#[derive(Clone, Deserialize, Debug)]
69pub struct EndpointRateLimit {
70    pub push_rps: u32,
71    pub pull_rps: u32,
72    pub ack_rps: u32,
73}
74
75impl Default for EndpointRateLimit {
76    fn default() -> Self {
77        EndpointRateLimit {
78            push_rps: 10,
79            pull_rps: 5,
80            ack_rps: 10,
81        }
82    }
83}
84
85#[derive(Clone, Deserialize, Debug)]
86pub struct RateLimitConfig {
87    pub enabled: bool,
88    pub per_ip_rps: u32,
89    pub burst: u32,
90    pub ban_seconds: u64,
91    #[serde(default)]
92    pub endpoints: EndpointRateLimit,
93}
94
95impl Default for RateLimitConfig {
96    fn default() -> Self {
97        RateLimitConfig {
98            enabled: true,
99            per_ip_rps: 20,
100            burst: 40,
101            ban_seconds: 300,
102            endpoints: EndpointRateLimit::default(),
103        }
104    }
105}
106
107#[derive(Clone, Deserialize, Debug)]
108pub struct RelayConfig {
109    pub address: String,
110    #[serde(default = "RelayConfig::default_mode")]
111    pub mode: RelayMode,
112    #[serde(default)]
113    pub tls: Option<TlsConfig>,
114    #[serde(default)]
115    pub storage: StorageConfig,
116    #[serde(default)]
117    pub relay: RelayLimits,
118    #[serde(default)]
119    pub rate_limit: RateLimitConfig,
120}
121
122impl Default for RelayConfig {
123    fn default() -> Self {
124        RelayConfig {
125            address: "127.0.0.1:0".to_string(),
126            mode: RelayMode::Http,
127            tls: None,
128            storage: StorageConfig::default(),
129            relay: RelayLimits::default(),
130            rate_limit: RateLimitConfig::default(),
131        }
132    }
133}
134
135impl RelayConfig {
136    fn default_mode() -> RelayMode {
137        RelayMode::Http
138    }
139
140    pub fn load(path: impl AsRef<Path>) -> Result<Self> {
141        let raw = fs::read_to_string(&path).map_err(|e| EnigmaRelayError::Config(e.to_string()))?;
142        let cfg: RelayConfig =
143            toml::from_str(&raw).map_err(|e| EnigmaRelayError::Config(e.to_string()))?;
144        cfg.validate()?;
145        Ok(cfg)
146    }
147
148    pub fn validate(&self) -> Result<()> {
149        if self.address.trim().is_empty() {
150            return Err(EnigmaRelayError::Config("address is required".to_string()));
151        }
152        match self.mode {
153            RelayMode::Http => {}
154            RelayMode::Tls => {
155                if self.tls.is_none() {
156                    return Err(EnigmaRelayError::Config(
157                        "tls mode requires tls config".to_string(),
158                    ));
159                }
160                #[cfg(not(feature = "tls"))]
161                {
162                    return Err(EnigmaRelayError::Disabled(
163                        "tls feature not enabled".to_string(),
164                    ));
165                }
166            }
167        }
168        if self.relay.max_message_bytes == 0 {
169            return Err(EnigmaRelayError::Config(
170                "max_message_bytes must be positive".to_string(),
171            ));
172        }
173        if self.relay.max_queue_bytes_per_user == 0 {
174            return Err(EnigmaRelayError::Config(
175                "max_queue_bytes_per_user must be positive".to_string(),
176            ));
177        }
178        if self.relay.max_messages_per_user == 0 {
179            return Err(EnigmaRelayError::Config(
180                "max_messages_per_user must be positive".to_string(),
181            ));
182        }
183        if self.relay.pull_batch_max == 0 {
184            return Err(EnigmaRelayError::Config(
185                "pull_batch_max must be positive".to_string(),
186            ));
187        }
188        if self.relay.gc_interval_seconds == 0 {
189            return Err(EnigmaRelayError::Config(
190                "gc_interval_seconds must be positive".to_string(),
191            ));
192        }
193        if self.rate_limit.enabled {
194            if self.rate_limit.per_ip_rps == 0 {
195                return Err(EnigmaRelayError::Config(
196                    "rate_limit.per_ip_rps must be positive".to_string(),
197                ));
198            }
199            if self.rate_limit.burst == 0 {
200                return Err(EnigmaRelayError::Config(
201                    "rate_limit.burst must be positive".to_string(),
202                ));
203            }
204            if self.rate_limit.endpoints.push_rps == 0
205                || self.rate_limit.endpoints.pull_rps == 0
206                || self.rate_limit.endpoints.ack_rps == 0
207            {
208                return Err(EnigmaRelayError::Config(
209                    "endpoint rate limits must be positive".to_string(),
210                ));
211            }
212        }
213        match self.storage.kind {
214            StorageKind::Sled => {
215                #[cfg(not(feature = "persistence"))]
216                {
217                    return Err(EnigmaRelayError::Disabled(
218                        "persistence feature not enabled".to_string(),
219                    ));
220                }
221            }
222            StorageKind::Memory => {}
223        }
224        Ok(())
225    }
226}