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