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