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