use std::{fmt::Debug, sync::mpsc::Receiver as Recv, sync::mpsc::Sender};
use kpal_plugin::Val as PluginValue;
use log;
use super::{Executor, PluginError};
use crate::models::{Attribute, Model, Peripheral, Value};
pub type Receiver = Recv<Message>;
pub type Transmitter = Sender<Message>;
pub enum Message {
GetPeripheral(Sender<Result<Peripheral, PluginError>>),
GetPeripheralAttribute(usize, Sender<Result<Attribute, PluginError>>),
GetPeripheralAttributes(Sender<Result<Vec<Attribute>, PluginError>>),
PatchPeripheralAttribute(usize, Value, Sender<Result<Attribute, PluginError>>),
}
impl Message {
pub fn handle(&self, ex: &mut Executor, periph: &mut Peripheral) {
match self {
Message::GetPeripheral(tx) => log_and_send(tx.clone(), Ok(periph.clone()), periph.id()),
Message::GetPeripheralAttribute(id, tx) => {
let result = attribute_value_wrapper(ex, periph, *id);
log_and_send(tx.clone(), result, periph.id());
}
Message::GetPeripheralAttributes(tx) => {
let ids = {
let mut ids = Vec::new();
for id in periph.attributes().keys() {
ids.push(*id);
}
ids
};
let mut attrs = Vec::new();
for id in &ids {
let result = attribute_value_wrapper(ex, periph, *id);
attrs.push(result);
}
log_and_send(tx.clone(), attrs.into_iter().collect(), periph.id());
}
Message::PatchPeripheralAttribute(id, value, tx) => {
let value: PluginValue = value.as_val();
let result = set_attribute_value_wrapper(ex, periph, *id, value);
log_and_send(tx.clone(), result, periph.id());
}
};
}
}
fn attribute_value_wrapper(
ex: &mut Executor,
periph: &mut Peripheral,
id: usize,
) -> Result<Attribute, PluginError> {
let mut value = PluginValue::Int(0);
ex.attribute_value(id, &mut value)
.map(|_| {
log::debug!(
"Retrieved value {:?} from peripheral {}",
value,
periph.id(),
);
})
.map_err(|e| {
log::error!("Message handler error: {:?}", e);
PluginError::from(e)
})?;
periph.set_attribute_from_value(id, value)?;
let attr = &periph.attributes()[&id];
Ok(attr.clone())
}
fn set_attribute_value_wrapper(
ex: &mut Executor,
periph: &mut Peripheral,
id: usize,
value: PluginValue,
) -> Result<Attribute, PluginError> {
ex.set_attribute_value(id, &value)
.map(|_| {
log::debug!("Set value {:?} on peripheral {}", value, periph.id(),);
})
.map_err(|e| {
log::error!("Message handler error: {:?}", e);
PluginError::from(e)
})?;
periph.set_attribute_from_value(id, value)?;
let attr = &periph.attributes()[&id];
Ok(attr.clone())
}
fn log_and_send<T: Debug>(
tx: Sender<Result<T, PluginError>>,
result: Result<T, PluginError>,
peripheral_id: usize,
) {
if let Err(err) = tx.send(result) {
log::error!(
"Failed to return response from peripheral: {}. Reason: {}",
peripheral_id,
err
);
} else {
log::debug!(
"Successfully sent response back to request of peripheral: {}",
peripheral_id
);
};
}