use actix::Actor; use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT; use emgauwa_lib::db; use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule}; use emgauwa_lib::errors::EmgauwaError; use emgauwa_lib::models::{Controller, FromDbModel}; use emgauwa_lib::types::ControllerUid; use emgauwa_lib::utils::init_logging; use sqlx::pool::PoolConnection; use sqlx::Sqlite; use tokio::time; use crate::relay_loop::run_relay_loop; use crate::settings::Settings; use crate::ws::run_websocket; mod app_state; mod driver; mod relay_loop; mod settings; mod utils; mod ws; async fn create_this_controller( conn: &mut PoolConnection, settings: &Settings, ) -> Result { DbController::create( conn, &ControllerUid::default(), &settings.name, settings.relays.len() as i64, ) .await .map_err(EmgauwaError::from) } async fn create_this_relay( conn: &mut PoolConnection, this_controller: &DbController, settings_relay: &settings::Relay, ) -> Result { let relay = DbRelay::create( conn, &settings_relay.name, settings_relay.number.ok_or(EmgauwaError::Internal( "Relay number is missing".to_string(), ))?, this_controller, ) .await?; let off = DbSchedule::get_off(conn).await?; for weekday in 0..7 { DbJunctionRelaySchedule::set_schedule(conn, &relay, &off, weekday).await?; } Ok(relay) } #[actix::main] async fn main() -> Result<(), std::io::Error> { let settings = settings::init()?; init_logging(&settings.logging.level)?; let pool = db::init(&settings.database) .await .map_err(EmgauwaError::from)?; let mut conn = pool.acquire().await.map_err(EmgauwaError::from)?; let db_controller = match DbController::get_all(&mut conn) .await .map_err(EmgauwaError::from)? .pop() { None => futures::executor::block_on(create_this_controller(&mut conn, &settings))?, Some(c) => c, }; for relay in &settings.relays { if DbRelay::get_by_controller_and_num( &mut conn, &db_controller, relay.number.ok_or(EmgauwaError::Internal( "Relay number is missing".to_string(), ))?, ) .await .map_err(EmgauwaError::from)? .is_none() { create_this_relay(&mut conn, &db_controller, relay) .await .map_err(EmgauwaError::from)?; } } let db_controller = db_controller .update(&mut conn, &db_controller.name, settings.relays.len() as i64) .await .map_err(EmgauwaError::from)?; let this = Controller::from_db_model(&mut conn, db_controller).map_err(EmgauwaError::from)?; let app_state = app_state::AppState::new(pool.clone(), this).start(); let url = format!( "ws://{}:{}/api/v1/ws/controllers", settings.core.host, settings.core.port ); tokio::spawn(run_relay_loop(settings)); loop { let run_result = run_websocket(pool.clone(), &app_state, &url).await; if let Err(err) = run_result { log::error!("Error running websocket: {}", err); } log::info!( "Retrying to connect in {} seconds...", WEBSOCKET_RETRY_TIMEOUT.as_secs() ); time::sleep(WEBSOCKET_RETRY_TIMEOUT).await; } }