use crate::bmc_quirks::BmcQuirks;
use crate::patch_support::Payload;
use crate::patch_support::ReadPatchFn;
use crate::patches::remove_invalid_resource_state;
use crate::schema::redfish::environment_metrics::EnvironmentMetrics;
use crate::schema::redfish::sensor::Sensor as SchemaSensor;
use crate::Error;
use crate::NvBmc;
use nv_redfish_core::Bmc;
use nv_redfish_core::NavProperty;
use nv_redfish_core::ODataId;
use std::sync::Arc;
#[macro_export(local_inner_macros)]
macro_rules! extract_sensor_uris {
($metrics:expr, $(single: $single_field:ident),* $(, vec: $vec_field:ident)* $(,)?) => {{
let mut uris = Vec::new();
$(
if let Some(Some(uri)) = $metrics.$single_field.as_ref()
.and_then(|f| f.data_source_uri.as_ref()) {
uris.push(uri.clone());
}
)*
$(
if let Some(items) = &$metrics.$vec_field {
for item in items {
if let Some(Some(uri)) = item.data_source_uri.as_ref() {
uris.push(uri.clone());
}
}
}
)*
$crate::sensor::collect_sensors(uris)
}};
}
struct Config {
read_patch_fn: Option<ReadPatchFn>,
}
impl Config {
fn new(quirks: &BmcQuirks) -> Self {
let mut patches = Vec::new();
if quirks.wrong_resource_status_state() {
patches.push(remove_invalid_resource_state);
}
let read_patch_fn = (!patches.is_empty())
.then(|| Arc::new(move |v| patches.iter().fold(v, |acc, f| f(acc))) as ReadPatchFn);
Self { read_patch_fn }
}
}
pub struct SensorRef<B: Bmc> {
bmc: NvBmc<B>,
nav: NavProperty<SchemaSensor>,
config: Config,
}
impl<B: Bmc> SensorRef<B> {
#[must_use]
pub(crate) fn new(bmc: NvBmc<B>, nav: NavProperty<SchemaSensor>) -> Self {
let config = Config::new(&bmc.quirks);
Self { bmc, nav, config }
}
pub async fn fetch(&self) -> Result<Arc<SchemaSensor>, Error<B>> {
if let Some(read_patch_fn) = &self.config.read_patch_fn {
Payload::get(self.bmc.as_ref(), &self.nav, read_patch_fn.as_ref()).await
} else {
self.nav.get(self.bmc.as_ref()).await.map_err(Error::Bmc)
}
}
#[must_use]
pub fn odata_id(&self) -> &ODataId {
self.nav.id()
}
}
pub(crate) fn collect_sensors(
uris: impl IntoIterator<Item = String>,
) -> Vec<NavProperty<SchemaSensor>> {
uris.into_iter()
.map(|uri| NavProperty::<SchemaSensor>::new_reference(ODataId::from(uri)))
.collect()
}
pub(crate) async fn extract_environment_sensors<B: Bmc>(
metrics_ref: &NavProperty<EnvironmentMetrics>,
bmc: &B,
) -> Result<Vec<NavProperty<SchemaSensor>>, Error<B>> {
metrics_ref
.get(bmc)
.await
.map(|m| {
extract_sensor_uris!(m,
single: temperature_celsius,
single: humidity_percent,
single: power_watts,
single: energyk_wh,
single: power_load_percent,
single: dew_point_celsius,
single: absolute_humidity,
single: energy_joules,
single: ambient_temperature_celsius,
single: voltage,
single: current_amps,
vec: fan_speeds_percent
)
})
.map_err(Error::Bmc)
}