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