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