Improved error handling
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
2023-01-18 22:37:57 +01:00
parent b6bf8a82a2
commit a0cefa8302
17 changed files with 189 additions and 184 deletions

View File

@@ -4,7 +4,7 @@ use rumqttc::{AsyncClient, matches};
use tracing::{error, warn, debug};
use crate::config::MqttDeviceConfig;
use crate::error;
use crate::error::DeviceError;
use crate::mqtt::{OnMqtt, RemoteMessage, RemoteAction};
use crate::presence::OnPresence;
@@ -21,16 +21,13 @@ pub struct AudioSetup {
}
impl AudioSetup {
pub async fn build(identifier: &str, mqtt: MqttDeviceConfig, mixer: DeviceBox, speakers: DeviceBox, client: AsyncClient) -> error::Result<Self> {
pub async fn build(identifier: &str, mqtt: MqttDeviceConfig, mixer: DeviceBox, speakers: DeviceBox, client: AsyncClient) -> Result<Self, DeviceError> {
// We expect the children devices to implement the OnOff trait
let mixer = match AsOnOff::consume(mixer) {
Some(mixer) => mixer,
None => Err(error::ExpectedOnOff::new(&(identifier.to_owned() + ".mixer")))?,
};
let speakers = match AsOnOff::consume(speakers) {
Some(speakers) => speakers,
None => Err(error::ExpectedOnOff::new(&(identifier.to_owned() + ".speakers")))?,
};
let mixer = AsOnOff::consume(mixer)
.ok_or_else(|| DeviceError::OnOffExpected(identifier.to_owned() + ".mixer"))?;
let speakers = AsOnOff::consume(speakers)
.ok_or_else(|| DeviceError::OnOffExpected(identifier.to_owned() + ".speakers"))?;
client.subscribe(mqtt.topic.clone(), rumqttc::QoS::AtLeastOnce).await?;

View File

@@ -5,7 +5,7 @@ use rumqttc::{AsyncClient, matches};
use tokio::task::JoinHandle;
use tracing::{error, debug, warn};
use crate::{config::{MqttDeviceConfig, PresenceDeviceConfig}, mqtt::{OnMqtt, ContactMessage, PresenceMessage}, presence::OnPresence, error};
use crate::{config::{MqttDeviceConfig, PresenceDeviceConfig}, mqtt::{OnMqtt, ContactMessage, PresenceMessage}, presence::OnPresence, error::DeviceError};
use super::Device;
@@ -22,7 +22,7 @@ pub struct ContactSensor {
}
impl ContactSensor {
pub async fn build(identifier: &str, mqtt: MqttDeviceConfig, presence: Option<PresenceDeviceConfig>, client: AsyncClient) -> error::Result<Self> {
pub async fn build(identifier: &str, mqtt: MqttDeviceConfig, presence: Option<PresenceDeviceConfig>, client: AsyncClient) -> Result<Self, DeviceError> {
client.subscribe(mqtt.topic.clone(), rumqttc::QoS::AtLeastOnce).await?;
Ok(Self {

View File

@@ -9,7 +9,7 @@ use pollster::FutureExt as _;
use crate::config::{KettleConfig, InfoConfig, MqttDeviceConfig};
use crate::devices::Device;
use crate::error;
use crate::error::DeviceError;
use crate::mqtt::{OnMqtt, OnOffMessage};
use crate::presence::OnPresence;
@@ -26,7 +26,7 @@ pub struct IkeaOutlet {
}
impl IkeaOutlet {
pub async fn build(identifier: &str, info: InfoConfig, mqtt: MqttDeviceConfig, kettle: Option<KettleConfig>, client: AsyncClient) -> error::Result<Self> {
pub async fn build(identifier: &str, info: InfoConfig, mqtt: MqttDeviceConfig, kettle: Option<KettleConfig>, client: AsyncClient) -> Result<Self, DeviceError> {
// @TODO Handle potential errors here
client.subscribe(mqtt.topic.clone(), rumqttc::QoS::AtLeastOnce).await?;

View File

@@ -1,5 +1,6 @@
use std::{net::{SocketAddr, Ipv4Addr, TcpStream}, io::{Write, Read}};
use std::{net::{SocketAddr, Ipv4Addr, TcpStream}, io::{Write, Read}, str::Utf8Error};
use thiserror::Error;
use bytes::{Buf, BufMut};
use google_home::{traits, errors::{self, DeviceError}};
use serde::{Serialize, Deserialize};
@@ -89,9 +90,9 @@ struct ErrorCode {
}
impl ErrorCode {
fn ok(&self) -> Result<(), anyhow::Error> {
fn ok(&self) -> Result<(), ResponseError> {
if self.err_code != 0 {
Err(anyhow::anyhow!("Error code: {}", self.err_code))
Err(ResponseError::ErrorCode(self.err_code))
} else {
Ok(())
}
@@ -122,28 +123,55 @@ struct Response {
system: ResponseSystem,
}
// @TODO Improve this error
#[derive(Debug, Error)]
enum ResponseError {
#[error("Expected a minimum data length of 4")]
ToShort,
#[error("No sysinfo found in response")]
SysinfoNotFound,
#[error("No relay_state not found in response")]
RelayStateNotFound,
#[error("Error code: {0}")]
ErrorCode(isize),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error>),
}
impl From<Utf8Error> for ResponseError {
fn from(err: Utf8Error) -> Self {
ResponseError::Other(err.into())
}
}
impl From<serde_json::Error> for ResponseError {
fn from(err: serde_json::Error) -> Self {
ResponseError::Other(err.into())
}
}
impl Response {
fn get_current_relay_state(&self) -> Result<bool, anyhow::Error> {
fn get_current_relay_state(&self) -> Result<bool, ResponseError> {
if let Some(sysinfo) = &self.system.get_sysinfo {
return sysinfo.err_code.ok()
.map(|_| sysinfo.relay_state == 1);
}
return Err(anyhow::anyhow!("No sysinfo found in response"));
return Err(ResponseError::SysinfoNotFound);
}
fn check_set_relay_success(&self) -> Result<(), anyhow::Error> {
fn check_set_relay_success(&self) -> Result<(), ResponseError> {
if let Some(set_relay_state) = &self.system.set_relay_state {
return set_relay_state.err_code.ok();
}
return Err(anyhow::anyhow!("No relay_state found in response"));
return Err(ResponseError::RelayStateNotFound);
}
fn decrypt(mut data: bytes::Bytes) -> Result<Self, anyhow::Error> {
fn decrypt(mut data: bytes::Bytes) -> Result<Self, ResponseError> {
let mut key: u8 = 171;
if data.len() < 4 {
return Err(anyhow::anyhow!("Expected a minimun data length of 4"));
return Err(ResponseError::ToShort.into());
}
let length = data.get_u32();

View File

@@ -1,11 +1,11 @@
use async_trait::async_trait;
use google_home::{GoogleHomeDevice, types::Type, device, traits::{self, Scene}, errors::{ErrorCode, DeviceError}};
use google_home::{GoogleHomeDevice, types::Type, device, traits::{self, Scene}, errors::ErrorCode};
use tracing::{debug, error};
use rumqttc::{AsyncClient, Publish, matches};
use pollster::FutureExt as _;
use eui48::MacAddress;
use crate::{config::{InfoConfig, MqttDeviceConfig}, mqtt::{OnMqtt, ActivateMessage}, error};
use crate::{config::{InfoConfig, MqttDeviceConfig}, mqtt::{OnMqtt, ActivateMessage}, error::DeviceError};
use super::Device;
@@ -18,7 +18,7 @@ pub struct WakeOnLAN {
}
impl WakeOnLAN {
pub async fn build(identifier: &str, info: InfoConfig, mqtt: MqttDeviceConfig, mac_address: MacAddress, client: AsyncClient) -> error::Result<Self> {
pub async fn build(identifier: &str, info: InfoConfig, mqtt: MqttDeviceConfig, mac_address: MacAddress, client: AsyncClient) -> Result<Self, DeviceError> {
// @TODO Handle potential errors here
client.subscribe(mqtt.topic.clone(), rumqttc::QoS::AtLeastOnce).await?;
@@ -89,7 +89,7 @@ impl traits::Scene for WakeOnLAN {
Ok(res) => res,
Err(err) => {
error!(id, "Failed to call webhook: {err}");
return Err(DeviceError::TransientError.into());
return Err(google_home::errors::DeviceError::TransientError.into());
}
};
@@ -102,7 +102,7 @@ impl traits::Scene for WakeOnLAN {
} else {
debug!(id = self.identifier, "Trying to deactive computer, this is not currently supported");
// We do not support deactivating this scene
Err(ErrorCode::DeviceError(DeviceError::ActionNotAvailable))
Err(ErrorCode::DeviceError(google_home::errors::DeviceError::ActionNotAvailable))
}
}
}