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>
make_action(T && action)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>
make_filter(T && filter)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>
make_path_condition(T && condition)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>
make_get_property(U && method)76 auto make_get_property(U&& method)
77 {
78 return GetProperty<T>(std::forward<U>(method));
79 }
80
81 template <typename T, typename... Args>
callArrayWithStatus(T && container,Args &&...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. */
destroyObjects(std::vector<const char * > && paths,std::vector<PathCondition> && conditions)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
createObjects(std::map<sdbusplus::message::object_path,Object> && objs)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>
setProperty(std::vector<const char * > && paths,std::vector<PathCondition> && conditions,const char * iface,U && member,V && value)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>
getProperty(const char * path,const char * iface,U && member,const char * prop)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;
PropertyChangedConditionphosphor::inventory::manager::functor::PropertyChangedCondition200 PropertyChangedCondition(const char* iface, const char* property,
201 U&& condition) :
202 _iface(iface), _property(property),
203 _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 */
operator ()phosphor::inventory::manager::functor::PropertyChangedCondition211 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 */
PropertyConditionBasephosphor::inventory::manager::functor::PropertyConditionBase268 PropertyConditionBase(const char* path, const char* iface,
269 const char* property, const char* service) :
270 _path(path ? path : std::string()), _iface(iface), _property(property),
271 _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 */
PropertyConditionphosphor::inventory::manager::functor::PropertyCondition337 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 */
evalphosphor::inventory::manager::functor::PropertyCondition349 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 */
evalphosphor::inventory::manager::functor::PropertyCondition362 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>
propertyChangedTo(const char * iface,const char * property,T && val)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>
propertyIs(const char * path,const char * iface,const char * property,T && val,const char * service=nullptr,GetProperty<V> && getProperty=nullptr)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