blob: 4d477057b2bdd3a86634b35772711f66659f59f8 [file] [log] [blame]
Potin Laie1fa8592025-08-29 15:27:08 +08001#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
14constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
15constexpr const char* HOST_STATE_BUSNAME = "xyz.openbmc_project.State.Host0";
16constexpr const char* HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
17constexpr const char* HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
18constexpr const char* CURRENT_HOST_STATE_PROPERTY = "CurrentHostState";
19
20class 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
55inline HostStateMonitor& HostStateMonitor::getInstance()
56{
57 static sdbusplus::bus_t defaultBus = sdbusplus::bus::new_default();
58 return getInstance(defaultBus);
59}
60
61inline HostStateMonitor& HostStateMonitor::getInstance(sdbusplus::bus_t& bus)
62{
63 static HostStateMonitor instance(bus);
64 return instance;
65}
66
67inline HostStateMonitor::HostStateMonitor(sdbusplus::bus_t& bus) :
68 bus(bus), powerStatusOn(false), hostStateMatch(nullptr)
69{
70 getInitialState();
71}
72
73inline 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
88inline void HostStateMonitor::stopMonitoring()
89{
90 hostStateMatch.reset();
91}
92
93inline 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
122inline 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}