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(); 38 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 55 inline HostStateMonitor& HostStateMonitor::getInstance() 56 { 57 static sdbusplus::bus_t defaultBus = sdbusplus::bus::new_default(); 58 return getInstance(defaultBus); 59 } 60 61 inline HostStateMonitor& HostStateMonitor::getInstance(sdbusplus::bus_t& bus) 62 { 63 static HostStateMonitor instance(bus); 64 return instance; 65 } 66 67 inline HostStateMonitor::HostStateMonitor(sdbusplus::bus_t& bus) : 68 bus(bus), powerStatusOn(false), hostStateMatch(nullptr) 69 { 70 getInitialState(); 71 } 72 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 88 inline void HostStateMonitor::stopMonitoring() 89 { 90 hostStateMatch.reset(); 91 } 92 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 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