1 #pragma once 2 3 #include <utility> 4 #include <memory> 5 #include <functional> 6 #include <sdbusplus/message.hpp> 7 #include "utils.hpp" 8 9 namespace phosphor 10 { 11 namespace inventory 12 { 13 namespace manager 14 { 15 16 class Manager; 17 using Filter = std::function < 18 bool (sdbusplus::bus::bus&, sdbusplus::message::message&, Manager&) >; 19 20 /** @struct Event 21 * @brief Event object interface. 22 * 23 * The event base is an assocation of an event type 24 * and an array of filter callbacks. 25 */ 26 struct Event : public std::vector<Filter> 27 { 28 enum class Type 29 { 30 DBUS_SIGNAL, 31 STARTUP, 32 }; 33 34 virtual ~Event() = default; 35 Event(const Event&) = delete; 36 Event& operator=(const Event&) = delete; 37 Event(Event&&) = default; 38 Event& operator=(Event&&) = default; 39 40 /** @brief Event constructor. 41 * 42 * @param[in] filters - An array of filter callbacks. 43 * @param[in] t - The event type. 44 */ 45 explicit Event( 46 const std::vector<Filter>& filters, Type t = Type::STARTUP) : 47 std::vector<Filter>(filters), 48 type(t) {} 49 50 /** @brief event class enumeration. */ 51 Type type; 52 }; 53 54 using StartupEvent = Event; 55 56 using EventBasePtr = std::shared_ptr<Event>; 57 58 /** @struct DbusSignal 59 * @brief DBus signal event. 60 * 61 * DBus signal events are an association of a match signature 62 * and filtering function object. 63 */ 64 struct DbusSignal final : public Event 65 { 66 ~DbusSignal() = default; 67 DbusSignal(const DbusSignal&) = delete; 68 DbusSignal& operator=(const DbusSignal&) = delete; 69 DbusSignal(DbusSignal&&) = default; 70 DbusSignal& operator=(DbusSignal&&) = default; 71 72 /** @brief Import from signature and filter constructor. 73 * 74 * @param[in] sig - The DBus match signature. 75 * @param[in] filter - An array of DBus signal 76 * match callback filtering functions. 77 */ 78 DbusSignal(const char* sig, const std::vector<Filter>& filters) : 79 Event(filters, Type::DBUS_SIGNAL), 80 signature(sig) {} 81 82 const char* signature; 83 }; 84 85 /** @brief make_filter 86 * 87 * Adapt a filter function object. 88 * 89 * @param[in] filter - The filter being adapted. 90 * @returns - The adapted filter. 91 * 92 * @tparam T - The type of the filter being adapted. 93 */ 94 template <typename T> 95 auto make_filter(T&& filter) 96 { 97 return Filter(std::forward<T>(filter)); 98 } 99 100 namespace filters 101 { 102 namespace property_condition 103 { 104 105 /** @struct PropertyChangedCondition 106 * @brief Match filter functor that tests a property value. 107 * 108 * @tparam T - The type of the property being tested. 109 * @tparam U - The type of the condition checking functor. 110 */ 111 template <typename T, typename U> 112 struct PropertyChangedCondition 113 { 114 PropertyChangedCondition() = delete; 115 ~PropertyChangedCondition() = default; 116 PropertyChangedCondition(const PropertyChangedCondition&) = default; 117 PropertyChangedCondition& operator=(const PropertyChangedCondition&) = default; 118 PropertyChangedCondition(PropertyChangedCondition&&) = default; 119 PropertyChangedCondition& operator=(PropertyChangedCondition&&) = default; 120 PropertyChangedCondition(const char* iface, const char* property, 121 U&& condition) : 122 _iface(iface), 123 _property(property), 124 _condition(std::forward<U>(condition)) { } 125 126 /** @brief Test a property value. 127 * 128 * Extract the property from the PropertiesChanged 129 * message and run the condition test. 130 */ 131 bool operator()( 132 sdbusplus::bus::bus&, 133 sdbusplus::message::message& msg, 134 Manager&) const 135 { 136 std::map < 137 std::string, 138 sdbusplus::message::variant<T >> properties; 139 const char* iface = nullptr; 140 141 msg.read(iface); 142 if (!iface || strcmp(iface, _iface)) 143 { 144 return false; 145 } 146 147 msg.read(properties); 148 auto it = properties.find(_property); 149 if (it == properties.cend()) 150 { 151 return false; 152 } 153 154 return _condition( 155 std::forward<T>(it->second.template get<T>())); 156 } 157 158 private: 159 const char* _iface; 160 const char* _property; 161 U _condition; 162 }; 163 164 /** @struct PropertyConditionBase 165 * @brief Match filter functor that tests a property value. 166 * 167 * Base class for PropertyCondition - factored out code that 168 * doesn't need to be templated. 169 */ 170 struct PropertyConditionBase 171 { 172 PropertyConditionBase() = delete; 173 virtual ~PropertyConditionBase() = default; 174 PropertyConditionBase(const PropertyConditionBase&) = default; 175 PropertyConditionBase& operator=(const PropertyConditionBase&) = default; 176 PropertyConditionBase(PropertyConditionBase&&) = default; 177 PropertyConditionBase& operator=(PropertyConditionBase&&) = default; 178 179 /** @brief Constructor 180 * 181 * The service argument can be nullptr. If something 182 * else is provided the function will call the the 183 * service directly. If omitted, the function will 184 * look up the service in the ObjectMapper. 185 * 186 * @param path - The path of the object containing 187 * the property to be tested. 188 * @param iface - The interface hosting the property 189 * to be tested. 190 * @param property - The property to be tested. 191 * @param service - The DBus service hosting the object. 192 */ 193 PropertyConditionBase( 194 const char* path, 195 const char* iface, 196 const char* property, 197 const char* service) : 198 _path(path), 199 _iface(iface), 200 _property(property), 201 _service(service) {} 202 203 /** @brief Forward comparison to type specific implementation. */ 204 virtual bool eval(sdbusplus::message::message&) const = 0; 205 206 /** @brief Test a property value. 207 * 208 * Make a DBus call and test the value of any property. 209 */ 210 bool operator()( 211 sdbusplus::bus::bus&, 212 sdbusplus::message::message&, 213 Manager&) const; 214 215 private: 216 std::string _path; 217 std::string _iface; 218 std::string _property; 219 const char* _service; 220 }; 221 222 /** @struct PropertyCondition 223 * @brief Match filter functor that tests a property value. 224 * 225 * @tparam T - The type of the property being tested. 226 * @tparam U - The type of the condition checking functor. 227 */ 228 template <typename T, typename U> 229 struct PropertyCondition final : public PropertyConditionBase 230 { 231 PropertyCondition() = delete; 232 ~PropertyCondition() = default; 233 PropertyCondition(const PropertyCondition&) = default; 234 PropertyCondition& operator=(const PropertyCondition&) = default; 235 PropertyCondition(PropertyCondition&&) = default; 236 PropertyCondition& operator=(PropertyCondition&&) = default; 237 238 /** @brief Constructor 239 * 240 * The service argument can be nullptr. If something 241 * else is provided the function will call the the 242 * service directly. If omitted, the function will 243 * look up the service in the ObjectMapper. 244 * 245 * @param path - The path of the object containing 246 * the property to be tested. 247 * @param iface - The interface hosting the property 248 * to be tested. 249 * @param property - The property to be tested. 250 * @param condition - The test to run on the property. 251 * @param service - The DBus service hosting the object. 252 */ 253 PropertyCondition( 254 const char* path, 255 const char* iface, 256 const char* property, 257 U&& condition, 258 const char* service) : 259 PropertyConditionBase(path, iface, property, service), 260 _condition(std::forward<decltype(condition)>(condition)) {} 261 262 /** @brief Test a property value. 263 * 264 * Make a DBus call and test the value of any property. 265 */ 266 bool eval(sdbusplus::message::message& msg) const override 267 { 268 sdbusplus::message::variant<T> value; 269 msg.read(value); 270 return _condition( 271 std::forward<T>(value.template get<T>())); 272 } 273 274 private: 275 U _condition; 276 }; 277 278 } // namespace property_condition 279 280 /** @brief Implicit type deduction for constructing PropertyChangedCondition. */ 281 template <typename T> 282 auto propertyChangedTo( 283 const char* iface, 284 const char* property, 285 T&& val) 286 { 287 auto condition = [val = std::forward<T>(val)](T && arg) 288 { 289 return arg == val; 290 }; 291 using U = decltype(condition); 292 return property_condition::PropertyChangedCondition<T, U>( 293 iface, property, std::move(condition)); 294 } 295 296 /** @brief Implicit type deduction for constructing PropertyCondition. */ 297 template <typename T> 298 auto propertyIs( 299 const char* path, 300 const char* iface, 301 const char* property, 302 T&& val, 303 const char* service = nullptr) 304 { 305 auto condition = [val = std::forward<T>(val)](T && arg) 306 { 307 return arg == val; 308 }; 309 using U = decltype(condition); 310 return property_condition::PropertyCondition<T, U>( 311 path, iface, property, std::move(condition), service); 312 } 313 314 } // namespace filters 315 } // namespace manager 316 } // namespace inventory 317 } // namespace phosphor 318 319 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 320