Add support for processing signal event triggers

Process signal event triggers' list of conditions on a group and perform
the defined actions.

This re-uses the following struct directly from
phosphor-inventory-manager:
--struct PropertyChangedCondition

Change-Id: I98552f3d168cfcd9f0c1c357289b7000374ae60e
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/src/functor.hpp b/src/functor.hpp
index c2c586e..b3ad9a0 100644
--- a/src/functor.hpp
+++ b/src/functor.hpp
@@ -23,6 +23,59 @@
     return Action(std::forward<T>(action));
 }
 
+template <typename T, typename U>
+struct PropertyChangedCondition
+{
+    PropertyChangedCondition() = delete;
+    ~PropertyChangedCondition() = default;
+    PropertyChangedCondition(const PropertyChangedCondition&) = default;
+    PropertyChangedCondition& operator=(const PropertyChangedCondition&) =
+        default;
+    PropertyChangedCondition(PropertyChangedCondition&&) = default;
+    PropertyChangedCondition& operator=(PropertyChangedCondition&&) =
+        default;
+    PropertyChangedCondition(const char* iface, const char* property,
+                             U&& condition) :
+        _iface(iface),
+        _property(property),
+        _condition(std::forward<U>(condition)) { }
+
+    /** @brief Test a property value.
+     *
+     * Extract the property from the PropertiesChanged
+     * message and run the condition test.
+     */
+    bool operator()(
+        sdbusplus::bus::bus&,
+        sdbusplus::message::message& msg,
+        Monitor&) const
+    {
+        std::map<std::string, sdbusplus::message::variant<T>> properties;
+        const char* iface = nullptr;
+
+        msg.read(iface);
+        if (!iface || strcmp(iface, _iface))
+        {
+            return false;
+        }
+
+        msg.read(properties);
+        auto it = properties.find(_property);
+        if (it == properties.cend())
+        {
+            return false;
+        }
+
+        return _condition(
+                   std::forward<T>(it->second.template get<T>()));
+    }
+
+private:
+    const char* _iface;
+    const char* _property;
+    U _condition;
+};
+
 struct PropertyConditionBase
 {
     PropertyConditionBase() = delete;
@@ -125,6 +178,16 @@
 };
 
 template <typename T, typename U>
+auto propertySignal(const char* iface,
+                    const char* property,
+                    U&& condition)
+{
+    return PropertyChangedCondition<T, U>(iface,
+                                          property,
+                                          std::move(condition));
+}
+
+template <typename T, typename U>
 auto propertyStart(const char* path,
                    const char* iface,
                    const char* property,
diff --git a/src/monitor.cpp b/src/monitor.cpp
index 2864924..aeb1fe5 100644
--- a/src/monitor.cpp
+++ b/src/monitor.cpp
@@ -16,7 +16,26 @@
 Monitor::Monitor(sdbusplus::bus::bus& bus) :
     bus(bus)
 {
+    // Process thru given events that are type 'signal'
+    for (auto& event : events)
+    {
+        for (auto& pEvent : std::get<std::vector<std::shared_ptr<Event>>>(event))
+        {
+            if (pEvent->trigger != Event::Trigger::SIGNAL)
+            {
+                continue;
+            }
 
+            auto signalEvent = static_cast<SignalEvent*>(pEvent.get());
+            eventArgs.emplace_back(std::make_unique<eventArg>(this,
+                                                              signalEvent,
+                                                              &event));
+            matches.emplace_back(bus,
+                                 signalEvent->signature,
+                                 handleSignal,
+                                 eventArgs.back().get());
+        }
+    }
 }
 
 void Monitor::processStart() noexcept
@@ -36,6 +55,19 @@
     }
 }
 
+int Monitor::handleSignal(sd_bus_message* msg,
+                          void* data,
+                          sd_bus_error* err)
+{
+    auto sdbpMsg = sdbusplus::message::message(msg);
+    auto& eventArg = *static_cast<Monitor::eventArg*>(data);
+    std::get<0>(eventArg)->handleEvent(
+        sdbpMsg,
+        static_cast<const SignalEvent&>(*std::get<1>(eventArg)),
+        *std::get<2>(eventArg));
+    return 0;
+}
+
 void Monitor::handleEvent(sdbusplus::message::message& msg,
                           const Event& event,
                           const std::tuple<std::vector<std::shared_ptr<Event>>,
diff --git a/src/monitor.hpp b/src/monitor.hpp
index aca64d8..5256582 100644
--- a/src/monitor.hpp
+++ b/src/monitor.hpp
@@ -30,6 +30,12 @@
                          const std::tuple<std::vector<std::shared_ptr<Event>>,
                                     std::vector<Action>>& eventDef);
 
+        using eventArg = std::tuple<Monitor*,
+                                    const SignalEvent*,
+                                    const std::tuple<
+                                        std::vector<std::shared_ptr<Event>>,
+                                        std::vector<Action>>*>;
+
     private:
         sdbusplus::bus::bus& bus;
 
@@ -37,6 +43,14 @@
             std::tuple<std::vector<std::shared_ptr<Event>>,
                        std::vector<Action>>> events;
 
+        std::vector<std::unique_ptr<eventArg>> eventArgs;
+
+        std::vector<sdbusplus::server::match::match> matches;
+
+        static int handleSignal(sd_bus_message* msg,
+                                void* data,
+                                sd_bus_error* err);
+
 };
 
 } // namespace monitoring