diff --git a/central_backend/src/devices/device.rs b/central_backend/src/devices/device.rs index 4b2bf08..aa6913f 100644 --- a/central_backend/src/devices/device.rs +++ b/central_backend/src/devices/device.rs @@ -106,9 +106,9 @@ pub struct DeviceRelay { /// Optional minimal runtime requirements for this relay daily_runtime: Option, /// Specify relay that must be turned on before this relay can be started - depends_on: Vec, + pub depends_on: Vec, /// Specify relays that must be turned off before this relay can be started - conflicts_with: Vec, + pub conflicts_with: Vec, } impl DeviceRelay { diff --git a/central_backend/src/devices/devices_list.rs b/central_backend/src/devices/devices_list.rs index 6115412..0f0fa95 100644 --- a/central_backend/src/devices/devices_list.rs +++ b/central_backend/src/devices/devices_list.rs @@ -23,6 +23,8 @@ pub enum DevicesListError { DeviceNotFound, #[error("Requested device is not validated")] DeviceNotValidated, + #[error("Failed to delete relay: {0}")] + DeleteRelayFailed(&'static str), } pub struct DevicesList(HashMap); @@ -221,4 +223,48 @@ impl DevicesList { pub fn relay_get_single(&self, relay_id: DeviceRelayID) -> Option { self.relays_list().into_iter().find(|i| i.id == relay_id) } + + /// Get the device hosting a relay + pub fn relay_get_device(&self, relay_id: DeviceRelayID) -> Option { + self.0 + .iter() + .find(|r| r.1.relays.iter().any(|r| r.id == relay_id)) + .map(|d| d.1.clone()) + } + + /// Get all the relays that depends directly on a relay + pub fn relay_get_direct_dependencies(&self, relay_id: DeviceRelayID) -> Vec { + self.relays_list() + .into_iter() + .filter(|d| d.depends_on.contains(&relay_id)) + .collect() + } + + /// Delete a relay + pub fn relay_delete(&mut self, relay_id: DeviceRelayID) -> anyhow::Result<()> { + if !self.relay_get_direct_dependencies(relay_id).is_empty() { + return Err(DevicesListError::DeleteRelayFailed( + "At least one other relay depend on this relay!", + ) + .into()); + } + + // Delete the relay + let device = self + .relay_get_device(relay_id) + .ok_or(DevicesListError::DeleteRelayFailed( + "Relay does not exists!", + ))?; + + let dev = self + .0 + .get_mut(&device.id) + .ok_or(DevicesListError::UpdateDeviceFailedDeviceNotFound)?; + + dev.relays.retain(|r| r.id != relay_id); + + self.persist_dev_config(&device.id)?; + + Ok(()) + } } diff --git a/central_backend/src/energy/energy_actor.rs b/central_backend/src/energy/energy_actor.rs index ec328fc..a1fd019 100644 --- a/central_backend/src/energy/energy_actor.rs +++ b/central_backend/src/energy/energy_actor.rs @@ -212,3 +212,16 @@ impl Handler for EnergyActor { self.devices.relay_get_single(msg.0) } } + +/// Delete a device relay +#[derive(Message)] +#[rtype(result = "anyhow::Result<()>")] +pub struct DeleteDeviceRelay(pub DeviceRelayID); + +impl Handler for EnergyActor { + type Result = anyhow::Result<()>; + + fn handle(&mut self, msg: DeleteDeviceRelay, _ctx: &mut Context) -> Self::Result { + self.devices.relay_delete(msg.0) + } +} diff --git a/central_backend/src/server/servers.rs b/central_backend/src/server/servers.rs index baf1189..5011eae 100644 --- a/central_backend/src/server/servers.rs +++ b/central_backend/src/server/servers.rs @@ -169,6 +169,10 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> "/web_api/relay/create", web::post().to(relays_controller::create), ) + .route( + "/web_api/relay/{id}", + web::delete().to(relays_controller::delete), + ) // Devices API .route( "/devices_api/utils/time", diff --git a/central_backend/src/server/web_api/relays_controller.rs b/central_backend/src/server/web_api/relays_controller.rs index 639eb3f..4e47d38 100644 --- a/central_backend/src/server/web_api/relays_controller.rs +++ b/central_backend/src/server/web_api/relays_controller.rs @@ -1,4 +1,4 @@ -use crate::devices::device::{DeviceId, DeviceRelay}; +use crate::devices::device::{DeviceId, DeviceRelay, DeviceRelayID}; use crate::energy::energy_actor; use crate::server::custom_error::HttpResult; use crate::server::WebEnergyActor; @@ -48,7 +48,7 @@ pub async fn create(actor: WebEnergyActor, req: web::Json) -> HttpResult { + actor + .send(energy_actor::DeleteDeviceRelay(path.id)) + .await??; + + Ok(HttpResponse::Accepted().finish()) +}