xref: /openbmc/phosphor-fan-presence/control/functor.hpp (revision 9d533806250cea56406bdd39e025f0d820c4ed90)
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