use std::collections::HashMap;
use std::path::PathBuf;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct PluginRuntimeConfig {
pub enabled: bool,
pub plugin_dir: PathBuf,
pub hot_reload: bool,
pub memory_limit: usize,
pub timeout: Duration,
pub max_plugins: usize,
pub fuel_metering: bool,
pub fuel_limit: u64,
pub enable_simd: bool,
pub enable_threads: bool,
pub cache_modules: bool,
pub cache_dir: Option<PathBuf>,
pub plugins: HashMap<String, PluginConfig>,
pub trust_root: Option<PathBuf>,
}
impl Default for PluginRuntimeConfig {
fn default() -> Self {
Self {
enabled: true,
plugin_dir: PathBuf::from("/etc/heliosproxy/plugins"),
hot_reload: false,
memory_limit: 64 * 1024 * 1024, timeout: Duration::from_millis(100),
max_plugins: 20,
fuel_metering: true,
fuel_limit: 1_000_000,
enable_simd: true,
enable_threads: false,
cache_modules: true,
cache_dir: None,
plugins: HashMap::new(),
trust_root: None,
}
}
}
impl From<&crate::config::PluginToml> for PluginRuntimeConfig {
fn from(t: &crate::config::PluginToml) -> Self {
Self {
enabled: t.enabled,
plugin_dir: PathBuf::from(&t.plugin_dir),
hot_reload: t.hot_reload,
memory_limit: t.memory_limit_mb.saturating_mul(1024 * 1024),
timeout: Duration::from_millis(t.timeout_ms),
max_plugins: t.max_plugins,
fuel_metering: t.fuel_metering,
fuel_limit: t.fuel_limit,
enable_simd: true,
enable_threads: false,
cache_modules: true,
cache_dir: None,
plugins: HashMap::new(),
trust_root: t.trust_root.as_ref().map(PathBuf::from),
}
}
}
pub struct PluginRuntimeConfigBuilder {
config: PluginRuntimeConfig,
}
impl PluginRuntimeConfigBuilder {
pub fn new() -> Self {
Self {
config: PluginRuntimeConfig::default(),
}
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.config.enabled = enabled;
self
}
pub fn plugin_dir(mut self, dir: PathBuf) -> Self {
self.config.plugin_dir = dir;
self
}
pub fn hot_reload(mut self, enabled: bool) -> Self {
self.config.hot_reload = enabled;
self
}
pub fn memory_limit(mut self, limit: usize) -> Self {
self.config.memory_limit = limit;
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.config.timeout = timeout;
self
}
pub fn max_plugins(mut self, max: usize) -> Self {
self.config.max_plugins = max;
self
}
pub fn fuel_metering(mut self, enabled: bool) -> Self {
self.config.fuel_metering = enabled;
self
}
pub fn fuel_limit(mut self, limit: u64) -> Self {
self.config.fuel_limit = limit;
self
}
pub fn enable_simd(mut self, enabled: bool) -> Self {
self.config.enable_simd = enabled;
self
}
pub fn enable_threads(mut self, enabled: bool) -> Self {
self.config.enable_threads = enabled;
self
}
pub fn cache_modules(mut self, enabled: bool) -> Self {
self.config.cache_modules = enabled;
self
}
pub fn cache_dir(mut self, dir: PathBuf) -> Self {
self.config.cache_dir = Some(dir);
self
}
pub fn add_plugin(mut self, name: String, config: PluginConfig) -> Self {
self.config.plugins.insert(name, config);
self
}
pub fn build(self) -> PluginRuntimeConfig {
self.config
}
}
impl Default for PluginRuntimeConfigBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct PluginConfig {
pub enabled: bool,
pub priority: i32,
pub config: HashMap<String, serde_json::Value>,
pub memory_limit: Option<usize>,
pub timeout: Option<Duration>,
pub fuel_limit: Option<u64>,
pub permissions: Vec<String>,
}
impl Default for PluginConfig {
fn default() -> Self {
Self {
enabled: true,
priority: 0,
config: HashMap::new(),
memory_limit: None,
timeout: None,
fuel_limit: None,
permissions: Vec::new(),
}
}
}
pub struct PluginConfigBuilder {
config: PluginConfig,
}
impl PluginConfigBuilder {
pub fn new() -> Self {
Self {
config: PluginConfig::default(),
}
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.config.enabled = enabled;
self
}
pub fn priority(mut self, priority: i32) -> Self {
self.config.priority = priority;
self
}
pub fn config_value(mut self, key: &str, value: serde_json::Value) -> Self {
self.config.config.insert(key.to_string(), value);
self
}
pub fn memory_limit(mut self, limit: usize) -> Self {
self.config.memory_limit = Some(limit);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.config.timeout = Some(timeout);
self
}
pub fn fuel_limit(mut self, limit: u64) -> Self {
self.config.fuel_limit = Some(limit);
self
}
pub fn permission(mut self, permission: &str) -> Self {
self.config.permissions.push(permission.to_string());
self
}
pub fn build(self) -> PluginConfig {
self.config
}
}
impl Default for PluginConfigBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_runtime_config_default() {
let config = PluginRuntimeConfig::default();
assert!(config.enabled);
assert!(!config.hot_reload);
assert_eq!(config.memory_limit, 64 * 1024 * 1024);
assert_eq!(config.max_plugins, 20);
}
#[test]
fn test_runtime_config_builder() {
let config = PluginRuntimeConfigBuilder::new()
.enabled(true)
.hot_reload(true)
.memory_limit(128 * 1024 * 1024)
.timeout(Duration::from_millis(200))
.max_plugins(50)
.fuel_metering(true)
.fuel_limit(2_000_000)
.build();
assert!(config.enabled);
assert!(config.hot_reload);
assert_eq!(config.memory_limit, 128 * 1024 * 1024);
assert_eq!(config.timeout, Duration::from_millis(200));
assert_eq!(config.max_plugins, 50);
}
#[test]
fn test_plugin_config_default() {
let config = PluginConfig::default();
assert!(config.enabled);
assert_eq!(config.priority, 0);
assert!(config.permissions.is_empty());
}
#[test]
fn test_plugin_config_builder() {
let config = PluginConfigBuilder::new()
.enabled(true)
.priority(100)
.config_value("key", serde_json::json!("value"))
.memory_limit(32 * 1024 * 1024)
.permission("http_fetch")
.permission("cache_read")
.build();
assert!(config.enabled);
assert_eq!(config.priority, 100);
assert_eq!(config.config.get("key"), Some(&serde_json::json!("value")));
assert_eq!(config.memory_limit, Some(32 * 1024 * 1024));
assert_eq!(config.permissions.len(), 2);
}
}