mod config;
mod device;
pub use config::ManagerConfig;
pub use device::Device;
use std::sync::Arc;
use anyhow::{Context, Result};
use crate::{certmanager, controller, transport};
pub struct DeviceManager {
base_path: String,
config: ManagerConfig,
transport: Arc<transport::Transport>,
controller: Arc<controller::Controller>,
certmanager: Arc<dyn certmanager::CertManager>,
registry: std::sync::Mutex<device::DeviceRegistry>,
}
impl DeviceManager {
pub async fn create(base_path: &str, config: ManagerConfig) -> Result<Self> {
std::fs::create_dir_all(base_path)
.context(format!("creating base directory {}", base_path))?;
config::save_config(base_path, &config)?;
let pem = config::pem_path(base_path);
let cm = certmanager::FileCertManager::new(config.fabric_id, &pem);
cm.bootstrap()?;
cm.create_user(config.controller_id)?;
let cm: Arc<dyn certmanager::CertManager> = certmanager::FileCertManager::load(&pem)?;
let transport = transport::Transport::new(&config.local_address).await?;
let controller = controller::Controller::new(&cm, &transport, config.fabric_id)?;
let registry = device::DeviceRegistry::load(&config::devices_path(base_path))?;
Ok(Self {
base_path: base_path.to_owned(),
config,
transport,
controller,
certmanager: cm,
registry: std::sync::Mutex::new(registry),
})
}
pub async fn load(base_path: &str) -> Result<Self> {
let config = config::load_config(base_path)?;
let pem = config::pem_path(base_path);
let cm: Arc<dyn certmanager::CertManager> = certmanager::FileCertManager::load(&pem)?;
let transport = transport::Transport::new(&config.local_address).await?;
let controller = controller::Controller::new(&cm, &transport, config.fabric_id)?;
let registry = device::DeviceRegistry::load(&config::devices_path(base_path))?;
Ok(Self {
base_path: base_path.to_owned(),
config,
transport,
controller,
certmanager: cm,
registry: std::sync::Mutex::new(registry),
})
}
pub async fn commission(
&self,
address: &str,
pin: u32,
node_id: u64,
name: &str,
) -> Result<controller::Connection> {
let conn = self.transport.create_connection(address).await;
let connection = self
.controller
.commission(&conn, pin, node_id, self.config.controller_id)
.await?;
let device = Device {
node_id,
address: address.to_owned(),
name: name.to_owned(),
};
self.registry
.lock()
.map_err(|e| anyhow::anyhow!("registry lock: {}", e))?
.add(device)?;
Ok(connection)
}
pub async fn connect(&self, node_id: u64) -> Result<controller::Connection> {
let address = {
let reg = self.registry.lock().map_err(|e| anyhow::anyhow!("registry lock: {}", e))?;
reg.get(node_id)
.context(format!("device {} not found in registry", node_id))?
.address
.clone()
};
let conn = self.transport.create_connection(&address).await;
self.controller
.auth_sigma(&conn, node_id, self.config.controller_id)
.await
}
pub async fn connect_by_name(&self, name: &str) -> Result<controller::Connection> {
let (node_id, address) = {
let reg = self.registry.lock().map_err(|e| anyhow::anyhow!("registry lock: {}", e))?;
let dev = reg
.get_by_name(name)
.context(format!("device '{}' not found in registry", name))?;
(dev.node_id, dev.address.clone())
};
let conn = self.transport.create_connection(&address).await;
self.controller
.auth_sigma(&conn, node_id, self.config.controller_id)
.await
}
pub fn list_devices(&self) -> Result<Vec<Device>> {
let reg = self.registry.lock().map_err(|e| anyhow::anyhow!("registry lock: {}", e))?;
Ok(reg.list().to_vec())
}
pub fn get_device(&self, node_id: u64) -> Result<Option<Device>> {
let reg = self.registry.lock().map_err(|e| anyhow::anyhow!("registry lock: {}", e))?;
Ok(reg.get(node_id).cloned())
}
pub fn get_device_by_name(&self, name: &str) -> Result<Option<Device>> {
let reg = self.registry.lock().map_err(|e| anyhow::anyhow!("registry lock: {}", e))?;
Ok(reg.get_by_name(name).cloned())
}
pub fn remove_device(&self, node_id: u64) -> Result<()> {
self.registry
.lock()
.map_err(|e| anyhow::anyhow!("registry lock: {}", e))?
.remove(node_id)
}
pub fn rename_device(&self, node_id: u64, name: &str) -> Result<()> {
self.registry
.lock()
.map_err(|e| anyhow::anyhow!("registry lock: {}", e))?
.rename(node_id, name)
}
pub fn update_device_address(&self, node_id: u64, address: &str) -> Result<()> {
self.registry
.lock()
.map_err(|e| anyhow::anyhow!("registry lock: {}", e))?
.update_address(node_id, address)
}
pub fn controller(&self) -> &Arc<controller::Controller> {
&self.controller
}
pub fn transport(&self) -> &Arc<transport::Transport> {
&self.transport
}
pub fn certmanager(&self) -> &Arc<dyn certmanager::CertManager> {
&self.certmanager
}
pub fn config(&self) -> &ManagerConfig {
&self.config
}
pub fn base_path(&self) -> &str {
&self.base_path
}
}