use std::time::Instant; use chrono::NaiveTime; use futures::executor::block_on; use serde_derive::{Deserialize, Serialize}; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use crate::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule}; use crate::errors::DatabaseError; use crate::models::FromDbModel; use crate::types::EmgauwaUid; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Relay { #[serde(flatten)] pub r: DbRelay, pub controller: DbController, pub controller_id: EmgauwaUid, pub schedules: Vec<DbSchedule>, pub active_schedule: DbSchedule, pub is_on: Option<bool>, pub tags: Vec<String>, // for internal use only. #[serde(skip)] pub pulsing: Option<Instant>, } impl FromDbModel for Relay { type DbModel = DbRelay; type DbModelCache = DbController; fn from_db_model( conn: &mut PoolConnection<Sqlite>, db_model: Self::DbModel, ) -> Result<Self, DatabaseError> { let cache = block_on(db_model.get_controller(conn))?; 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> { let tags = block_on(db_model.get_tags(conn))?; let controller_id = cache.uid.clone(); let schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &db_model))?; let active_schedule = block_on(db_model.get_active_schedule(conn))?; let is_on = None; Ok(Relay { r: db_model, controller: cache, controller_id, schedules, active_schedule, is_on, tags, pulsing: None, }) } } impl Relay { pub fn reload(&mut self, conn: &mut PoolConnection<Sqlite>) -> Result<(), DatabaseError> { self.r = block_on(self.r.reload(conn))?; self.schedules = block_on(DbJunctionRelaySchedule::get_schedules(conn, &self.r))?; self.reload_active_schedule(conn)?; Ok(()) } pub fn reload_active_schedule( &mut self, conn: &mut PoolConnection<Sqlite>, ) -> Result<(), DatabaseError> { self.active_schedule = block_on(self.r.get_active_schedule(conn))?; Ok(()) } pub fn is_on(&self, now: &NaiveTime) -> bool { self.active_schedule.is_on(now) } pub fn get_next_time(&self, now: &NaiveTime) -> Option<NaiveTime> { self.active_schedule.get_next_time(now) } pub fn check_pulsing(&mut self, now: &Instant) -> Option<Instant> { match self.pulsing { Some(dur_instant) => { if dur_instant.lt(now) { self.pulsing = None; None } else { Some(dur_instant) } } None => None, } } }