blob: 67bbaffb100519b2c7a2c8f8b2bfef29093f3620 [file] [log] [blame]
Brad Bishop4b916f12017-05-23 18:06:38 -04001#pragma once
2
3#include <sdbusplus/message.hpp>
4#include <sdbusplus/bus/match.hpp>
5#include <vector>
Brad Bishopfccdc392017-05-22 21:11:09 -04006#include "callback.hpp"
Brad Bishop4b916f12017-05-23 18:06:38 -04007#include "data_types.hpp"
8#include "propertywatch.hpp"
9
10namespace phosphor
11{
12namespace dbus
13{
14namespace monitoring
15{
16
17static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
18static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
19static constexpr auto MAPPER_INTERFACE =
20 "xyz.openbmc_project.ObjectMapper";
21
22using MappedPropertyIndex =
23 RefKeyMap<const std::string,
24 RefKeyMap<const std::string,
25 RefVector<const std::string>>>;
26
27MappedPropertyIndex convert(const PropertyIndex& index);
28
29template <typename DBusInterfaceType>
30void PropertyWatch<DBusInterfaceType>::start()
31{
32 if (alreadyRan)
33 {
34 return;
35 }
Brad Bishop4b916f12017-05-23 18:06:38 -040036
37 // The index has a flat layout which is not optimal here. Nest
38 // properties in a map of interface names in a map of object paths.
39 auto mapped = convert(index);
40
41 for (const auto& m : mapped)
42 {
43 const auto& path = m.first.get();
44 const auto& interfaces = m.second;
45
46 // Watch for new interfaces on this path.
47 DBusInterfaceType::addMatch(
48 sdbusplus::bus::match::rules::interfacesAdded(path),
49 [this](auto & msg)
50 // *INDENT-OFF*
51 {
52 this->interfacesAdded(msg);
53 });
54 // *INDENT-ON*
55
56 // Do a query to populate the cache. Start with a mapper query.
57 // The specific services are queried below.
58 const std::vector<std::string> queryInterfaces; // all interfaces
59 auto mapperResp =
60 DBusInterfaceType::template callMethodAndRead<GetObject>(
61 MAPPER_BUSNAME,
62 MAPPER_PATH,
63 MAPPER_INTERFACE,
64 "GetObject",
65 path,
66 queryInterfaces);
67
68 for (const auto& i : interfaces)
69 {
70 const auto& interface = i.first.get();
71
72 // Watch for property changes on this interface.
73 DBusInterfaceType::addMatch(
74 sdbusplus::bus::match::rules::propertiesChanged(
75 path, interface),
76 [this](auto & msg)
77 // *INDENT-OFF*
78 {
79 std::string interface;
80 msg.read(interface);
81 auto path = msg.get_path();
82 this->propertiesChanged(msg, path, interface);
83 });
84 // *INDENT-ON*
85
86 // The mapper response is a busname:[interfaces] map. Look for
87 // each interface in the index and if found, query the service and
88 // populate the cache entries for the interface.
89 for (const auto& mr : mapperResp)
90 {
91 const auto& busName = mr.first;
92 const auto& mapperInterfaces = mr.second;
93 if (mapperInterfaces.end() == std::find(
94 mapperInterfaces.begin(),
95 mapperInterfaces.end(),
96 interface))
97 {
98 // This interface isn't being watched.
99 continue;
100 }
101
102 // Delegate type specific property updates to subclasses.
103 updateProperties(busName, path, interface);
104 }
105 }
106 }
Brad Bishopc1283ae2017-05-20 21:42:38 -0400107
108 alreadyRan = true;
Brad Bishop4b916f12017-05-23 18:06:38 -0400109}
110
Brad Bishopce4fbe12017-06-06 23:58:09 -0400111template <typename DBusInterfaceType>
112void PropertyWatch<DBusInterfaceType>::callback()
113{
114 // Invoke callback if present.
115 if (this->alreadyRan && this->cb)
116 {
117 (*this->cb)();
118 }
119}
120
Brad Bishop4b916f12017-05-23 18:06:38 -0400121template <typename T, typename DBusInterfaceType>
122void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
123 const std::string& busName,
124 const std::string& path,
125 const std::string& interface)
126{
127 auto properties =
128 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
129 busName.c_str(),
130 path.c_str(),
131 "org.freedesktop.DBus.Properties",
132 "GetAll",
133 interface);
134 propertiesChanged(path, interface, properties);
135}
136
137template <typename T, typename DBusInterfaceType>
138void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
139 const std::string& path,
140 const std::string& interface,
141 const PropertiesChanged<T>& properties)
142{
143 // Update the cache for any watched properties.
144 for (const auto& p : properties)
145 {
146 auto key = std::make_tuple(path, interface, p.first);
147 auto item = this->index.find(key);
148 if (item == this->index.end())
149 {
150 // This property isn't being watched.
151 continue;
152 }
153
154 std::get<2>(item->second).get() = p.second.template get<T>();
Brad Bishopfccdc392017-05-22 21:11:09 -0400155
156 // Invoke callback if present.
Brad Bishopce4fbe12017-06-06 23:58:09 -0400157 this->callback();
Brad Bishop4b916f12017-05-23 18:06:38 -0400158 }
159}
160
161template <typename T, typename DBusInterfaceType>
162void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
163 sdbusplus::message::message& msg,
164 const std::string& path,
165 const std::string& interface)
166{
167 PropertiesChanged<T> properties;
168 msg.read(properties);
169 propertiesChanged(path, interface, properties);
170}
171
172template <typename T, typename DBusInterfaceType>
173void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
174 const std::string& path,
175 const InterfacesAdded<T>& interfaces)
176{
177 for (const auto& i : interfaces)
178 {
179 propertiesChanged(path, i.first, i.second);
180 }
181}
182
183template <typename T, typename DBusInterfaceType>
184void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
185 sdbusplus::message::message& msg)
186{
187 sdbusplus::message::object_path path;
188 InterfacesAdded<T> interfaces;
189 msg.read(path, interfaces);
190 interfacesAdded(path, interfaces);
191}
192
193} // namespace monitoring
194} // namespace dbus
195} // namespace phosphor