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