1 #include "trigger_factory.hpp" 2 3 #include "discrete_threshold.hpp" 4 #include "numeric_threshold.hpp" 5 #include "on_change_threshold.hpp" 6 #include "sensor.hpp" 7 #include "trigger.hpp" 8 #include "trigger_actions.hpp" 9 #include "utils/dbus_mapper.hpp" 10 #include "utils/transform.hpp" 11 12 namespace ts = utils::tstring; 13 14 TriggerFactory::TriggerFactory( 15 std::shared_ptr<sdbusplus::asio::connection> bus, 16 std::shared_ptr<sdbusplus::asio::object_server> objServer, 17 SensorCache& sensorCache) : 18 bus(std::move(bus)), 19 objServer(std::move(objServer)), sensorCache(sensorCache) 20 {} 21 22 void TriggerFactory::updateDiscreteThresholds( 23 std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds, 24 const std::vector<TriggerAction>& triggerActions, 25 const std::shared_ptr<std::vector<std::string>>& reportIds, 26 const Sensors& sensors, 27 const std::vector<discrete::LabeledThresholdParam>& newParams) const 28 { 29 auto oldThresholds = currentThresholds; 30 std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds; 31 32 bool isCurrentOnChange = false; 33 if (oldThresholds.size() == 1 && 34 std::holds_alternative<std::monostate>( 35 oldThresholds.back()->getThresholdParam())) 36 { 37 isCurrentOnChange = true; 38 } 39 40 newThresholds.reserve(newParams.size()); 41 42 if (!isCurrentOnChange) 43 { 44 for (const auto& labeledThresholdParam : newParams) 45 { 46 auto paramChecker = [labeledThresholdParam](auto threshold) { 47 return labeledThresholdParam == 48 std::get<discrete::LabeledThresholdParam>( 49 threshold->getThresholdParam()); 50 }; 51 if (auto existing = std::find_if(oldThresholds.begin(), 52 oldThresholds.end(), paramChecker); 53 existing != oldThresholds.end()) 54 { 55 newThresholds.emplace_back(*existing); 56 oldThresholds.erase(existing); 57 continue; 58 } 59 60 makeDiscreteThreshold(newThresholds, triggerActions, reportIds, 61 sensors, labeledThresholdParam); 62 } 63 } 64 else 65 { 66 for (const auto& labeledThresholdParam : newParams) 67 { 68 makeDiscreteThreshold(newThresholds, triggerActions, reportIds, 69 sensors, labeledThresholdParam); 70 } 71 } 72 if (newParams.empty()) 73 { 74 if (isCurrentOnChange) 75 { 76 newThresholds.emplace_back(*oldThresholds.begin()); 77 } 78 else 79 { 80 makeOnChangeThreshold(newThresholds, triggerActions, reportIds, 81 sensors); 82 } 83 } 84 currentThresholds = std::move(newThresholds); 85 } 86 87 void TriggerFactory::updateNumericThresholds( 88 std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds, 89 const std::vector<TriggerAction>& triggerActions, 90 const std::shared_ptr<std::vector<std::string>>& reportIds, 91 const Sensors& sensors, 92 const std::vector<numeric::LabeledThresholdParam>& newParams) const 93 { 94 auto oldThresholds = currentThresholds; 95 std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds; 96 97 newThresholds.reserve(newParams.size()); 98 99 for (const auto& labeledThresholdParam : newParams) 100 { 101 auto paramChecker = [labeledThresholdParam](auto threshold) { 102 return labeledThresholdParam == 103 std::get<numeric::LabeledThresholdParam>( 104 threshold->getThresholdParam()); 105 }; 106 if (auto existing = std::find_if(oldThresholds.begin(), 107 oldThresholds.end(), paramChecker); 108 existing != oldThresholds.end()) 109 { 110 newThresholds.emplace_back(*existing); 111 oldThresholds.erase(existing); 112 continue; 113 } 114 115 makeNumericThreshold(newThresholds, triggerActions, reportIds, sensors, 116 labeledThresholdParam); 117 } 118 currentThresholds = std::move(newThresholds); 119 } 120 121 void TriggerFactory::updateThresholds( 122 std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds, 123 const std::vector<TriggerAction>& triggerActions, 124 const std::shared_ptr<std::vector<std::string>>& reportIds, 125 const Sensors& sensors, 126 const LabeledTriggerThresholdParams& newParams) const 127 { 128 if (isTriggerThresholdDiscrete(newParams)) 129 { 130 const auto& labeledDiscreteThresholdParams = 131 std::get<std::vector<discrete::LabeledThresholdParam>>(newParams); 132 133 updateDiscreteThresholds(currentThresholds, triggerActions, reportIds, 134 sensors, labeledDiscreteThresholdParams); 135 } 136 else 137 { 138 const auto& labeledNumericThresholdParams = 139 std::get<std::vector<numeric::LabeledThresholdParam>>(newParams); 140 141 updateNumericThresholds(currentThresholds, triggerActions, reportIds, 142 sensors, labeledNumericThresholdParams); 143 } 144 } 145 146 void TriggerFactory::makeDiscreteThreshold( 147 std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, 148 const std::vector<TriggerAction>& triggerActions, 149 const std::shared_ptr<std::vector<std::string>>& reportIds, 150 const Sensors& sensors, 151 const discrete::LabeledThresholdParam& thresholdParam) const 152 { 153 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 154 155 std::string thresholdName = thresholdParam.at_label<ts::UserId>(); 156 discrete::Severity severity = thresholdParam.at_label<ts::Severity>(); 157 auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>()); 158 std::string thresholdValue = thresholdParam.at_label<ts::ThresholdValue>(); 159 160 action::discrete::fillActions(actions, triggerActions, severity, 161 bus->get_io_context(), reportIds); 162 163 thresholds.emplace_back(std::make_shared<DiscreteThreshold>( 164 bus->get_io_context(), sensors, std::move(actions), 165 Milliseconds(dwellTime), thresholdValue, thresholdName, severity)); 166 } 167 168 void TriggerFactory::makeNumericThreshold( 169 std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, 170 const std::vector<TriggerAction>& triggerActions, 171 const std::shared_ptr<std::vector<std::string>>& reportIds, 172 const Sensors& sensors, 173 const numeric::LabeledThresholdParam& thresholdParam) const 174 { 175 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 176 177 auto type = thresholdParam.at_label<ts::Type>(); 178 auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>()); 179 auto direction = thresholdParam.at_label<ts::Direction>(); 180 auto thresholdValue = double{thresholdParam.at_label<ts::ThresholdValue>()}; 181 182 action::numeric::fillActions(actions, triggerActions, type, thresholdValue, 183 bus->get_io_context(), reportIds); 184 185 thresholds.emplace_back(std::make_shared<NumericThreshold>( 186 bus->get_io_context(), sensors, std::move(actions), dwellTime, 187 direction, thresholdValue, type)); 188 } 189 190 void TriggerFactory::makeOnChangeThreshold( 191 std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, 192 const std::vector<TriggerAction>& triggerActions, 193 const std::shared_ptr<std::vector<std::string>>& reportIds, 194 const Sensors& sensors) const 195 { 196 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 197 198 action::discrete::onChange::fillActions(actions, triggerActions, 199 bus->get_io_context(), reportIds); 200 201 thresholds.emplace_back( 202 std::make_shared<OnChangeThreshold>(sensors, std::move(actions))); 203 } 204 205 std::unique_ptr<interfaces::Trigger> TriggerFactory::make( 206 const std::string& id, const std::string& name, 207 const std::vector<std::string>& triggerActionsIn, 208 const std::vector<std::string>& reportIdsIn, 209 interfaces::TriggerManager& triggerManager, 210 interfaces::JsonStorage& triggerStorage, 211 const LabeledTriggerThresholdParams& labeledThresholdParams, 212 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 213 { 214 const auto& sensors = getSensors(labeledSensorsInfo); 215 auto triggerActions = 216 utils::transform(triggerActionsIn, [](const auto& triggerActionStr) { 217 return toTriggerAction(triggerActionStr); 218 }); 219 std::vector<std::shared_ptr<interfaces::Threshold>> thresholds; 220 221 auto reportIds = std::make_shared<std::vector<std::string>>(reportIdsIn); 222 223 updateThresholds(thresholds, triggerActions, reportIds, sensors, 224 labeledThresholdParams); 225 226 return std::make_unique<Trigger>( 227 bus->get_io_context(), objServer, id, name, triggerActions, reportIds, 228 std::move(thresholds), triggerManager, triggerStorage, *this, sensors); 229 } 230 231 Sensors TriggerFactory::getSensors( 232 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 233 { 234 Sensors sensors; 235 updateSensors(sensors, labeledSensorsInfo); 236 return sensors; 237 } 238 239 void TriggerFactory::updateSensors( 240 Sensors& currentSensors, 241 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 242 { 243 Sensors oldSensors = currentSensors; 244 Sensors newSensors; 245 246 for (const auto& labeledSensorInfo : labeledSensorsInfo) 247 { 248 auto existing = std::find_if(oldSensors.begin(), oldSensors.end(), 249 [labeledSensorInfo](auto sensor) { 250 return labeledSensorInfo == 251 sensor->getLabeledSensorInfo(); 252 }); 253 254 if (existing != oldSensors.end()) 255 { 256 newSensors.emplace_back(*existing); 257 oldSensors.erase(existing); 258 continue; 259 } 260 261 const auto& service = labeledSensorInfo.at_label<ts::Service>(); 262 const auto& sensorPath = labeledSensorInfo.at_label<ts::Path>(); 263 const auto& metadata = labeledSensorInfo.at_label<ts::Metadata>(); 264 265 newSensors.emplace_back(sensorCache.makeSensor<Sensor>( 266 service, sensorPath, metadata, bus->get_io_context(), bus)); 267 } 268 269 currentSensors = std::move(newSensors); 270 } 271 272 std::vector<LabeledSensorInfo> 273 TriggerFactory::getLabeledSensorsInfo(boost::asio::yield_context& yield, 274 const SensorsInfo& sensorsInfo) const 275 { 276 if (sensorsInfo.empty()) 277 { 278 return {}; 279 } 280 auto tree = utils::getSubTreeSensors(yield, bus); 281 return parseSensorTree(tree, sensorsInfo); 282 } 283 284 std::vector<LabeledSensorInfo> 285 TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const 286 { 287 if (sensorsInfo.empty()) 288 { 289 return {}; 290 } 291 auto tree = utils::getSubTreeSensors(bus); 292 return parseSensorTree(tree, sensorsInfo); 293 } 294 295 std::vector<LabeledSensorInfo> 296 TriggerFactory::parseSensorTree(const std::vector<utils::SensorTree>& tree, 297 const SensorsInfo& sensorsInfo) 298 { 299 return utils::transform(sensorsInfo, [&tree](const auto& item) { 300 const auto& [sensorPath, metadata] = item; 301 auto found = std::find_if( 302 tree.begin(), tree.end(), 303 [path = sensorPath](const auto& x) { return x.first == path; }); 304 305 if (tree.end() != found) 306 { 307 const auto& [service, ifaces] = found->second.front(); 308 return LabeledSensorInfo(service, sensorPath, metadata); 309 } 310 throw std::runtime_error("Not found"); 311 }); 312 } 313