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