Replace expect usage with Result
This commit is contained in:
		
							parent
							
								
									9394a1ae52
								
							
						
					
					
						commit
						b3228ea6b5
					
				
					 11 changed files with 135 additions and 95 deletions
				
			
		| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT;
 | 
					use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT;
 | 
				
			||||||
use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
 | 
					use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule};
 | 
				
			||||||
use emgauwa_lib::errors::DatabaseError;
 | 
					use emgauwa_lib::errors::{DatabaseError, EmgauwaError};
 | 
				
			||||||
use emgauwa_lib::models::{Controller, FromDbModel};
 | 
					use emgauwa_lib::models::{Controller, FromDbModel};
 | 
				
			||||||
use emgauwa_lib::types::{ControllerUid, ControllerWsAction};
 | 
					use emgauwa_lib::types::{ControllerUid, ControllerWsAction};
 | 
				
			||||||
use emgauwa_lib::{db, utils};
 | 
					use emgauwa_lib::{db, utils};
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ mod settings;
 | 
				
			||||||
async fn create_this_controller(
 | 
					async fn create_this_controller(
 | 
				
			||||||
	conn: &mut PoolConnection<Sqlite>,
 | 
						conn: &mut PoolConnection<Sqlite>,
 | 
				
			||||||
	settings: &Settings,
 | 
						settings: &Settings,
 | 
				
			||||||
) -> DbController {
 | 
					) -> Result<DbController, EmgauwaError> {
 | 
				
			||||||
	DbController::create(
 | 
						DbController::create(
 | 
				
			||||||
		conn,
 | 
							conn,
 | 
				
			||||||
		&ControllerUid::default(),
 | 
							&ControllerUid::default(),
 | 
				
			||||||
| 
						 | 
					@ -31,18 +31,20 @@ async fn create_this_controller(
 | 
				
			||||||
		settings.relays.len() as i64,
 | 
							settings.relays.len() as i64,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	.await
 | 
						.await
 | 
				
			||||||
	.expect("Failed to create controller")
 | 
						.map_err(EmgauwaError::from)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async fn create_this_relay(
 | 
					async fn create_this_relay(
 | 
				
			||||||
	conn: &mut PoolConnection<Sqlite>,
 | 
						conn: &mut PoolConnection<Sqlite>,
 | 
				
			||||||
	this_controller: &DbController,
 | 
						this_controller: &DbController,
 | 
				
			||||||
	settings_relay: &settings::Relay,
 | 
						settings_relay: &settings::Relay,
 | 
				
			||||||
) -> Result<DbRelay, DatabaseError> {
 | 
					) -> Result<DbRelay, EmgauwaError> {
 | 
				
			||||||
	let relay = DbRelay::create(
 | 
						let relay = DbRelay::create(
 | 
				
			||||||
		conn,
 | 
							conn,
 | 
				
			||||||
		&settings_relay.name,
 | 
							&settings_relay.name,
 | 
				
			||||||
		settings_relay.number.expect("Relay number is missing"),
 | 
							settings_relay.number.ok_or(EmgauwaError::Internal(
 | 
				
			||||||
 | 
								"Relay number is missing".to_string(),
 | 
				
			||||||
 | 
							))?,
 | 
				
			||||||
		this_controller,
 | 
							this_controller,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	.await?;
 | 
						.await?;
 | 
				
			||||||
| 
						 | 
					@ -55,7 +57,7 @@ async fn create_this_relay(
 | 
				
			||||||
	Ok(relay)
 | 
						Ok(relay)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async fn run_websocket(this: Controller, url: &str) {
 | 
					async fn run_websocket(this: Controller, url: &str) -> Result<(), EmgauwaError> {
 | 
				
			||||||
	match connect_async(url).await {
 | 
						match connect_async(url).await {
 | 
				
			||||||
		Ok(connection) => {
 | 
							Ok(connection) => {
 | 
				
			||||||
			let (ws_stream, _) = connection;
 | 
								let (ws_stream, _) = connection;
 | 
				
			||||||
| 
						 | 
					@ -64,11 +66,10 @@ async fn run_websocket(this: Controller, url: &str) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let ws_action = ControllerWsAction::Register(this.clone());
 | 
								let ws_action = ControllerWsAction::Register(this.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let ws_action_json =
 | 
								let ws_action_json = serde_json::to_string(&ws_action)?;
 | 
				
			||||||
				serde_json::to_string(&ws_action).expect("Failed to serialize action");
 | 
					 | 
				
			||||||
			if let Err(err) = write.send(Message::text(ws_action_json)).await {
 | 
								if let Err(err) = write.send(Message::text(ws_action_json)).await {
 | 
				
			||||||
				log::error!("Failed to register at websocket: {}", err);
 | 
									log::error!("Failed to register at websocket: {}", err);
 | 
				
			||||||
				return;
 | 
									return Ok(());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let read_handler = read.for_each(handle_message);
 | 
								let read_handler = read.for_each(handle_message);
 | 
				
			||||||
| 
						 | 
					@ -81,23 +82,23 @@ async fn run_websocket(this: Controller, url: &str) {
 | 
				
			||||||
			log::warn!("Failed to connect to websocket: {}", err,);
 | 
								log::warn!("Failed to connect to websocket: {}", err,);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::main]
 | 
					#[tokio::main]
 | 
				
			||||||
async fn main() {
 | 
					async fn main() -> Result<(), std::io::Error> {
 | 
				
			||||||
	let settings = settings::init();
 | 
						let settings = settings::init()?;
 | 
				
			||||||
	init_logging(&settings.logging.level);
 | 
						init_logging(&settings.logging.level)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let pool = db::init(&settings.database).await;
 | 
						let pool = db::init(&settings.database)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	let mut conn = pool
 | 
					 | 
				
			||||||
		.acquire()
 | 
					 | 
				
			||||||
		.await
 | 
							.await
 | 
				
			||||||
		.expect("Failed to get database connection");
 | 
							.map_err(EmgauwaError::from)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						let mut conn = pool.acquire().await.map_err(EmgauwaError::from)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let db_controller = match DbController::get_all(&mut conn)
 | 
						let db_controller = match DbController::get_all(&mut conn)
 | 
				
			||||||
		.await
 | 
							.await
 | 
				
			||||||
		.expect("Failed to get controller from database")
 | 
							.map_err(EmgauwaError::from)?
 | 
				
			||||||
		.pop()
 | 
							.pop()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None => futures::executor::block_on(create_this_controller(&mut conn, &settings)),
 | 
							None => futures::executor::block_on(create_this_controller(&mut conn, &settings)),
 | 
				
			||||||
| 
						 | 
					@ -108,25 +109,26 @@ async fn main() {
 | 
				
			||||||
		if DbRelay::get_by_controller_and_num(
 | 
							if DbRelay::get_by_controller_and_num(
 | 
				
			||||||
			&mut conn,
 | 
								&mut conn,
 | 
				
			||||||
			&db_controller,
 | 
								&db_controller,
 | 
				
			||||||
			relay.number.expect("Relay number is missing"),
 | 
								relay.number.ok_or(EmgauwaError::Internal(
 | 
				
			||||||
 | 
									"Relay number is missing".to_string(),
 | 
				
			||||||
 | 
								))?,
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		.await
 | 
							.await
 | 
				
			||||||
		.expect("Failed to get relay from database")
 | 
							.map_err(EmgauwaError::from)?
 | 
				
			||||||
		.is_none()
 | 
							.is_none()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			create_this_relay(&mut conn, &db_controller, relay)
 | 
								create_this_relay(&mut conn, &db_controller, relay)
 | 
				
			||||||
				.await
 | 
									.await
 | 
				
			||||||
				.expect("Failed to create schedule.");
 | 
									.map_err(EmgauwaError::from)?;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let db_controller = db_controller
 | 
						let db_controller = db_controller
 | 
				
			||||||
		.update(&mut conn, &db_controller.name, settings.relays.len() as i64)
 | 
							.update(&mut conn, &db_controller.name, settings.relays.len() as i64)
 | 
				
			||||||
		.await
 | 
							.await
 | 
				
			||||||
		.expect("Failed to update controller");
 | 
							.map_err(EmgauwaError::from)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let this = Controller::from_db_model(&mut conn, db_controller)
 | 
						let this = Controller::from_db_model(&mut conn, db_controller).map_err(EmgauwaError::from)?;
 | 
				
			||||||
		.expect("Failed to convert database models");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let url = format!(
 | 
						let url = format!(
 | 
				
			||||||
		"ws://{}:{}/api/v1/ws/controllers",
 | 
							"ws://{}:{}/api/v1/ws/controllers",
 | 
				
			||||||
| 
						 | 
					@ -136,7 +138,10 @@ async fn main() {
 | 
				
			||||||
	tokio::spawn(run_relay_loop(settings));
 | 
						tokio::spawn(run_relay_loop(settings));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	loop {
 | 
						loop {
 | 
				
			||||||
		run_websocket(this.clone(), &url).await;
 | 
							let run_result = run_websocket(this.clone(), &url).await;
 | 
				
			||||||
 | 
							if let Err(err) = run_result {
 | 
				
			||||||
 | 
								log::error!("Error running websocket: {}", err);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log::info!(
 | 
							log::info!(
 | 
				
			||||||
			"Retrying to connect in {} seconds...",
 | 
								"Retrying to connect in {} seconds...",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					use emgauwa_lib::errors::EmgauwaError;
 | 
				
			||||||
use emgauwa_lib::{constants, utils};
 | 
					use emgauwa_lib::{constants, utils};
 | 
				
			||||||
use serde_derive::Deserialize;
 | 
					use serde_derive::Deserialize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,8 +84,8 @@ impl Default for Logging {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init() -> Settings {
 | 
					pub fn init() -> Result<Settings, EmgauwaError> {
 | 
				
			||||||
	let mut settings: Settings = utils::load_settings("controller", "CONTROLLER");
 | 
						let mut settings: Settings = utils::load_settings("controller", "CONTROLLER")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (num, relay) in settings.relays.iter_mut().enumerate() {
 | 
						for (num, relay) in settings.relays.iter_mut().enumerate() {
 | 
				
			||||||
		if relay.number.is_none() {
 | 
							if relay.number.is_none() {
 | 
				
			||||||
| 
						 | 
					@ -92,5 +93,5 @@ pub fn init() -> Settings {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	settings
 | 
						Ok(settings)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,14 +116,17 @@ impl StreamHandler<Result<Message, ProtocolError>> for ControllerWs {
 | 
				
			||||||
					let action_res = self.handle_action(&mut pool_conn, ctx, action);
 | 
										let action_res = self.handle_action(&mut pool_conn, ctx, action);
 | 
				
			||||||
					if let Err(e) = action_res {
 | 
										if let Err(e) = action_res {
 | 
				
			||||||
						log::error!("Error handling action: {:?}", e);
 | 
											log::error!("Error handling action: {:?}", e);
 | 
				
			||||||
						ctx.text(serde_json::to_string(&e).expect("Failed to serialize error"));
 | 
											ctx.text(
 | 
				
			||||||
 | 
												serde_json::to_string(&e)
 | 
				
			||||||
 | 
													.unwrap_or(format!("Error in handling action: {:?}", e)),
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				Err(e) => {
 | 
									Err(e) => {
 | 
				
			||||||
					log::error!("Error deserializing action: {:?}", e);
 | 
										log::error!("Error deserializing action: {:?}", e);
 | 
				
			||||||
					ctx.text(
 | 
										ctx.text(
 | 
				
			||||||
						serde_json::to_string(&EmgauwaError::Serialization(e))
 | 
											serde_json::to_string(&EmgauwaError::Serialization(e))
 | 
				
			||||||
							.expect("Failed to serialize error"),
 | 
												.unwrap_or(String::from("Error in deserializing action")),
 | 
				
			||||||
					);
 | 
										);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ use actix_cors::Cors;
 | 
				
			||||||
use actix_web::middleware::TrailingSlash;
 | 
					use actix_web::middleware::TrailingSlash;
 | 
				
			||||||
use actix_web::{middleware, web, App, HttpServer};
 | 
					use actix_web::{middleware, web, App, HttpServer};
 | 
				
			||||||
use emgauwa_lib::db::DbController;
 | 
					use emgauwa_lib::db::DbController;
 | 
				
			||||||
 | 
					use emgauwa_lib::errors::EmgauwaError;
 | 
				
			||||||
use emgauwa_lib::utils::init_logging;
 | 
					use emgauwa_lib::utils::init_logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::app_state::AppServer;
 | 
					use crate::app_state::AppServer;
 | 
				
			||||||
| 
						 | 
					@ -16,27 +17,21 @@ mod settings;
 | 
				
			||||||
mod utils;
 | 
					mod utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[actix_web::main]
 | 
					#[actix_web::main]
 | 
				
			||||||
async fn main() -> std::io::Result<()> {
 | 
					async fn main() -> Result<(), std::io::Error> {
 | 
				
			||||||
	let settings = settings::init();
 | 
						let settings = settings::init()?;
 | 
				
			||||||
	init_logging(&settings.logging.level);
 | 
						init_logging(&settings.logging.level)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let listener = TcpListener::bind(format!("{}:{}", settings.host, settings.port))
 | 
						let listener = TcpListener::bind(format!("{}:{}", settings.host, settings.port))?;
 | 
				
			||||||
		.expect("Error creating listener");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drop_privileges(&settings).expect("Error dropping privileges");
 | 
						drop_privileges(&settings)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let pool = emgauwa_lib::db::init(&settings.database).await;
 | 
						let pool = emgauwa_lib::db::init(&settings.database).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This block is to ensure that the connection is dropped after use.
 | 
						let mut conn = pool.acquire().await.map_err(EmgauwaError::from)?;
 | 
				
			||||||
	{
 | 
						DbController::all_inactive(&mut conn)
 | 
				
			||||||
		let mut conn = pool
 | 
							.await
 | 
				
			||||||
			.acquire()
 | 
							.map_err(EmgauwaError::from)?;
 | 
				
			||||||
			.await
 | 
						conn.close().await.map_err(EmgauwaError::from)?;
 | 
				
			||||||
			.expect("Failed to get database connection");
 | 
					 | 
				
			||||||
		DbController::all_inactive(&mut conn)
 | 
					 | 
				
			||||||
			.await
 | 
					 | 
				
			||||||
			.expect("Error setting all controllers inactive");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let app_server = AppServer::new(pool.clone()).start();
 | 
						let app_server = AppServer::new(pool.clone()).start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					use emgauwa_lib::errors::EmgauwaError;
 | 
				
			||||||
use emgauwa_lib::{constants, utils};
 | 
					use emgauwa_lib::{constants, utils};
 | 
				
			||||||
use serde_derive::Deserialize;
 | 
					use serde_derive::Deserialize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,6 +52,6 @@ impl Default for Logging {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init() -> Settings {
 | 
					pub fn init() -> Result<Settings, EmgauwaError> {
 | 
				
			||||||
	utils::load_settings("core", "CORE")
 | 
						utils::load_settings("core", "CORE")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,38 +19,31 @@ pub use relays::DbRelay;
 | 
				
			||||||
pub use schedules::{DbPeriods, DbSchedule};
 | 
					pub use schedules::{DbPeriods, DbSchedule};
 | 
				
			||||||
pub use tag::DbTag;
 | 
					pub use tag::DbTag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::errors::{DatabaseError, EmgauwaError};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
 | 
					static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn run_migrations(pool: &Pool<Sqlite>) {
 | 
					pub async fn run_migrations(pool: &Pool<Sqlite>) -> Result<(), EmgauwaError> {
 | 
				
			||||||
	log::info!("Running migrations");
 | 
						log::info!("Running migrations");
 | 
				
			||||||
	MIGRATOR.run(pool).await.expect("Failed to run migrations.");
 | 
						MIGRATOR.run(pool).await.map_err(DatabaseError::from)?;
 | 
				
			||||||
 | 
						Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn init(db: &str) -> Pool<Sqlite> {
 | 
					pub async fn init(db: &str) -> Result<Pool<Sqlite>, EmgauwaError> {
 | 
				
			||||||
	let options = SqliteConnectOptions::from_str(db)
 | 
						let options = SqliteConnectOptions::from_str(db)?.create_if_missing(true);
 | 
				
			||||||
		.expect("Error parsing database path")
 | 
					 | 
				
			||||||
		.create_if_missing(true);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let pool: Pool<Sqlite> = SqlitePoolOptions::new()
 | 
						let pool: Pool<Sqlite> = SqlitePoolOptions::new()
 | 
				
			||||||
		.acquire_timeout(std::time::Duration::from_secs(1))
 | 
							.acquire_timeout(std::time::Duration::from_secs(1))
 | 
				
			||||||
		.max_connections(5)
 | 
							.max_connections(5)
 | 
				
			||||||
		.connect_with(options)
 | 
							.connect_with(options)
 | 
				
			||||||
		.await
 | 
							.await?;
 | 
				
			||||||
		.expect("Error connecting to database");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	run_migrations(&pool).await;
 | 
						run_migrations(&pool).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let mut pool_conn = pool
 | 
						let mut pool_conn = pool.acquire().await?;
 | 
				
			||||||
		.acquire()
 | 
					 | 
				
			||||||
		.await
 | 
					 | 
				
			||||||
		.expect("Failed to acquire pool connection");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DbSchedule::get_on(&mut pool_conn)
 | 
						DbSchedule::get_on(&mut pool_conn).await?;
 | 
				
			||||||
		.await
 | 
						DbSchedule::get_off(&mut pool_conn).await?;
 | 
				
			||||||
		.expect("Failed to init 'on' schedule");
 | 
					 | 
				
			||||||
	DbSchedule::get_off(&mut pool_conn)
 | 
					 | 
				
			||||||
		.await
 | 
					 | 
				
			||||||
		.expect("Failed to init 'off' schedule");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool
 | 
						Ok(pool)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ use actix_web::http::StatusCode;
 | 
				
			||||||
use actix_web::HttpResponse;
 | 
					use actix_web::HttpResponse;
 | 
				
			||||||
use serde::ser::SerializeStruct;
 | 
					use serde::ser::SerializeStruct;
 | 
				
			||||||
use serde::{Serialize, Serializer};
 | 
					use serde::{Serialize, Serializer};
 | 
				
			||||||
 | 
					use sqlx::migrate::MigrateError;
 | 
				
			||||||
use sqlx::Error;
 | 
					use sqlx::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					@ -13,7 +14,8 @@ pub enum DatabaseError {
 | 
				
			||||||
	Protected,
 | 
						Protected,
 | 
				
			||||||
	UpdateError,
 | 
						UpdateError,
 | 
				
			||||||
	UpdateGetError,
 | 
						UpdateGetError,
 | 
				
			||||||
	Unknown(String),
 | 
						MigrationError(MigrateError),
 | 
				
			||||||
 | 
						Unknown(Error),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DatabaseError {
 | 
					impl DatabaseError {
 | 
				
			||||||
| 
						 | 
					@ -53,6 +55,7 @@ impl From<&DatabaseError> for String {
 | 
				
			||||||
			DatabaseError::UpdateGetError => {
 | 
								DatabaseError::UpdateGetError => {
 | 
				
			||||||
				"error on retrieving updated model from database (your entry was saved)"
 | 
									"error on retrieving updated model from database (your entry was saved)"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								DatabaseError::MigrationError(_) => "error on running migrations",
 | 
				
			||||||
			DatabaseError::Unknown(_) => "unknown error",
 | 
								DatabaseError::Unknown(_) => "unknown error",
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -68,7 +71,13 @@ impl From<Error> for DatabaseError {
 | 
				
			||||||
	fn from(value: Error) -> Self {
 | 
						fn from(value: Error) -> Self {
 | 
				
			||||||
		match value {
 | 
							match value {
 | 
				
			||||||
			Error::RowNotFound => DatabaseError::NotFound,
 | 
								Error::RowNotFound => DatabaseError::NotFound,
 | 
				
			||||||
			_ => DatabaseError::Unknown(value.to_string()),
 | 
								_ => DatabaseError::Unknown(value),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<MigrateError> for DatabaseError {
 | 
				
			||||||
 | 
						fn from(value: MigrateError) -> Self {
 | 
				
			||||||
 | 
							Self::MigrationError(value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,11 @@
 | 
				
			||||||
 | 
					use std::error::Error;
 | 
				
			||||||
use std::fmt::{Debug, Display, Formatter};
 | 
					use std::fmt::{Debug, Display, Formatter};
 | 
				
			||||||
 | 
					use std::io::ErrorKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use actix::MailboxError;
 | 
					use actix::MailboxError;
 | 
				
			||||||
use actix_web::http::StatusCode;
 | 
					use actix_web::http::StatusCode;
 | 
				
			||||||
use actix_web::HttpResponse;
 | 
					use actix_web::HttpResponse;
 | 
				
			||||||
 | 
					use config::ConfigError;
 | 
				
			||||||
use serde::ser::SerializeStruct;
 | 
					use serde::ser::SerializeStruct;
 | 
				
			||||||
use serde::{Serialize, Serializer};
 | 
					use serde::{Serialize, Serializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +18,7 @@ pub enum EmgauwaError {
 | 
				
			||||||
	Uid(uuid::Error),
 | 
						Uid(uuid::Error),
 | 
				
			||||||
	Serialization(serde_json::Error),
 | 
						Serialization(serde_json::Error),
 | 
				
			||||||
	Database(DatabaseError),
 | 
						Database(DatabaseError),
 | 
				
			||||||
 | 
						Other(String),
 | 
				
			||||||
	Internal(String),
 | 
						Internal(String),
 | 
				
			||||||
	Connection(ControllerUid),
 | 
						Connection(ControllerUid),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -28,6 +32,7 @@ impl EmgauwaError {
 | 
				
			||||||
			EmgauwaError::Uid(_) => StatusCode::BAD_REQUEST,
 | 
								EmgauwaError::Uid(_) => StatusCode::BAD_REQUEST,
 | 
				
			||||||
			EmgauwaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
 | 
								EmgauwaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
 | 
				
			||||||
			EmgauwaError::Connection(_) => StatusCode::GATEWAY_TIMEOUT,
 | 
								EmgauwaError::Connection(_) => StatusCode::GATEWAY_TIMEOUT,
 | 
				
			||||||
 | 
								EmgauwaError::Other(_) => StatusCode::INTERNAL_SERVER_ERROR,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -39,8 +44,9 @@ impl From<&EmgauwaError> for String {
 | 
				
			||||||
			EmgauwaError::Serialization(_) => String::from("error during (de-)serialization"),
 | 
								EmgauwaError::Serialization(_) => String::from("error during (de-)serialization"),
 | 
				
			||||||
			EmgauwaError::Database(err) => String::from(err),
 | 
								EmgauwaError::Database(err) => String::from(err),
 | 
				
			||||||
			EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
 | 
								EmgauwaError::Uid(_) => String::from("the uid is in a bad format"),
 | 
				
			||||||
			EmgauwaError::Internal(_) => String::from("general error"),
 | 
								EmgauwaError::Internal(_) => String::from("internal error"),
 | 
				
			||||||
			EmgauwaError::Connection(_) => String::from("the target controller is not connected"),
 | 
								EmgauwaError::Connection(_) => String::from("the target controller is not connected"),
 | 
				
			||||||
 | 
								EmgauwaError::Other(err) => format!("other error: {}", err),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -81,12 +87,26 @@ impl From<MailboxError> for EmgauwaError {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<ConfigError> for EmgauwaError {
 | 
				
			||||||
 | 
						fn from(value: ConfigError) -> Self {
 | 
				
			||||||
 | 
							Self::Other(value.to_string())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<&EmgauwaError> for HttpResponse {
 | 
					impl From<&EmgauwaError> for HttpResponse {
 | 
				
			||||||
	fn from(err: &EmgauwaError) -> Self {
 | 
						fn from(err: &EmgauwaError) -> Self {
 | 
				
			||||||
		HttpResponse::build(err.get_code()).json(err)
 | 
							HttpResponse::build(err.get_code()).json(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Error for EmgauwaError {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<EmgauwaError> for std::io::Error {
 | 
				
			||||||
 | 
						fn from(value: EmgauwaError) -> Self {
 | 
				
			||||||
 | 
							std::io::Error::new(ErrorKind::Other, value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Serialize for EmgauwaError {
 | 
					impl Serialize for EmgauwaError {
 | 
				
			||||||
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
						fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
				
			||||||
	where
 | 
						where
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,15 +62,20 @@ impl Type<Sqlite> for ControllerUid {
 | 
				
			||||||
impl<'q> Encode<'q, Sqlite> for ControllerUid {
 | 
					impl<'q> Encode<'q, Sqlite> for ControllerUid {
 | 
				
			||||||
	//noinspection DuplicatedCode
 | 
						//noinspection DuplicatedCode
 | 
				
			||||||
	fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
 | 
						fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
 | 
				
			||||||
		let uuid_val = self.0.as_bytes().to_vec();
 | 
							<Vec<u8> as Encode<Sqlite>>::encode(Vec::from(self), buf)
 | 
				
			||||||
		<&Vec<u8> as Encode<Sqlite>>::encode(&uuid_val, buf)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'r> Decode<'r, Sqlite> for ControllerUid {
 | 
					impl<'r> Decode<'r, Sqlite> for ControllerUid {
 | 
				
			||||||
	//noinspection DuplicatedCode
 | 
						//noinspection DuplicatedCode
 | 
				
			||||||
	fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
 | 
						fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
 | 
				
			||||||
		Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
 | 
							Self::try_from(<&[u8] as Decode<Sqlite>>::decode(value)?).map_err(Into::into)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<&ControllerUid> for Vec<u8> {
 | 
				
			||||||
 | 
						fn from(uid: &ControllerUid) -> Vec<u8> {
 | 
				
			||||||
 | 
							uid.0.as_bytes().to_vec()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,14 +88,16 @@ impl TryFrom<&str> for ControllerUid {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<&[u8]> for ControllerUid {
 | 
					impl TryFrom<&[u8]> for ControllerUid {
 | 
				
			||||||
	fn from(value: &[u8]) -> Self {
 | 
						type Error = uuid::Error;
 | 
				
			||||||
		Self(Uuid::from_slice(value).expect("Failed to parse controller uid from database"))
 | 
					
 | 
				
			||||||
 | 
						fn try_from(value: &[u8]) -> Result<ControllerUid, uuid::Error> {
 | 
				
			||||||
 | 
							Ok(Self(Uuid::from_slice(value)?))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<Vec<u8>> for ControllerUid {
 | 
					impl From<Vec<u8>> for ControllerUid {
 | 
				
			||||||
	fn from(value: Vec<u8>) -> Self {
 | 
						fn from(value: Vec<u8>) -> Self {
 | 
				
			||||||
		Self::from(value.as_slice())
 | 
							Self::try_from(value.as_slice()).expect("Failed to parse controller uid from database")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,14 +55,14 @@ impl Type<Sqlite> for ScheduleUid {
 | 
				
			||||||
impl<'q> Encode<'q, Sqlite> for ScheduleUid {
 | 
					impl<'q> Encode<'q, Sqlite> for ScheduleUid {
 | 
				
			||||||
	//noinspection DuplicatedCode
 | 
						//noinspection DuplicatedCode
 | 
				
			||||||
	fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
 | 
						fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
 | 
				
			||||||
		<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
 | 
							<Vec<u8> as Encode<Sqlite>>::encode(Vec::from(self), buf)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'r> Decode<'r, Sqlite> for ScheduleUid {
 | 
					impl<'r> Decode<'r, Sqlite> for ScheduleUid {
 | 
				
			||||||
	//noinspection DuplicatedCode
 | 
						//noinspection DuplicatedCode
 | 
				
			||||||
	fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
 | 
						fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
 | 
				
			||||||
		Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
 | 
							Self::try_from(<&[u8] as Decode<Sqlite>>::decode(value)?).map_err(Into::into)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,20 +140,21 @@ impl From<&ScheduleUid> for Vec<u8> {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<&[u8]> for ScheduleUid {
 | 
					impl TryFrom<&[u8]> for ScheduleUid {
 | 
				
			||||||
	fn from(value: &[u8]) -> Self {
 | 
						type Error = uuid::Error;
 | 
				
			||||||
		match value {
 | 
					
 | 
				
			||||||
 | 
						fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
							let result = match value {
 | 
				
			||||||
			[Self::OFF_U8] => Self::Off,
 | 
								[Self::OFF_U8] => Self::Off,
 | 
				
			||||||
			[Self::ON_U8] => Self::On,
 | 
								[Self::ON_U8] => Self::On,
 | 
				
			||||||
			value_bytes => Self::Any(
 | 
								value_bytes => Self::Any(Uuid::from_slice(value_bytes)?),
 | 
				
			||||||
				Uuid::from_slice(value_bytes).expect("Failed to parse schedule uid from database"),
 | 
							};
 | 
				
			||||||
			),
 | 
							Ok(result)
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<Vec<u8>> for ScheduleUid {
 | 
					impl From<Vec<u8>> for ScheduleUid {
 | 
				
			||||||
	fn from(value: Vec<u8>) -> Self {
 | 
						fn from(value: Vec<u8>) -> Self {
 | 
				
			||||||
		Self::from(value.as_slice())
 | 
							Self::try_from(value.as_slice()).expect("Failed to parse schedule uid from database")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,9 +4,10 @@ use chrono::Datelike;
 | 
				
			||||||
use log::LevelFilter;
 | 
					use log::LevelFilter;
 | 
				
			||||||
use simple_logger::SimpleLogger;
 | 
					use simple_logger::SimpleLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::errors::EmgauwaError;
 | 
				
			||||||
use crate::types::Weekday;
 | 
					use crate::types::Weekday;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn load_settings<T>(config_name: &str, env_prefix: &str) -> T
 | 
					pub fn load_settings<T>(config_name: &str, env_prefix: &str) -> Result<T, EmgauwaError>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
	for<'de> T: serde::Deserialize<'de>,
 | 
						for<'de> T: serde::Deserialize<'de>,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -19,20 +20,24 @@ where
 | 
				
			||||||
				.prefix_separator("__")
 | 
									.prefix_separator("__")
 | 
				
			||||||
				.separator("__"),
 | 
									.separator("__"),
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
		.build()
 | 
							.build()?
 | 
				
			||||||
		.expect("Error building settings")
 | 
					 | 
				
			||||||
		.try_deserialize::<T>()
 | 
							.try_deserialize::<T>()
 | 
				
			||||||
		.expect("Error reading settings")
 | 
							.map_err(EmgauwaError::from)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init_logging(level: &str) {
 | 
					pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
 | 
				
			||||||
	let log_level: LevelFilter = LevelFilter::from_str(level).expect("Error parsing log level.");
 | 
						let log_level: LevelFilter = LevelFilter::from_str(level)
 | 
				
			||||||
 | 
							.map_err(|_| EmgauwaError::Other(format!("Invalid log level: {}", level.to_string())))?;
 | 
				
			||||||
	log::trace!("Log level set to {:?}", log_level);
 | 
						log::trace!("Log level set to {:?}", log_level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SimpleLogger::new()
 | 
						SimpleLogger::new()
 | 
				
			||||||
		.with_level(log_level)
 | 
							.with_level(log_level)
 | 
				
			||||||
		.init()
 | 
							.init()
 | 
				
			||||||
		.expect("Error initializing logger.");
 | 
							.map_err(|err| {
 | 
				
			||||||
 | 
								EmgauwaError::Other(format!("Failed to initialize logger: {}", err.to_string()))
 | 
				
			||||||
 | 
							})?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_weekday() -> Weekday {
 | 
					pub fn get_weekday() -> Weekday {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue