xref: /openbmc/phosphor-pid-control/hoststatemonitor.hpp (revision d112f4938698a1e9d3e13e94e2ea6a74ca355593)
1 #pragma once
2 
3 #include <boost/container/flat_map.hpp>
4 #include <sdbusplus/bus.hpp>
5 #include <sdbusplus/bus/match.hpp>
6 #include <sdbusplus/message.hpp>
7 #include <xyz/openbmc_project/State/Host/common.hpp>
8 
9 #include <functional>
10 #include <iostream>
11 #include <memory>
12 #include <string>
13 #include <variant>
14 
15 using HostState = sdbusplus::common::xyz::openbmc_project::state::Host;
16 
17 constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
18 constexpr const char* HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
19 
20 class HostStateMonitor
21 {
22   public:
23     static HostStateMonitor& getInstance();
24     static HostStateMonitor& getInstance(sdbusplus::bus_t& bus);
25 
26     ~HostStateMonitor() = default;
27 
28     // Delete copy constructor and assignment operator
29     HostStateMonitor(const HostStateMonitor&) = delete;
30     HostStateMonitor& operator=(const HostStateMonitor&) = delete;
31 
32     // Delete move constructor and assignment operator for singleton
33     HostStateMonitor(HostStateMonitor&&) = delete;
34     HostStateMonitor& operator=(HostStateMonitor&&) = delete;
35 
36     void startMonitoring();
37     void stopMonitoring();
isPowerOn() const38     bool isPowerOn() const
39     {
40         return powerStatusOn;
41     }
42 
43   private:
44     explicit HostStateMonitor(sdbusplus::bus_t& bus);
45 
46     void handleStateChange(sdbusplus::message_t& message);
47     void getInitialState();
48 
49     sdbusplus::bus_t& bus;
50     bool powerStatusOn;
51     std::unique_ptr<sdbusplus::bus::match_t> hostStateMatch;
52 };
53 
54 // Implementation
getInstance()55 inline HostStateMonitor& HostStateMonitor::getInstance()
56 {
57     static sdbusplus::bus_t defaultBus = sdbusplus::bus::new_default();
58     return getInstance(defaultBus);
59 }
60 
getInstance(sdbusplus::bus_t & bus)61 inline HostStateMonitor& HostStateMonitor::getInstance(sdbusplus::bus_t& bus)
62 {
63     static HostStateMonitor instance(bus);
64     return instance;
65 }
66 
HostStateMonitor(sdbusplus::bus_t & bus)67 inline HostStateMonitor::HostStateMonitor(sdbusplus::bus_t& bus) :
68     bus(bus), powerStatusOn(false), hostStateMatch(nullptr)
69 {
70     getInitialState();
71 }
72 
startMonitoring()73 inline void HostStateMonitor::startMonitoring()
74 {
75     if (hostStateMatch == nullptr)
76     {
77         using namespace sdbusplus::bus::match::rules;
78 
79         hostStateMatch = std::make_unique<sdbusplus::bus::match_t>(
80             bus,
81             propertiesChangedNamespace(HOST_STATE_PATH, HostState::interface),
82             [this](sdbusplus::message_t& message) {
83                 handleStateChange(message);
84             });
85     }
86 }
87 
stopMonitoring()88 inline void HostStateMonitor::stopMonitoring()
89 {
90     hostStateMatch.reset();
91 }
92 
handleStateChange(sdbusplus::message_t & message)93 inline void HostStateMonitor::handleStateChange(sdbusplus::message_t& message)
94 {
95     std::string objectName;
96     boost::container::flat_map<std::string, std::variant<std::string>> values;
97 
98     try
99     {
100         message.read(objectName, values);
101 
102         auto findState =
103             values.find(HostState::property_names::current_host_state);
104         if (findState != values.end())
105         {
106             const std::string& stateValue =
107                 std::get<std::string>(findState->second);
108             bool newPowerStatus = stateValue.ends_with(".Running");
109 
110             if (newPowerStatus != powerStatusOn)
111             {
112                 powerStatusOn = newPowerStatus;
113             }
114         }
115     }
116     catch (const std::exception& e)
117     {
118         std::cerr << "Failed to handle host state change: " << e.what()
119                   << std::endl;
120     }
121 }
122 
getInitialState()123 inline void HostStateMonitor::getInitialState()
124 {
125     try
126     {
127         auto method =
128             bus.new_method_call("xyz.openbmc_project.State.Host0",
129                                 HOST_STATE_PATH, PROPERTIES_INTERFACE, "Get");
130         method.append(HostState::interface,
131                       HostState::property_names::current_host_state);
132 
133         auto reply = bus.call(method);
134         std::variant<std::string> currentState;
135         reply.read(currentState);
136 
137         const std::string& stateValue = std::get<std::string>(currentState);
138         powerStatusOn = stateValue.ends_with(".Running");
139     }
140     catch (const std::exception& e)
141     {
142         powerStatusOn = false;
143     }
144 }
145