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
TriggerFactory(std::shared_ptr<sdbusplus::asio::connection> bus,std::shared_ptr<sdbusplus::asio::object_server> objServer,SensorCache & sensorCache)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)), objServer(std::move(objServer)),
20 sensorCache(sensorCache)
21 {}
22
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) const23 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
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) const89 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
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) const124 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
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) const152 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
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) const177 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
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) const200 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
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) const216 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 = utils::transform(triggerActionsIn,
227 [](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
getSensors(const std::vector<LabeledSensorInfo> & labeledSensorsInfo) const244 Sensors TriggerFactory::getSensors(
245 const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
246 {
247 Sensors sensors;
248 updateSensors(sensors, labeledSensorsInfo);
249 return sensors;
250 }
251
updateSensors(Sensors & currentSensors,const std::vector<LabeledSensorInfo> & labeledSensorsInfo) const252 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 == sensor->getLabeledSensorInfo();
264 });
265
266 if (existing != oldSensors.end())
267 {
268 newSensors.emplace_back(*existing);
269 oldSensors.erase(existing);
270 continue;
271 }
272
273 const auto& service = labeledSensorInfo.at_label<ts::Service>();
274 const auto& sensorPath = labeledSensorInfo.at_label<ts::Path>();
275 const auto& metadata = labeledSensorInfo.at_label<ts::Metadata>();
276
277 newSensors.emplace_back(sensorCache.makeSensor<Sensor>(
278 service, sensorPath, metadata, bus->get_io_context(), bus));
279 }
280
281 currentSensors = std::move(newSensors);
282 }
283
284 std::vector<LabeledSensorInfo>
getLabeledSensorsInfo(boost::asio::yield_context & yield,const SensorsInfo & sensorsInfo) const285 TriggerFactory::getLabeledSensorsInfo(boost::asio::yield_context& yield,
286 const SensorsInfo& sensorsInfo) const
287 {
288 if (sensorsInfo.empty())
289 {
290 return {};
291 }
292 auto tree = utils::getSubTreeSensors(yield, bus);
293 return parseSensorTree(tree, sensorsInfo);
294 }
295
296 std::vector<LabeledSensorInfo>
getLabeledSensorsInfo(const SensorsInfo & sensorsInfo) const297 TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const
298 {
299 if (sensorsInfo.empty())
300 {
301 return {};
302 }
303 auto tree = utils::getSubTreeSensors(bus);
304 return parseSensorTree(tree, sensorsInfo);
305 }
306
307 std::vector<LabeledSensorInfo>
parseSensorTree(const std::vector<utils::SensorTree> & tree,const SensorsInfo & sensorsInfo)308 TriggerFactory::parseSensorTree(const std::vector<utils::SensorTree>& tree,
309 const SensorsInfo& sensorsInfo)
310 {
311 return utils::transform(sensorsInfo, [&tree](const auto& item) {
312 const auto& [sensorPath, metadata] = item;
313 auto found = std::find_if(
314 tree.begin(), tree.end(),
315 [path = sensorPath](const auto& x) { return x.first == path; });
316
317 if (tree.end() != found)
318 {
319 const auto& [service, ifaces] = found->second.front();
320 return LabeledSensorInfo(service, sensorPath, metadata);
321 }
322 throw std::runtime_error("Not found");
323 });
324 }
325