1use std::collections::HashMap;
7use std::sync::Arc;
8
9use parking_lot::RwLock;
10
11use crate::config::DeviceConfig;
12use crate::device::BoxedDevice;
13use crate::error::{Error, Result};
14use crate::protocol::Protocol;
15
16pub trait DeviceFactory: Send + Sync {
36 fn protocol(&self) -> Protocol;
38
39 fn create(&self, config: DeviceConfig) -> Result<BoxedDevice>;
41
42 fn create_batch(&self, configs: Vec<DeviceConfig>) -> Result<Vec<BoxedDevice>> {
44 configs.into_iter().map(|c| self.create(c)).collect()
45 }
46
47 fn validate(&self, config: &DeviceConfig) -> Result<()> {
49 if config.id.is_empty() {
50 return Err(Error::Config("Device ID cannot be empty".into()));
51 }
52 if config.name.is_empty() {
53 return Err(Error::Config("Device name cannot be empty".into()));
54 }
55 if config.protocol != self.protocol() {
56 return Err(Error::Config(format!(
57 "Protocol mismatch: expected {:?}, got {:?}",
58 self.protocol(),
59 config.protocol
60 )));
61 }
62 Ok(())
63 }
64
65 fn metadata(&self) -> FactoryMetadata {
67 FactoryMetadata {
68 protocol: self.protocol(),
69 version: "1.0.0".to_string(),
70 description: format!("{:?} device factory", self.protocol()),
71 capabilities: Vec::new(),
72 }
73 }
74}
75
76#[derive(Debug, Clone)]
78pub struct FactoryMetadata {
79 pub protocol: Protocol,
81 pub version: String,
83 pub description: String,
85 pub capabilities: Vec<String>,
87}
88
89pub type BoxedFactory = Box<dyn DeviceFactory>;
91
92pub struct FactoryRegistry {
107 factories: RwLock<HashMap<Protocol, Arc<BoxedFactory>>>,
108}
109
110impl FactoryRegistry {
111 pub fn new() -> Self {
113 Self {
114 factories: RwLock::new(HashMap::new()),
115 }
116 }
117
118 pub fn register<F: DeviceFactory + 'static>(&self, factory: F) -> Result<()> {
120 let protocol = factory.protocol();
121 let mut factories = self.factories.write();
122
123 if factories.contains_key(&protocol) {
124 return Err(Error::Config(format!(
125 "Factory already registered for protocol {:?}",
126 protocol
127 )));
128 }
129
130 factories.insert(protocol, Arc::new(Box::new(factory)));
131 Ok(())
132 }
133
134 pub fn register_boxed(&self, factory: BoxedFactory) -> Result<()> {
136 let protocol = factory.protocol();
137 let mut factories = self.factories.write();
138
139 if factories.contains_key(&protocol) {
140 return Err(Error::Config(format!(
141 "Factory already registered for protocol {:?}",
142 protocol
143 )));
144 }
145
146 factories.insert(protocol, Arc::new(factory));
147 Ok(())
148 }
149
150 pub fn unregister(&self, protocol: Protocol) -> bool {
152 self.factories.write().remove(&protocol).is_some()
153 }
154
155 pub fn get(&self, protocol: Protocol) -> Option<Arc<BoxedFactory>> {
157 self.factories.read().get(&protocol).cloned()
158 }
159
160 pub fn has(&self, protocol: Protocol) -> bool {
162 self.factories.read().contains_key(&protocol)
163 }
164
165 pub fn protocols(&self) -> Vec<Protocol> {
167 self.factories.read().keys().copied().collect()
168 }
169
170 pub fn all_metadata(&self) -> Vec<FactoryMetadata> {
172 self.factories
173 .read()
174 .values()
175 .map(|f| f.metadata())
176 .collect()
177 }
178
179 pub fn create_device(&self, config: DeviceConfig) -> Result<BoxedDevice> {
181 let factory = self
182 .get(config.protocol)
183 .ok_or_else(|| Error::NotSupported(format!("Protocol {:?}", config.protocol)))?;
184
185 factory.validate(&config)?;
186 factory.create(config)
187 }
188
189 pub fn create_devices(&self, configs: Vec<DeviceConfig>) -> Result<Vec<BoxedDevice>> {
191 configs
192 .into_iter()
193 .map(|c| self.create_device(c))
194 .collect()
195 }
196}
197
198impl Default for FactoryRegistry {
199 fn default() -> Self {
200 Self::new()
201 }
202}
203
204pub trait Plugin: Send + Sync {
208 fn name(&self) -> &str;
210
211 fn version(&self) -> &str {
213 "1.0.0"
214 }
215
216 fn description(&self) -> &str {
218 ""
219 }
220
221 fn initialize(&mut self) -> Result<()> {
223 Ok(())
224 }
225
226 fn register_factories(&self, _registry: &FactoryRegistry) -> Result<()> {
228 Ok(())
229 }
230
231 fn shutdown(&mut self) -> Result<()> {
233 Ok(())
234 }
235}
236
237pub type BoxedPlugin = Box<dyn Plugin>;
239
240pub struct PluginManager {
242 plugins: RwLock<Vec<BoxedPlugin>>,
243 registry: Arc<FactoryRegistry>,
244}
245
246impl PluginManager {
247 pub fn new(registry: Arc<FactoryRegistry>) -> Self {
249 Self {
250 plugins: RwLock::new(Vec::new()),
251 registry,
252 }
253 }
254
255 pub fn load<P: Plugin + 'static>(&self, mut plugin: P) -> Result<()> {
257 plugin.initialize()?;
258 plugin.register_factories(&self.registry)?;
259
260 self.plugins.write().push(Box::new(plugin));
261 Ok(())
262 }
263
264 pub fn load_boxed(&self, mut plugin: BoxedPlugin) -> Result<()> {
266 plugin.initialize()?;
267 plugin.register_factories(&self.registry)?;
268
269 self.plugins.write().push(plugin);
270 Ok(())
271 }
272
273 pub fn plugin_count(&self) -> usize {
275 self.plugins.read().len()
276 }
277
278 pub fn plugin_info(&self) -> Vec<PluginInfo> {
280 self.plugins
281 .read()
282 .iter()
283 .map(|p| PluginInfo {
284 name: p.name().to_string(),
285 version: p.version().to_string(),
286 description: p.description().to_string(),
287 })
288 .collect()
289 }
290
291 pub fn registry(&self) -> &Arc<FactoryRegistry> {
293 &self.registry
294 }
295
296 pub fn shutdown_all(&self) -> Result<()> {
298 for plugin in self.plugins.write().iter_mut() {
299 plugin.shutdown()?;
300 }
301 Ok(())
302 }
303}
304
305#[derive(Debug, Clone)]
307pub struct PluginInfo {
308 pub name: String,
310 pub version: String,
312 pub description: String,
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319 use crate::device::{Device, DeviceInfo, DeviceStatistics};
320 use crate::types::{DataPoint, DataPointDef, DataPointId};
321 use crate::value::Value;
322 use async_trait::async_trait;
323
324 struct MockDevice {
326 info: DeviceInfo,
327 }
328
329 impl MockDevice {
330 fn new(id: &str, name: &str) -> Self {
331 Self {
332 info: DeviceInfo::new(id, name, Protocol::ModbusTcp),
333 }
334 }
335 }
336
337 #[async_trait]
338 impl Device for MockDevice {
339 fn info(&self) -> &DeviceInfo {
340 &self.info
341 }
342
343 async fn initialize(&mut self) -> Result<()> {
344 Ok(())
345 }
346
347 async fn start(&mut self) -> Result<()> {
348 Ok(())
349 }
350
351 async fn stop(&mut self) -> Result<()> {
352 Ok(())
353 }
354
355 async fn tick(&mut self) -> Result<()> {
356 Ok(())
357 }
358
359 fn point_definitions(&self) -> Vec<&DataPointDef> {
360 vec![]
361 }
362
363 fn point_definition(&self, _point_id: &str) -> Option<&DataPointDef> {
364 None
365 }
366
367 async fn read(&self, point_id: &str) -> Result<DataPoint> {
368 Ok(DataPoint::new(
369 DataPointId::new(&self.info.id, point_id),
370 Value::F64(0.0),
371 ))
372 }
373
374 async fn write(&mut self, _point_id: &str, _value: Value) -> Result<()> {
375 Ok(())
376 }
377
378 fn statistics(&self) -> DeviceStatistics {
379 DeviceStatistics::default()
380 }
381 }
382
383 struct MockFactory;
385
386 impl DeviceFactory for MockFactory {
387 fn protocol(&self) -> Protocol {
388 Protocol::ModbusTcp
389 }
390
391 fn create(&self, config: DeviceConfig) -> Result<BoxedDevice> {
392 Ok(Box::new(MockDevice::new(&config.id, &config.name)))
393 }
394 }
395
396 struct MockPlugin {
398 name: String,
399 }
400
401 impl MockPlugin {
402 fn new(name: &str) -> Self {
403 Self {
404 name: name.to_string(),
405 }
406 }
407 }
408
409 impl Plugin for MockPlugin {
410 fn name(&self) -> &str {
411 &self.name
412 }
413
414 fn description(&self) -> &str {
415 "Mock plugin for testing"
416 }
417
418 fn register_factories(&self, registry: &FactoryRegistry) -> Result<()> {
419 registry.register(MockFactory)
420 }
421 }
422
423 #[test]
424 fn test_factory_registry() {
425 let registry = FactoryRegistry::new();
426
427 assert!(!registry.has(Protocol::ModbusTcp));
428
429 registry.register(MockFactory).unwrap();
430
431 assert!(registry.has(Protocol::ModbusTcp));
432 assert!(registry.protocols().contains(&Protocol::ModbusTcp));
433 }
434
435 #[test]
436 fn test_factory_create_device() {
437 let registry = FactoryRegistry::new();
438 registry.register(MockFactory).unwrap();
439
440 let config = DeviceConfig {
441 id: "test-001".to_string(),
442 name: "Test Device".to_string(),
443 description: String::new(),
444 protocol: Protocol::ModbusTcp,
445 address: None,
446 points: vec![],
447 metadata: Default::default(),
448 };
449
450 let device = registry.create_device(config).unwrap();
451 assert_eq!(device.id(), "test-001");
452 }
453
454 #[test]
455 fn test_factory_validation() {
456 let factory = MockFactory;
457
458 let config = DeviceConfig {
460 id: String::new(),
461 name: "Test".to_string(),
462 description: String::new(),
463 protocol: Protocol::ModbusTcp,
464 address: None,
465 points: vec![],
466 metadata: Default::default(),
467 };
468 assert!(factory.validate(&config).is_err());
469
470 let config = DeviceConfig {
472 id: "test".to_string(),
473 name: "Test".to_string(),
474 description: String::new(),
475 protocol: Protocol::OpcUa,
476 address: None,
477 points: vec![],
478 metadata: Default::default(),
479 };
480 assert!(factory.validate(&config).is_err());
481 }
482
483 #[test]
484 fn test_plugin_manager() {
485 let registry = Arc::new(FactoryRegistry::new());
486 let manager = PluginManager::new(registry.clone());
487
488 assert_eq!(manager.plugin_count(), 0);
489
490 manager.load(MockPlugin::new("test-plugin")).unwrap();
491
492 assert_eq!(manager.plugin_count(), 1);
493 assert!(registry.has(Protocol::ModbusTcp));
494
495 let info = manager.plugin_info();
496 assert_eq!(info[0].name, "test-plugin");
497 }
498
499 #[test]
500 fn test_duplicate_factory_registration() {
501 let registry = FactoryRegistry::new();
502
503 registry.register(MockFactory).unwrap();
504 let result = registry.register(MockFactory);
505
506 assert!(result.is_err());
507 }
508}