From a90ea25b87b11a772dbe7ecfa683782cd2d968f6 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Wed, 29 Nov 2023 17:55:49 +0100
Subject: [PATCH] Refactor initialization of on/off schedule

---
 emgauwa-controller/src/main.rs            | 17 ++++----
 emgauwa-core/src/handlers/v1/schedules.rs | 17 ++++++--
 emgauwa-lib/src/db/mod.rs                 | 51 ++++-------------------
 emgauwa-lib/src/db/schedules.rs           | 20 ++++++++-
 4 files changed, 47 insertions(+), 58 deletions(-)

diff --git a/emgauwa-controller/src/main.rs b/emgauwa-controller/src/main.rs
index 3759a11..b3022e1 100644
--- a/emgauwa-controller/src/main.rs
+++ b/emgauwa-controller/src/main.rs
@@ -27,7 +27,7 @@ async fn create_this_controller(
 		conn,
 		&ControllerUid::default(),
 		&settings.name,
-		i64::try_from(settings.relays.len()).expect("Too many relays"),
+		settings.relays.len() as i64,
 	)
 	.await
 	.expect("Failed to create controller")
@@ -91,15 +91,15 @@ async fn main() {
 	tokio::spawn(run_relay_loop(settings));
 
 	loop {
+		log::info!(
+			"Trying to connect in {} seconds...",
+			WEBSOCKET_RETRY_TIMEOUT.as_secs()
+		);
 		time::sleep(WEBSOCKET_RETRY_TIMEOUT).await;
 
 		let connect_result = connect_async(&url).await;
 		if let Err(err) = connect_result {
-			log::warn!(
-				"Failed to connect to websocket: {}. Retrying in {} seconds...",
-				err,
-				WEBSOCKET_RETRY_TIMEOUT.as_secs()
-			);
+			log::warn!("Failed to connect to websocket: {}", err,);
 			continue;
 		}
 		let (ws_stream, _) = connect_result.unwrap();
@@ -115,10 +115,7 @@ async fn main() {
 
 		read_handler.await;
 
-		log::warn!(
-			"Lost connection to websocket. Retrying in {} seconds...",
-			WEBSOCKET_RETRY_TIMEOUT.as_secs()
-		);
+		log::warn!("Lost connection to websocket");
 	}
 }
 
diff --git a/emgauwa-core/src/handlers/v1/schedules.rs b/emgauwa-core/src/handlers/v1/schedules.rs
index babeebd..b3d1710 100644
--- a/emgauwa-core/src/handlers/v1/schedules.rs
+++ b/emgauwa-core/src/handlers/v1/schedules.rs
@@ -70,7 +70,13 @@ pub async fn add(
 ) -> Result<HttpResponse, ApiError> {
 	let mut pool_conn = pool.acquire().await?;
 
-	let new_schedule = DbSchedule::create(&mut pool_conn, &data.name, &data.periods).await?;
+	let new_schedule = DbSchedule::create(
+		&mut pool_conn,
+		ScheduleUid::default(),
+		&data.name,
+		&data.periods,
+	)
+	.await?;
 
 	new_schedule
 		.set_tags(&mut pool_conn, data.tags.as_slice())
@@ -84,8 +90,13 @@ async fn add_list_single(
 	conn: &mut PoolConnection<Sqlite>,
 	request_schedule: &RequestSchedule,
 ) -> Result<DbSchedule, DatabaseError> {
-	let new_schedule =
-		DbSchedule::create(conn, &request_schedule.name, &request_schedule.periods).await?;
+	let new_schedule = DbSchedule::create(
+		conn,
+		ScheduleUid::default(),
+		&request_schedule.name,
+		&request_schedule.periods,
+	)
+	.await?;
 
 	new_schedule
 		.set_tags(conn, request_schedule.tags.as_slice())
diff --git a/emgauwa-lib/src/db/mod.rs b/emgauwa-lib/src/db/mod.rs
index 91b4787..c21e96f 100644
--- a/emgauwa-lib/src/db/mod.rs
+++ b/emgauwa-lib/src/db/mod.rs
@@ -1,14 +1,9 @@
 use std::str::FromStr;
 
-use log::{info, trace};
 use sqlx::migrate::Migrator;
 use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
 use sqlx::{Pool, Sqlite};
 
-use crate::db::errors::DatabaseError;
-use crate::db::model_utils::Period;
-use crate::types::ScheduleUid;
-
 mod controllers;
 pub mod errors;
 mod model_utils;
@@ -24,36 +19,10 @@ pub use tag::DbTag;
 static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
 
 pub async fn run_migrations(pool: &Pool<Sqlite>) {
-	info!("Running migrations");
+	log::info!("Running migrations");
 	MIGRATOR.run(pool).await.expect("Failed to run migrations.");
 }
 
-async fn init_schedule(
-	pool: &Pool<Sqlite>,
-	uid: &ScheduleUid,
-	name: &str,
-	periods: DbPeriods,
-) -> Result<(), DatabaseError> {
-	trace!("Initializing schedule {:?}", name);
-	match DbSchedule::get_by_uid(&mut pool.acquire().await.unwrap(), uid).await? {
-		Some(_) => Ok(()),
-		None => {
-			trace!("Schedule {:?} not found, inserting", name);
-			sqlx::query_as!(
-				DbSchedule,
-				"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
-				uid,
-				name,
-				periods,
-			)
-			.fetch_optional(pool)
-			.await?
-			.ok_or(DatabaseError::InsertGetError)
-			.map(|_| ())
-		}
-	}
-}
-
 pub async fn init(db: &str) -> Pool<Sqlite> {
 	let options = SqliteConnectOptions::from_str(db)
 		.expect("Error parsing database path")
@@ -68,18 +37,14 @@ pub async fn init(db: &str) -> Pool<Sqlite> {
 
 	run_migrations(&pool).await;
 
-	init_schedule(&pool, &ScheduleUid::Off, "Off", DbPeriods(vec![]))
-		.await
-		.expect("Error initializing schedule Off");
+	let mut pool_conn = pool.acquire().await.unwrap();
 
-	init_schedule(
-		&pool,
-		&ScheduleUid::On,
-		"On",
-		DbPeriods(vec![Period::new_on()]),
-	)
-	.await
-	.expect("Error initializing schedule On");
+	DbSchedule::get_on(&mut pool_conn)
+		.await
+		.expect("Failed to init 'on' schedule");
+	DbSchedule::get_off(&mut pool_conn)
+		.await
+		.expect("Failed to init 'off' schedule");
 
 	pool
 }
diff --git a/emgauwa-lib/src/db/schedules.rs b/emgauwa-lib/src/db/schedules.rs
index 988bb30..d2596a6 100644
--- a/emgauwa-lib/src/db/schedules.rs
+++ b/emgauwa-lib/src/db/schedules.rs
@@ -88,14 +88,14 @@ impl DbSchedule {
 
 	pub async fn create(
 		conn: &mut PoolConnection<Sqlite>,
+		new_uid: ScheduleUid,
 		new_name: &str,
 		new_periods: &DbPeriods,
 	) -> Result<DbSchedule, DatabaseError> {
-		let uid = ScheduleUid::default();
 		sqlx::query_as!(
 			DbSchedule,
 			"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
-			uid,
+			new_uid,
 			new_name,
 			new_periods,
 		)
@@ -104,6 +104,22 @@ impl DbSchedule {
 		.ok_or(DatabaseError::InsertGetError)
 	}
 
+	pub async fn get_on(conn: &mut PoolConnection<Sqlite>) -> Result<DbSchedule, DatabaseError> {
+		if let Some(schedule) = DbSchedule::get_by_uid(conn, &ScheduleUid::On).await? {
+			return Ok(schedule);
+		}
+		let periods = DbPeriods(vec![Period::new_on()]);
+		Self::create(conn, ScheduleUid::On, "On", &periods).await
+	}
+
+	pub async fn get_off(conn: &mut PoolConnection<Sqlite>) -> Result<DbSchedule, DatabaseError> {
+		if let Some(schedule) = DbSchedule::get_by_uid(conn, &ScheduleUid::Off).await? {
+			return Ok(schedule);
+		}
+		let periods = DbPeriods(vec![]);
+		Self::create(conn, ScheduleUid::Off, "Off", &periods).await
+	}
+
 	pub async fn update(
 		&self,
 		conn: &mut PoolConnection<Sqlite>,