summaryrefslogtreecommitdiffstats
path: root/src/propertywatchimpl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/propertywatchimpl.hpp')
-rw-r--r--src/propertywatchimpl.hpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/propertywatchimpl.hpp b/src/propertywatchimpl.hpp
new file mode 100644
index 0000000..46799ed
--- /dev/null
+++ b/src/propertywatchimpl.hpp
@@ -0,0 +1,183 @@
+#pragma once
+
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <vector>
+#include "data_types.hpp"
+#include "propertywatch.hpp"
+
+namespace phosphor
+{
+namespace dbus
+{
+namespace monitoring
+{
+
+static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+static constexpr auto MAPPER_INTERFACE =
+ "xyz.openbmc_project.ObjectMapper";
+
+using MappedPropertyIndex =
+ RefKeyMap<const std::string,
+ RefKeyMap<const std::string,
+ RefVector<const std::string>>>;
+
+MappedPropertyIndex convert(const PropertyIndex& index);
+
+template <typename DBusInterfaceType>
+void PropertyWatch<DBusInterfaceType>::start()
+{
+ if (alreadyRan)
+ {
+ return;
+ }
+ else
+ {
+ alreadyRan = true;
+ }
+
+ // The index has a flat layout which is not optimal here. Nest
+ // properties in a map of interface names in a map of object paths.
+ auto mapped = convert(index);
+
+ for (const auto& m : mapped)
+ {
+ const auto& path = m.first.get();
+ const auto& interfaces = m.second;
+
+ // Watch for new interfaces on this path.
+ DBusInterfaceType::addMatch(
+ sdbusplus::bus::match::rules::interfacesAdded(path),
+ [this](auto & msg)
+ // *INDENT-OFF*
+ {
+ this->interfacesAdded(msg);
+ });
+ // *INDENT-ON*
+
+ // Do a query to populate the cache. Start with a mapper query.
+ // The specific services are queried below.
+ const std::vector<std::string> queryInterfaces; // all interfaces
+ auto mapperResp =
+ DBusInterfaceType::template callMethodAndRead<GetObject>(
+ MAPPER_BUSNAME,
+ MAPPER_PATH,
+ MAPPER_INTERFACE,
+ "GetObject",
+ path,
+ queryInterfaces);
+
+ for (const auto& i : interfaces)
+ {
+ const auto& interface = i.first.get();
+
+ // Watch for property changes on this interface.
+ DBusInterfaceType::addMatch(
+ sdbusplus::bus::match::rules::propertiesChanged(
+ path, interface),
+ [this](auto & msg)
+ // *INDENT-OFF*
+ {
+ std::string interface;
+ msg.read(interface);
+ auto path = msg.get_path();
+ this->propertiesChanged(msg, path, interface);
+ });
+ // *INDENT-ON*
+
+ // The mapper response is a busname:[interfaces] map. Look for
+ // each interface in the index and if found, query the service and
+ // populate the cache entries for the interface.
+ for (const auto& mr : mapperResp)
+ {
+ const auto& busName = mr.first;
+ const auto& mapperInterfaces = mr.second;
+ if (mapperInterfaces.end() == std::find(
+ mapperInterfaces.begin(),
+ mapperInterfaces.end(),
+ interface))
+ {
+ // This interface isn't being watched.
+ continue;
+ }
+
+ // Delegate type specific property updates to subclasses.
+ updateProperties(busName, path, interface);
+ }
+ }
+ }
+}
+
+template <typename T, typename DBusInterfaceType>
+void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
+ const std::string& busName,
+ const std::string& path,
+ const std::string& interface)
+{
+ auto properties =
+ DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
+ busName.c_str(),
+ path.c_str(),
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ interface);
+ propertiesChanged(path, interface, properties);
+}
+
+template <typename T, typename DBusInterfaceType>
+void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
+ const std::string& path,
+ const std::string& interface,
+ const PropertiesChanged<T>& properties)
+{
+ // Update the cache for any watched properties.
+ for (const auto& p : properties)
+ {
+ auto key = std::make_tuple(path, interface, p.first);
+ auto item = this->index.find(key);
+ if (item == this->index.end())
+ {
+ // This property isn't being watched.
+ continue;
+ }
+
+ std::get<2>(item->second).get() = p.second.template get<T>();
+ }
+}
+
+template <typename T, typename DBusInterfaceType>
+void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
+ sdbusplus::message::message& msg,
+ const std::string& path,
+ const std::string& interface)
+{
+ PropertiesChanged<T> properties;
+ msg.read(properties);
+ propertiesChanged(path, interface, properties);
+}
+
+template <typename T, typename DBusInterfaceType>
+void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
+ const std::string& path,
+ const InterfacesAdded<T>& interfaces)
+{
+ for (const auto& i : interfaces)
+ {
+ propertiesChanged(path, i.first, i.second);
+ }
+}
+
+template <typename T, typename DBusInterfaceType>
+void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
+ sdbusplus::message::message& msg)
+{
+ sdbusplus::message::object_path path;
+ InterfacesAdded<T> interfaces;
+ msg.read(path, interfaces);
+ interfacesAdded(path, interfaces);
+}
+
+} // namespace monitoring
+} // namespace dbus
+} // namespace phosphor
OpenPOWER on IntegriCloud