blob: 746765cf7802b03d38d1ad6fb43e30c636fa6a72 [file] [log] [blame]
Ed Tanous08bbe112023-04-06 13:10:02 -07001#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
13namespace crow
14{
15namespace detail
16{
17namespace routing_handler_call_helper
18{
19template <typename T, int Pos>
20struct CallPair
21{
22 using type = T;
23 static const int pos = Pos;
24};
25
26template <typename H1>
27struct CallParams
28{
29 H1& handler;
30 const std::vector<std::string>& params;
31 const Request& req;
32 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
33};
34
35template <typename F, int NString, typename S1, typename S2>
36struct Call
37{};
38
39template <typename F, int NString, typename... Args1, typename... Args2>
40struct Call<F, NString, black_magic::S<std::string, Args1...>,
41 black_magic::S<Args2...>>
42{
43 void operator()(F cparams)
44 {
45 using pushed = typename black_magic::S<Args2...>::template push_back<
46 CallPair<std::string, NString>>;
47 Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
48 }
49};
50
51template <typename F, int NString, typename... Args1>
52struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
53{
54 void operator()(F cparams)
55 {
56 cparams.handler(cparams.req, cparams.asyncResp,
57 cparams.params[Args1::pos]...);
58 }
59};
60
61template <typename Func, typename... ArgsWrapped>
62struct Wrapped
63{
64 template <typename... Args>
65 void set(
66 Func f,
67 typename std::enable_if<
68 !std::is_same<
69 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
70 const Request&>::value,
71 int>::type /*enable*/
72 = 0)
73 {
74 handler = [f = std::forward<Func>(f)](
75 const Request&,
76 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
77 Args... args) { asyncResp->res.result(f(args...)); };
78 }
79
80 template <typename Req, typename... Args>
81 struct ReqHandlerWrapper
82 {
83 explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
84
85 void operator()(const Request& req,
86 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
87 Args... args)
88 {
89 asyncResp->res.result(f(req, args...));
90 }
91
92 Func f;
93 };
94
95 template <typename... Args>
96 void set(
97 Func f,
98 typename std::enable_if<
99 std::is_same<
100 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
101 const Request&>::value &&
102 !std::is_same<typename std::tuple_element<
103 1, std::tuple<Args..., void, void>>::type,
104 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
105 int>::type /*enable*/
106 = 0)
107 {
108 handler = ReqHandlerWrapper<Args...>(std::move(f));
109 /*handler = (
110 [f = std::move(f)]
111 (const Request& req, Response& res, Args... args){
112 res.result(f(req, args...));
113 res.end();
114 });*/
115 }
116
117 template <typename... Args>
118 void set(
119 Func f,
120 typename std::enable_if<
121 std::is_same<
122 typename std::tuple_element<0, std::tuple<Args..., void>>::type,
123 const Request&>::value &&
124 std::is_same<typename std::tuple_element<
125 1, std::tuple<Args..., void, void>>::type,
126 const std::shared_ptr<bmcweb::AsyncResp>&>::value,
127 int>::type /*enable*/
128 = 0)
129 {
130 handler = std::move(f);
131 }
132
133 template <typename... Args>
134 struct HandlerTypeHelper
135 {
136 using type = std::function<void(
137 const crow::Request& /*req*/,
138 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
139 using args_type = black_magic::S<Args...>;
140 };
141
142 template <typename... Args>
143 struct HandlerTypeHelper<const Request&, Args...>
144 {
145 using type = std::function<void(
146 const crow::Request& /*req*/,
147 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
148 using args_type = black_magic::S<Args...>;
149 };
150
151 template <typename... Args>
152 struct HandlerTypeHelper<const Request&,
153 const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
154 {
155 using type = std::function<void(
156 const crow::Request& /*req*/,
157 const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
158 using args_type = black_magic::S<Args...>;
159 };
160
161 typename HandlerTypeHelper<ArgsWrapped...>::type handler;
162
163 void operator()(const Request& req,
164 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
165 const std::vector<std::string>& params)
166 {
167 detail::routing_handler_call_helper::Call<
168 detail::routing_handler_call_helper::CallParams<decltype(handler)>,
169 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
170 black_magic::S<>>()(
171 detail::routing_handler_call_helper::CallParams<decltype(handler)>{
172 handler, params, req, asyncResp});
173 }
174};
175} // namespace routing_handler_call_helper
176} // namespace detail
177
178class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
179{
180 public:
181 explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
182
183 void validate() override
184 {
185 if (!erasedHandler)
186 {
187 throw std::runtime_error("no handler for url " + rule);
188 }
189 }
190
191 void handle(const Request& req,
192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
193 const std::vector<std::string>& params) override
194 {
195 erasedHandler(req, asyncResp, params);
196 }
197
198 template <typename Func>
199 void operator()(Func f)
200 {
201 using boost::callable_traits::args_t;
202 constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
203 constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
204 erasedHandler = wrap(std::move(f), is);
205 }
206
207 // enable_if Arg1 == request && Arg2 == Response
208 // enable_if Arg1 == request && Arg2 != response
209 // enable_if Arg1 != request
210
211 template <typename Func, unsigned... Indices>
212 std::function<void(const Request&,
213 const std::shared_ptr<bmcweb::AsyncResp>&,
214 const std::vector<std::string>&)>
215 wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
216 {
217 using function_t = crow::utility::FunctionTraits<Func>;
218
219 auto ret = detail::routing_handler_call_helper::Wrapped<
220 Func, typename function_t::template arg<Indices>...>();
221 ret.template set<typename function_t::template arg<Indices>...>(
222 std::move(f));
223 return ret;
224 }
225
226 private:
227 std::function<void(const Request&,
228 const std::shared_ptr<bmcweb::AsyncResp>&,
229 const std::vector<std::string>&)>
230 erasedHandler;
231};
232
233} // namespace crow