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