From 87fb3360fbd29d5660018ea6135ccc751167009c Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Tue, 27 Aug 2024 22:32:22 +0200 Subject: [PATCH] Can create a relay --- central_backend/src/devices/device.rs | 12 ++++---- central_backend/src/devices/devices_list.rs | 25 ++++++++++++++-- central_backend/src/energy/energy_actor.rs | 30 ++++++++++++++++++- central_backend/src/server/servers.rs | 2 +- .../src/server/web_api/relays_controller.rs | 30 ++++++++++++++++++- central_frontend/src/api/RelayApi.ts | 1 + 6 files changed, 89 insertions(+), 11 deletions(-) diff --git a/central_backend/src/devices/device.rs b/central_backend/src/devices/device.rs index e93f01c..4b2bf08 100644 --- a/central_backend/src/devices/device.rs +++ b/central_backend/src/devices/device.rs @@ -13,7 +13,7 @@ pub struct DeviceInfo { /// Device firmware / software version version: semver::Version, /// Maximum number of relay that the device can support - max_relays: usize, + pub max_relays: usize, } impl DeviceInfo { @@ -90,7 +90,7 @@ impl Default for DeviceRelayID { pub struct DeviceRelay { /// Device relay id. Should be unique across the whole application #[serde(default)] - id: DeviceRelayID, + pub id: DeviceRelayID, /// Human-readable name for the relay name: String, /// Whether this relay can be turned on or not @@ -165,7 +165,7 @@ impl DeviceRelay { } } - let mut relays_map = list.iter().map(|r| (r.id, r)).collect::>(); + let relays_map = list.iter().map(|r| (r.id, r)).collect::>(); if self.depends_on.iter().any(|d| !relays_map.contains_key(d)) { return Some("A specified dependent relay does not exists!"); @@ -212,12 +212,12 @@ impl DeviceRelay { clone.insert(self.id); for d in &self.depends_on { - if visited.contains(&d) { + if visited.contains(d) { return true; } if list - .get(&d) + .get(d) .expect("Missing a relay!") .check_for_loop_in_dependencies(&clone, list) { @@ -235,7 +235,7 @@ impl DeviceRelay { list: &HashMap, ) { for d in &self.depends_on { - let dependency = list.get(&d).expect("Missing a relay!"); + let dependency = list.get(d).expect("Missing a relay!"); deps_out.insert(dependency.id); diff --git a/central_backend/src/devices/devices_list.rs b/central_backend/src/devices/devices_list.rs index 095f95f..6115412 100644 --- a/central_backend/src/devices/devices_list.rs +++ b/central_backend/src/devices/devices_list.rs @@ -1,6 +1,8 @@ use crate::app_config::AppConfig; use crate::crypto::pki; -use crate::devices::device::{Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay}; +use crate::devices::device::{ + Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID, +}; use crate::utils::time_utils::time_secs; use openssl::x509::{X509Req, X509}; use std::collections::HashMap; @@ -194,10 +196,29 @@ impl DevicesList { } /// Get the full list of relays - pub fn relays_list(&mut self) -> Vec { + pub fn relays_list(&self) -> Vec { self.0 .iter() .flat_map(|(_id, d)| d.relays.clone()) .collect() } + + /// Create a new relay + pub fn relay_create(&mut self, dev_id: &DeviceId, relay: DeviceRelay) -> anyhow::Result<()> { + let dev = self + .0 + .get_mut(dev_id) + .ok_or(DevicesListError::DeviceNotFound)?; + + dev.relays.push(relay); + + self.persist_dev_config(dev_id)?; + + Ok(()) + } + + /// Get a single relay + pub fn relay_get_single(&self, relay_id: DeviceRelayID) -> Option { + self.relays_list().into_iter().find(|i| i.id == relay_id) + } } diff --git a/central_backend/src/energy/energy_actor.rs b/central_backend/src/energy/energy_actor.rs index 91067d2..ec328fc 100644 --- a/central_backend/src/energy/energy_actor.rs +++ b/central_backend/src/energy/energy_actor.rs @@ -1,5 +1,7 @@ use crate::constants; -use crate::devices::device::{Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay}; +use crate::devices::device::{ + Device, DeviceGeneralInfo, DeviceId, DeviceInfo, DeviceRelay, DeviceRelayID, +}; use crate::devices::devices_list::DevicesList; use crate::energy::consumption; use crate::energy::consumption::EnergyConsumption; @@ -184,3 +186,29 @@ impl Handler for EnergyActor { self.devices.relays_list() } } + +/// Create a new device relay +#[derive(Message)] +#[rtype(result = "anyhow::Result<()>")] +pub struct CreateDeviceRelay(pub DeviceId, pub DeviceRelay); + +impl Handler for EnergyActor { + type Result = anyhow::Result<()>; + + fn handle(&mut self, msg: CreateDeviceRelay, _ctx: &mut Context) -> Self::Result { + self.devices.relay_create(&msg.0, msg.1) + } +} + +/// Get the information about a single relay +#[derive(Message)] +#[rtype(result = "Option")] +pub struct GetSingleRelay(pub DeviceRelayID); + +impl Handler for EnergyActor { + type Result = Option; + + fn handle(&mut self, msg: GetSingleRelay, _ctx: &mut Context) -> Self::Result { + self.devices.relay_get_single(msg.0) + } +} diff --git a/central_backend/src/server/servers.rs b/central_backend/src/server/servers.rs index 7e717ec..baf1189 100644 --- a/central_backend/src/server/servers.rs +++ b/central_backend/src/server/servers.rs @@ -166,7 +166,7 @@ pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> web::get().to(relays_controller::get_list), ) .route( - "/web_api/relays/create", + "/web_api/relay/create", web::post().to(relays_controller::create), ) // Devices API diff --git a/central_backend/src/server/web_api/relays_controller.rs b/central_backend/src/server/web_api/relays_controller.rs index 8f62978..63484ee 100644 --- a/central_backend/src/server/web_api/relays_controller.rs +++ b/central_backend/src/server/web_api/relays_controller.rs @@ -19,5 +19,33 @@ pub struct CreateDeviceRelayRequest { /// Create a new relay pub async fn create(actor: WebEnergyActor, req: web::Json) -> HttpResult { - todo!() + let list = actor.send(energy_actor::GetRelaysList).await?; + + if let Some(e) = req.relay.error(&list) { + log::error!("Invalid relay create query: {e}"); + return Ok(HttpResponse::BadRequest().json(e)); + } + + let Some(device) = actor + .send(energy_actor::GetSingleDevice(req.device_id.clone())) + .await? + else { + log::error!("Invalid relay create query: specified device does not exists!"); + return Ok(HttpResponse::NotFound().json("Linked device not found!")); + }; + + if device.relays.len() >= device.info.max_relays { + log::error!("Invalid relay create query: too many relay for the target device!"); + return Ok(HttpResponse::BadRequest().json("Too many relays for the target device!")); + } + + // Create the device + actor + .send(energy_actor::CreateDeviceRelay( + req.device_id.clone(), + req.relay.clone(), + )) + .await??; + + Ok(HttpResponse::Accepted().finish()) } diff --git a/central_frontend/src/api/RelayApi.ts b/central_frontend/src/api/RelayApi.ts index 2951884..7296bef 100644 --- a/central_frontend/src/api/RelayApi.ts +++ b/central_frontend/src/api/RelayApi.ts @@ -23,6 +23,7 @@ export class RelayApi { uri: "/relay/create", jsonData: { ...relay, + id: undefined, device_id: device.id, }, });