diff --git a/src/action.rs b/src/action.rs index b6b1583..eb91b98 100644 --- a/src/action.rs +++ b/src/action.rs @@ -40,8 +40,13 @@ impl FromStr for ActionType { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ActionID(pub(crate) i64); + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Action { + pub(crate) id: Option, + pub device_id: String, pub action_type: ActionType, pub parameter: String, @@ -54,6 +59,8 @@ impl Action { parameter: impl ToString, ) -> Self { Self { + id: None, + device_id: device_id.to_string(), action_type, parameter: parameter.to_string(), @@ -86,6 +93,10 @@ impl ActionSet { } } + pub(crate) fn first_id(&self) -> Option { + self.actions.get(0).map(|action| action.id).flatten() + } + pub fn parameter(&self, parameter: &str) -> bool { match self.actions.get(0) { Some(action) => action.parameter == parameter, diff --git a/src/db.rs b/src/db.rs index f37b697..7347f2b 100644 --- a/src/db.rs +++ b/src/db.rs @@ -4,7 +4,7 @@ use anyhow::Result; use rusqlite::{Connection, OptionalExtension, ToSql}; use crate::{ - action::{Action, ActionSet, ActionType}, + action::{Action, ActionID, ActionSet, ActionType}, devices::{DeviceWithName, Devices, DevicesWithName}, }; @@ -100,7 +100,7 @@ impl DataBase { .query_row([], |row| Ok(row.get(0)?))?) } - pub fn insert_action_set(&self, action_set: ActionSet) -> Result { + pub fn insert_action_set(&self, action_set: ActionSet) -> Result { let mut action_ids = Vec::new(); for (i, action) in action_set.iter().enumerate() { @@ -134,10 +134,24 @@ impl DataBase { } } - Ok(action_ids[0]) + Ok(ActionID(action_ids[0])) } - pub fn action_set(&self, mut action_id: i64) -> Result { + pub fn remove_action_set(&self, action_set: &ActionSet) -> Result<()> { + if let Some(action_id) = action_set.first_id() { + self.sql.execute( + " + DELETE FROM actions + WHERE id=?1 + ", + &[&action_id.0], + )?; + } + + Ok(()) + } + + pub fn action_set(&self, mut action_id: ActionID) -> Result { let mut action_set = ActionSet::default(); loop { @@ -148,7 +162,7 @@ impl DataBase { FROM actions WHERE id=?1 ", - &[&action_id], + &[&action_id.0], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), )?; @@ -162,12 +176,13 @@ impl DataBase { |row| row.get(0), )?; - let action = Action::new(device_name, ActionType::from_str(&action)?, parameter); + let mut action = Action::new(device_name, ActionType::from_str(&action)?, parameter); + action.id = Some(action_id); action_set.chain(action); match next_action { - Some(id) => action_id = id, + Some(id) => action_id.0 = id, None => break, } } @@ -213,7 +228,7 @@ impl DataBase { { Some(id) => action_id = id, None => { - action_sets.push(self.action_set(action_id)?); + action_sets.push(self.action_set(ActionID(action_id))?); break; } } diff --git a/src/web_server.rs b/src/web_server.rs index f672553..e3a741b 100644 --- a/src/web_server.rs +++ b/src/web_server.rs @@ -8,6 +8,7 @@ use serde::Serialize; use serde_json::to_string; use crate::{ + action::{Action, ActionSet, ActionType}, db::DataBase, task_scheduler::Scheduler, tasmota::Tasmota, @@ -271,6 +272,42 @@ async fn push_humidity( Ok("Ok") } +#[post("/update_push_action/{source_device}/{parameter}/{destination_device}")] +async fn update_push_action( + param: Path<(String, String, String)>, + db: Data>>, +) -> Result { + let (source_device, parameter, destination_device) = param.into_inner(); + let db_lock = db.lock().unwrap(); + + let action_sets = db_lock + .action_sets(&source_device) + .map_err(|err| MyError::from(err))?; + + // check if action set is already present + if let Some(old_action_set) = action_sets.iter().find(|action_set| { + action_set.push_device() == Some(source_device.clone()) + && action_set.receive_device() == Some(destination_device.clone()) + && action_set.parameter(¶meter) + }) { + // remove old action set + db_lock + .remove_action_set(old_action_set) + .map_err(|err| MyError::from(err))?; + } + + let new_action_set = ActionSet::from(vec![ + Action::new(source_device, ActionType::Push, parameter.clone()), + Action::new(destination_device, ActionType::Receive, parameter), + ]); + + db_lock + .insert_action_set(new_action_set) + .map_err(|err| MyError::from(err))?; + + Ok("Ok") +} + fn collapse_data(data: Vec<(u64, f32)>, f: F) -> Vec<(u64, f32)> where F: Fn(NaiveDateTime) -> NaiveDateTime,