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