| #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<sdbusplus::asio::connection> bus, |
| std::shared_ptr<sdbusplus::asio::object_server> objServer, |
| SensorCache& sensorCache) : |
| bus(std::move(bus)), |
| objServer(std::move(objServer)), sensorCache(sensorCache) |
| {} |
| |
| void TriggerFactory::updateDiscreteThresholds( |
| std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors, |
| const std::vector<discrete::LabeledThresholdParam>& newParams) const |
| { |
| auto oldThresholds = currentThresholds; |
| std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds; |
| |
| bool isCurrentOnChange = false; |
| if (oldThresholds.size() == 1 && |
| std::holds_alternative<std::monostate>( |
| 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<discrete::LabeledThresholdParam>( |
| 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<std::shared_ptr<interfaces::Threshold>>& currentThresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors, |
| const std::vector<numeric::LabeledThresholdParam>& newParams) const |
| { |
| auto oldThresholds = currentThresholds; |
| std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds; |
| |
| newThresholds.reserve(newParams.size()); |
| |
| for (const auto& labeledThresholdParam : newParams) |
| { |
| auto paramChecker = [labeledThresholdParam](auto threshold) { |
| return labeledThresholdParam == |
| std::get<numeric::LabeledThresholdParam>( |
| 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<std::shared_ptr<interfaces::Threshold>>& currentThresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors, |
| const LabeledTriggerThresholdParams& newParams) const |
| { |
| if (isTriggerThresholdDiscrete(newParams)) |
| { |
| const auto& labeledDiscreteThresholdParams = |
| std::get<std::vector<discrete::LabeledThresholdParam>>(newParams); |
| |
| updateDiscreteThresholds(currentThresholds, triggerId, triggerActions, |
| reportIds, sensors, |
| labeledDiscreteThresholdParams); |
| } |
| else |
| { |
| const auto& labeledNumericThresholdParams = |
| std::get<std::vector<numeric::LabeledThresholdParam>>(newParams); |
| |
| updateNumericThresholds(currentThresholds, triggerId, triggerActions, |
| reportIds, sensors, |
| labeledNumericThresholdParams); |
| } |
| } |
| |
| void TriggerFactory::makeDiscreteThreshold( |
| std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors, |
| const discrete::LabeledThresholdParam& thresholdParam) const |
| { |
| std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; |
| |
| const std::string& thresholdName = thresholdParam.at_label<ts::UserId>(); |
| discrete::Severity severity = thresholdParam.at_label<ts::Severity>(); |
| auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>()); |
| const std::string& thresholdValue = |
| thresholdParam.at_label<ts::ThresholdValue>(); |
| |
| action::discrete::fillActions(actions, triggerActions, severity, |
| bus->get_io_context(), reportIds); |
| |
| thresholds.emplace_back(std::make_shared<DiscreteThreshold>( |
| bus->get_io_context(), triggerId, sensors, std::move(actions), |
| Milliseconds(dwellTime), thresholdValue, thresholdName, severity, |
| std::make_unique<Clock>())); |
| } |
| |
| void TriggerFactory::makeNumericThreshold( |
| std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors, |
| const numeric::LabeledThresholdParam& thresholdParam) const |
| { |
| std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; |
| |
| auto type = thresholdParam.at_label<ts::Type>(); |
| auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>()); |
| auto direction = thresholdParam.at_label<ts::Direction>(); |
| auto thresholdValue = double{thresholdParam.at_label<ts::ThresholdValue>()}; |
| |
| action::numeric::fillActions(actions, triggerActions, type, thresholdValue, |
| bus->get_io_context(), reportIds); |
| |
| thresholds.emplace_back(std::make_shared<NumericThreshold>( |
| bus->get_io_context(), triggerId, sensors, std::move(actions), |
| dwellTime, direction, thresholdValue, type, std::make_unique<Clock>())); |
| } |
| |
| void TriggerFactory::makeOnChangeThreshold( |
| std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, |
| const std::string& triggerId, |
| const std::vector<TriggerAction>& triggerActions, |
| const std::shared_ptr<std::vector<std::string>>& reportIds, |
| const Sensors& sensors) const |
| { |
| std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; |
| |
| action::discrete::onChange::fillActions(actions, triggerActions, |
| bus->get_io_context(), reportIds); |
| |
| thresholds.emplace_back(std::make_shared<OnChangeThreshold>( |
| triggerId, sensors, std::move(actions), std::make_unique<Clock>())); |
| } |
| |
| std::unique_ptr<interfaces::Trigger> TriggerFactory::make( |
| const std::string& idIn, const std::string& name, |
| const std::vector<std::string>& triggerActionsIn, |
| const std::vector<std::string>& reportIdsIn, |
| interfaces::TriggerManager& triggerManager, |
| interfaces::JsonStorage& triggerStorage, |
| const LabeledTriggerThresholdParams& labeledThresholdParams, |
| const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const |
| { |
| const auto& sensors = getSensors(labeledSensorsInfo); |
| auto triggerActions = utils::transform(triggerActionsIn, |
| [](const auto& triggerActionStr) { |
| return toTriggerAction(triggerActionStr); |
| }); |
| std::vector<std::shared_ptr<interfaces::Threshold>> thresholds; |
| auto id = std::make_unique<const std::string>(idIn); |
| |
| auto reportIds = std::make_shared<std::vector<std::string>>(reportIdsIn); |
| |
| updateThresholds(thresholds, *id, triggerActions, reportIds, sensors, |
| labeledThresholdParams); |
| |
| return std::make_unique<Trigger>( |
| bus->get_io_context(), objServer, std::move(id), name, triggerActions, |
| reportIds, std::move(thresholds), triggerManager, triggerStorage, *this, |
| sensors); |
| } |
| |
| Sensors TriggerFactory::getSensors( |
| const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const |
| { |
| Sensors sensors; |
| updateSensors(sensors, labeledSensorsInfo); |
| return sensors; |
| } |
| |
| void TriggerFactory::updateSensors( |
| Sensors& currentSensors, |
| const std::vector<LabeledSensorInfo>& 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<ts::Service>(); |
| const auto& sensorPath = labeledSensorInfo.at_label<ts::Path>(); |
| const auto& metadata = labeledSensorInfo.at_label<ts::Metadata>(); |
| |
| newSensors.emplace_back(sensorCache.makeSensor<Sensor>( |
| service, sensorPath, metadata, bus->get_io_context(), bus)); |
| } |
| |
| currentSensors = std::move(newSensors); |
| } |
| |
| std::vector<LabeledSensorInfo> |
| 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<LabeledSensorInfo> |
| TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const |
| { |
| if (sensorsInfo.empty()) |
| { |
| return {}; |
| } |
| auto tree = utils::getSubTreeSensors(bus); |
| return parseSensorTree(tree, sensorsInfo); |
| } |
| |
| std::vector<LabeledSensorInfo> |
| TriggerFactory::parseSensorTree(const std::vector<utils::SensorTree>& 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"); |
| }); |
| } |