xref: /openbmc/bmcweb/http/routing/dynamicrule.hpp (revision fca2cbea)
1 #pragma once
2 #include "baserule.hpp"
3 #include "ruleparametertraits.hpp"
4 #include "websocket.hpp"
5 
6 #include <boost/beast/http/verb.hpp>
7 
8 #include <functional>
9 #include <limits>
10 #include <string>
11 #include <type_traits>
12 
13 namespace crow
14 {
15 namespace detail
16 {
17 namespace routing_handler_call_helper
18 {
19 
20 template <typename Func, typename... ArgsWrapped>
21 struct Wrapped
22 {
23     template <typename... Args>
24     void set(Func f)
25     {
26         handler = std::move(f);
27     }
28 
29     std::function<void(ArgsWrapped...)> handler;
30 
31     void operator()(const Request& req,
32                     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
33                     const std::vector<std::string>& params)
34     {
35         if constexpr (sizeof...(ArgsWrapped) == 2)
36         {
37             handler(req, asyncResp);
38         }
39         else if constexpr (sizeof...(ArgsWrapped) == 3)
40         {
41             handler(req, asyncResp, params[0]);
42         }
43         else if constexpr (sizeof...(ArgsWrapped) == 4)
44         {
45             handler(req, asyncResp, params[0], params[1]);
46         }
47         else if constexpr (sizeof...(ArgsWrapped) == 5)
48         {
49             handler(req, asyncResp, params[0], params[1], params[2]);
50         }
51         else if constexpr (sizeof...(ArgsWrapped) == 6)
52         {
53             handler(req, asyncResp, params[0], params[1], params[2], params[3]);
54         }
55         else if constexpr (sizeof...(ArgsWrapped) == 7)
56         {
57             handler(req, asyncResp, params[0], params[1], params[2], params[3],
58                     params[4]);
59         }
60     }
61 };
62 } // namespace routing_handler_call_helper
63 } // namespace detail
64 
65 class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
66 {
67   public:
68     explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
69 
70     void validate() override
71     {
72         if (!erasedHandler)
73         {
74             throw std::runtime_error("no handler for url " + rule);
75         }
76     }
77 
78     void handle(const Request& req,
79                 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
80                 const std::vector<std::string>& params) override
81     {
82         erasedHandler(req, asyncResp, params);
83     }
84 
85     template <typename Func>
86     void operator()(Func f)
87     {
88         using boost::callable_traits::args_t;
89         constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
90         constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
91         erasedHandler = wrap(std::move(f), is);
92     }
93 
94     // enable_if Arg1 == request && Arg2 == Response
95     // enable_if Arg1 == request && Arg2 != response
96     // enable_if Arg1 != request
97 
98     template <typename Func, unsigned... Indices>
99     std::function<void(const Request&,
100                        const std::shared_ptr<bmcweb::AsyncResp>&,
101                        const std::vector<std::string>&)>
102         wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
103     {
104         using function_t = crow::utility::FunctionTraits<Func>;
105 
106         auto ret = detail::routing_handler_call_helper::Wrapped<
107             Func, typename function_t::template arg<Indices>...>();
108         ret.template set<typename function_t::template arg<Indices>...>(
109             std::move(f));
110         return ret;
111     }
112 
113   private:
114     std::function<void(const Request&,
115                        const std::shared_ptr<bmcweb::AsyncResp>&,
116                        const std::vector<std::string>&)>
117         erasedHandler;
118 };
119 
120 } // namespace crow
121