1use std::collections::HashMap;
6use std::path::PathBuf;
7use std::time::Duration;
8
9#[derive(Debug, Clone)]
11pub struct PluginRuntimeConfig {
12 pub enabled: bool,
14
15 pub plugin_dir: PathBuf,
17
18 pub hot_reload: bool,
20
21 pub memory_limit: usize,
23
24 pub timeout: Duration,
26
27 pub max_plugins: usize,
29
30 pub fuel_metering: bool,
32
33 pub fuel_limit: u64,
35
36 pub enable_simd: bool,
38
39 pub enable_threads: bool,
41
42 pub cache_modules: bool,
44
45 pub cache_dir: Option<PathBuf>,
47
48 pub plugins: HashMap<String, PluginConfig>,
50
51 pub trust_root: Option<PathBuf>,
57
58 pub kv_max_value_bytes: usize,
61
62 pub kv_max_keys_per_plugin: usize,
64
65 pub kv_max_plugins: usize,
68
69 pub kv_max_total_bytes: usize,
75}
76
77impl Default for PluginRuntimeConfig {
78 fn default() -> Self {
79 Self {
80 enabled: true,
81 plugin_dir: PathBuf::from("/etc/heliosproxy/plugins"),
82 hot_reload: false,
83 memory_limit: 64 * 1024 * 1024, timeout: Duration::from_millis(100),
85 max_plugins: 20,
86 fuel_metering: true,
87 fuel_limit: 1_000_000,
88 enable_simd: true,
89 enable_threads: false,
90 cache_modules: true,
91 cache_dir: None,
92 plugins: HashMap::new(),
93 trust_root: None,
94 kv_max_value_bytes: 65536,
95 kv_max_keys_per_plugin: 1024,
96 kv_max_plugins: 256,
97 kv_max_total_bytes: 64 * 1024 * 1024,
98 }
99 }
100}
101
102impl From<&crate::config::PluginToml> for PluginRuntimeConfig {
107 fn from(t: &crate::config::PluginToml) -> Self {
108 Self {
109 enabled: t.enabled,
110 plugin_dir: PathBuf::from(&t.plugin_dir),
111 hot_reload: t.hot_reload,
112 memory_limit: t.memory_limit_mb.saturating_mul(1024 * 1024),
113 timeout: Duration::from_millis(t.timeout_ms),
114 max_plugins: t.max_plugins,
115 fuel_metering: t.fuel_metering,
116 fuel_limit: t.fuel_limit,
117 enable_simd: true,
118 enable_threads: false,
119 cache_modules: true,
120 cache_dir: None,
121 plugins: HashMap::new(),
122 trust_root: t.trust_root.as_ref().map(PathBuf::from),
123 kv_max_value_bytes: t.kv_max_value_bytes,
124 kv_max_keys_per_plugin: t.kv_max_keys_per_plugin,
125 kv_max_plugins: t.kv_max_plugins,
126 kv_max_total_bytes: t.kv_max_total_bytes,
127 }
128 }
129}
130
131pub struct PluginRuntimeConfigBuilder {
133 config: PluginRuntimeConfig,
134}
135
136impl PluginRuntimeConfigBuilder {
137 pub fn new() -> Self {
139 Self {
140 config: PluginRuntimeConfig::default(),
141 }
142 }
143
144 pub fn enabled(mut self, enabled: bool) -> Self {
146 self.config.enabled = enabled;
147 self
148 }
149
150 pub fn plugin_dir(mut self, dir: PathBuf) -> Self {
152 self.config.plugin_dir = dir;
153 self
154 }
155
156 pub fn hot_reload(mut self, enabled: bool) -> Self {
158 self.config.hot_reload = enabled;
159 self
160 }
161
162 pub fn memory_limit(mut self, limit: usize) -> Self {
164 self.config.memory_limit = limit;
165 self
166 }
167
168 pub fn timeout(mut self, timeout: Duration) -> Self {
170 self.config.timeout = timeout;
171 self
172 }
173
174 pub fn max_plugins(mut self, max: usize) -> Self {
176 self.config.max_plugins = max;
177 self
178 }
179
180 pub fn fuel_metering(mut self, enabled: bool) -> Self {
182 self.config.fuel_metering = enabled;
183 self
184 }
185
186 pub fn fuel_limit(mut self, limit: u64) -> Self {
188 self.config.fuel_limit = limit;
189 self
190 }
191
192 pub fn enable_simd(mut self, enabled: bool) -> Self {
194 self.config.enable_simd = enabled;
195 self
196 }
197
198 pub fn enable_threads(mut self, enabled: bool) -> Self {
200 self.config.enable_threads = enabled;
201 self
202 }
203
204 pub fn cache_modules(mut self, enabled: bool) -> Self {
206 self.config.cache_modules = enabled;
207 self
208 }
209
210 pub fn cache_dir(mut self, dir: PathBuf) -> Self {
212 self.config.cache_dir = Some(dir);
213 self
214 }
215
216 pub fn add_plugin(mut self, name: String, config: PluginConfig) -> Self {
218 self.config.plugins.insert(name, config);
219 self
220 }
221
222 pub fn build(self) -> PluginRuntimeConfig {
224 self.config
225 }
226}
227
228impl Default for PluginRuntimeConfigBuilder {
229 fn default() -> Self {
230 Self::new()
231 }
232}
233
234#[derive(Debug, Clone)]
236pub struct PluginConfig {
237 pub enabled: bool,
239
240 pub priority: i32,
242
243 pub config: HashMap<String, serde_json::Value>,
245
246 pub memory_limit: Option<usize>,
248
249 pub timeout: Option<Duration>,
251
252 pub fuel_limit: Option<u64>,
254
255 pub permissions: Vec<String>,
257}
258
259impl Default for PluginConfig {
260 fn default() -> Self {
261 Self {
262 enabled: true,
263 priority: 0,
264 config: HashMap::new(),
265 memory_limit: None,
266 timeout: None,
267 fuel_limit: None,
268 permissions: Vec::new(),
269 }
270 }
271}
272
273pub struct PluginConfigBuilder {
275 config: PluginConfig,
276}
277
278impl PluginConfigBuilder {
279 pub fn new() -> Self {
281 Self {
282 config: PluginConfig::default(),
283 }
284 }
285
286 pub fn enabled(mut self, enabled: bool) -> Self {
288 self.config.enabled = enabled;
289 self
290 }
291
292 pub fn priority(mut self, priority: i32) -> Self {
294 self.config.priority = priority;
295 self
296 }
297
298 pub fn config_value(mut self, key: &str, value: serde_json::Value) -> Self {
300 self.config.config.insert(key.to_string(), value);
301 self
302 }
303
304 pub fn memory_limit(mut self, limit: usize) -> Self {
306 self.config.memory_limit = Some(limit);
307 self
308 }
309
310 pub fn timeout(mut self, timeout: Duration) -> Self {
312 self.config.timeout = Some(timeout);
313 self
314 }
315
316 pub fn fuel_limit(mut self, limit: u64) -> Self {
318 self.config.fuel_limit = Some(limit);
319 self
320 }
321
322 pub fn permission(mut self, permission: &str) -> Self {
324 self.config.permissions.push(permission.to_string());
325 self
326 }
327
328 pub fn build(self) -> PluginConfig {
330 self.config
331 }
332}
333
334impl Default for PluginConfigBuilder {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_runtime_config_default() {
346 let config = PluginRuntimeConfig::default();
347 assert!(config.enabled);
348 assert!(!config.hot_reload);
349 assert_eq!(config.memory_limit, 64 * 1024 * 1024);
350 assert_eq!(config.max_plugins, 20);
351 }
352
353 #[test]
354 fn test_runtime_config_builder() {
355 let config = PluginRuntimeConfigBuilder::new()
356 .enabled(true)
357 .hot_reload(true)
358 .memory_limit(128 * 1024 * 1024)
359 .timeout(Duration::from_millis(200))
360 .max_plugins(50)
361 .fuel_metering(true)
362 .fuel_limit(2_000_000)
363 .build();
364
365 assert!(config.enabled);
366 assert!(config.hot_reload);
367 assert_eq!(config.memory_limit, 128 * 1024 * 1024);
368 assert_eq!(config.timeout, Duration::from_millis(200));
369 assert_eq!(config.max_plugins, 50);
370 }
371
372 #[test]
373 fn test_plugin_config_default() {
374 let config = PluginConfig::default();
375 assert!(config.enabled);
376 assert_eq!(config.priority, 0);
377 assert!(config.permissions.is_empty());
378 }
379
380 #[test]
381 fn test_plugin_config_builder() {
382 let config = PluginConfigBuilder::new()
383 .enabled(true)
384 .priority(100)
385 .config_value("key", serde_json::json!("value"))
386 .memory_limit(32 * 1024 * 1024)
387 .permission("http_fetch")
388 .permission("cache_read")
389 .build();
390
391 assert!(config.enabled);
392 assert_eq!(config.priority, 100);
393 assert_eq!(config.config.get("key"), Some(&serde_json::json!("value")));
394 assert_eq!(config.memory_limit, Some(32 * 1024 * 1024));
395 assert_eq!(config.permissions.len(), 2);
396 }
397}