| #pragma once | 
 |  | 
 | #include "dbus_types.hpp" | 
 |  | 
 | #include <sdbusplus/bus/match.hpp> | 
 |  | 
 | namespace openpower::pels | 
 | { | 
 |  | 
 | namespace match_rules = sdbusplus::bus::match::rules; | 
 |  | 
 | /** | 
 |  * @class DBusWatcher | 
 |  * | 
 |  * The base class for the PropertyWatcher and InterfaceWatcher classes. | 
 |  */ | 
 | class DBusWatcher | 
 | { | 
 |   public: | 
 |     DBusWatcher() = delete; | 
 |     virtual ~DBusWatcher() = default; | 
 |     DBusWatcher(const DBusWatcher&) = default; | 
 |     DBusWatcher& operator=(const DBusWatcher&) = default; | 
 |     DBusWatcher(DBusWatcher&&) = default; | 
 |     DBusWatcher& operator=(DBusWatcher&&) = default; | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * @param[in] path - The D-Bus path that will be watched | 
 |      * @param[in] interface - The D-Bus interface that will be watched | 
 |      */ | 
 |     DBusWatcher(const std::string& path, const std::string& interface) : | 
 |         _path(path), _interface(interface) | 
 |     {} | 
 |  | 
 |   protected: | 
 |     /** | 
 |      * @brief The D-Bus path | 
 |      */ | 
 |     std::string _path; | 
 |  | 
 |     /** | 
 |      * @brief The D-Bus interface | 
 |      */ | 
 |     std::string _interface; | 
 |  | 
 |     /** | 
 |      * @brief The match objects for the propertiesChanged and | 
 |      *        interfacesAdded signals. | 
 |      */ | 
 |     std::vector<sdbusplus::bus::match_t> _matches; | 
 | }; | 
 |  | 
 | /** | 
 |  * @class PropertyWatcher | 
 |  * | 
 |  * This class allows the user to be kept up to data with a D-Bus | 
 |  * property's value.  It does this by calling a user specified function | 
 |  * that is passed the variant that contains the property's value when: | 
 |  * | 
 |  * 1) The property is read when the class is constructed, if | 
 |  *    the property is on D-Bus at the time. | 
 |  * 2) The property changes (via a property changed signal). | 
 |  * 3) An interfacesAdded signal is received with that property. | 
 |  * | 
 |  * The DataInterface class is used to access D-Bus, and is a template | 
 |  * to avoid any circular include issues as that class is one of the | 
 |  * users of this one. | 
 |  */ | 
 | template <typename DataIface> | 
 | class PropertyWatcher : public DBusWatcher | 
 | { | 
 |   public: | 
 |     PropertyWatcher() = delete; | 
 |     ~PropertyWatcher() = default; | 
 |     PropertyWatcher(const PropertyWatcher&) = delete; | 
 |     PropertyWatcher& operator=(const PropertyWatcher&) = delete; | 
 |     PropertyWatcher(PropertyWatcher&&) = delete; | 
 |     PropertyWatcher& operator=(PropertyWatcher&&) = delete; | 
 |  | 
 |     using PropertySetFunc = std::function<void(const DBusValue&)>; | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * Reads the property if it is on D-Bus, and sets up the match | 
 |      * objects for the propertiesChanged and interfacesAdded signals. | 
 |      * | 
 |      * @param[in] bus - The sdbusplus bus object | 
 |      * @param[in] path - The D-Bus path of the property | 
 |      * @param[in] interface - The D-Bus interface that contains the property | 
 |      * @param[in] propertyName - The property name | 
 |      * @param[in] service - The D-Bus service to use for the property read. | 
 |      *                      Can be empty to look it up instead. | 
 |      * @param[in] dataIface - The DataInterface object | 
 |      * @param[in] func - The callback used any time the property is read | 
 |      */ | 
 |     PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path, | 
 |                     const std::string& interface, | 
 |                     const std::string& propertyName, const std::string& service, | 
 |                     const DataIface& dataIface, PropertySetFunc func) : | 
 |         DBusWatcher(path, interface), | 
 |         _name(propertyName), _setFunc(func) | 
 |     { | 
 |         _matches.emplace_back( | 
 |             bus, match_rules::propertiesChanged(_path, _interface), | 
 |             std::bind(std::mem_fn(&PropertyWatcher::propChanged), this, | 
 |                       std::placeholders::_1)); | 
 |  | 
 |         _matches.emplace_back( | 
 |             bus, | 
 |             match_rules::interfacesAdded() + match_rules::argNpath(0, _path), | 
 |             std::bind(std::mem_fn(&PropertyWatcher::interfaceAdded), this, | 
 |                       std::placeholders::_1)); | 
 |  | 
 |         try | 
 |         { | 
 |             read(dataIface, service); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             // Path doesn't exist now | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * Reads the property if it is on D-Bus, and sets up the match | 
 |      * objects for the propertiesChanged and interfacesAdded signals. | 
 |      * | 
 |      * Unlike the other constructor, this contructor doesn't take the | 
 |      * service to use for the property read so it will look it up with | 
 |      * an ObjectMapper GetObject call. | 
 |      * | 
 |      * @param[in] bus - The sdbusplus bus object | 
 |      * @param[in] path - The D-Bus path of the property | 
 |      * @param[in] interface - The D-Bus interface that contains the property | 
 |      * @param[in] propertyName - The property name | 
 |      * @param[in] dataIface - The DataInterface object | 
 |      * @param[in] func - The callback used any time the property is read | 
 |      */ | 
 |     PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path, | 
 |                     const std::string& interface, | 
 |                     const std::string& propertyName, const DataIface& dataIface, | 
 |                     PropertySetFunc func) : | 
 |         PropertyWatcher(bus, path, interface, propertyName, "", dataIface, func) | 
 |     {} | 
 |  | 
 |     /** | 
 |      * @brief Reads the property on D-Bus, and calls | 
 |      *        the user defined function with the value. | 
 |      * | 
 |      * If the passed in service is empty, look up the service to use. | 
 |      * | 
 |      * @param[in] dataIface - The DataInterface object | 
 |      * @param[in] service - The D-Bus service to make the getProperty | 
 |      *                      call with, if not empty | 
 |      */ | 
 |     void read(const DataIface& dataIface, std::string service) | 
 |     { | 
 |         if (service.empty()) | 
 |         { | 
 |             service = dataIface.getService(_path, _interface); | 
 |         } | 
 |  | 
 |         if (!service.empty()) | 
 |         { | 
 |             DBusValue value; | 
 |             dataIface.getProperty(service, _path, _interface, _name, value); | 
 |  | 
 |             _setFunc(value); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief The propertiesChanged callback | 
 |      * | 
 |      * Calls the user defined function with the property value | 
 |      * | 
 |      * @param[in] msg - The sdbusplus message object | 
 |      */ | 
 |     void propChanged(sdbusplus::message_t& msg) | 
 |     { | 
 |         DBusInterface interface; | 
 |         DBusPropertyMap properties; | 
 |  | 
 |         msg.read(interface, properties); | 
 |  | 
 |         auto prop = properties.find(_name); | 
 |         if (prop != properties.end()) | 
 |         { | 
 |             _setFunc(prop->second); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief The interfacesAdded callback | 
 |      * | 
 |      * Calls the user defined function with the property value | 
 |      * | 
 |      * @param[in] msg - The sdbusplus message object | 
 |      */ | 
 |     void interfaceAdded(sdbusplus::message_t& msg) | 
 |     { | 
 |         sdbusplus::message::object_path path; | 
 |         DBusInterfaceMap interfaces; | 
 |  | 
 |         msg.read(path, interfaces); | 
 |  | 
 |         auto iface = interfaces.find(_interface); | 
 |         if (iface != interfaces.end()) | 
 |         { | 
 |             auto prop = iface->second.find(_name); | 
 |             if (prop != iface->second.end()) | 
 |             { | 
 |                 _setFunc(prop->second); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |   private: | 
 |     /** | 
 |      * @brief The D-Bus property name | 
 |      */ | 
 |     std::string _name; | 
 |  | 
 |     /** | 
 |      * @brief The function that will be called any time the | 
 |      *        property is read. | 
 |      */ | 
 |     PropertySetFunc _setFunc; | 
 | }; | 
 |  | 
 | /** | 
 |  * @class InterfaceWatcher | 
 |  * | 
 |  * This class allows the user to be kept up to data with a D-Bus | 
 |  * interface's properties..  It does this by calling a user specified | 
 |  * function that is passed a map of the D-Bus property names and values | 
 |  * on that interface when: | 
 |  * | 
 |  * 1) The interface is read when the class is constructed, if | 
 |  *    the interface is on D-Bus at the time. | 
 |  * 2) The interface has a property that changes (via a property changed signal). | 
 |  * 3) An interfacesAdded signal is received. | 
 |  * | 
 |  * The DataInterface class is used to access D-Bus, and is a template | 
 |  * to avoid any circular include issues as that class is one of the | 
 |  * users of this one. | 
 |  */ | 
 | template <typename DataIface> | 
 | class InterfaceWatcher : public DBusWatcher | 
 | { | 
 |   public: | 
 |     InterfaceWatcher() = delete; | 
 |     ~InterfaceWatcher() = default; | 
 |     InterfaceWatcher(const InterfaceWatcher&) = delete; | 
 |     InterfaceWatcher& operator=(const InterfaceWatcher&) = delete; | 
 |     InterfaceWatcher(InterfaceWatcher&&) = delete; | 
 |     InterfaceWatcher& operator=(InterfaceWatcher&&) = delete; | 
 |  | 
 |     using InterfaceSetFunc = std::function<void(const DBusPropertyMap&)>; | 
 |  | 
 |     /** | 
 |      * @brief Constructor | 
 |      * | 
 |      * Reads all properties on the interface if it is on D-Bus, | 
 |      * and sets up the match objects for the propertiesChanged | 
 |      * and interfacesAdded signals. | 
 |      * | 
 |      * @param[in] bus - The sdbusplus bus object | 
 |      * @param[in] path - The D-Bus path of the property | 
 |      * @param[in] interface - The D-Bus interface that contains the property | 
 |      * @param[in] dataIface - The DataInterface object | 
 |      * @param[in] func - The callback used any time the property is read | 
 |      */ | 
 |     InterfaceWatcher(sdbusplus::bus_t& bus, const std::string& path, | 
 |                      const std::string& interface, const DataIface& dataIface, | 
 |                      InterfaceSetFunc func) : | 
 |         DBusWatcher(path, interface), | 
 |         _setFunc(func) | 
 |     { | 
 |         _matches.emplace_back( | 
 |             bus, match_rules::propertiesChanged(_path, _interface), | 
 |             std::bind(std::mem_fn(&InterfaceWatcher::propChanged), this, | 
 |                       std::placeholders::_1)); | 
 |  | 
 |         _matches.emplace_back( | 
 |             bus, | 
 |             match_rules::interfacesAdded() + match_rules::argNpath(0, _path), | 
 |             std::bind(std::mem_fn(&InterfaceWatcher::interfaceAdded), this, | 
 |                       std::placeholders::_1)); | 
 |  | 
 |         try | 
 |         { | 
 |             read(dataIface); | 
 |         } | 
 |         catch (const sdbusplus::exception_t& e) | 
 |         { | 
 |             // Path doesn't exist now | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief Reads the interface's properties on D-Bus, and | 
 |      * calls the the user defined function with the property map. | 
 |      * | 
 |      * @param[in] dataIface - The DataInterface object | 
 |      */ | 
 |     void read(const DataIface& dataIface) | 
 |     { | 
 |         auto service = dataIface.getService(_path, _interface); | 
 |         if (!service.empty()) | 
 |         { | 
 |             auto properties = dataIface.getAllProperties(service, _path, | 
 |                                                          _interface); | 
 |  | 
 |             _setFunc(properties); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief The propertiesChanged callback | 
 |      * | 
 |      * Calls the user defined function with the property map.  Only the | 
 |      * properties that changed will be in the map. | 
 |      * | 
 |      * @param[in] msg - The sdbusplus message object | 
 |      */ | 
 |     void propChanged(sdbusplus::message_t& msg) | 
 |     { | 
 |         DBusInterface interface; | 
 |         DBusPropertyMap properties; | 
 |  | 
 |         msg.read(interface, properties); | 
 |  | 
 |         _setFunc(properties); | 
 |     } | 
 |  | 
 |     /** | 
 |      * @brief The interfacesAdded callback | 
 |      * | 
 |      * Calls the user defined function with the property map | 
 |      * | 
 |      * @param[in] msg - The sdbusplus message object | 
 |      */ | 
 |     void interfaceAdded(sdbusplus::message_t& msg) | 
 |     { | 
 |         sdbusplus::message::object_path path; | 
 |         DBusInterfaceMap interfaces; | 
 |  | 
 |         msg.read(path, interfaces); | 
 |  | 
 |         auto iface = interfaces.find(_interface); | 
 |         if (iface != interfaces.end()) | 
 |         { | 
 |             _setFunc(iface->second); | 
 |         } | 
 |     } | 
 |  | 
 |   private: | 
 |     /** | 
 |      * @brief The function that will be called any time the | 
 |      *        interface is read. | 
 |      */ | 
 |     InterfaceSetFunc _setFunc; | 
 | }; | 
 |  | 
 | } // namespace openpower::pels |