blob: d0153e48bcf1481ae6ed57e2a99934da33102ee2 [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
111template <typename T, typename DBusInterfaceType>
112void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
113 const std::string& busName,
114 const std::string& path,
115 const std::string& interface)
116{
117 auto properties =
118 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
119 busName.c_str(),
120 path.c_str(),
121 "org.freedesktop.DBus.Properties",
122 "GetAll",
123 interface);
124 propertiesChanged(path, interface, properties);
125}
126
127template <typename T, typename DBusInterfaceType>
128void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
129 const std::string& path,
130 const std::string& interface,
131 const PropertiesChanged<T>& properties)
132{
133 // Update the cache for any watched properties.
134 for (const auto& p : properties)
135 {
136 auto key = std::make_tuple(path, interface, p.first);
137 auto item = this->index.find(key);
138 if (item == this->index.end())
139 {
140 // This property isn't being watched.
141 continue;
142 }
143
144 std::get<2>(item->second).get() = p.second.template get<T>();
Brad Bishopfccdc392017-05-22 21:11:09 -0400145
146 // Invoke callback if present.
147 if (this->alreadyRan && this->callback)
148 {
149 (*this->callback)();
150 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400151 }
152}
153
154template <typename T, typename DBusInterfaceType>
155void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
156 sdbusplus::message::message& msg,
157 const std::string& path,
158 const std::string& interface)
159{
160 PropertiesChanged<T> properties;
161 msg.read(properties);
162 propertiesChanged(path, interface, properties);
163}
164
165template <typename T, typename DBusInterfaceType>
166void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
167 const std::string& path,
168 const InterfacesAdded<T>& interfaces)
169{
170 for (const auto& i : interfaces)
171 {
172 propertiesChanged(path, i.first, i.second);
173 }
174}
175
176template <typename T, typename DBusInterfaceType>
177void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
178 sdbusplus::message::message& msg)
179{
180 sdbusplus::message::object_path path;
181 InterfacesAdded<T> interfaces;
182 msg.read(path, interfaces);
183 interfacesAdded(path, interfaces);
184}
185
186} // namespace monitoring
187} // namespace dbus
188} // namespace phosphor