blob: 670caa0643c3025427f0e2c8ee019e460c18c20d [file] [log] [blame]
#pragma once
#include "data_types.hpp"
#include <sdbusplus/bus.hpp>
#include <sdbusplus/bus/match.hpp>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/message.hpp>
#include <string>
struct Loop;
namespace phosphor
{
namespace dbus
{
namespace monitoring
{
/** @class SDBusPlus
* @brief DBus access delegate implementation for sdbusplus.
*/
class SDBusPlus
{
private:
static auto& getWatches()
{
static std::vector<sdbusplus::bus::match_t> watches;
return watches;
}
public:
static auto& getBus()
{
static auto bus = sdbusplus::bus::new_default();
return bus;
}
/** @brief Invoke a method; ignore reply. */
template <typename... Args>
static void callMethodNoReply(const std::string& busName,
const std::string& path,
const std::string& interface,
const std::string& method, Args&&... args)
{
auto reqMsg = getBus().new_method_call(
busName.c_str(), path.c_str(), interface.c_str(), method.c_str());
reqMsg.append(std::forward<Args>(args)...);
getBus().call_noreply(reqMsg);
// TODO: openbmc/openbmc#1719
// invoke these methods async, with a callback
// handler that checks for errors and logs.
}
/** @brief Invoke a method. */
template <typename... Args>
static auto callMethod(const std::string& busName, const std::string& path,
const std::string& interface,
const std::string& method, Args&&... args)
{
auto reqMsg = getBus().new_method_call(
busName.c_str(), path.c_str(), interface.c_str(), method.c_str());
reqMsg.append(std::forward<Args>(args)...);
return getBus().call(reqMsg);
}
/** @brief Invoke a method and read the response. */
template <typename Ret, typename... Args>
static auto callMethodAndRead(const std::string& busName,
const std::string& path,
const std::string& interface,
const std::string& method, Args&&... args)
{
Ret resp;
sdbusplus::message_t respMsg = callMethod<Args...>(
busName, path, interface, method, std::forward<Args>(args)...);
try
{
respMsg.read(resp);
}
catch (const sdbusplus::exception_t& e)
{
// Empty responses are expected sometimes, and the calling
// code is set up to handle it.
}
return resp;
}
/** @brief Register a DBus signal callback. */
static auto addMatch(const std::string& match,
sdbusplus::bus::match_t::callback_t&& callback)
{
getWatches().emplace_back(getBus(), match, std::move(callback));
}
/** @brief Look up the bus name for a path and interface */
static auto getBusName(const std::string& path,
const std::string& interface)
{
std::vector<std::string> interfaces{interface};
std::string name;
try
{
auto object = callMethodAndRead<GetObject>(
MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
path, interfaces);
if (!object.empty())
{
name = object.begin()->first;
}
}
catch (const sdbusplus::exception_t& e)
{
// Empty responses are expected sometimes, and the calling
// code is set up to handle it.
}
return name;
}
friend Loop;
};
} // namespace monitoring
} // namespace dbus
} // namespace phosphor