UpdateVirtualSensor uses information from signals

UpdateVirtualSensor uses information obtained from signals to avoid
extensive dbus queries.

Tested:
1:Execute DBus cmd to see if VirtualSensor can correctly obtain the
value of DbusSensor
    busctl tree xyz.openbmc_project.VirtualSensor
    busctl introspect xyz.openbmc_project.VirtualSensor xxx
2:Waiting for the value change of DbusSensor,Check if the value of
the virtual sensor has changed after the dbusSensor changes.

Fixes openbmc/phosphor-virtual-sensor#1

Change-Id: If11f9017b31ce5cf06f910a38c65637c55d74b24
Signed-off-by: Tao Lin <lintao.lc@ieisystem.com>
diff --git a/dbusSensor.cpp b/dbusSensor.cpp
new file mode 100644
index 0000000..f79705b
--- /dev/null
+++ b/dbusSensor.cpp
@@ -0,0 +1,152 @@
+#include "dbusSensor.hpp"
+
+#include "virtualSensor.hpp"
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+
+#include <cmath>
+static constexpr auto sensorIntf =
+    sdbusplus::common::xyz::openbmc_project::sensor::Value::interface;
+
+/** When the Entity Manager removes the sensor, the interfaceRemoveSignal sent
+ * uses the path /xyz/openbmc_project/sensors
+ * */
+static constexpr auto interfacesSensorPath = "/xyz/openbmc_project/sensors";
+
+namespace phosphor::virtual_sensor
+{
+
+DbusSensor::DbusSensor(sdbusplus::bus_t& bus, const std::string& path,
+                       VirtualSensor& virtualSensor) :
+    bus(bus),
+    path(path), virtualSensor(virtualSensor),
+    signalPropChange(
+        bus, sdbusplus::bus::match::rules::propertiesChanged(path, sensorIntf),
+        [this](sdbusplus::message_t& message) {
+    handleDbusSignalPropChange(message);
+}),
+    signalRemove(
+        bus,
+        sdbusplus::bus::match::rules::interfacesRemoved(interfacesSensorPath),
+        [this](sdbusplus::message_t& message) {
+    handleDbusSignalRemove(message);
+})
+{
+    initSensorValue();
+}
+
+double DbusSensor::getSensorValue()
+{
+    return value;
+}
+
+void DbusSensor::initSensorValue()
+{
+    try
+    {
+        // If servName is not empty, reduce one DbusCall
+        if (servName.empty())
+        {
+            value = std::numeric_limits<double>::quiet_NaN();
+            servName = getService(bus, path, sensorIntf);
+        }
+
+        if (!servName.empty())
+        {
+            signalNameOwnerChanged.reset();
+            signalNameOwnerChanged = std::make_unique<sdbusplus::bus::match_t>(
+                bus,
+                sdbusplus::bus::match::rules::nameOwnerChanged() +
+                    sdbusplus::bus::match::rules::arg0namespace(servName),
+                [this](sdbusplus::message_t& message) {
+                handleDbusSignalNameOwnerChanged(message);
+            });
+
+            value = getDbusProperty<double>(bus, servName, path, sensorIntf,
+                                            "Value");
+        }
+    }
+    catch (const std::exception& e)
+    {
+        value = std::numeric_limits<double>::quiet_NaN();
+    }
+
+    return;
+}
+
+void DbusSensor::handleDbusSignalNameOwnerChanged(sdbusplus::message_t& msg)
+{
+    try
+    {
+        auto [name, oldOwner,
+              newOwner] = msg.unpack<std::string, std::string, std::string>();
+
+        if (!oldOwner.empty() && !name.empty())
+        {
+            if (name == servName)
+            {
+                // Connection removed
+
+                value = std::numeric_limits<double>::quiet_NaN();
+                virtualSensor.updateVirtualSensor();
+            }
+        }
+    }
+    catch (const std::exception& e)
+    {
+        lg2::error("Error in dbusSensor NameOwnerChanged: {PATH}  {ERROR}",
+                   "PATH", path, "ERROR", e);
+    }
+}
+
+void DbusSensor::handleDbusSignalPropChange(sdbusplus::message_t& msg)
+{
+    try
+    {
+        using SensorValuePropertiesVariant = sdbusplus::server::xyz::
+            openbmc_project::sensor::Value::PropertiesVariant;
+        auto [msgIfce, msgData] =
+            msg.unpack<std::string,
+                       std::map<std::string, SensorValuePropertiesVariant>>();
+
+        std::string path = msg.get_path();
+
+        if (auto itr = msgData.find("Value"); itr != msgData.end())
+        {
+            value = std::get<double>(itr->second);
+            if (!std::isfinite(value))
+            {
+                value = std::numeric_limits<double>::quiet_NaN();
+            }
+
+            virtualSensor.updateVirtualSensor();
+        }
+    }
+    catch (const std::exception& e)
+    {
+        lg2::error("Error in dbusSensor PropertyChange: {PATH}  {ERROR}",
+                   "PATH", path, "ERROR", e);
+    }
+}
+
+void DbusSensor::handleDbusSignalRemove(sdbusplus::message_t& msg)
+{
+    try
+    {
+        auto objPath = msg.unpack<sdbusplus::message::object_path>();
+
+        if (this->path == objPath)
+        {
+            value = std::numeric_limits<double>::quiet_NaN();
+            virtualSensor.updateVirtualSensor();
+        }
+    }
+    catch (const std::exception& e)
+    {
+        lg2::error("Error in dbusSensor interfaceRemove: {PATH}  {ERROR}",
+                   "PATH", path, "ERROR", e);
+    }
+}
+
+} // namespace phosphor::virtual_sensor