1 #pragma once
2 
3 #include "callback.hpp"
4 
5 #include <phosphor-logging/log.hpp>
6 #include <string>
7 #include <tuple>
8 
9 namespace phosphor
10 {
11 namespace dbus
12 {
13 namespace monitoring
14 {
15 namespace detail
16 {
17 
18 using namespace phosphor::logging;
19 
20 /** @class CallDBusMethod
21  *  @brief Provide explicit call forwarding to
22  *     DBusInterface::callMethodNoReply.
23  *
24  *  @tparam DBusInterface - The DBus interface to use.
25  *  @tparam MethodArgs - DBus method argument types.
26  */
27 template <typename DBusInterface, typename... MethodArgs>
28 struct CallDBusMethod
29 {
30     static void op(const std::string& bus, const std::string& path,
31                    const std::string& iface, const std::string& method,
32                    MethodArgs&&... args)
33     {
34         try
35         {
36             DBusInterface::callMethodNoReply(bus, path, iface, method,
37                                              std::forward<MethodArgs>(args)...);
38         }
39         catch (const sdbusplus::exception::exception& e)
40         {
41             // clang-format off
42             log<level::ERR>("Unable to call DBus method",
43                             entry("BUS=%s", bus.c_str(),
44                                   "PATH=%s", path.c_str(),
45                                   "IFACE=%s", iface.c_str(),
46                                   "METHOD=%s", method.c_str(),
47                                   "ERROR=%s", e.what()));
48             // clang-format on
49         }
50     }
51 };
52 } // namespace detail
53 
54 /** @class MethodBase
55  *  @brief Invoke DBus method callback implementation.
56  *
57  *  The method callback invokes the client supplied DBus method.
58  */
59 class MethodBase : public Callback
60 {
61   public:
62     MethodBase() = delete;
63     MethodBase(const MethodBase&) = delete;
64     MethodBase(MethodBase&&) = default;
65     MethodBase& operator=(const MethodBase&) = delete;
66     MethodBase& operator=(MethodBase&&) = default;
67     virtual ~MethodBase() = default;
68     MethodBase(const std::string& b, const std::string& p, const std::string& i,
69                const std::string& m) :
70         Callback(),
71         bus(b), path(p), interface(i), method(m)
72     {
73     }
74 
75     /** @brief Callback interface implementation. */
76     void operator()(Context ctx) override = 0;
77 
78   protected:
79     const std::string& bus;
80     const std::string& path;
81     const std::string& interface;
82     const std::string& method;
83 };
84 
85 /** @class Method
86  *  @brief C++ type specific logic for the method callback.
87  *
88  *  @tparam DBusInterface - The DBus interface to use to call the method.
89  *  @tparam MethodArgs - DBus method argument types.
90  */
91 template <typename DBusInterface, typename... MethodArgs>
92 class Method : public MethodBase
93 {
94   public:
95     Method() = delete;
96     Method(const Method&) = default;
97     Method(Method&&) = default;
98     Method& operator=(const Method&) = default;
99     Method& operator=(Method&&) = default;
100     ~Method() = default;
101     Method(const std::string& bus, const std::string& path,
102            const std::string& iface, const std::string& method,
103            MethodArgs&&... arguments) :
104         MethodBase(bus, path, iface, method),
105         args(std::forward<MethodArgs>(arguments)...)
106     {
107     }
108 
109     /** @brief Callback interface implementation. */
110     void operator()(Context ctx) override
111     {
112         std::apply(detail::CallDBusMethod<DBusInterface, MethodArgs...>::op,
113                    std::tuple_cat(std::make_tuple(bus), std::make_tuple(path),
114                                   std::make_tuple(interface),
115                                   std::make_tuple(method), args));
116     }
117 
118   private:
119     std::tuple<MethodArgs...> args;
120 };
121 
122 /** @brief Argument type deduction for constructing Method instances. */
123 template <typename DBusInterface, typename... MethodArgs>
124 auto makeMethod(const std::string& bus, const std::string& path,
125                 const std::string& iface, const std::string& method,
126                 MethodArgs&&... arguments)
127 {
128     return std::make_unique<Method<DBusInterface, MethodArgs...>>(
129         bus, path, iface, method, std::forward<MethodArgs>(arguments)...);
130 }
131 
132 } // namespace monitoring
133 } // namespace dbus
134 } // namespace phosphor
135