blob: 248b3b4f3d8572badb12271a16aed8c933a058fa [file] [log] [blame]
#pragma once
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message.hpp>
#include <sdbusplus/slot.hpp>
#include <functional>
#include <memory>
#include <string>
namespace sdbusplus
{
namespace bus
{
namespace match
{
struct match : private sdbusplus::bus::details::bus_friend
{
/* Define all of the basic class operations:
* Not allowed:
* - Default constructor to avoid nullptrs.
* - Copy operations due to internal unique_ptr.
* Allowed:
* - Move operations.
* - Destructor.
*/
match() = delete;
match(const match&) = delete;
match& operator=(const match&) = delete;
match(match&&) = default;
match& operator=(match&&) = default;
~match() = default;
/** @brief Register a signal match.
*
* @param[in] bus - The bus to register on.
* @param[in] match - The match to register.
* @param[in] handler - The callback for matches.
* @param[in] context - An optional context to pass to the handler.
*/
match(sdbusplus::bus_t& bus, const char* match,
sd_bus_message_handler_t handler, void* context = nullptr)
{
sd_bus_slot* slot = nullptr;
sd_bus_add_match(get_busp(bus), &slot, match, handler, context);
_slot = std::move(slot);
}
match(sdbusplus::bus_t& bus, const std::string& _match,
sd_bus_message_handler_t handler, void* context = nullptr) :
match(bus, _match.c_str(), handler, context)
{}
using callback_t = std::function<void(sdbusplus::message_t&)>;
/** @brief Register a signal match.
*
* @param[in] bus - The bus to register on.
* @param[in] match - The match to register.
* @param[in] callback - The callback for matches.
*/
match(sdbusplus::bus_t& bus, const char* match, callback_t callback) :
_callback(std::make_unique<callback_t>(std::move(callback)))
{
sd_bus_slot* slot = nullptr;
sd_bus_add_match(get_busp(bus), &slot, match, callCallback,
_callback.get());
_slot = std::move(slot);
}
match(sdbusplus::bus_t& bus, const std::string& _match,
callback_t callback) :
match(bus, _match.data(), callback)
{}
private:
slot_t _slot{};
std::unique_ptr<callback_t> _callback = nullptr;
// The callback is 'noexcept' because it is called from C code (sd-bus).
// If it were to throw, this will cause undefined behavior so force noexcept
// and we'll std::terminate instead.
static int callCallback(sd_bus_message* m, void* context,
sd_bus_error* /*e*/) noexcept
{
auto c = static_cast<callback_t*>(context);
message_t message{m};
(*c)(message);
return 0;
}
};
/** Utilities for defining match rules based on the DBus specification */
namespace rules
{
using namespace std::string_literals;
namespace type
{
constexpr auto signal() noexcept
{
return "type='signal',"s;
}
constexpr auto method() noexcept
{
return "type='method',"s;
}
constexpr auto method_return() noexcept
{
return "type='method_return',"s;
}
constexpr auto error() noexcept
{
return "type='error',"s;
}
} // namespace type
constexpr auto sender(std::string_view s) noexcept
{
return "sender='"s.append(s).append("',");
}
constexpr auto interface(std::string_view s) noexcept
{
return "interface='"s.append(s).append("',");
}
constexpr auto member(std::string_view s) noexcept
{
return "member='"s.append(s).append("',");
}
constexpr auto path(std::string_view s) noexcept
{
return "path='"s.append(s).append("',");
}
constexpr auto path_namespace(std::string_view s) noexcept
{
return "path_namespace='"s.append(s).append("',");
}
constexpr auto destination(std::string_view s) noexcept
{
return "destination='"s.append(s).append("',");
}
inline auto argN(size_t n, std::string_view s) noexcept
{
return "arg"s.append(std::to_string(n)).append("='").append(s).append("',");
}
inline auto argNpath(size_t n, std::string_view s) noexcept
{
return "arg"s.append(std::to_string(n))
.append("path='"s)
.append(s)
.append("',");
}
constexpr auto arg0namespace(std::string_view s) noexcept
{
return "arg0namespace='"s.append(s).append("',");
}
constexpr auto eavesdrop() noexcept
{
return "eavesdrop='true',"s;
}
constexpr auto nameOwnerChanged() noexcept
{
return "type='signal',sender='org.freedesktop.DBus',member='NameOwnerChanged',"s;
}
constexpr auto interfacesAdded() noexcept
{
return "type='signal',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded',"s;
}
constexpr auto interfacesRemoved() noexcept
{
return "type='signal',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved',"s;
}
constexpr auto interfacesAdded(std::string_view p) noexcept
{
return interfacesAdded().append(path(p));
}
constexpr auto interfacesRemoved(std::string_view p) noexcept
{
return interfacesRemoved().append(path(p));
}
inline auto propertiesChanged(std::string_view p, std::string_view i) noexcept
{
return type::signal()
.append(path(p))
.append(member("PropertiesChanged"s))
.append(interface("org.freedesktop.DBus.Properties"s))
.append(argN(0, i));
}
constexpr auto propertiesChangedNamespace(std::string_view p,
std::string_view i) noexcept
{
return type::signal()
.append(path_namespace(p))
.append(member("PropertiesChanged"s))
.append(interface("org.freedesktop.DBus.Properties"s))
.append(arg0namespace(i));
}
/**
* @brief Constructs a NameOwnerChanged match string for a service name
*
* @param[in] s - Service name
*
* @return NameOwnerChanged match string for a service name
*/
inline auto nameOwnerChanged(std::string_view s) noexcept
{
return nameOwnerChanged().append(argN(0, s));
}
} // namespace rules
} // namespace match
using match_t = match::match;
} // namespace bus
} // namespace sdbusplus