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