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