#include "trigger_factory.hpp" #include "discrete_threshold.hpp" #include "numeric_threshold.hpp" #include "on_change_threshold.hpp" #include "sensor.hpp" #include "trigger.hpp" #include "trigger_actions.hpp" #include "utils/clock.hpp" #include "utils/dbus_mapper.hpp" #include "utils/transform.hpp" namespace ts = utils::tstring; TriggerFactory::TriggerFactory( std::shared_ptr bus, std::shared_ptr objServer, SensorCache& sensorCache) : bus(std::move(bus)), objServer(std::move(objServer)), sensorCache(sensorCache) {} void TriggerFactory::updateDiscreteThresholds( std::vector>& currentThresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors, const std::vector& newParams) const { auto oldThresholds = currentThresholds; std::vector> newThresholds; bool isCurrentOnChange = false; if (oldThresholds.size() == 1 && std::holds_alternative( oldThresholds.back()->getThresholdParam())) { isCurrentOnChange = true; } newThresholds.reserve(newParams.size()); if (!isCurrentOnChange) { for (const auto& labeledThresholdParam : newParams) { auto paramChecker = [labeledThresholdParam](auto threshold) { return labeledThresholdParam == std::get( threshold->getThresholdParam()); }; if (auto existing = std::find_if(oldThresholds.begin(), oldThresholds.end(), paramChecker); existing != oldThresholds.end()) { newThresholds.emplace_back(*existing); oldThresholds.erase(existing); continue; } makeDiscreteThreshold(newThresholds, triggerId, triggerActions, reportIds, sensors, labeledThresholdParam); } } else { for (const auto& labeledThresholdParam : newParams) { makeDiscreteThreshold(newThresholds, triggerId, triggerActions, reportIds, sensors, labeledThresholdParam); } } if (newParams.empty()) { if (isCurrentOnChange) { newThresholds.emplace_back(*oldThresholds.begin()); } else { makeOnChangeThreshold(newThresholds, triggerId, triggerActions, reportIds, sensors); } } currentThresholds = std::move(newThresholds); } void TriggerFactory::updateNumericThresholds( std::vector>& currentThresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors, const std::vector& newParams) const { auto oldThresholds = currentThresholds; std::vector> newThresholds; newThresholds.reserve(newParams.size()); for (const auto& labeledThresholdParam : newParams) { auto paramChecker = [labeledThresholdParam](auto threshold) { return labeledThresholdParam == std::get( threshold->getThresholdParam()); }; if (auto existing = std::find_if(oldThresholds.begin(), oldThresholds.end(), paramChecker); existing != oldThresholds.end()) { newThresholds.emplace_back(*existing); oldThresholds.erase(existing); continue; } makeNumericThreshold(newThresholds, triggerId, triggerActions, reportIds, sensors, labeledThresholdParam); } currentThresholds = std::move(newThresholds); } void TriggerFactory::updateThresholds( std::vector>& currentThresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors, const LabeledTriggerThresholdParams& newParams) const { if (isTriggerThresholdDiscrete(newParams)) { const auto& labeledDiscreteThresholdParams = std::get>(newParams); updateDiscreteThresholds(currentThresholds, triggerId, triggerActions, reportIds, sensors, labeledDiscreteThresholdParams); } else { const auto& labeledNumericThresholdParams = std::get>(newParams); updateNumericThresholds(currentThresholds, triggerId, triggerActions, reportIds, sensors, labeledNumericThresholdParams); } } void TriggerFactory::makeDiscreteThreshold( std::vector>& thresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors, const discrete::LabeledThresholdParam& thresholdParam) const { std::vector> actions; const std::string& thresholdName = thresholdParam.at_label(); discrete::Severity severity = thresholdParam.at_label(); auto dwellTime = Milliseconds(thresholdParam.at_label()); const std::string& thresholdValue = thresholdParam.at_label(); action::discrete::fillActions(actions, triggerActions, severity, bus->get_io_context(), reportIds); thresholds.emplace_back(std::make_shared( bus->get_io_context(), triggerId, sensors, std::move(actions), Milliseconds(dwellTime), thresholdValue, thresholdName, severity, std::make_unique())); } void TriggerFactory::makeNumericThreshold( std::vector>& thresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors, const numeric::LabeledThresholdParam& thresholdParam) const { std::vector> actions; auto type = thresholdParam.at_label(); auto dwellTime = Milliseconds(thresholdParam.at_label()); auto direction = thresholdParam.at_label(); auto thresholdValue = double{thresholdParam.at_label()}; action::numeric::fillActions(actions, triggerActions, type, thresholdValue, bus->get_io_context(), reportIds); thresholds.emplace_back(std::make_shared( bus->get_io_context(), triggerId, sensors, std::move(actions), dwellTime, direction, thresholdValue, type, std::make_unique())); } void TriggerFactory::makeOnChangeThreshold( std::vector>& thresholds, const std::string& triggerId, const std::vector& triggerActions, const std::shared_ptr>& reportIds, const Sensors& sensors) const { std::vector> actions; action::discrete::onChange::fillActions(actions, triggerActions, bus->get_io_context(), reportIds); thresholds.emplace_back(std::make_shared( triggerId, sensors, std::move(actions), std::make_unique())); } std::unique_ptr TriggerFactory::make( const std::string& idIn, const std::string& name, const std::vector& triggerActionsIn, const std::vector& reportIdsIn, interfaces::TriggerManager& triggerManager, interfaces::JsonStorage& triggerStorage, const LabeledTriggerThresholdParams& labeledThresholdParams, const std::vector& labeledSensorsInfo) const { const auto& sensors = getSensors(labeledSensorsInfo); auto triggerActions = utils::transform(triggerActionsIn, [](const auto& triggerActionStr) { return toTriggerAction(triggerActionStr); }); std::vector> thresholds; auto id = std::make_unique(idIn); auto reportIds = std::make_shared>(reportIdsIn); updateThresholds(thresholds, *id, triggerActions, reportIds, sensors, labeledThresholdParams); return std::make_unique( bus->get_io_context(), objServer, std::move(id), name, triggerActions, reportIds, std::move(thresholds), triggerManager, triggerStorage, *this, sensors); } Sensors TriggerFactory::getSensors( const std::vector& labeledSensorsInfo) const { Sensors sensors; updateSensors(sensors, labeledSensorsInfo); return sensors; } void TriggerFactory::updateSensors( Sensors& currentSensors, const std::vector& labeledSensorsInfo) const { Sensors oldSensors = currentSensors; Sensors newSensors; for (const auto& labeledSensorInfo : labeledSensorsInfo) { auto existing = std::find_if(oldSensors.begin(), oldSensors.end(), [labeledSensorInfo](auto sensor) { return labeledSensorInfo == sensor->getLabeledSensorInfo(); }); if (existing != oldSensors.end()) { newSensors.emplace_back(*existing); oldSensors.erase(existing); continue; } const auto& service = labeledSensorInfo.at_label(); const auto& sensorPath = labeledSensorInfo.at_label(); const auto& metadata = labeledSensorInfo.at_label(); newSensors.emplace_back(sensorCache.makeSensor( service, sensorPath, metadata, bus->get_io_context(), bus)); } currentSensors = std::move(newSensors); } std::vector TriggerFactory::getLabeledSensorsInfo(boost::asio::yield_context& yield, const SensorsInfo& sensorsInfo) const { if (sensorsInfo.empty()) { return {}; } auto tree = utils::getSubTreeSensors(yield, bus); return parseSensorTree(tree, sensorsInfo); } std::vector TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const { if (sensorsInfo.empty()) { return {}; } auto tree = utils::getSubTreeSensors(bus); return parseSensorTree(tree, sensorsInfo); } std::vector TriggerFactory::parseSensorTree(const std::vector& tree, const SensorsInfo& sensorsInfo) { return utils::transform(sensorsInfo, [&tree](const auto& item) { const auto& [sensorPath, metadata] = item; auto found = std::find_if( tree.begin(), tree.end(), [path = sensorPath](const auto& x) { return x.first == path; }); if (tree.end() != found) { const auto& [service, ifaces] = found->second.front(); return LabeledSensorInfo(service, sensorPath, metadata); } throw std::runtime_error("Not found"); }); }