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