use std::time::Instant; use actix::MessageResponse; use chrono::NaiveTime; use futures::executor::block_on; use serde_derive::{Deserialize, Serialize}; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::DbController; use crate::errors::{DatabaseError, EmgauwaError}; use crate::models::{convert_db_list_cache, FromDbModel, Relay}; use crate::types::RelayStates; #[derive(Serialize, Deserialize, Debug, Clone, MessageResponse)] pub struct Controller { #[serde(flatten)] pub c: DbController, pub relays: Vec<Relay>, } impl FromDbModel for Controller { type DbModel = DbController; type DbModelCache = Vec<Relay>; fn from_db_model( conn: &mut PoolConnection<Sqlite>, db_model: Self::DbModel, ) -> Result<Self, DatabaseError> { let relays_db = block_on(db_model.get_relays(conn))?; let cache = convert_db_list_cache(conn, relays_db, db_model.clone())?; Self::from_db_model_cache(conn, db_model, cache) } fn from_db_model_cache( _conn: &mut PoolConnection<Sqlite>, db_model: Self::DbModel, cache: Self::DbModelCache, ) -> Result<Self, DatabaseError> { Ok(Controller { c: db_model, relays: cache, }) } } impl Controller { pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), EmgauwaError> { self.c = block_on(self.c.reload(conn))?; for relay in &mut self.relays { relay.reload(conn)?; } Ok(()) } pub fn apply_relay_states(&mut self, relay_states: &RelayStates) { self.relays .iter_mut() .zip(relay_states.iter()) .for_each(|(relay, is_on)| { relay.is_on = *is_on; }); } pub fn get_relay_states(&self) -> RelayStates { self.relays.iter().map(|r| r.is_on).collect() } pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> { self.relays .iter() .filter_map(|r| r.active_schedule.get_next_time(now)) .min() } pub fn relay_pulse(&mut self, relay_num: i64, until: Instant) -> Result<(), EmgauwaError> { let relay = self .relays .iter_mut() .find(|r| r.r.number == relay_num) .ok_or(EmgauwaError::Other(String::from("Relay not found")))?; relay.pulsing = Some(until); Ok(()) } }