regs: Subscribe to InterfacesAdded signals

Subscribe to InterfacesAdded signals to handle not being able to read
the JSON configuration data filename from dbus due to the service
hosting that property is not available yet. The InterfacesAdded signal
is used to get notified when that property becomes available on dbus and
is read upon receiving the signal.

Tested:
    InterfacesAdded signals on an object path is received
    A string is used as the filename when the path, interface, and
property match from the InterfacesAdded signals received

Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
Change-Id: I0256145b9d2772efaae560513c73dc883ecd0a5b
diff --git a/phosphor-regulators/src/manager.cpp b/phosphor-regulators/src/manager.cpp
index 8b8134c..2c44916 100644
--- a/phosphor-regulators/src/manager.cpp
+++ b/phosphor-regulators/src/manager.cpp
@@ -21,6 +21,7 @@
 #include <sdbusplus/bus.hpp>
 
 #include <chrono>
+#include <variant>
 
 namespace phosphor
 {
@@ -32,12 +33,18 @@
 Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
     ManagerObject(bus, objPath, true), bus(bus), eventLoop(event), fileName("")
 {
+    // Subscribe to interfacesAdded signal for filename property
+    std::unique_ptr<sdbusplus::server::match::match> matchPtr =
+        std::make_unique<sdbusplus::server::match::match>(
+            bus,
+            sdbusplus::bus::match::rules::interfacesAdded(sysDbusObj).c_str(),
+            std::bind(std::mem_fn(&Manager::signalHandler), this,
+                      std::placeholders::_1));
+    signals.emplace_back(std::move(matchPtr));
+
     // Attempt to get the filename property from dbus
     setFileName(getFileNameDbus());
 
-    // TODO Subscribe to interfacesAdded signal for filename property
-    // Callback should set fileName and call parse json function
-
     if (!fileName.empty())
     {
         // TODO Load & parse JSON configuration data file
@@ -82,6 +89,42 @@
     // TODO Reload and process the configuration data
 }
 
+void Manager::signalHandler(sdbusplus::message::message& msg)
+{
+    if (msg)
+    {
+        sdbusplus::message::object_path op;
+        msg.read(op);
+        if (static_cast<const std::string&>(op) != sysDbusPath)
+        {
+            // Object path does not match the path
+            return;
+        }
+
+        // An interfacesAdded signal returns a dictionary of interface
+        // names to a dictionary of properties and their values
+        // https://dbus.freedesktop.org/doc/dbus-specification.html
+        std::map<std::string, std::map<std::string, std::variant<std::string>>>
+            intfProp;
+        msg.read(intfProp);
+        auto itIntf = intfProp.find(sysDbusIntf);
+        if (itIntf == intfProp.cend())
+        {
+            // Interface not found on the path
+            return;
+        }
+        auto itProp = itIntf->second.find(sysDbusProp);
+        if (itProp == itIntf->second.cend())
+        {
+            // Property not found on the interface
+            return;
+        }
+        // Set fileName and call parse json function
+        setFileName(std::get<std::string>(itProp->second));
+        // TODO Load & parse JSON configuration data file
+    }
+}
+
 const std::string Manager::getFileNameDbus()
 {
     std::string fileName = "";