blob: 22b7ea5c404d5dd42e5cc87005d6c10dff256341 [file] [log] [blame]
#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");
});
}