blob: fdf71e0c6dcb0ff6daa16cae4ebdabd63e9408a9 [file] [log] [blame]
Matt Spinler2a28c932020-02-03 14:23:40 -06001#pragma once
2
3#include "dbus_types.hpp"
4
5#include <sdbusplus/bus/match.hpp>
6
7namespace openpower::pels
8{
9
Matt Spinler2a28c932020-02-03 14:23:40 -060010namespace match_rules = sdbusplus::bus::match::rules;
11
12/**
13 * @class DBusWatcher
14 *
15 * The base class for the PropertyWatcher and InterfaceWatcher classes.
16 */
17class DBusWatcher
18{
19 public:
20 DBusWatcher() = delete;
21 virtual ~DBusWatcher() = default;
22 DBusWatcher(const DBusWatcher&) = default;
23 DBusWatcher& operator=(const DBusWatcher&) = default;
24 DBusWatcher(DBusWatcher&&) = default;
25 DBusWatcher& operator=(DBusWatcher&&) = default;
26
27 /**
28 * @brief Constructor
29 *
30 * @param[in] path - The D-Bus path that will be watched
31 * @param[in] interface - The D-Bus interface that will be watched
32 */
33 DBusWatcher(const std::string& path, const std::string& interface) :
34 _path(path), _interface(interface)
Patrick Williams2544b412022-10-04 08:41:06 -050035 {}
Matt Spinler2a28c932020-02-03 14:23:40 -060036
37 protected:
38 /**
39 * @brief The D-Bus path
40 */
41 std::string _path;
42
43 /**
44 * @brief The D-Bus interface
45 */
46 std::string _interface;
47
48 /**
49 * @brief The match objects for the propertiesChanged and
50 * interfacesAdded signals.
51 */
52 std::vector<sdbusplus::bus::match_t> _matches;
53};
54
55/**
56 * @class PropertyWatcher
57 *
58 * This class allows the user to be kept up to data with a D-Bus
59 * property's value. It does this by calling a user specified function
60 * that is passed the variant that contains the property's value when:
61 *
62 * 1) The property is read when the class is constructed, if
63 * the property is on D-Bus at the time.
64 * 2) The property changes (via a property changed signal).
65 * 3) An interfacesAdded signal is received with that property.
66 *
67 * The DataInterface class is used to access D-Bus, and is a template
68 * to avoid any circular include issues as that class is one of the
69 * users of this one.
70 */
71template <typename DataIface>
72class PropertyWatcher : public DBusWatcher
73{
74 public:
75 PropertyWatcher() = delete;
76 ~PropertyWatcher() = default;
77 PropertyWatcher(const PropertyWatcher&) = delete;
78 PropertyWatcher& operator=(const PropertyWatcher&) = delete;
79 PropertyWatcher(PropertyWatcher&&) = delete;
80 PropertyWatcher& operator=(PropertyWatcher&&) = delete;
81
82 using PropertySetFunc = std::function<void(const DBusValue&)>;
83
84 /**
85 * @brief Constructor
86 *
87 * Reads the property if it is on D-Bus, and sets up the match
88 * objects for the propertiesChanged and interfacesAdded signals.
89 *
90 * @param[in] bus - The sdbusplus bus object
91 * @param[in] path - The D-Bus path of the property
92 * @param[in] interface - The D-Bus interface that contains the property
93 * @param[in] propertyName - The property name
Matt Spinlerc1746f62020-02-21 15:03:52 -060094 * @param[in] service - The D-Bus service to use for the property read.
95 * Can be empty to look it up instead.
Matt Spinler2a28c932020-02-03 14:23:40 -060096 * @param[in] dataIface - The DataInterface object
97 * @param[in] func - The callback used any time the property is read
98 */
Patrick Williams45e83522022-07-22 19:26:52 -050099 PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path,
Matt Spinler2a28c932020-02-03 14:23:40 -0600100 const std::string& interface,
Matt Spinlerc1746f62020-02-21 15:03:52 -0600101 const std::string& propertyName, const std::string& service,
102 const DataIface& dataIface, PropertySetFunc func) :
Matt Spinler2a28c932020-02-03 14:23:40 -0600103 DBusWatcher(path, interface),
104 _name(propertyName), _setFunc(func)
105 {
Matt Spinler2a28c932020-02-03 14:23:40 -0600106 _matches.emplace_back(
107 bus, match_rules::propertiesChanged(_path, _interface),
108 std::bind(std::mem_fn(&PropertyWatcher::propChanged), this,
109 std::placeholders::_1));
110
111 _matches.emplace_back(
112 bus,
113 match_rules::interfacesAdded() + match_rules::argNpath(0, _path),
114 std::bind(std::mem_fn(&PropertyWatcher::interfaceAdded), this,
115 std::placeholders::_1));
Matt Spinler51e927c2020-02-27 10:35:10 -0600116
117 try
118 {
119 read(dataIface, service);
120 }
Patrick Williams45e83522022-07-22 19:26:52 -0500121 catch (const sdbusplus::exception_t& e)
Matt Spinler51e927c2020-02-27 10:35:10 -0600122 {
123 // Path doesn't exist now
124 }
Matt Spinler2a28c932020-02-03 14:23:40 -0600125 }
126
127 /**
Matt Spinlerc1746f62020-02-21 15:03:52 -0600128 * @brief Constructor
129 *
130 * Reads the property if it is on D-Bus, and sets up the match
131 * objects for the propertiesChanged and interfacesAdded signals.
132 *
133 * Unlike the other constructor, this contructor doesn't take the
134 * service to use for the property read so it will look it up with
135 * an ObjectMapper GetObject call.
136 *
137 * @param[in] bus - The sdbusplus bus object
138 * @param[in] path - The D-Bus path of the property
139 * @param[in] interface - The D-Bus interface that contains the property
140 * @param[in] propertyName - The property name
141 * @param[in] dataIface - The DataInterface object
142 * @param[in] func - The callback used any time the property is read
143 */
Patrick Williams45e83522022-07-22 19:26:52 -0500144 PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path,
Matt Spinlerc1746f62020-02-21 15:03:52 -0600145 const std::string& interface,
146 const std::string& propertyName, const DataIface& dataIface,
147 PropertySetFunc func) :
148 PropertyWatcher(bus, path, interface, propertyName, "", dataIface, func)
Patrick Williams2544b412022-10-04 08:41:06 -0500149 {}
Matt Spinlerc1746f62020-02-21 15:03:52 -0600150
151 /**
Matt Spinler2a28c932020-02-03 14:23:40 -0600152 * @brief Reads the property on D-Bus, and calls
153 * the user defined function with the value.
154 *
Matt Spinlerc1746f62020-02-21 15:03:52 -0600155 * If the passed in service is empty, look up the service to use.
156 *
Matt Spinler2a28c932020-02-03 14:23:40 -0600157 * @param[in] dataIface - The DataInterface object
Matt Spinlerc1746f62020-02-21 15:03:52 -0600158 * @param[in] service - The D-Bus service to make the getProperty
159 * call with, if not empty
Matt Spinler2a28c932020-02-03 14:23:40 -0600160 */
Matt Spinlerc1746f62020-02-21 15:03:52 -0600161 void read(const DataIface& dataIface, std::string service)
Matt Spinler2a28c932020-02-03 14:23:40 -0600162 {
Matt Spinlerc1746f62020-02-21 15:03:52 -0600163 if (service.empty())
164 {
165 service = dataIface.getService(_path, _interface);
166 }
167
Matt Spinler2a28c932020-02-03 14:23:40 -0600168 if (!service.empty())
169 {
170 DBusValue value;
171 dataIface.getProperty(service, _path, _interface, _name, value);
172
173 _setFunc(value);
174 }
175 }
176
177 /**
178 * @brief The propertiesChanged callback
179 *
180 * Calls the user defined function with the property value
181 *
182 * @param[in] msg - The sdbusplus message object
183 */
Patrick Williams45e83522022-07-22 19:26:52 -0500184 void propChanged(sdbusplus::message_t& msg)
Matt Spinler2a28c932020-02-03 14:23:40 -0600185 {
186 DBusInterface interface;
187 DBusPropertyMap properties;
188
189 msg.read(interface, properties);
190
191 auto prop = properties.find(_name);
192 if (prop != properties.end())
193 {
194 _setFunc(prop->second);
195 }
196 }
197
198 /**
199 * @brief The interfacesAdded callback
200 *
201 * Calls the user defined function with the property value
202 *
203 * @param[in] msg - The sdbusplus message object
204 */
Patrick Williams45e83522022-07-22 19:26:52 -0500205 void interfaceAdded(sdbusplus::message_t& msg)
Matt Spinler2a28c932020-02-03 14:23:40 -0600206 {
207 sdbusplus::message::object_path path;
208 DBusInterfaceMap interfaces;
209
210 msg.read(path, interfaces);
211
212 auto iface = interfaces.find(_interface);
213 if (iface != interfaces.end())
214 {
215 auto prop = iface->second.find(_name);
216 if (prop != iface->second.end())
217 {
218 _setFunc(prop->second);
219 }
220 }
221 }
222
223 private:
224 /**
225 * @brief The D-Bus property name
226 */
227 std::string _name;
228
229 /**
230 * @brief The function that will be called any time the
231 * property is read.
232 */
233 PropertySetFunc _setFunc;
234};
235
236/**
237 * @class InterfaceWatcher
238 *
239 * This class allows the user to be kept up to data with a D-Bus
240 * interface's properties.. It does this by calling a user specified
241 * function that is passed a map of the D-Bus property names and values
242 * on that interface when:
243 *
244 * 1) The interface is read when the class is constructed, if
245 * the interface is on D-Bus at the time.
246 * 2) The interface has a property that changes (via a property changed signal).
247 * 3) An interfacesAdded signal is received.
248 *
249 * The DataInterface class is used to access D-Bus, and is a template
250 * to avoid any circular include issues as that class is one of the
251 * users of this one.
252 */
253template <typename DataIface>
254class InterfaceWatcher : public DBusWatcher
255{
256 public:
257 InterfaceWatcher() = delete;
258 ~InterfaceWatcher() = default;
259 InterfaceWatcher(const InterfaceWatcher&) = delete;
260 InterfaceWatcher& operator=(const InterfaceWatcher&) = delete;
261 InterfaceWatcher(InterfaceWatcher&&) = delete;
262 InterfaceWatcher& operator=(InterfaceWatcher&&) = delete;
263
264 using InterfaceSetFunc = std::function<void(const DBusPropertyMap&)>;
265
266 /**
267 * @brief Constructor
268 *
269 * Reads all properties on the interface if it is on D-Bus,
270 * and sets up the match objects for the propertiesChanged
271 * and interfacesAdded signals.
272 *
273 * @param[in] bus - The sdbusplus bus object
274 * @param[in] path - The D-Bus path of the property
275 * @param[in] interface - The D-Bus interface that contains the property
276 * @param[in] dataIface - The DataInterface object
277 * @param[in] func - The callback used any time the property is read
278 */
Patrick Williams45e83522022-07-22 19:26:52 -0500279 InterfaceWatcher(sdbusplus::bus_t& bus, const std::string& path,
Matt Spinler2a28c932020-02-03 14:23:40 -0600280 const std::string& interface, const DataIface& dataIface,
281 InterfaceSetFunc func) :
282 DBusWatcher(path, interface),
283 _setFunc(func)
284 {
Matt Spinler2a28c932020-02-03 14:23:40 -0600285 _matches.emplace_back(
286 bus, match_rules::propertiesChanged(_path, _interface),
287 std::bind(std::mem_fn(&InterfaceWatcher::propChanged), this,
288 std::placeholders::_1));
289
290 _matches.emplace_back(
291 bus,
292 match_rules::interfacesAdded() + match_rules::argNpath(0, _path),
293 std::bind(std::mem_fn(&InterfaceWatcher::interfaceAdded), this,
294 std::placeholders::_1));
Matt Spinler51e927c2020-02-27 10:35:10 -0600295
296 try
297 {
298 read(dataIface);
299 }
Patrick Williams45e83522022-07-22 19:26:52 -0500300 catch (const sdbusplus::exception_t& e)
Matt Spinler51e927c2020-02-27 10:35:10 -0600301 {
302 // Path doesn't exist now
303 }
Matt Spinler2a28c932020-02-03 14:23:40 -0600304 }
305
306 /**
307 * @brief Reads the interface's properties on D-Bus, and
308 * calls the the user defined function with the property map.
309 *
310 * @param[in] dataIface - The DataInterface object
311 */
312 void read(const DataIface& dataIface)
313 {
314 auto service = dataIface.getService(_path, _interface);
315 if (!service.empty())
316 {
Patrick Williams2544b412022-10-04 08:41:06 -0500317 auto properties = dataIface.getAllProperties(service, _path,
318 _interface);
Matt Spinler2a28c932020-02-03 14:23:40 -0600319
320 _setFunc(properties);
321 }
322 }
323
324 /**
325 * @brief The propertiesChanged callback
326 *
327 * Calls the user defined function with the property map. Only the
328 * properties that changed will be in the map.
329 *
330 * @param[in] msg - The sdbusplus message object
331 */
Patrick Williams45e83522022-07-22 19:26:52 -0500332 void propChanged(sdbusplus::message_t& msg)
Matt Spinler2a28c932020-02-03 14:23:40 -0600333 {
334 DBusInterface interface;
335 DBusPropertyMap properties;
336
337 msg.read(interface, properties);
338
339 _setFunc(properties);
340 }
341
342 /**
343 * @brief The interfacesAdded callback
344 *
345 * Calls the user defined function with the property map
346 *
347 * @param[in] msg - The sdbusplus message object
348 */
Patrick Williams45e83522022-07-22 19:26:52 -0500349 void interfaceAdded(sdbusplus::message_t& msg)
Matt Spinler2a28c932020-02-03 14:23:40 -0600350 {
351 sdbusplus::message::object_path path;
352 DBusInterfaceMap interfaces;
353
354 msg.read(path, interfaces);
355
356 auto iface = interfaces.find(_interface);
357 if (iface != interfaces.end())
358 {
359 _setFunc(iface->second);
360 }
361 }
362
363 private:
364 /**
365 * @brief The function that will be called any time the
366 * interface is read.
367 */
368 InterfaceSetFunc _setFunc;
369};
370
371} // namespace openpower::pels