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
59impl Default for PluginRuntimeConfig {
60 fn default() -> Self {
61 Self {
62 enabled: true,
63 plugin_dir: PathBuf::from("/etc/heliosproxy/plugins"),
64 hot_reload: false,
65 memory_limit: 64 * 1024 * 1024, timeout: Duration::from_millis(100),
67 max_plugins: 20,
68 fuel_metering: true,
69 fuel_limit: 1_000_000,
70 enable_simd: true,
71 enable_threads: false,
72 cache_modules: true,
73 cache_dir: None,
74 plugins: HashMap::new(),
75 trust_root: None,
76 }
77 }
78}
79
80impl From<&crate::config::PluginToml> for PluginRuntimeConfig {
85 fn from(t: &crate::config::PluginToml) -> Self {
86 Self {
87 enabled: t.enabled,
88 plugin_dir: PathBuf::from(&t.plugin_dir),
89 hot_reload: t.hot_reload,
90 memory_limit: t.memory_limit_mb.saturating_mul(1024 * 1024),
91 timeout: Duration::from_millis(t.timeout_ms),
92 max_plugins: t.max_plugins,
93 fuel_metering: t.fuel_metering,
94 fuel_limit: t.fuel_limit,
95 enable_simd: true,
96 enable_threads: false,
97 cache_modules: true,
98 cache_dir: None,
99 plugins: HashMap::new(),
100 trust_root: t.trust_root.as_ref().map(PathBuf::from),
101 }
102 }
103}
104
105pub struct PluginRuntimeConfigBuilder {
107 config: PluginRuntimeConfig,
108}
109
110impl PluginRuntimeConfigBuilder {
111 pub fn new() -> Self {
113 Self {
114 config: PluginRuntimeConfig::default(),
115 }
116 }
117
118 pub fn enabled(mut self, enabled: bool) -> Self {
120 self.config.enabled = enabled;
121 self
122 }
123
124 pub fn plugin_dir(mut self, dir: PathBuf) -> Self {
126 self.config.plugin_dir = dir;
127 self
128 }
129
130 pub fn hot_reload(mut self, enabled: bool) -> Self {
132 self.config.hot_reload = enabled;
133 self
134 }
135
136 pub fn memory_limit(mut self, limit: usize) -> Self {
138 self.config.memory_limit = limit;
139 self
140 }
141
142 pub fn timeout(mut self, timeout: Duration) -> Self {
144 self.config.timeout = timeout;
145 self
146 }
147
148 pub fn max_plugins(mut self, max: usize) -> Self {
150 self.config.max_plugins = max;
151 self
152 }
153
154 pub fn fuel_metering(mut self, enabled: bool) -> Self {
156 self.config.fuel_metering = enabled;
157 self
158 }
159
160 pub fn fuel_limit(mut self, limit: u64) -> Self {
162 self.config.fuel_limit = limit;
163 self
164 }
165
166 pub fn enable_simd(mut self, enabled: bool) -> Self {
168 self.config.enable_simd = enabled;
169 self
170 }
171
172 pub fn enable_threads(mut self, enabled: bool) -> Self {
174 self.config.enable_threads = enabled;
175 self
176 }
177
178 pub fn cache_modules(mut self, enabled: bool) -> Self {
180 self.config.cache_modules = enabled;
181 self
182 }
183
184 pub fn cache_dir(mut self, dir: PathBuf) -> Self {
186 self.config.cache_dir = Some(dir);
187 self
188 }
189
190 pub fn add_plugin(mut self, name: String, config: PluginConfig) -> Self {
192 self.config.plugins.insert(name, config);
193 self
194 }
195
196 pub fn build(self) -> PluginRuntimeConfig {
198 self.config
199 }
200}
201
202impl Default for PluginRuntimeConfigBuilder {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208#[derive(Debug, Clone)]
210pub struct PluginConfig {
211 pub enabled: bool,
213
214 pub priority: i32,
216
217 pub config: HashMap<String, serde_json::Value>,
219
220 pub memory_limit: Option<usize>,
222
223 pub timeout: Option<Duration>,
225
226 pub fuel_limit: Option<u64>,
228
229 pub permissions: Vec<String>,
231}
232
233impl Default for PluginConfig {
234 fn default() -> Self {
235 Self {
236 enabled: true,
237 priority: 0,
238 config: HashMap::new(),
239 memory_limit: None,
240 timeout: None,
241 fuel_limit: None,
242 permissions: Vec::new(),
243 }
244 }
245}
246
247pub struct PluginConfigBuilder {
249 config: PluginConfig,
250}
251
252impl PluginConfigBuilder {
253 pub fn new() -> Self {
255 Self {
256 config: PluginConfig::default(),
257 }
258 }
259
260 pub fn enabled(mut self, enabled: bool) -> Self {
262 self.config.enabled = enabled;
263 self
264 }
265
266 pub fn priority(mut self, priority: i32) -> Self {
268 self.config.priority = priority;
269 self
270 }
271
272 pub fn config_value(mut self, key: &str, value: serde_json::Value) -> Self {
274 self.config.config.insert(key.to_string(), value);
275 self
276 }
277
278 pub fn memory_limit(mut self, limit: usize) -> Self {
280 self.config.memory_limit = Some(limit);
281 self
282 }
283
284 pub fn timeout(mut self, timeout: Duration) -> Self {
286 self.config.timeout = Some(timeout);
287 self
288 }
289
290 pub fn fuel_limit(mut self, limit: u64) -> Self {
292 self.config.fuel_limit = Some(limit);
293 self
294 }
295
296 pub fn permission(mut self, permission: &str) -> Self {
298 self.config.permissions.push(permission.to_string());
299 self
300 }
301
302 pub fn build(self) -> PluginConfig {
304 self.config
305 }
306}
307
308impl Default for PluginConfigBuilder {
309 fn default() -> Self {
310 Self::new()
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[test]
319 fn test_runtime_config_default() {
320 let config = PluginRuntimeConfig::default();
321 assert!(config.enabled);
322 assert!(!config.hot_reload);
323 assert_eq!(config.memory_limit, 64 * 1024 * 1024);
324 assert_eq!(config.max_plugins, 20);
325 }
326
327 #[test]
328 fn test_runtime_config_builder() {
329 let config = PluginRuntimeConfigBuilder::new()
330 .enabled(true)
331 .hot_reload(true)
332 .memory_limit(128 * 1024 * 1024)
333 .timeout(Duration::from_millis(200))
334 .max_plugins(50)
335 .fuel_metering(true)
336 .fuel_limit(2_000_000)
337 .build();
338
339 assert!(config.enabled);
340 assert!(config.hot_reload);
341 assert_eq!(config.memory_limit, 128 * 1024 * 1024);
342 assert_eq!(config.timeout, Duration::from_millis(200));
343 assert_eq!(config.max_plugins, 50);
344 }
345
346 #[test]
347 fn test_plugin_config_default() {
348 let config = PluginConfig::default();
349 assert!(config.enabled);
350 assert_eq!(config.priority, 0);
351 assert!(config.permissions.is_empty());
352 }
353
354 #[test]
355 fn test_plugin_config_builder() {
356 let config = PluginConfigBuilder::new()
357 .enabled(true)
358 .priority(100)
359 .config_value("key", serde_json::json!("value"))
360 .memory_limit(32 * 1024 * 1024)
361 .permission("http_fetch")
362 .permission("cache_read")
363 .build();
364
365 assert!(config.enabled);
366 assert_eq!(config.priority, 100);
367 assert_eq!(config.config.get("key"), Some(&serde_json::json!("value")));
368 assert_eq!(config.memory_limit, Some(32 * 1024 * 1024));
369 assert_eq!(config.permissions.len(), 2);
370 }
371}