1 #pragma once
2
3 #include <systemd/sd-bus.h>
4
5 #include <sdbusplus/bus.hpp>
6 #include <sdbusplus/message.hpp>
7 #include <sdbusplus/slot.hpp>
8
9 #include <functional>
10 #include <memory>
11 #include <string>
12
13 namespace sdbusplus::bus
14 {
15
16 namespace match
17 {
18
19 struct match : private sdbusplus::bus::details::bus_friend
20 {
21 /** @brief Register a signal match.
22 *
23 * @param[in] bus - The bus to register on.
24 * @param[in] match - The match to register.
25 * @param[in] handler - The callback for matches.
26 * @param[in] context - An optional context to pass to the handler.
27 */
28 match(sdbusplus::bus_t& bus, const char* _match,
29 sd_bus_message_handler_t handler, void* context = nullptr);
matchsdbusplus::bus::match::match30 inline match(sdbusplus::bus_t& bus, const std::string& _match,
31 sd_bus_message_handler_t handler, void* context = nullptr) :
32 match(bus, _match.c_str(), handler, context)
33 {}
34
35 /** @brief Register a signal match.
36 *
37 * @param[in] bus - The bus to register on.
38 * @param[in] match - The match to register.
39 * @param[in] callback - The callback for matches.
40 */
41 using callback_t = std::function<void(sdbusplus::message_t&)>;
42 match(sdbusplus::bus_t& bus, const char* _match, callback_t callback);
matchsdbusplus::bus::match::match43 inline match(sdbusplus::bus_t& bus, const std::string& _match,
44 callback_t callback) :
45 match(bus, _match.c_str(), std::move(callback))
46 {}
47
48 private:
49 std::unique_ptr<callback_t> _callback;
50 slot_t _slot;
51 };
52
53 /** Utilities for defining match rules based on the DBus specification */
54 namespace rules
55 {
56
57 using namespace std::string_literals;
58
59 namespace type
60 {
61
signal()62 constexpr auto signal() noexcept
63 {
64 return "type='signal',"s;
65 }
method()66 constexpr auto method() noexcept
67 {
68 return "type='method',"s;
69 }
method_return()70 constexpr auto method_return() noexcept
71 {
72 return "type='method_return',"s;
73 }
error()74 constexpr auto error() noexcept
75 {
76 return "type='error',"s;
77 }
78
79 } // namespace type
80
sender(std::string_view s)81 constexpr auto sender(std::string_view s) noexcept
82 {
83 return "sender='"s.append(s).append("',");
84 }
interface(std::string_view s)85 constexpr auto interface(std::string_view s) noexcept
86 {
87 return "interface='"s.append(s).append("',");
88 }
member(std::string_view s)89 constexpr auto member(std::string_view s) noexcept
90 {
91 return "member='"s.append(s).append("',");
92 }
path(std::string_view s)93 constexpr auto path(std::string_view s) noexcept
94 {
95 return "path='"s.append(s).append("',");
96 }
path_namespace(std::string_view s)97 constexpr auto path_namespace(std::string_view s) noexcept
98 {
99 return "path_namespace='"s.append(s).append("',");
100 }
destination(std::string_view s)101 constexpr auto destination(std::string_view s) noexcept
102 {
103 return "destination='"s.append(s).append("',");
104 }
argN(size_t n,std::string_view s)105 inline auto argN(size_t n, std::string_view s) noexcept
106 {
107 return "arg"s.append(std::to_string(n)).append("='").append(s).append("',");
108 }
argNpath(size_t n,std::string_view s)109 inline auto argNpath(size_t n, std::string_view s) noexcept
110 {
111 return "arg"s.append(std::to_string(n))
112 .append("path='"s)
113 .append(s)
114 .append("',");
115 }
arg0namespace(std::string_view s)116 constexpr auto arg0namespace(std::string_view s) noexcept
117 {
118 return "arg0namespace='"s.append(s).append("',");
119 }
eavesdrop()120 constexpr auto eavesdrop() noexcept
121 {
122 return "eavesdrop='true',"s;
123 }
124
nameOwnerChanged()125 constexpr auto nameOwnerChanged() noexcept
126 {
127 return "type='signal',sender='org.freedesktop.DBus',member='NameOwnerChanged',"s;
128 }
129
interfacesAdded()130 constexpr auto interfacesAdded() noexcept
131 {
132 return "type='signal',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded',"s;
133 }
134
interfacesRemoved()135 constexpr auto interfacesRemoved() noexcept
136 {
137 return "type='signal',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved',"s;
138 }
139
interfacesAdded(std::string_view p)140 constexpr auto interfacesAdded(std::string_view p) noexcept
141 {
142 return interfacesAdded().append(path(p));
143 }
144
interfacesAddedAtPath(std::string_view p)145 constexpr auto interfacesAddedAtPath(std::string_view p) noexcept
146 {
147 return interfacesAdded().append(argNpath(0, p));
148 }
149
interfacesRemoved(std::string_view p)150 constexpr auto interfacesRemoved(std::string_view p) noexcept
151 {
152 return interfacesRemoved().append(path(p));
153 }
154
interfacesRemovedAtPath(std::string_view p)155 constexpr auto interfacesRemovedAtPath(std::string_view p) noexcept
156 {
157 return interfacesRemoved().append(argNpath(0, p));
158 }
159
propertiesChanged(std::string_view p,std::string_view i)160 inline auto propertiesChanged(std::string_view p, std::string_view i) noexcept
161 {
162 return type::signal()
163 .append(path(p))
164 .append(member("PropertiesChanged"s))
165 .append(interface("org.freedesktop.DBus.Properties"s))
166 .append(argN(0, i));
167 }
168
propertiesChangedNamespace(std::string_view p,std::string_view i)169 constexpr auto propertiesChangedNamespace(std::string_view p,
170 std::string_view i) noexcept
171 {
172 return type::signal()
173 .append(path_namespace(p))
174 .append(member("PropertiesChanged"s))
175 .append(interface("org.freedesktop.DBus.Properties"s))
176 .append(arg0namespace(i));
177 }
178 /**
179 * @brief Constructs a NameOwnerChanged match string for a service name
180 *
181 * @param[in] s - Service name
182 *
183 * @return NameOwnerChanged match string for a service name
184 */
nameOwnerChanged(std::string_view s)185 inline auto nameOwnerChanged(std::string_view s) noexcept
186 {
187 return nameOwnerChanged().append(argN(0, s));
188 }
189
190 } // namespace rules
191 } // namespace match
192
193 using match_t = match::match;
194
195 } // namespace sdbusplus::bus
196