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