blob: 7948802fffcd29f08dc320889730c549a62a1514 [file] [log] [blame]
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024. All rights
* reserved. SPDX-License-Identifier: Apache-2.0
*/
#include "config_provider.hpp"
#include <boost/container/flat_map.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/async/match.hpp>
#include <sdbusplus/bus/match.hpp>
#include <xyz/openbmc_project/ObjectMapper/client.hpp>
#include <ranges>
#include <string>
PHOSPHOR_LOG2_USING;
using VariantType =
std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
using ConfigMap = boost::container::flat_map<std::string, VariantType>;
using ConfigData = boost::container::flat_map<std::string, ConfigMap>;
namespace gpio_presence
{
ConfigProvider::ConfigProvider(sdbusplus::async::context& ctx,
const std::string& interface) :
interface(interface), ctx(ctx)
{}
auto ConfigProvider::initialize(AddedCallback addConfig,
RemovedCallback removeConfig)
-> sdbusplus::async::task<void>
{
ctx.spawn(handleInterfacesAdded(addConfig));
ctx.spawn(handleInterfacesRemoved(removeConfig));
co_await getConfig(addConfig);
}
auto ConfigProvider::getConfig(AddedCallback addConfig)
-> sdbusplus::async::task<void>
{
auto client = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>(ctx)
.service("xyz.openbmc_project.ObjectMapper")
.path("/xyz/openbmc_project/object_mapper");
debug("calling 'GetSubTree' to find instances of {INTF}", "INTF",
interface);
using SubTreeType =
std::map<std::string, std::map<std::string, std::vector<std::string>>>;
SubTreeType res = {};
try
{
std::vector<std::string> interfaces = {interface};
res = co_await client.get_sub_tree("/xyz/openbmc_project/inventory", 0,
interfaces);
}
catch (std::exception& e)
{
error("Failed GetSubTree call for configuration interface: {ERR}",
"ERR", e);
}
if (res.empty())
{
co_return;
}
// call the user callback for all the device that is already available
for (auto& [path, serviceInterfaceMap] : res)
{
for (const auto& service :
std::ranges::views::keys(serviceInterfaceMap))
{
debug("found configuration interface at {SERVICE} {PATH} {INTF}",
"SERVICE", service, "PATH", path, "INTF", interface);
addConfig(path);
}
}
}
namespace rules_intf = sdbusplus::bus::match::rules;
const auto senderRule = rules_intf::sender("xyz.openbmc_project.EntityManager");
auto ConfigProvider::handleInterfacesAdded(AddedCallback addConfig)
-> sdbusplus::async::task<void>
{
debug("setting up dbus match for interfaces added");
sdbusplus::async::match addedMatch(
ctx, rules_intf::interfacesAdded() + senderRule);
while (!ctx.stop_requested())
{
auto [objPath, intfMap] =
co_await addedMatch
.next<sdbusplus::message::object_path, ConfigData>();
debug("Detected interface added on {OBJPATH}", "OBJPATH", objPath);
if (!std::ranges::contains(std::views::keys(intfMap), interface))
{
continue;
}
try
{
addConfig(objPath);
}
catch (std::exception& e)
{
error("Incomplete or invalid config found: {ERR}", "ERR", e);
}
}
};
auto ConfigProvider::handleInterfacesRemoved(RemovedCallback removeConfig)
-> sdbusplus::async::task<void>
{
debug("setting up dbus match for interfaces removed");
sdbusplus::async::match removedMatch(
ctx, rules_intf::interfacesRemoved() + senderRule);
while (!ctx.stop_requested())
{
auto [objectPath, interfaces] =
co_await removedMatch.next<sdbusplus::message::object_path,
std::vector<std::string>>();
if (!std::ranges::contains(interfaces, interface))
{
continue;
}
debug("Detected interface {INTF} removed on {OBJPATH}", "INTF",
interface, "OBJPATH", objectPath);
removeConfig(objectPath);
}
};
} // namespace gpio_presence