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
8 #include <functional>
9 #include <iostream>
10 #include <memory>
11 #include <string>
12 #include <variant>
13
14 constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
15 constexpr const char* HOST_STATE_BUSNAME = "xyz.openbmc_project.State.Host0";
16 constexpr const char* HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
17 constexpr const char* HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
18 constexpr const char* CURRENT_HOST_STATE_PROPERTY = "CurrentHostState";
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, HOST_STATE_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 = values.find(CURRENT_HOST_STATE_PROPERTY);
103 if (findState != values.end())
104 {
105 const std::string& stateValue =
106 std::get<std::string>(findState->second);
107 bool newPowerStatus = stateValue.ends_with(".Running");
108
109 if (newPowerStatus != powerStatusOn)
110 {
111 powerStatusOn = newPowerStatus;
112 }
113 }
114 }
115 catch (const std::exception& e)
116 {
117 std::cerr << "Failed to handle host state change: " << e.what()
118 << std::endl;
119 }
120 }
121
getInitialState()122 inline void HostStateMonitor::getInitialState()
123 {
124 try
125 {
126 auto method = bus.new_method_call(HOST_STATE_BUSNAME, HOST_STATE_PATH,
127 PROPERTIES_INTERFACE, "Get");
128 method.append(HOST_STATE_INTERFACE, CURRENT_HOST_STATE_PROPERTY);
129
130 auto reply = bus.call(method);
131 std::variant<std::string> currentState;
132 reply.read(currentState);
133
134 const std::string& stateValue = std::get<std::string>(currentState);
135 powerStatusOn = stateValue.ends_with(".Running");
136 }
137 catch (const std::exception& e)
138 {
139 powerStatusOn = false;
140 }
141 }
142