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