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), std::stod(thresholdValue), thresholdName, 166 severity)); 167 } 168 169 void TriggerFactory::makeNumericThreshold( 170 std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, 171 const std::vector<TriggerAction>& triggerActions, 172 const std::shared_ptr<std::vector<std::string>>& reportIds, 173 const Sensors& sensors, 174 const numeric::LabeledThresholdParam& thresholdParam) const 175 { 176 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 177 178 auto type = thresholdParam.at_label<ts::Type>(); 179 auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>()); 180 auto direction = thresholdParam.at_label<ts::Direction>(); 181 auto thresholdValue = double{thresholdParam.at_label<ts::ThresholdValue>()}; 182 183 action::numeric::fillActions(actions, triggerActions, type, thresholdValue, 184 bus->get_io_context(), reportIds); 185 186 thresholds.emplace_back(std::make_shared<NumericThreshold>( 187 bus->get_io_context(), sensors, std::move(actions), dwellTime, 188 direction, thresholdValue, type)); 189 } 190 191 void TriggerFactory::makeOnChangeThreshold( 192 std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds, 193 const std::vector<TriggerAction>& triggerActions, 194 const std::shared_ptr<std::vector<std::string>>& reportIds, 195 const Sensors& sensors) const 196 { 197 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 198 199 action::discrete::onChange::fillActions(actions, triggerActions, 200 bus->get_io_context(), reportIds); 201 202 thresholds.emplace_back( 203 std::make_shared<OnChangeThreshold>(sensors, std::move(actions))); 204 } 205 206 std::unique_ptr<interfaces::Trigger> TriggerFactory::make( 207 const std::string& id, const std::string& name, 208 const std::vector<std::string>& triggerActionsIn, 209 const std::vector<std::string>& reportIdsIn, 210 interfaces::TriggerManager& triggerManager, 211 interfaces::JsonStorage& triggerStorage, 212 const LabeledTriggerThresholdParams& labeledThresholdParams, 213 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 214 { 215 const auto& sensors = getSensors(labeledSensorsInfo); 216 auto triggerActions = 217 utils::transform(triggerActionsIn, [](const auto& triggerActionStr) { 218 return toTriggerAction(triggerActionStr); 219 }); 220 std::vector<std::shared_ptr<interfaces::Threshold>> thresholds; 221 222 auto reportIds = std::make_shared<std::vector<std::string>>(reportIdsIn); 223 224 updateThresholds(thresholds, triggerActions, reportIds, sensors, 225 labeledThresholdParams); 226 227 return std::make_unique<Trigger>( 228 bus->get_io_context(), objServer, id, name, triggerActions, reportIds, 229 std::move(thresholds), triggerManager, triggerStorage, *this, sensors); 230 } 231 232 Sensors TriggerFactory::getSensors( 233 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 234 { 235 Sensors sensors; 236 updateSensors(sensors, labeledSensorsInfo); 237 return sensors; 238 } 239 240 void TriggerFactory::updateSensors( 241 Sensors& currentSensors, 242 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const 243 { 244 Sensors oldSensors = currentSensors; 245 Sensors newSensors; 246 247 for (const auto& labeledSensorInfo : labeledSensorsInfo) 248 { 249 auto existing = std::find_if(oldSensors.begin(), oldSensors.end(), 250 [labeledSensorInfo](auto sensor) { 251 return labeledSensorInfo == 252 sensor->getLabeledSensorInfo(); 253 }); 254 255 if (existing != oldSensors.end()) 256 { 257 newSensors.emplace_back(*existing); 258 oldSensors.erase(existing); 259 continue; 260 } 261 262 const auto& service = labeledSensorInfo.at_label<ts::Service>(); 263 const auto& sensorPath = labeledSensorInfo.at_label<ts::Path>(); 264 const auto& metadata = labeledSensorInfo.at_label<ts::Metadata>(); 265 266 newSensors.emplace_back(sensorCache.makeSensor<Sensor>( 267 service, sensorPath, metadata, bus->get_io_context(), bus)); 268 } 269 270 currentSensors = std::move(newSensors); 271 } 272 273 std::vector<LabeledSensorInfo> 274 TriggerFactory::getLabeledSensorsInfo(boost::asio::yield_context& yield, 275 const SensorsInfo& sensorsInfo) const 276 { 277 if (sensorsInfo.empty()) 278 { 279 return {}; 280 } 281 auto tree = utils::getSubTreeSensors(yield, bus); 282 return parseSensorTree(tree, sensorsInfo); 283 } 284 285 std::vector<LabeledSensorInfo> 286 TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const 287 { 288 if (sensorsInfo.empty()) 289 { 290 return {}; 291 } 292 auto tree = utils::getSubTreeSensors(bus); 293 return parseSensorTree(tree, sensorsInfo); 294 } 295 296 std::vector<LabeledSensorInfo> 297 TriggerFactory::parseSensorTree(const std::vector<utils::SensorTree>& tree, 298 const SensorsInfo& sensorsInfo) 299 { 300 return utils::transform(sensorsInfo, [&tree](const auto& item) { 301 const auto& [sensorPath, metadata] = item; 302 auto found = std::find_if( 303 tree.begin(), tree.end(), 304 [path = sensorPath](const auto& x) { return x.first == path; }); 305 306 if (tree.end() != found) 307 { 308 const auto& [service, ifaces] = found->second.front(); 309 return LabeledSensorInfo(service, sensorPath, metadata); 310 } 311 throw std::runtime_error("Not found"); 312 }); 313 } 314