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