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::bus&, sdbusplus::message::message& 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::message&) 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::bus&, sdbusplus::message::message&, 285 Manager&) const; 286 287 /** @brief Test a property value. 288 * 289 * Make a DBus call and test the value of any property. 290 */ 291 bool operator()(const std::string&, sdbusplus::bus::bus&, Manager&) const; 292 293 private: 294 std::string _path; 295 std::string _iface; 296 std::string _property; 297 const char* _service; 298 }; 299 300 /** @struct PropertyCondition 301 * @brief Match filter functor that tests a property value. 302 * 303 * @tparam T - The type of the property being tested. 304 * @tparam U - The type of the condition checking functor. 305 * @tparam V - The getProperty functor return type. 306 */ 307 template <typename T, typename U, typename V> 308 struct PropertyCondition final : public PropertyConditionBase 309 { 310 PropertyCondition() = delete; 311 ~PropertyCondition() = default; 312 PropertyCondition(const PropertyCondition&) = default; 313 PropertyCondition& operator=(const PropertyCondition&) = default; 314 PropertyCondition(PropertyCondition&&) = default; 315 PropertyCondition& operator=(PropertyCondition&&) = default; 316 317 /** @brief Constructor 318 * 319 * The service & getProperty arguments can be nullptrs. 320 * If something else is provided the function will call the the 321 * service directly. If omitted, the function will 322 * look up the service in the ObjectMapper. 323 * The getProperty function will be called to retrieve a property 324 * value when given and the property is hosted by inventory manager. 325 * When not given, the condition will default to return that the 326 * condition failed and will not be executed. 327 * 328 * @param path - The path of the object containing 329 * the property to be tested. 330 * @param iface - The interface hosting the property 331 * to be tested. 332 * @param property - The property to be tested. 333 * @param condition - The test to run on the property. 334 * @param service - The DBus service hosting the object. 335 * @param getProperty - The function to get a property value 336 * for the condition. 337 */ 338 PropertyCondition(const char* path, const char* iface, const char* property, 339 U&& condition, const char* service, 340 GetProperty<V>&& getProperty = nullptr) : 341 PropertyConditionBase(path, iface, property, service), 342 _condition(std::forward<decltype(condition)>(condition)), 343 _getProperty(getProperty) 344 {} 345 346 /** @brief Test a property value. 347 * 348 * Make a DBus call and test the value of any property. 349 */ 350 bool eval(sdbusplus::message::message& msg) const override 351 { 352 std::variant<T> value; 353 msg.read(value); 354 return _condition(std::forward<T>(std::get<T>(value))); 355 } 356 357 /** @brief Retrieve a property value from inventory and test it. 358 * 359 * Get a property from the inventory manager and test the value. 360 * Default to fail the test where no function is given to get the 361 * property from the inventory manager. 362 */ 363 bool eval(Manager& mgr) const override 364 { 365 if (_getProperty) 366 { 367 auto variant = _getProperty(mgr); 368 auto value = std::get<T>(variant); 369 return _condition(std::forward<T>(value)); 370 } 371 return false; 372 } 373 374 private: 375 U _condition; 376 GetProperty<V> _getProperty; 377 }; 378 379 /** @brief Implicit type deduction for constructing PropertyChangedCondition. */ 380 template <typename T> 381 auto propertyChangedTo(const char* iface, const char* property, T&& val) 382 { 383 auto condition = [val = std::forward<T>(val)](T&& arg) { 384 return arg == val; 385 }; 386 using U = decltype(condition); 387 return PropertyChangedCondition<T, U>(iface, property, 388 std::move(condition)); 389 } 390 391 /** @brief Implicit type deduction for constructing PropertyCondition. */ 392 template <typename T, typename V = InterfaceVariantType> 393 auto propertyIs(const char* path, const char* iface, const char* property, 394 T&& val, const char* service = nullptr, 395 GetProperty<V>&& getProperty = nullptr) 396 { 397 auto condition = [val = std::forward<T>(val)](T&& arg) { 398 return arg == val; 399 }; 400 using U = decltype(condition); 401 return PropertyCondition<T, U, V>(path, iface, property, 402 std::move(condition), service, 403 std::move(getProperty)); 404 } 405 } // namespace functor 406 } // namespace manager 407 } // namespace inventory 408 } // namespace phosphor 409 410 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 411