blob: e583238f70895829c6fe2b32636da911fb4c3d7a [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>
Alexander Hansend112f492025-11-12 16:58:08 +01007#include <xyz/openbmc_project/State/Host/common.hpp>
Potin Laie1fa8592025-08-29 15:27:08 +08008
9#include <functional>
10#include <iostream>
11#include <memory>
12#include <string>
13#include <variant>
14
Alexander Hansend112f492025-11-12 16:58:08 +010015using HostState = sdbusplus::common::xyz::openbmc_project::state::Host;
16
Potin Laie1fa8592025-08-29 15:27:08 +080017constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
Potin Laie1fa8592025-08-29 15:27:08 +080018constexpr const char* HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
Potin Laie1fa8592025-08-29 15:27:08 +080019
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,
Alexander Hansend112f492025-11-12 16:58:08 +010081 propertiesChangedNamespace(HOST_STATE_PATH, HostState::interface),
Potin Laie1fa8592025-08-29 15:27:08 +080082 [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
Alexander Hansend112f492025-11-12 16:58:08 +0100102 auto findState =
103 values.find(HostState::property_names::current_host_state);
Potin Laie1fa8592025-08-29 15:27:08 +0800104 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
123inline void HostStateMonitor::getInitialState()
124{
125 try
126 {
Alexander Hansend112f492025-11-12 16:58:08 +0100127 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);
Potin Laie1fa8592025-08-29 15:27:08 +0800132
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}