Expand description
Connection factory implementation for plugin-based connections.
This module provides the infrastructure to integrate plugin-based connections
into the core inventory system’s connection management. It bridges the gap
between the PluginConnection trait used by plugins and the Connection trait
expected by the inventory system.
§Overview
The module consists of two main components:
-
[
PluginConnectionAdapter] - An adapter that wrapsPluginConnectionimplementations and provides theConnectioninterface. It tracks connection lifecycle state and delegates operations to the underlying plugin. -
build_connection_factory- A factory function that creates aConnectionFactoryclosure. This factory looks up plugins by connection type and creates appropriate connection instances wrapped in adapters.
§Architecture
┌─────────────────────────────────────────────────────────────┐
│ Connection Manager │
│ (genja_core::inventory) │
└─────────────────────────┬───────────────────────────────────┘
│
│ Uses ConnectionFactory
▼
┌─────────────────────────────────────────────────────────────┐
│ build_connection_factory() │
│ Returns: Arc<ConnectionFactory> │
└─────────────────────────┬───────────────────────────────────┘
│
│ Queries for plugins
▼
┌─────────────────────────────────────────────────────────────┐
│ PluginManager │
│ (Registered Connection Plugins) │
└─────────────────────────┬───────────────────────────────────┘
│
│ Returns plugin instance
▼
┌─────────────────────────────────────────────────────────────┐
│ PluginConnectionAdapter │
│ Wraps: Box<dyn PluginConnection> │
│ Implements: Connection trait │
└─────────────────────────┬───────────────────────────────────┘
│
│ Delegates to
▼
┌─────────────────────────────────────────────────────────────┐
│ Plugin Implementation │
│ (e.g., SSH, Telnet, NETCONF) │
│ Implements: PluginConnection trait │
└─────────────────────────────────────────────────────────────┘§Usage
§Basic Setup
use genja_plugin_manager::{PluginManager, connection_factory::build_connection_factory};
use genja_core::inventory::{ConnectionManager, ConnectionKey};
use std::sync::Arc;
// 1. Create and configure plugin manager
let mut plugin_manager = PluginManager::new();
// Register connection plugins...
// 2. Build connection factory
let factory = build_connection_factory(Arc::new(plugin_manager));
// 3. Set factory in connection manager
let connection_manager = ConnectionManager::default();
connection_manager.set_connection_factory(factory);
// 4. Use connection manager to create connections
let key = ConnectionKey::new("router1", "ssh");
// let connection = connection_manager.get_or_create(key);§Plugin Integration
Connection plugins must implement the PluginConnection trait:
use async_trait::async_trait;
use genja_plugin_manager::plugin_types::{Plugin, PluginConnection};
use genja_core::inventory::{ConnectionKey, ResolvedConnectionParams};
struct MyConnectionPlugin {
key: ConnectionKey,
}
impl Plugin for MyConnectionPlugin {
fn name(&self) -> String {
"my_connection".to_string()
}
}
#[async_trait]
impl PluginConnection for MyConnectionPlugin {
fn create(&self, key: &ConnectionKey) -> Box<dyn PluginConnection> {
Box::new(MyConnectionPlugin { key: key.clone() })
}
async fn open(&mut self, params: &ResolvedConnectionParams) -> Result<(), String> {
// Establish connection
let _ = params;
Ok(())
}
fn close(&mut self) -> ConnectionKey {
// Clean up connection
self.key.clone()
}
fn is_alive(&self) -> bool {
// Check connection status
true
}
}§Connection Lifecycle
The adapter manages the connection lifecycle through the following states:
- Created - Adapter is instantiated with
alive = false - Opening -
open()is called with connection parameters - Open - Connection established successfully,
alive = true - Closing -
close()is called to tear down connection - Closed - Connection terminated,
alive = false
§State Transitions
┌─────────┐
│ Created │ (alive = false)
└────┬────┘
│
│ open() called
▼
┌─────────┐
│ Opening │
└────┬────┘
│
├─ Success ──► ┌──────┐
│ │ Open │ (alive = true)
│ └───┬──┘
│ │
│ │ close() called
│ ▼
│ ┌────────┐
└─ Failure ──► │ Closed │ (alive = false)
└────────┘§Thread Safety
All components in this module are designed for concurrent use:
- The connection factory is wrapped in
Arcand can be shared across threads - Each connection adapter is wrapped in
Arc<Mutex<_>>for safe mutation - The
PluginManagerreference is shared viaArcin the factory closure
§Error Handling
The factory returns Option<Arc<Mutex<dyn Connection>>>:
Some(connection)- Plugin found and connection created successfullyNone- Plugin not found or not a connection plugin
Connection operations return Result<(), String>:
Ok(())- Operation succeededErr(message)- Operation failed with error description
§Performance Considerations
- Connection Pooling: The
ConnectionManagerhandles connection reuse - Lazy Creation: Connections are created only when needed
- Plugin Lookup: Plugin queries are O(1) hash map lookups
- Lock Contention: Each connection has its own mutex to minimize contention
§Examples
§Complete Integration Example
use genja_plugin_manager::{PluginManager, connection_factory::build_connection_factory};
use genja_core::inventory::{
ConnectionManager, ConnectionKey, ResolvedConnectionParams,
BaseBuilderHost, Host, Hosts, Inventory,
};
use std::sync::Arc;
use tokio::runtime::Builder;
// Set up plugin manager with connection plugins
let mut plugin_manager = PluginManager::new();
// plugin_manager.load_plugins_from_directory("plugins")?;
// Create connection factory
let factory = build_connection_factory(Arc::new(plugin_manager));
// Build inventory with hosts
let mut hosts = Hosts::new();
hosts.add_host("router1", Host::builder()
.hostname("10.0.0.1")
.port(22)
.username("admin")
.platform("cisco_ios")
.build());
let inventory = Inventory::builder()
.hosts(hosts)
.build();
// Set up connection manager
let connection_manager = inventory.connections();
connection_manager.set_connection_factory(factory);
// Create and use connection
let key = ConnectionKey::new("router1", "ssh");
// Open connection
let params = ResolvedConnectionParams {
hostname: "10.0.0.1".to_string(),
port: Some(22),
username: Some("admin".to_string()),
password: Some("secret".to_string()),
platform: Some("cisco_ios".to_string()),
extras: None,
};
let runtime = Builder::new_current_thread().enable_all().build()?;
let connection = runtime
.block_on(async { connection_manager.open_connection(&key, ¶ms).await })?
.expect("connection plugin not found");
let conn = runtime.block_on(connection.lock());
// Use connection...
assert!(conn.is_alive());
// Close connection
drop(conn);
connection_manager.close_connection(&key);§See Also
PluginManager- Manages plugin registration and lookupPluginConnection- Plugin connection traitConnection- Core connection traitConnectionFactory- Factory function type for creating connections
Functions§
- build_
connection_ factory - Builds a connection factory that creates connections from registered plugins.