Replace expect usage with Result
This commit is contained in:
		
							parent
							
								
									9394a1ae52
								
							
						
					
					
						commit
						b3228ea6b5
					
				
					 11 changed files with 135 additions and 95 deletions
				
			
		| 
						 | 
				
			
			@ -19,38 +19,31 @@ pub use relays::DbRelay;
 | 
			
		|||
pub use schedules::{DbPeriods, DbSchedule};
 | 
			
		||||
pub use tag::DbTag;
 | 
			
		||||
 | 
			
		||||
use crate::errors::{DatabaseError, EmgauwaError};
 | 
			
		||||
 | 
			
		||||
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");
 | 
			
		||||
	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> {
 | 
			
		||||
	let options = SqliteConnectOptions::from_str(db)
 | 
			
		||||
		.expect("Error parsing database path")
 | 
			
		||||
		.create_if_missing(true);
 | 
			
		||||
pub async fn init(db: &str) -> Result<Pool<Sqlite>, EmgauwaError> {
 | 
			
		||||
	let options = SqliteConnectOptions::from_str(db)?.create_if_missing(true);
 | 
			
		||||
 | 
			
		||||
	let pool: Pool<Sqlite> = SqlitePoolOptions::new()
 | 
			
		||||
		.acquire_timeout(std::time::Duration::from_secs(1))
 | 
			
		||||
		.max_connections(5)
 | 
			
		||||
		.connect_with(options)
 | 
			
		||||
		.await
 | 
			
		||||
		.expect("Error connecting to database");
 | 
			
		||||
		.await?;
 | 
			
		||||
 | 
			
		||||
	run_migrations(&pool).await;
 | 
			
		||||
	run_migrations(&pool).await?;
 | 
			
		||||
 | 
			
		||||
	let mut pool_conn = pool
 | 
			
		||||
		.acquire()
 | 
			
		||||
		.await
 | 
			
		||||
		.expect("Failed to acquire pool connection");
 | 
			
		||||
	let mut pool_conn = pool.acquire().await?;
 | 
			
		||||
 | 
			
		||||
	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");
 | 
			
		||||
	DbSchedule::get_on(&mut pool_conn).await?;
 | 
			
		||||
	DbSchedule::get_off(&mut pool_conn).await?;
 | 
			
		||||
 | 
			
		||||
	pool
 | 
			
		||||
	Ok(pool)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ use actix_web::http::StatusCode;
 | 
			
		|||
use actix_web::HttpResponse;
 | 
			
		||||
use serde::ser::SerializeStruct;
 | 
			
		||||
use serde::{Serialize, Serializer};
 | 
			
		||||
use sqlx::migrate::MigrateError;
 | 
			
		||||
use sqlx::Error;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +14,8 @@ pub enum DatabaseError {
 | 
			
		|||
	Protected,
 | 
			
		||||
	UpdateError,
 | 
			
		||||
	UpdateGetError,
 | 
			
		||||
	Unknown(String),
 | 
			
		||||
	MigrationError(MigrateError),
 | 
			
		||||
	Unknown(Error),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DatabaseError {
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +55,7 @@ impl From<&DatabaseError> for String {
 | 
			
		|||
			DatabaseError::UpdateGetError => {
 | 
			
		||||
				"error on retrieving updated model from database (your entry was saved)"
 | 
			
		||||
			}
 | 
			
		||||
			DatabaseError::MigrationError(_) => "error on running migrations",
 | 
			
		||||
			DatabaseError::Unknown(_) => "unknown error",
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +71,13 @@ impl From<Error> for DatabaseError {
 | 
			
		|||
	fn from(value: Error) -> Self {
 | 
			
		||||
		match value {
 | 
			
		||||
			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::io::ErrorKind;
 | 
			
		||||
 | 
			
		||||
use actix::MailboxError;
 | 
			
		||||
use actix_web::http::StatusCode;
 | 
			
		||||
use actix_web::HttpResponse;
 | 
			
		||||
use config::ConfigError;
 | 
			
		||||
use serde::ser::SerializeStruct;
 | 
			
		||||
use serde::{Serialize, Serializer};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +18,7 @@ pub enum EmgauwaError {
 | 
			
		|||
	Uid(uuid::Error),
 | 
			
		||||
	Serialization(serde_json::Error),
 | 
			
		||||
	Database(DatabaseError),
 | 
			
		||||
	Other(String),
 | 
			
		||||
	Internal(String),
 | 
			
		||||
	Connection(ControllerUid),
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +32,7 @@ impl EmgauwaError {
 | 
			
		|||
			EmgauwaError::Uid(_) => StatusCode::BAD_REQUEST,
 | 
			
		||||
			EmgauwaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
 | 
			
		||||
			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::Database(err) => String::from(err),
 | 
			
		||||
			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::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 {
 | 
			
		||||
	fn from(err: &EmgauwaError) -> Self {
 | 
			
		||||
		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 {
 | 
			
		||||
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
	where
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,15 +62,20 @@ impl Type<Sqlite> for ControllerUid {
 | 
			
		|||
impl<'q> Encode<'q, Sqlite> for ControllerUid {
 | 
			
		||||
	//noinspection DuplicatedCode
 | 
			
		||||
	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(&uuid_val, buf)
 | 
			
		||||
		<Vec<u8> as Encode<Sqlite>>::encode(Vec::from(self), buf)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'r> Decode<'r, Sqlite> for ControllerUid {
 | 
			
		||||
	//noinspection DuplicatedCode
 | 
			
		||||
	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 {
 | 
			
		||||
	fn from(value: &[u8]) -> Self {
 | 
			
		||||
		Self(Uuid::from_slice(value).expect("Failed to parse controller uid from database"))
 | 
			
		||||
impl TryFrom<&[u8]> for ControllerUid {
 | 
			
		||||
	type Error = uuid::Error;
 | 
			
		||||
 | 
			
		||||
	fn try_from(value: &[u8]) -> Result<ControllerUid, uuid::Error> {
 | 
			
		||||
		Ok(Self(Uuid::from_slice(value)?))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Vec<u8>> for ControllerUid {
 | 
			
		||||
	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 {
 | 
			
		||||
	//noinspection DuplicatedCode
 | 
			
		||||
	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 {
 | 
			
		||||
	//noinspection DuplicatedCode
 | 
			
		||||
	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 {
 | 
			
		||||
	fn from(value: &[u8]) -> Self {
 | 
			
		||||
		match value {
 | 
			
		||||
impl TryFrom<&[u8]> for ScheduleUid {
 | 
			
		||||
	type Error = uuid::Error;
 | 
			
		||||
 | 
			
		||||
	fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
 | 
			
		||||
		let result = match value {
 | 
			
		||||
			[Self::OFF_U8] => Self::Off,
 | 
			
		||||
			[Self::ON_U8] => Self::On,
 | 
			
		||||
			value_bytes => Self::Any(
 | 
			
		||||
				Uuid::from_slice(value_bytes).expect("Failed to parse schedule uid from database"),
 | 
			
		||||
			),
 | 
			
		||||
		}
 | 
			
		||||
			value_bytes => Self::Any(Uuid::from_slice(value_bytes)?),
 | 
			
		||||
		};
 | 
			
		||||
		Ok(result)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Vec<u8>> for ScheduleUid {
 | 
			
		||||
	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 simple_logger::SimpleLogger;
 | 
			
		||||
 | 
			
		||||
use crate::errors::EmgauwaError;
 | 
			
		||||
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
 | 
			
		||||
	for<'de> T: serde::Deserialize<'de>,
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -19,20 +20,24 @@ where
 | 
			
		|||
				.prefix_separator("__")
 | 
			
		||||
				.separator("__"),
 | 
			
		||||
		)
 | 
			
		||||
		.build()
 | 
			
		||||
		.expect("Error building settings")
 | 
			
		||||
		.build()?
 | 
			
		||||
		.try_deserialize::<T>()
 | 
			
		||||
		.expect("Error reading settings")
 | 
			
		||||
		.map_err(EmgauwaError::from)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn init_logging(level: &str) {
 | 
			
		||||
	let log_level: LevelFilter = LevelFilter::from_str(level).expect("Error parsing log level.");
 | 
			
		||||
pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	SimpleLogger::new()
 | 
			
		||||
		.with_level(log_level)
 | 
			
		||||
		.init()
 | 
			
		||||
		.expect("Error initializing logger.");
 | 
			
		||||
		.map_err(|err| {
 | 
			
		||||
			EmgauwaError::Other(format!("Failed to initialize logger: {}", err.to_string()))
 | 
			
		||||
		})?;
 | 
			
		||||
 | 
			
		||||
	Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn get_weekday() -> Weekday {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue