control: Support `member` signal triggers

`member` signals are signals that a dbus object could send out on dbus
that acts as a notification that does not contain any other data. This
adds support to fan control events that can be triggered by this type of
signal on dbus to essentially run a set of actions. The configuration of
this trigger is contained within the JSON configuration of the trigger
on the event and not against the event's group(s).

i.e.)
"triggers": [
  {
    "class": "signal",
    "signal": "member",
    "member":
      {
        "name": "Pressed",
        "path": "/xyz/openbmc_project/Chassis/Buttons/Power0",
        "interface": "xyz.openbmc_project.Chassis.Buttons.Power"
      }
  }
]

Change-Id: Ie7924174333c604fb54c8f18560a890bf6a7c489
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/triggers/handlers.hpp b/control/json/triggers/handlers.hpp
index 1ad4766..f4e7adb 100644
--- a/control/json/triggers/handlers.hpp
+++ b/control/json/triggers/handlers.hpp
@@ -154,6 +154,15 @@
         mgr.setOwner(std::get<Path>(obj), serv, std::get<Intf>(obj), hasOwner);
         return true;
     }
+
+    /**
+     * @brief Processes a dbus member signal, there is nothing associated or
+     * any cache to update when this signal is received
+     */
+    static bool member(message&, const SignalObject&, Manager&)
+    {
+        return true;
+    }
 };
 
 } // namespace phosphor::fan::control::json::trigger::signal
diff --git a/control/json/triggers/signal.cpp b/control/json/triggers/signal.cpp
index fa6d32b..5786049 100644
--- a/control/json/triggers/signal.cpp
+++ b/control/json/triggers/signal.cpp
@@ -214,6 +214,31 @@
     }
 }
 
+void member(Manager* mgr, std::unique_ptr<ActionBase>& action,
+            const json& jsonObj)
+{
+    if (!jsonObj.contains("member") || !jsonObj["member"].contains("name") ||
+        !jsonObj["member"].contains("path") ||
+        !jsonObj["member"].contains("interface"))
+    {
+        log<level::ERR>("Missing required member trigger attributes",
+                        entry("JSON=%s", jsonObj.dump().c_str()));
+        throw std::runtime_error("Missing required member trigger attributes");
+    }
+    const auto match =
+        rules::type::signal() +
+        rules::member(jsonObj["member"]["name"].get<std::string>()) +
+        rules::path(jsonObj["member"]["path"].get<std::string>()) +
+        rules::interface(jsonObj["member"]["interface"].get<std::string>());
+    // No SignalObject required to associate to this signal
+    SignalPkg signalPkg = {Handlers::member, SignalObject(),
+                           SignalActions({action})};
+    // If signal match already exists, then the member signal will be the
+    // same so add action to be run
+    auto isSameSig = [](SignalPkg& pkg) { return true; };
+    subscribe(match, std::move(signalPkg), isSameSig, mgr);
+}
+
 enableTrigger triggerSignal(const json& jsonObj, const std::string& eventName,
                             std::vector<std::unique_ptr<ActionBase>>& actions)
 {
diff --git a/control/json/triggers/signal.hpp b/control/json/triggers/signal.hpp
index 5ec7e2f..2030a5d 100644
--- a/control/json/triggers/signal.hpp
+++ b/control/json/triggers/signal.hpp
@@ -78,6 +78,16 @@
 void nameOwnerChanged(Manager* mgr, std::unique_ptr<ActionBase>& action,
                       const json&);
 
+/**
+ * @brief Subscribes to a dbus member signal
+ *
+ * @param[in] mgr - Pointer to manager of the trigger
+ * @param[in] action - Action to be run when signal is received
+ * @param[in] jsonObj - JSON object for the trigger
+ */
+void member(Manager* mgr, std::unique_ptr<ActionBase>& action,
+            const json& jsonObj);
+
 // Match setup function for signals
 using SignalMatch = std::function<void(
     Manager*, std::unique_ptr<ActionBase>& action, const json&)>;
@@ -87,7 +97,8 @@
     {"properties_changed", propertiesChanged},
     {"interfaces_added", interfacesAdded},
     {"interfaces_removed", interfacesRemoved},
-    {"name_owner_changed", nameOwnerChanged}};
+    {"name_owner_changed", nameOwnerChanged},
+    {"member", member}};
 
 /**
  * @brief Trigger to process an event after a signal is received