rust_ethernet_ip/
config.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::fs;
4use std::path::Path;
5use std::time::Duration;
6
7/// Production configuration for EtherNet/IP library
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ProductionConfig {
10    /// Connection settings
11    pub connection: ConnectionConfig,
12    /// Performance settings
13    pub performance: PerformanceConfig,
14    /// Monitoring settings
15    pub monitoring: MonitoringConfig,
16    /// Security settings
17    pub security: SecurityConfig,
18    /// Logging settings
19    pub logging: LoggingConfig,
20    /// PLC-specific settings
21    pub plc_settings: HashMap<String, PlcSpecificConfig>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ConnectionConfig {
26    /// Default connection timeout
27    pub connection_timeout: Duration,
28    /// Default read timeout
29    pub read_timeout: Duration,
30    /// Default write timeout
31    pub write_timeout: Duration,
32    /// Maximum number of concurrent connections
33    pub max_connections: u32,
34    /// Connection retry attempts
35    pub retry_attempts: u32,
36    /// Retry delay between attempts
37    pub retry_delay: Duration,
38    /// Keep-alive interval
39    pub keep_alive_interval: Duration,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct PerformanceConfig {
44    /// Maximum packet size
45    pub max_packet_size: usize,
46    /// Batch operation configuration
47    pub batch_config: BatchConfig,
48    /// Connection pool settings
49    pub connection_pool: ConnectionPoolConfig,
50    /// Memory limits
51    pub memory_limits: MemoryLimits,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct BatchConfig {
56    /// Maximum operations per batch
57    pub max_operations_per_batch: usize,
58    /// Batch timeout
59    pub batch_timeout: Duration,
60    /// Continue on error
61    pub continue_on_error: bool,
62    /// Optimize packet packing
63    pub optimize_packet_packing: bool,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct ConnectionPoolConfig {
68    /// Initial pool size
69    pub initial_size: u32,
70    /// Maximum pool size
71    pub max_size: u32,
72    /// Pool growth increment
73    pub growth_increment: u32,
74    /// Connection idle timeout
75    pub idle_timeout: Duration,
76    /// Pool cleanup interval
77    pub cleanup_interval: Duration,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct MemoryLimits {
82    /// Maximum memory usage in MB
83    pub max_memory_mb: usize,
84    /// Memory warning threshold in MB
85    pub warning_threshold_mb: usize,
86    /// Enable memory monitoring
87    pub enable_monitoring: bool,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct MonitoringConfig {
92    /// Enable production monitoring
93    pub enabled: bool,
94    /// Metrics collection interval
95    pub collection_interval: Duration,
96    /// Health check interval
97    pub health_check_interval: Duration,
98    /// Metrics retention period
99    pub retention_period: Duration,
100    /// Enable performance profiling
101    pub enable_profiling: bool,
102    /// Alert thresholds
103    pub alert_thresholds: AlertThresholds,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct AlertThresholds {
108    /// Error rate threshold (0.0 to 1.0)
109    pub error_rate_threshold: f64,
110    /// Latency threshold in milliseconds
111    pub latency_threshold_ms: f64,
112    /// Memory usage threshold in MB
113    pub memory_threshold_mb: usize,
114    /// Connection failure threshold
115    pub connection_failure_threshold: u32,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct SecurityConfig {
120    /// Enable connection encryption (if supported by PLC)
121    pub enable_encryption: bool,
122    /// Connection validation
123    pub validate_connections: bool,
124    /// Input validation
125    pub validate_inputs: bool,
126    /// Rate limiting
127    pub rate_limiting: RateLimitingConfig,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct RateLimitingConfig {
132    /// Enable rate limiting
133    pub enabled: bool,
134    /// Maximum requests per second
135    pub max_requests_per_second: u32,
136    /// Burst capacity
137    pub burst_capacity: u32,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct LoggingConfig {
142    /// Log level (trace, debug, info, warn, error)
143    pub level: String,
144    /// Log format (json, text)
145    pub format: String,
146    /// Log file path
147    pub file_path: Option<String>,
148    /// Enable console logging
149    pub enable_console: bool,
150    /// Enable structured logging
151    pub enable_structured: bool,
152    /// Log rotation settings
153    pub rotation: LogRotationConfig,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct LogRotationConfig {
158    /// Enable log rotation
159    pub enabled: bool,
160    /// Maximum file size in MB
161    pub max_file_size_mb: usize,
162    /// Maximum number of files
163    pub max_files: usize,
164    /// Rotation schedule (daily, weekly, monthly)
165    pub schedule: String,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct PlcSpecificConfig {
170    /// PLC model/type
171    pub model: String,
172    /// Specific connection settings
173    pub connection_settings: HashMap<String, String>,
174    /// Tag discovery settings
175    pub tag_discovery: TagDiscoveryConfig,
176    /// Performance tuning
177    pub performance_tuning: HashMap<String, String>,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct TagDiscoveryConfig {
182    /// Enable automatic tag discovery
183    pub enabled: bool,
184    /// Discovery interval
185    pub interval: Duration,
186    /// Cache discovered tags
187    pub cache_tags: bool,
188    /// Maximum tags to discover
189    pub max_tags: usize,
190}
191
192impl Default for ProductionConfig {
193    fn default() -> Self {
194        Self {
195            connection: ConnectionConfig {
196                connection_timeout: Duration::from_secs(10),
197                read_timeout: Duration::from_secs(5),
198                write_timeout: Duration::from_secs(5),
199                max_connections: 10,
200                retry_attempts: 3,
201                retry_delay: Duration::from_secs(1),
202                keep_alive_interval: Duration::from_secs(30),
203            },
204            performance: PerformanceConfig {
205                max_packet_size: 4000,
206                batch_config: BatchConfig {
207                    max_operations_per_batch: 50,
208                    batch_timeout: Duration::from_secs(10),
209                    continue_on_error: true,
210                    optimize_packet_packing: true,
211                },
212                connection_pool: ConnectionPoolConfig {
213                    initial_size: 2,
214                    max_size: 10,
215                    growth_increment: 2,
216                    idle_timeout: Duration::from_secs(300),
217                    cleanup_interval: Duration::from_secs(60),
218                },
219                memory_limits: MemoryLimits {
220                    max_memory_mb: 100,
221                    warning_threshold_mb: 80,
222                    enable_monitoring: true,
223                },
224            },
225            monitoring: MonitoringConfig {
226                enabled: true,
227                collection_interval: Duration::from_secs(30),
228                health_check_interval: Duration::from_secs(60),
229                retention_period: Duration::from_secs(86400), // 24 hours
230                enable_profiling: false,
231                alert_thresholds: AlertThresholds {
232                    error_rate_threshold: 0.05,
233                    latency_threshold_ms: 1000.0,
234                    memory_threshold_mb: 80,
235                    connection_failure_threshold: 5,
236                },
237            },
238            security: SecurityConfig {
239                enable_encryption: false,
240                validate_connections: true,
241                validate_inputs: true,
242                rate_limiting: RateLimitingConfig {
243                    enabled: true,
244                    max_requests_per_second: 100,
245                    burst_capacity: 200,
246                },
247            },
248            logging: LoggingConfig {
249                level: "info".to_string(),
250                format: "json".to_string(),
251                file_path: Some("logs/ethernet_ip.log".to_string()),
252                enable_console: true,
253                enable_structured: true,
254                rotation: LogRotationConfig {
255                    enabled: true,
256                    max_file_size_mb: 100,
257                    max_files: 10,
258                    schedule: "daily".to_string(),
259                },
260            },
261            plc_settings: HashMap::new(),
262        }
263    }
264}
265
266impl ProductionConfig {
267    /// Load configuration from file
268    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
269        let content = fs::read_to_string(path)?;
270        let config: ProductionConfig = toml::from_str(&content)?;
271        Ok(config)
272    }
273
274    /// Save configuration to file
275    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), Box<dyn std::error::Error>> {
276        let content = toml::to_string_pretty(self)?;
277        fs::write(path, content)?;
278        Ok(())
279    }
280
281    /// Validate configuration
282    pub fn validate(&self) -> Result<(), Vec<String>> {
283        let mut errors = Vec::new();
284
285        // Validate connection settings
286        if self.connection.connection_timeout.as_secs() == 0 {
287            errors.push("Connection timeout must be greater than 0".to_string());
288        }
289
290        if self.connection.max_connections == 0 {
291            errors.push("Maximum connections must be greater than 0".to_string());
292        }
293
294        // Validate performance settings
295        if self.performance.max_packet_size < 100 {
296            errors.push("Maximum packet size must be at least 100 bytes".to_string());
297        }
298
299        if self.performance.batch_config.max_operations_per_batch == 0 {
300            errors.push("Maximum operations per batch must be greater than 0".to_string());
301        }
302
303        // Validate monitoring settings
304        if self.monitoring.collection_interval.as_secs() == 0 {
305            errors.push("Collection interval must be greater than 0".to_string());
306        }
307
308        // Validate security settings
309        if self.security.rate_limiting.enabled
310            && self.security.rate_limiting.max_requests_per_second == 0
311        {
312            errors.push(
313                "Max requests per second must be greater than 0 when rate limiting is enabled"
314                    .to_string(),
315            );
316        }
317
318        // Validate logging settings
319        let valid_levels = ["trace", "debug", "info", "warn", "error"];
320        if !valid_levels.contains(&self.logging.level.as_str()) {
321            errors.push(format!(
322                "Invalid log level: {}. Must be one of: {:?}",
323                self.logging.level, valid_levels
324            ));
325        }
326
327        if errors.is_empty() {
328            Ok(())
329        } else {
330            Err(errors)
331        }
332    }
333
334    /// Get PLC-specific configuration
335    pub fn get_plc_config(&self, plc_address: &str) -> Option<&PlcSpecificConfig> {
336        self.plc_settings.get(plc_address)
337    }
338
339    /// Add or update PLC-specific configuration
340    pub fn set_plc_config(&mut self, plc_address: String, config: PlcSpecificConfig) {
341        self.plc_settings.insert(plc_address, config);
342    }
343
344    /// Create a development configuration
345    pub fn development() -> Self {
346        let mut config = Self::default();
347        config.logging.level = "debug".to_string();
348        config.monitoring.enabled = false;
349        config.security.rate_limiting.enabled = false;
350        config.performance.memory_limits.enable_monitoring = false;
351        config
352    }
353
354    /// Create a production configuration
355    pub fn production() -> Self {
356        let mut config = Self::default();
357        config.logging.level = "info".to_string();
358        config.monitoring.enabled = true;
359        config.security.rate_limiting.enabled = true;
360        config.performance.memory_limits.enable_monitoring = true;
361        config.performance.memory_limits.max_memory_mb = 500;
362        config
363    }
364}