1 #pragma once
2
3 #include "sdbusplus.hpp"
4 #include "types.hpp"
5 #include "zone.hpp"
6
7 namespace phosphor
8 {
9 namespace fan
10 {
11 namespace control
12 {
13 class Zone;
14
15 using namespace phosphor::fan;
16 using namespace sdbusplus::bus::match;
17
18 /**
19 * @brief Create a zone handler function object
20 *
21 * @param[in] handler - The handler being created
22 *
23 * @return - The created zone handler function object
24 */
25 template <typename T>
make_zoneHandler(T && handler)26 auto make_zoneHandler(T&& handler)
27 {
28 return ZoneHandler(std::forward<T>(handler));
29 }
30
31 /**
32 * @brief Create a trigger function object
33 *
34 * @param[in] trigger - The trigger being created
35 *
36 * @return - The created trigger function object
37 */
38 template <typename T>
make_trigger(T && trigger)39 auto make_trigger(T&& trigger)
40 {
41 return Trigger(std::forward<T>(trigger));
42 }
43
44 /**
45 * @brief Create a handler function object
46 *
47 * @param[in] handler - The handler being created
48 *
49 * @return - The created handler function object
50 */
51 template <typename T, typename U>
make_handler(U && handler)52 auto make_handler(U&& handler)
53 {
54 return T(std::forward<U>(handler));
55 }
56
57 /**
58 * @brief Create an action function object
59 *
60 * @param[in] action - The action being created
61 *
62 * @return - The created action function object
63 */
64 template <typename T>
make_action(T && action)65 auto make_action(T&& action)
66 {
67 return Action(std::forward<T>(action));
68 }
69
70 /**
71 * @struct Properties
72 * @brief A set of match filter functors for Dbus property values. Each
73 * functor provides an associated process for retrieving the value
74 * for a given property and providing it to the given handler function.
75 *
76 * @tparam T - The type of the property value
77 * @tparam U - The type of the handler
78 */
79 template <typename T, typename U>
80 struct Properties
81 {
82 Properties() = delete;
83 ~Properties() = default;
84 Properties(const Properties&) = default;
85 Properties& operator=(const Properties&) = default;
86 Properties(Properties&&) = default;
87 Properties& operator=(Properties&&) = default;
Propertiesphosphor::fan::control::Properties88 explicit Properties(U&& handler) :
89 _path(""), _intf(""), _prop(""), _handler(std::forward<U>(handler))
90 {}
Propertiesphosphor::fan::control::Properties91 Properties(const char* path, const char* intf, const char* prop,
92 U&& handler) :
93 _path(path), _intf(intf), _prop(prop),
94 _handler(std::forward<U>(handler))
95 {}
96
97 /** @brief Run signal handler function
98 *
99 * Extract the property from the PropertiesChanged
100 * message and run the handler function.
101 */
operator ()phosphor::fan::control::Properties102 void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
103 Zone& zone) const
104 {
105 if (msg)
106 {
107 std::string intf;
108 msg.read(intf);
109 if (intf != _intf)
110 {
111 // Interface name does not match on object
112 return;
113 }
114
115 std::map<std::string, PropertyVariantType> props;
116 msg.read(props);
117 auto it = props.find(_prop);
118 if (it == props.cend())
119 {
120 // Property not included in dictionary of properties changed
121 return;
122 }
123
124 // Retrieve the property's value applying any visitors necessary
125 auto value =
126 zone.getPropertyValueVisitor<T>(_intf, _prop, it->second);
127
128 _handler(zone, _path, _intf, _prop, std::forward<T>(value));
129 }
130 else
131 {
132 try
133 {
134 auto val = zone.getPropertyByName<T>(_path, _intf, _prop);
135 _handler(zone, _path, _intf, _prop, std::forward<T>(val));
136 }
137 catch (const sdbusplus::exception_t&)
138 {
139 // Property will not be used unless a property changed
140 // signal message is received for this property.
141 }
142 catch (const util::DBusError&)
143 {
144 // Property will not be used unless a property changed
145 // signal message is received for this property.
146 }
147 }
148 }
149
150 /** @brief Run init handler function
151 *
152 * Get the property from each member object of the group
153 * and run the handler function.
154 */
operator ()phosphor::fan::control::Properties155 void operator()(Zone& zone, const Group& group) const
156 {
157 std::for_each(
158 group.begin(), group.end(),
159 [&zone, handler = std::move(_handler)](const auto& member) {
160 auto path = std::get<pathPos>(member);
161 auto intf = std::get<intfPos>(member);
162 auto prop = std::get<propPos>(member);
163 try
164 {
165 auto val = zone.getPropertyByName<T>(path, intf, prop);
166 handler(zone, path, intf, prop, std::forward<T>(val));
167 }
168 catch (const sdbusplus::exception_t&)
169 {
170 // Property value not sent to handler
171 }
172 catch (const util::DBusError&)
173 {
174 // Property value not sent to handler
175 }
176 });
177 }
178
179 private:
180 const char* _path;
181 const char* _intf;
182 const char* _prop;
183 U _handler;
184 };
185
186 /**
187 * @brief Used to process a Dbus properties changed signal event
188 *
189 * @param[in] path - Object path
190 * @param[in] intf - Object interface
191 * @param[in] prop - Object property
192 * @param[in] handler - Handler function to perform
193 *
194 * @tparam T - The type of the property
195 * @tparam U - The type of the handler
196 */
197 template <typename T, typename U>
propertiesChanged(const char * path,const char * intf,const char * prop,U && handler)198 auto propertiesChanged(const char* path, const char* intf, const char* prop,
199 U&& handler)
200 {
201 return Properties<T, U>(path, intf, prop, std::forward<U>(handler));
202 }
203
204 /**
205 * @brief Used to get the properties of an event's group
206 *
207 * @param[in] handler - Handler function to perform
208 *
209 * @tparam T - The type of all the properties
210 * @tparam U - The type of the handler
211 */
212 template <typename T, typename U>
getProperties(U && handler)213 auto getProperties(U&& handler)
214 {
215 return Properties<T, U>(std::forward<U>(handler));
216 }
217
218 /**
219 * @struct Interfaces Added
220 * @brief A match filter functor for Dbus interfaces added signals
221 *
222 * @tparam T - The type of the property value
223 * @tparam U - The type of the handler
224 */
225 template <typename T, typename U>
226 struct InterfacesAdded
227 {
228 InterfacesAdded() = delete;
229 ~InterfacesAdded() = default;
230 InterfacesAdded(const InterfacesAdded&) = default;
231 InterfacesAdded& operator=(const InterfacesAdded&) = default;
232 InterfacesAdded(InterfacesAdded&&) = default;
233 InterfacesAdded& operator=(InterfacesAdded&&) = default;
InterfacesAddedphosphor::fan::control::InterfacesAdded234 InterfacesAdded(const char* path, const char* intf, const char* prop,
235 U&& handler) :
236 _path(path), _intf(intf), _prop(prop),
237 _handler(std::forward<U>(handler))
238 {}
239
240 /** @brief Run signal handler function
241 *
242 * Extract the property from the InterfacesAdded
243 * message and run the handler function.
244 */
operator ()phosphor::fan::control::InterfacesAdded245 void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
246 Zone& zone) const
247 {
248 if (msg)
249 {
250 sdbusplus::message::object_path op;
251
252 msg.read(op);
253 if (static_cast<const std::string&>(op) != _path)
254 {
255 // Object path does not match this handler's path
256 return;
257 }
258
259 std::map<std::string, std::map<std::string, PropertyVariantType>>
260 intfProp;
261 msg.read(intfProp);
262 auto itIntf = intfProp.find(_intf);
263 if (itIntf == intfProp.cend())
264 {
265 // Interface not found on this handler's path
266 return;
267 }
268 auto itProp = itIntf->second.find(_prop);
269 if (itProp == itIntf->second.cend())
270 {
271 // Property not found on this handler's path
272 return;
273 }
274
275 // Retrieve the property's value applying any visitors necessary
276 auto value =
277 zone.getPropertyValueVisitor<T>(_intf, _prop, itProp->second);
278
279 _handler(zone, _path, _intf, _prop, std::forward<T>(value));
280 }
281 }
282
283 private:
284 const char* _path;
285 const char* _intf;
286 const char* _prop;
287 U _handler;
288 };
289
290 /**
291 * @brief Used to process a Dbus interfaces added signal event
292 *
293 * @param[in] path - Object path
294 * @param[in] intf - Object interface
295 * @param[in] prop - Object property
296 * @param[in] handler - Handler function to perform
297 *
298 * @tparam T - The type of the property
299 * @tparam U - The type of the handler
300 */
301 template <typename T, typename U>
interfacesAdded(const char * path,const char * intf,const char * prop,U && handler)302 auto interfacesAdded(const char* path, const char* intf, const char* prop,
303 U&& handler)
304 {
305 return InterfacesAdded<T, U>(path, intf, prop, std::forward<U>(handler));
306 }
307
308 /**
309 * @struct Interfaces Removed
310 * @brief A match filter functor for Dbus interfaces removed signals
311 *
312 * @tparam U - The type of the handler
313 */
314 template <typename U>
315 struct InterfacesRemoved
316 {
317 InterfacesRemoved() = delete;
318 ~InterfacesRemoved() = default;
319 InterfacesRemoved(const InterfacesRemoved&) = default;
320 InterfacesRemoved& operator=(const InterfacesRemoved&) = default;
321 InterfacesRemoved(InterfacesRemoved&&) = default;
322 InterfacesRemoved& operator=(InterfacesRemoved&&) = default;
InterfacesRemovedphosphor::fan::control::InterfacesRemoved323 InterfacesRemoved(const char* path, const char* intf, U&& handler) :
324 _path(path), _intf(intf), _handler(std::forward<U>(handler))
325 {}
326
327 /** @brief Run signal handler function
328 *
329 * Extract the interfaces from the InterfacesRemoved
330 * message and run the handler function.
331 */
operator ()phosphor::fan::control::InterfacesRemoved332 void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
333 Zone& zone) const
334 {
335 if (msg)
336 {
337 std::vector<std::string> intfs;
338 sdbusplus::message::object_path op;
339
340 msg.read(op);
341 if (static_cast<const std::string&>(op) != _path)
342 {
343 // Object path does not match this handler's path
344 return;
345 }
346
347 msg.read(intfs);
348 auto itIntf = std::find(intfs.begin(), intfs.end(), _intf);
349 if (itIntf == intfs.cend())
350 {
351 // Interface not found on this handler's path
352 return;
353 }
354
355 _handler(zone);
356 }
357 }
358
359 private:
360 const char* _path;
361 const char* _intf;
362 U _handler;
363 };
364
365 /**
366 * @brief Used to process a Dbus interfaces removed signal event
367 *
368 * @param[in] path - Object path
369 * @param[in] intf - Object interface
370 * @param[in] handler - Handler function to perform
371 *
372 * @tparam U - The type of the handler
373 */
374 template <typename U>
interfacesRemoved(const char * path,const char * intf,U && handler)375 auto interfacesRemoved(const char* path, const char* intf, U&& handler)
376 {
377 return InterfacesRemoved<U>(path, intf, std::forward<U>(handler));
378 }
379
380 /**
381 * @struct Name Owner
382 * @brief A functor for Dbus name owner signals and methods
383 *
384 * @tparam U - The type of the handler
385 */
386 template <typename U>
387 struct NameOwner
388 {
389 NameOwner() = delete;
390 ~NameOwner() = default;
391 NameOwner(const NameOwner&) = default;
392 NameOwner& operator=(const NameOwner&) = default;
393 NameOwner(NameOwner&&) = default;
394 NameOwner& operator=(NameOwner&&) = default;
NameOwnerphosphor::fan::control::NameOwner395 explicit NameOwner(U&& handler) : _handler(std::forward<U>(handler)) {}
396
397 /** @brief Run signal handler function
398 *
399 * Extract the name owner from the NameOwnerChanged
400 * message and run the handler function.
401 */
operator ()phosphor::fan::control::NameOwner402 void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
403 Zone& zone) const
404 {
405 if (msg)
406 {
407 std::string name;
408 bool hasOwner = false;
409
410 // Handle NameOwnerChanged signals
411 msg.read(name);
412
413 std::string oldOwn;
414 msg.read(oldOwn);
415
416 std::string newOwn;
417 msg.read(newOwn);
418 if (!newOwn.empty())
419 {
420 hasOwner = true;
421 }
422 _handler(zone, name, hasOwner);
423 }
424 }
425
operator ()phosphor::fan::control::NameOwner426 void operator()(Zone& zone, const Group& group) const
427 {
428 std::string name = "";
429 bool hasOwner = false;
430 std::for_each(
431 group.begin(), group.end(),
432 [&zone, &group, &name, &hasOwner,
433 handler = std::move(_handler)](const auto& member) {
434 auto path = std::get<pathPos>(member);
435 auto intf = std::get<intfPos>(member);
436 try
437 {
438 auto servName = zone.getService(path, intf);
439 if (name != servName)
440 {
441 name = servName;
442 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
443 zone.getBus(), "org.freedesktop.DBus",
444 "/org/freedesktop/DBus", "org.freedesktop.DBus",
445 "NameHasOwner", name);
446 // Update service name owner state list of a group
447 handler(zone, name, hasOwner);
448 }
449 }
450 catch (const util::DBusMethodError& e)
451 {
452 // Failed to get service name owner state
453 name = "";
454 hasOwner = false;
455 }
456 });
457 }
458
459 private:
460 U _handler;
461 };
462
463 /**
464 * @brief Used to process a Dbus name owner changed signal event
465 *
466 * @param[in] handler - Handler function to perform
467 *
468 * @tparam U - The type of the handler
469 *
470 * @return - The NameOwnerChanged signal struct
471 */
472 template <typename U>
nameOwnerChanged(U && handler)473 auto nameOwnerChanged(U&& handler)
474 {
475 return NameOwner<U>(std::forward<U>(handler));
476 }
477
478 /**
479 * @brief Used to process the init of a name owner event
480 *
481 * @param[in] handler - Handler function to perform
482 *
483 * @tparam U - The type of the handler
484 *
485 * @return - The NameOwnerChanged signal struct
486 */
487 template <typename U>
nameHasOwner(U && handler)488 auto nameHasOwner(U&& handler)
489 {
490 return NameOwner<U>(std::forward<U>(handler));
491 }
492
493 } // namespace control
494 } // namespace fan
495 } // namespace phosphor
496