Check for loops in relays
This commit is contained in:
parent
d890b23670
commit
50e61707cc
@ -1,7 +1,7 @@
|
||||
//! # Devices entities definition
|
||||
|
||||
use crate::constants::StaticConstraints;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
/// Device information provided directly by the device during syncrhonisation.
|
||||
///
|
||||
@ -165,7 +165,7 @@ impl DeviceRelay {
|
||||
}
|
||||
}
|
||||
|
||||
let relays_map = list.iter().map(|r| (r.id, r)).collect::<HashMap<_, _>>();
|
||||
let mut relays_map = list.iter().map(|r| (r.id, r)).collect::<HashMap<_, _>>();
|
||||
|
||||
if self.depends_on.iter().any(|d| !relays_map.contains_key(d)) {
|
||||
return Some("A specified dependent relay does not exists!");
|
||||
@ -179,10 +179,73 @@ impl DeviceRelay {
|
||||
return Some("A specified conflicting relay does not exists!");
|
||||
}
|
||||
|
||||
// TODO : check for loops
|
||||
// Check for loops in dependencies
|
||||
if self.check_for_loop_in_dependencies(&HashSet::new(), &relays_map) {
|
||||
return Some("A loop was detected in relay dependencies!");
|
||||
}
|
||||
|
||||
// Check if relay is in conflicts with one of its dependencies
|
||||
let mut all_dependencies = HashSet::new();
|
||||
let mut all_conflicts = HashSet::new();
|
||||
self.get_list_of_dependencies_and_conflicts(
|
||||
&mut all_dependencies,
|
||||
&mut all_conflicts,
|
||||
&relays_map,
|
||||
);
|
||||
for conf_id in all_conflicts {
|
||||
if all_dependencies.contains(&conf_id) {
|
||||
return Some(
|
||||
"The relay or one of its dependencies is in conflict with a dependency!",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn check_for_loop_in_dependencies(
|
||||
&self,
|
||||
visited: &HashSet<DeviceRelayID>,
|
||||
list: &HashMap<DeviceRelayID, &Self>,
|
||||
) -> bool {
|
||||
let mut clone = visited.clone();
|
||||
clone.insert(self.id);
|
||||
|
||||
for d in &self.depends_on {
|
||||
if visited.contains(&d) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if list
|
||||
.get(&d)
|
||||
.expect("Missing a relay!")
|
||||
.check_for_loop_in_dependencies(&clone, list)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn get_list_of_dependencies_and_conflicts(
|
||||
&self,
|
||||
deps_out: &mut HashSet<DeviceRelayID>,
|
||||
conflicts_out: &mut HashSet<DeviceRelayID>,
|
||||
list: &HashMap<DeviceRelayID, &Self>,
|
||||
) {
|
||||
for d in &self.depends_on {
|
||||
let dependency = list.get(&d).expect("Missing a relay!");
|
||||
|
||||
deps_out.insert(dependency.id);
|
||||
|
||||
dependency.get_list_of_dependencies_and_conflicts(deps_out, conflicts_out, list);
|
||||
}
|
||||
|
||||
for d in &self.conflicts_with {
|
||||
conflicts_out.insert(*d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Device general information
|
||||
@ -213,7 +276,7 @@ impl DeviceGeneralInfo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::devices::device::DeviceRelay;
|
||||
use crate::devices::device::{DeviceRelay, DeviceRelayID};
|
||||
|
||||
#[test]
|
||||
fn check_device_relay_error() {
|
||||
@ -238,5 +301,53 @@ mod tests {
|
||||
assert!(bad_name.error(&[]).is_some());
|
||||
assert_eq!(dep_on_unitary.error(&[unitary.clone()]), None);
|
||||
assert!(dep_on_unitary.error(&[]).is_some());
|
||||
|
||||
// Dependency loop
|
||||
let mut dep_cycle_1 = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "dep_cycle_1".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
let dep_cycle_2 = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "dep_cycle_2".to_string(),
|
||||
depends_on: vec![dep_cycle_1.id],
|
||||
..Default::default()
|
||||
};
|
||||
let dep_cycle_3 = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "dep_cycle_3".to_string(),
|
||||
depends_on: vec![dep_cycle_2.id],
|
||||
..Default::default()
|
||||
};
|
||||
dep_cycle_1.depends_on = vec![dep_cycle_3.id];
|
||||
|
||||
assert!(dep_cycle_1.error(&[dep_cycle_2, dep_cycle_3]).is_some());
|
||||
|
||||
// Impossible conflict
|
||||
let other_dep = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "other_dep".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
let second_dep = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "second_dep".to_string(),
|
||||
conflicts_with: vec![other_dep.id],
|
||||
..Default::default()
|
||||
};
|
||||
let target_relay = DeviceRelay {
|
||||
id: DeviceRelayID::default(),
|
||||
name: "target_relay".to_string(),
|
||||
depends_on: vec![other_dep.id, second_dep.id],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert!(target_relay
|
||||
.error(&[other_dep.clone(), second_dep.clone()])
|
||||
.is_some());
|
||||
assert!(target_relay
|
||||
.error(&[other_dep, second_dep, target_relay.clone()])
|
||||
.is_some());
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()>
|
||||
"/web_api/relays/list",
|
||||
web::get().to(relays_controller::get_list),
|
||||
)
|
||||
.route(
|
||||
"/web_api/relays/create",
|
||||
web::post().to(relays_controller::create),
|
||||
)
|
||||
// Devices API
|
||||
.route(
|
||||
"/devices_api/utils/time",
|
||||
|
@ -1,10 +1,23 @@
|
||||
use crate::devices::device::{DeviceId, DeviceRelay};
|
||||
use crate::energy::energy_actor;
|
||||
use crate::server::custom_error::HttpResult;
|
||||
use crate::server::WebEnergyActor;
|
||||
use actix_web::HttpResponse;
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
/// Get the full list of relays
|
||||
pub async fn get_list(actor: WebEnergyActor) -> HttpResult {
|
||||
let list = actor.send(energy_actor::GetRelaysList).await?;
|
||||
Ok(HttpResponse::Ok().json(list))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CreateDeviceRelayRequest {
|
||||
device_id: DeviceId,
|
||||
#[serde(flatten)]
|
||||
relay: DeviceRelay,
|
||||
}
|
||||
|
||||
/// Create a new relay
|
||||
pub async fn create(actor: WebEnergyActor, req: web::Json<CreateDeviceRelayRequest>) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user