1 #pragma once 2 3 #include "types.hpp" 4 #include "utils.hpp" 5 6 #include <memory> 7 #include <sdbusplus/bus.hpp> 8 #include <utility> 9 10 namespace phosphor 11 { 12 namespace inventory 13 { 14 namespace manager 15 { 16 17 class Manager; 18 19 /** @brief make_action 20 * 21 * Adapt an action function object. 22 * 23 * @param[in] action - The action being adapted. 24 * @returns - The adapted action. 25 * 26 * @tparam T - The type of the action being adapted. 27 */ 28 template <typename T> 29 auto make_action(T&& action) 30 { 31 return Action(std::forward<T>(action)); 32 } 33 34 /** @brief make_filter 35 * 36 * Adapt a filter function object. 37 * 38 * @param[in] filter - The filter being adapted. 39 * @returns - The adapted filter. 40 * 41 * @tparam T - The type of the filter being adapted. 42 */ 43 template <typename T> 44 auto make_filter(T&& filter) 45 { 46 return Filter(std::forward<T>(filter)); 47 } 48 49 /** @brief make_path_condition 50 * 51 * Adapt a path_condition function object. 52 * 53 * @param[in] filter - The functor being adapted. 54 * @returns - The adapted functor. 55 * 56 * @tparam T - The type of the functor being adapted. 57 */ 58 template <typename T> 59 auto make_path_condition(T&& condition) 60 { 61 return PathCondition(std::forward<T>(condition)); 62 } 63 64 /** @brief make_get_property 65 * 66 * Adapt a get_property function object. 67 * 68 * @param[in] method - The functor being adapted. 69 * @returns - The adapted functor. 70 * 71 * @tparam T - The return type of the function object. 72 * @tparam U - The type of the functor being adapted. 73 */ 74 template <typename T, typename U> 75 auto make_get_property(U&& method) 76 { 77 return GetProperty<T>(std::forward<U>(method)); 78 } 79 80 template <typename T, typename... Args> 81 auto callArrayWithStatus(T&& container, Args&&... args) 82 { 83 for (auto f : container) 84 { 85 if (!f(std::forward<Args>(args)...)) 86 { 87 return false; 88 } 89 } 90 return true; 91 } 92 93 namespace functor 94 { 95 96 /** @brief Destroy objects action. */ 97 inline auto destroyObjects(std::vector<const char*>&& paths, 98 std::vector<PathCondition>&& conditions) 99 { 100 return [=](auto& b, auto& m) { 101 for (const auto& p : paths) 102 { 103 if (callArrayWithStatus(conditions, p, b, m)) 104 { 105 m.destroyObjects({p}); 106 } 107 } 108 }; 109 } 110 111 /** @brief Create objects action. */ 112 inline auto 113 createObjects(std::map<sdbusplus::message::object_path, Object>&& objs) 114 { 115 return [=](auto&, auto& m) { m.createObjects(objs); }; 116 } 117 118 /** @brief Set a property action. 119 * 120 * Invoke the requested method with a reference to the requested 121 * sdbusplus server binding interface as a parameter. 122 * 123 * @tparam T - The sdbusplus server binding interface type. 124 * @tparam U - The type of the sdbusplus server binding member 125 * function that sets the property. 126 * @tparam V - The property value type. 127 * 128 * @param[in] paths - The DBus paths on which the property should 129 * be set. 130 * @param[in] iface - The DBus interface hosting the property. 131 * @param[in] member - Pointer to sdbusplus server binding member. 132 * @param[in] value - The value the property should be set to. 133 * 134 * @returns - A function object that sets the requested property 135 * to the requested value. 136 */ 137 template <typename T, typename U, typename V> 138 auto setProperty(std::vector<const char*>&& paths, 139 std::vector<PathCondition>&& conditions, const char* iface, 140 U&& member, V&& value) 141 { 142 // The manager is the only parameter passed to actions. 143 // Bind the path, interface, interface member function pointer, 144 // and value to a lambda. When it is called, forward the 145 // path, interface and value on to the manager member function. 146 return [paths, conditions = conditions, iface, member, 147 value = std::forward<V>(value)](auto& b, auto& m) { 148 for (auto p : paths) 149 { 150 if (callArrayWithStatus(conditions, p, b, m)) 151 { 152 m.template invokeMethod<T>(p, iface, member, value); 153 } 154 } 155 }; 156 } 157 158 /** @brief Get a property. 159 * 160 * Invoke the requested method with a reference to the requested 161 * sdbusplus server binding interface as a parameter. 162 * 163 * @tparam T - The sdbusplus server binding interface type. 164 * @tparam U - The type of the sdbusplus server binding member 165 * function that sets the property. 166 * 167 * @param[in] path - The DBus path to get the property from. 168 * @param[in] iface - The DBus interface hosting the property. 169 * @param[in] member - Pointer to sdbusplus server binding member. 170 * @param[in] prop - The property name to get the value from. 171 * 172 * @returns - A function object that gets the requested property. 173 */ 174 template <typename T, typename U> 175 inline auto getProperty(const char* path, const char* iface, U&& member, 176 const char* prop) 177 { 178 return [path, iface, member, prop](auto& mgr) { 179 return mgr.template invokeMethod<T>(path, iface, member, prop); 180 }; 181 } 182 183 /** @struct PropertyChangedCondition 184 * @brief Match filter functor that tests a property value. 185 * 186 * @tparam T - The type of the property being tested. 187 * @tparam U - The type of the condition checking functor. 188 */ 189 template <typename T, typename U> 190 struct PropertyChangedCondition 191 { 192 PropertyChangedCondition() = delete; 193 ~PropertyChangedCondition() = default; 194 PropertyChangedCondition(const PropertyChangedCondition&) = default; 195 PropertyChangedCondition& 196 operator=(const PropertyChangedCondition&) = default; 197 PropertyChangedCondition(PropertyChangedCondition&&) = default; 198 PropertyChangedCondition& operator=(PropertyChangedCondition&&) = default; 199 PropertyChangedCondition(const char* iface, const char* property, 200 U&& condition) : 201 _iface(iface), 202 _property(property), _condition(std::forward<U>(condition)) 203 { 204 } 205 206 /** @brief Test a property value. 207 * 208 * Extract the property from the PropertiesChanged 209 * message and run the condition test. 210 */ 211 bool operator()(sdbusplus::bus::bus&, sdbusplus::message::message& msg, 212 Manager&) const 213 { 214 std::map<std::string, sdbusplus::message::variant<T>> properties; 215 const char* iface = nullptr; 216 217 msg.read(iface); 218 if (!iface || strcmp(iface, _iface)) 219 { 220 return false; 221 } 222 223 msg.read(properties); 224 auto it = properties.find(_property); 225 if (it == properties.cend()) 226 { 227 return false; 228 } 229 230 return _condition(std::forward<T>( 231 sdbusplus::message::variant_ns::get<T>(it->second))); 232 } 233 234 private: 235 const char* _iface; 236 const char* _property; 237 U _condition; 238 }; 239 240 /** @struct PropertyConditionBase 241 * @brief Match filter functor that tests a property value. 242 * 243 * Base class for PropertyCondition - factored out code that 244 * doesn't need to be templated. 245 */ 246 struct PropertyConditionBase 247 { 248 PropertyConditionBase() = delete; 249 virtual ~PropertyConditionBase() = default; 250 PropertyConditionBase(const PropertyConditionBase&) = default; 251 PropertyConditionBase& operator=(const PropertyConditionBase&) = default; 252 PropertyConditionBase(PropertyConditionBase&&) = default; 253 PropertyConditionBase& operator=(PropertyConditionBase&&) = default; 254 255 /** @brief Constructor 256 * 257 * The service argument can be nullptr. If something 258 * else is provided the function will call the the 259 * service directly. If omitted, the function will 260 * look up the service in the ObjectMapper. 261 * 262 * @param path - The path of the object containing 263 * the property to be tested. 264 * @param iface - The interface hosting the property 265 * to be tested. 266 * @param property - The property to be tested. 267 * @param service - The DBus service hosting the object. 268 */ 269 PropertyConditionBase(const char* path, const char* iface, 270 const char* property, const char* service) : 271 _path(path ? path : std::string()), 272 _iface(iface), _property(property), _service(service) 273 { 274 } 275 276 /** @brief Forward comparison to type specific implementation. */ 277 virtual bool eval(sdbusplus::message::message&) const = 0; 278 279 /** @brief Forward comparison to type specific implementation. */ 280 virtual bool eval(Manager&) const = 0; 281 282 /** @brief Test a property value. 283 * 284 * Make a DBus call and test the value of any property. 285 */ 286 bool operator()(sdbusplus::bus::bus&, sdbusplus::message::message&, 287 Manager&) const; 288 289 /** @brief Test a property value. 290 * 291 * Make a DBus call and test the value of any property. 292 */ 293 bool operator()(const std::string&, sdbusplus::bus::bus&, Manager&) const; 294 295 private: 296 std::string _path; 297 std::string _iface; 298 std::string _property; 299 const char* _service; 300 }; 301 302 /** @struct PropertyCondition 303 * @brief Match filter functor that tests a property value. 304 * 305 * @tparam T - The type of the property being tested. 306 * @tparam U - The type of the condition checking functor. 307 * @tparam V - The getProperty functor return type. 308 */ 309 template <typename T, typename U, typename V> 310 struct PropertyCondition final : public PropertyConditionBase 311 { 312 PropertyCondition() = delete; 313 ~PropertyCondition() = default; 314 PropertyCondition(const PropertyCondition&) = default; 315 PropertyCondition& operator=(const PropertyCondition&) = default; 316 PropertyCondition(PropertyCondition&&) = default; 317 PropertyCondition& operator=(PropertyCondition&&) = default; 318 319 /** @brief Constructor 320 * 321 * The service & getProperty arguments can be nullptrs. 322 * If something else is provided the function will call the the 323 * service directly. If omitted, the function will 324 * look up the service in the ObjectMapper. 325 * The getProperty function will be called to retrieve a property 326 * value when given and the property is hosted by inventory manager. 327 * When not given, the condition will default to return that the 328 * condition failed and will not be executed. 329 * 330 * @param path - The path of the object containing 331 * the property to be tested. 332 * @param iface - The interface hosting the property 333 * to be tested. 334 * @param property - The property to be tested. 335 * @param condition - The test to run on the property. 336 * @param service - The DBus service hosting the object. 337 * @param getProperty - The function to get a property value 338 * for the condition. 339 */ 340 PropertyCondition(const char* path, const char* iface, const char* property, 341 U&& condition, const char* service, 342 GetProperty<V>&& getProperty = nullptr) : 343 PropertyConditionBase(path, iface, property, service), 344 _condition(std::forward<decltype(condition)>(condition)), 345 _getProperty(getProperty) 346 { 347 } 348 349 /** @brief Test a property value. 350 * 351 * Make a DBus call and test the value of any property. 352 */ 353 bool eval(sdbusplus::message::message& msg) const override 354 { 355 sdbusplus::message::variant<T> value; 356 msg.read(value); 357 return _condition( 358 std::forward<T>(sdbusplus::message::variant_ns::get<T>(value))); 359 } 360 361 /** @brief Retrieve a property value from inventory and test it. 362 * 363 * Get a property from the inventory manager and test the value. 364 * Default to fail the test where no function is given to get the 365 * property from the inventory manager. 366 */ 367 bool eval(Manager& mgr) const override 368 { 369 if (_getProperty) 370 { 371 auto variant = _getProperty(mgr); 372 auto value = sdbusplus::message::variant_ns::get<T>(variant); 373 return _condition(std::forward<T>(value)); 374 } 375 return false; 376 } 377 378 private: 379 U _condition; 380 GetProperty<V> _getProperty; 381 }; 382 383 /** @brief Implicit type deduction for constructing PropertyChangedCondition. */ 384 template <typename T> 385 auto propertyChangedTo(const char* iface, const char* property, T&& val) 386 { 387 auto condition = [val = std::forward<T>(val)](T&& arg) { 388 return arg == val; 389 }; 390 using U = decltype(condition); 391 return PropertyChangedCondition<T, U>(iface, property, 392 std::move(condition)); 393 } 394 395 /** @brief Implicit type deduction for constructing PropertyCondition. */ 396 template <typename T, typename V = InterfaceVariantType> 397 auto propertyIs(const char* path, const char* iface, const char* property, 398 T&& val, const char* service = nullptr, 399 GetProperty<V>&& getProperty = nullptr) 400 { 401 auto condition = [val = std::forward<T>(val)](T&& arg) { 402 return arg == val; 403 }; 404 using U = decltype(condition); 405 return PropertyCondition<T, U, V>(path, iface, property, 406 std::move(condition), service, 407 std::move(getProperty)); 408 } 409 } // namespace functor 410 } // namespace manager 411 } // namespace inventory 412 } // namespace phosphor 413 414 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 415