mabi_modbus/runtime/
config.rs1use std::time::Duration;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ConnectionLimits {
10 pub max_connections: usize,
12
13 pub max_per_ip: Option<usize>,
15
16 pub rate_limit: Option<f64>,
18
19 pub burst_size: Option<usize>,
21}
22
23impl Default for ConnectionLimits {
24 fn default() -> Self {
25 Self {
26 max_connections: 100,
27 max_per_ip: Some(10),
28 rate_limit: None,
29 burst_size: None,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct TimeoutConfig {
37 pub idle: Duration,
39
40 pub request: Duration,
42
43 pub handshake: Duration,
45}
46
47impl Default for TimeoutConfig {
48 fn default() -> Self {
49 Self {
50 idle: Duration::from_secs(300),
51 request: Duration::from_secs(30),
52 handshake: Duration::from_secs(10),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct AccessControl {
60 pub default_read: bool,
62
63 pub default_write: bool,
65
66 pub read_only_ranges: Vec<AddressRange>,
68
69 pub write_only_ranges: Vec<AddressRange>,
71
72 pub blocked_ranges: Vec<AddressRange>,
74}
75
76impl Default for AccessControl {
77 fn default() -> Self {
78 Self {
79 default_read: true,
80 default_write: true,
81 read_only_ranges: Vec::new(),
82 write_only_ranges: Vec::new(),
83 blocked_ranges: Vec::new(),
84 }
85 }
86}
87
88impl AccessControl {
89 pub fn can_read(&self, address: u16) -> bool {
91 for range in &self.blocked_ranges {
93 if range.contains(address) {
94 return false;
95 }
96 }
97
98 for range in &self.write_only_ranges {
100 if range.contains(address) {
101 return false;
102 }
103 }
104
105 for range in &self.read_only_ranges {
107 if range.contains(address) {
108 return true;
109 }
110 }
111
112 self.default_read
113 }
114
115 pub fn can_write(&self, address: u16) -> bool {
117 for range in &self.blocked_ranges {
119 if range.contains(address) {
120 return false;
121 }
122 }
123
124 for range in &self.read_only_ranges {
126 if range.contains(address) {
127 return false;
128 }
129 }
130
131 for range in &self.write_only_ranges {
133 if range.contains(address) {
134 return true;
135 }
136 }
137
138 self.default_write
139 }
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct AddressRange {
145 pub start: u16,
147
148 pub end: u16,
150}
151
152impl AddressRange {
153 pub fn new(start: u16, end: u16) -> Self {
155 Self {
156 start: start.min(end),
157 end: start.max(end),
158 }
159 }
160
161 pub fn single(address: u16) -> Self {
163 Self::new(address, address)
164 }
165
166 pub fn contains(&self, address: u16) -> bool {
168 address >= self.start && address <= self.end
169 }
170
171 pub fn len(&self) -> usize {
173 (self.end - self.start + 1) as usize
174 }
175
176 pub fn is_empty(&self) -> bool {
178 false }
180}
181
182#[derive(Debug, Clone, Default, Serialize, Deserialize)]
184pub struct FeatureFlags {
185 pub detailed_metrics: bool,
187
188 pub request_logging: bool,
190
191 pub connection_logging: bool,
193
194 pub slow_request_warnings: bool,
196
197 pub slow_request_threshold_ms: u64,
199
200 pub broadcast_enabled: bool,
202
203 pub writes_enabled: bool,
205
206 pub diagnostics_enabled: bool,
208}
209
210impl FeatureFlags {
211 pub fn production() -> Self {
213 Self {
214 detailed_metrics: false,
215 request_logging: false,
216 connection_logging: false,
217 slow_request_warnings: true,
218 slow_request_threshold_ms: 100,
219 broadcast_enabled: false,
220 writes_enabled: true,
221 diagnostics_enabled: false,
222 }
223 }
224
225 pub fn development() -> Self {
227 Self {
228 detailed_metrics: true,
229 request_logging: true,
230 connection_logging: true,
231 slow_request_warnings: true,
232 slow_request_threshold_ms: 50,
233 broadcast_enabled: true,
234 writes_enabled: true,
235 diagnostics_enabled: true,
236 }
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn test_address_range() {
246 let range = AddressRange::new(100, 200);
247 assert!(range.contains(100));
248 assert!(range.contains(150));
249 assert!(range.contains(200));
250 assert!(!range.contains(99));
251 assert!(!range.contains(201));
252 assert_eq!(range.len(), 101);
253 }
254
255 #[test]
256 fn test_address_range_reversed() {
257 let range = AddressRange::new(200, 100);
259 assert_eq!(range.start, 100);
260 assert_eq!(range.end, 200);
261 }
262
263 #[test]
264 fn test_access_control_default() {
265 let access = AccessControl::default();
266 assert!(access.can_read(0));
267 assert!(access.can_read(65535));
268 assert!(access.can_write(0));
269 assert!(access.can_write(65535));
270 }
271
272 #[test]
273 fn test_access_control_read_only() {
274 let mut access = AccessControl::default();
275 access.read_only_ranges.push(AddressRange::new(100, 200));
276
277 assert!(access.can_read(150));
278 assert!(!access.can_write(150)); assert!(access.can_write(50)); }
281
282 #[test]
283 fn test_access_control_blocked() {
284 let mut access = AccessControl::default();
285 access.blocked_ranges.push(AddressRange::new(500, 600));
286
287 assert!(!access.can_read(550));
288 assert!(!access.can_write(550));
289 assert!(access.can_read(499));
290 assert!(access.can_read(601));
291 }
292
293 #[test]
294 fn test_feature_flags_production() {
295 let flags = FeatureFlags::production();
296 assert!(!flags.detailed_metrics);
297 assert!(!flags.request_logging);
298 assert!(flags.writes_enabled);
299 }
300
301 #[test]
302 fn test_feature_flags_development() {
303 let flags = FeatureFlags::development();
304 assert!(flags.detailed_metrics);
305 assert!(flags.request_logging);
306 assert!(flags.diagnostics_enabled);
307 }
308
309 #[test]
310 fn test_timeout_config_default() {
311 let config = TimeoutConfig::default();
312 assert_eq!(config.idle, Duration::from_secs(300));
313 assert_eq!(config.request, Duration::from_secs(30));
314 }
315
316 #[test]
317 fn test_connection_limits_default() {
318 let limits = ConnectionLimits::default();
319 assert_eq!(limits.max_connections, 100);
320 assert_eq!(limits.max_per_ip, Some(10));
321 }
322}