use std::fs;
use std::net::Ipv4Addr;
use log::*;
use serde::{Deserialize, Serialize};
use crate::drivers::InstrumentError;
use super::{validators, Device, ModelError};
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct RTU {
pub name: String,
pub id: String,
pub ip_addr: Ipv4Addr,
pub devices: Vec<Device>,
}
impl RTU {
pub async fn enact(&mut self) -> Result<(), InstrumentError> {
info!("[RTU `{}`] enacting...", self.id);
for dev in self.devices.iter_mut() {
dev.enact().await?;
}
info!("[RTU `{}`] enacted.", self.id);
Ok(())
}
pub async fn update(&mut self) -> Result<(), InstrumentError> {
info!("[RTU `{}`] updating...", self.id);
for dev in self.devices.iter_mut() {
dev.update().await?;
}
info!("[RTU `{}`] updated.", self.id);
Ok(())
}
pub fn device(&mut self, device_id: &str) -> Option<&mut Device> {
self.devices.iter_mut().find(|dev| dev.id == device_id)
}
pub fn generate(conf_path: Option<&str>) -> Result<RTU, ModelError> {
let file_path = conf_path.or(Some(crate::defaults::config_file()));
info!("Generating RTU. Using config file: {:?}", file_path);
let file_contents = fs::read_to_string(
file_path.unwrap(),
)
.map_err(|err| ModelError::IOError(err))?;
let rtu = serde_yaml::from_str::<RTU>(&file_contents)
.map_err(|err| ModelError::SerdeParseError(err))?;
info!("[RTU `{}`] generated.", rtu.id);
rtu.validate()?;
Ok(rtu)
}
pub fn validate(&self) -> Result<(), ModelError> {
use validators::*;
if let Err(e) = all_validators(&self) {
error!("{e}");
return Err(e);
}
info!("RTU passed all validators");
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use tokio::test;
#[test]
async fn test_generate_rtu() {
let rtu = RTU::generate(Some(crate::defaults::test_config_file()));
assert!(rtu.is_ok());
assert!(rtu.unwrap().devices.len() > 0);
}
}