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 template <typename T, int Pos> 20 struct CallPair 21 { 22 using type = T; 23 static const int pos = Pos; 24 }; 25 26 template <typename H1> 27 struct 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 35 template <typename F, int NString, typename S1, typename S2> 36 struct Call 37 {}; 38 39 template <typename F, int NString, typename... Args1, typename... Args2> 40 struct 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 51 template <typename F, int NString, typename... Args1> 52 struct 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 61 template <typename Func, typename... ArgsWrapped> 62 struct 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 178 class 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 234