Break up router into separate files

The router is a giant behemoth.  Start breaking it down into pieces.

Tested: Redfish service validator passes.

Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I9d04f53a58ffce3ecbd88dded1aa6e9648d2a762
diff --git a/http/routing/dynamicrule.hpp b/http/routing/dynamicrule.hpp
new file mode 100644
index 0000000..746765c
--- /dev/null
+++ b/http/routing/dynamicrule.hpp
@@ -0,0 +1,233 @@
+#pragma once
+#include "baserule.hpp"
+#include "ruleparametertraits.hpp"
+#include "websocket.hpp"
+
+#include <boost/beast/http/verb.hpp>
+
+#include <functional>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+namespace crow
+{
+namespace detail
+{
+namespace routing_handler_call_helper
+{
+template <typename T, int Pos>
+struct CallPair
+{
+    using type = T;
+    static const int pos = Pos;
+};
+
+template <typename H1>
+struct CallParams
+{
+    H1& handler;
+    const std::vector<std::string>& params;
+    const Request& req;
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp;
+};
+
+template <typename F, int NString, typename S1, typename S2>
+struct Call
+{};
+
+template <typename F, int NString, typename... Args1, typename... Args2>
+struct Call<F, NString, black_magic::S<std::string, Args1...>,
+            black_magic::S<Args2...>>
+{
+    void operator()(F cparams)
+    {
+        using pushed = typename black_magic::S<Args2...>::template push_back<
+            CallPair<std::string, NString>>;
+        Call<F, NString + 1, black_magic::S<Args1...>, pushed>()(cparams);
+    }
+};
+
+template <typename F, int NString, typename... Args1>
+struct Call<F, NString, black_magic::S<>, black_magic::S<Args1...>>
+{
+    void operator()(F cparams)
+    {
+        cparams.handler(cparams.req, cparams.asyncResp,
+                        cparams.params[Args1::pos]...);
+    }
+};
+
+template <typename Func, typename... ArgsWrapped>
+struct Wrapped
+{
+    template <typename... Args>
+    void set(
+        Func f,
+        typename std::enable_if<
+            !std::is_same<
+                typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+                const Request&>::value,
+            int>::type /*enable*/
+        = 0)
+    {
+        handler = [f = std::forward<Func>(f)](
+                      const Request&,
+                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                      Args... args) { asyncResp->res.result(f(args...)); };
+    }
+
+    template <typename Req, typename... Args>
+    struct ReqHandlerWrapper
+    {
+        explicit ReqHandlerWrapper(Func fIn) : f(std::move(fIn)) {}
+
+        void operator()(const Request& req,
+                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                        Args... args)
+        {
+            asyncResp->res.result(f(req, args...));
+        }
+
+        Func f;
+    };
+
+    template <typename... Args>
+    void set(
+        Func f,
+        typename std::enable_if<
+            std::is_same<
+                typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+                const Request&>::value &&
+                !std::is_same<typename std::tuple_element<
+                                  1, std::tuple<Args..., void, void>>::type,
+                              const std::shared_ptr<bmcweb::AsyncResp>&>::value,
+            int>::type /*enable*/
+        = 0)
+    {
+        handler = ReqHandlerWrapper<Args...>(std::move(f));
+        /*handler = (
+            [f = std::move(f)]
+            (const Request& req, Response& res, Args... args){
+                 res.result(f(req, args...));
+                 res.end();
+            });*/
+    }
+
+    template <typename... Args>
+    void set(
+        Func f,
+        typename std::enable_if<
+            std::is_same<
+                typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+                const Request&>::value &&
+                std::is_same<typename std::tuple_element<
+                                 1, std::tuple<Args..., void, void>>::type,
+                             const std::shared_ptr<bmcweb::AsyncResp>&>::value,
+            int>::type /*enable*/
+        = 0)
+    {
+        handler = std::move(f);
+    }
+
+    template <typename... Args>
+    struct HandlerTypeHelper
+    {
+        using type = std::function<void(
+            const crow::Request& /*req*/,
+            const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
+        using args_type = black_magic::S<Args...>;
+    };
+
+    template <typename... Args>
+    struct HandlerTypeHelper<const Request&, Args...>
+    {
+        using type = std::function<void(
+            const crow::Request& /*req*/,
+            const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
+        using args_type = black_magic::S<Args...>;
+    };
+
+    template <typename... Args>
+    struct HandlerTypeHelper<const Request&,
+                             const std::shared_ptr<bmcweb::AsyncResp>&, Args...>
+    {
+        using type = std::function<void(
+            const crow::Request& /*req*/,
+            const std::shared_ptr<bmcweb::AsyncResp>&, Args...)>;
+        using args_type = black_magic::S<Args...>;
+    };
+
+    typename HandlerTypeHelper<ArgsWrapped...>::type handler;
+
+    void operator()(const Request& req,
+                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                    const std::vector<std::string>& params)
+    {
+        detail::routing_handler_call_helper::Call<
+            detail::routing_handler_call_helper::CallParams<decltype(handler)>,
+            0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
+            black_magic::S<>>()(
+            detail::routing_handler_call_helper::CallParams<decltype(handler)>{
+                handler, params, req, asyncResp});
+    }
+};
+} // namespace routing_handler_call_helper
+} // namespace detail
+
+class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
+{
+  public:
+    explicit DynamicRule(const std::string& ruleIn) : BaseRule(ruleIn) {}
+
+    void validate() override
+    {
+        if (!erasedHandler)
+        {
+            throw std::runtime_error("no handler for url " + rule);
+        }
+    }
+
+    void handle(const Request& req,
+                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                const std::vector<std::string>& params) override
+    {
+        erasedHandler(req, asyncResp, params);
+    }
+
+    template <typename Func>
+    void operator()(Func f)
+    {
+        using boost::callable_traits::args_t;
+        constexpr size_t arity = std::tuple_size<args_t<Func>>::value;
+        constexpr auto is = std::make_integer_sequence<unsigned, arity>{};
+        erasedHandler = wrap(std::move(f), is);
+    }
+
+    // enable_if Arg1 == request && Arg2 == Response
+    // enable_if Arg1 == request && Arg2 != response
+    // enable_if Arg1 != request
+
+    template <typename Func, unsigned... Indices>
+    std::function<void(const Request&,
+                       const std::shared_ptr<bmcweb::AsyncResp>&,
+                       const std::vector<std::string>&)>
+        wrap(Func f, std::integer_sequence<unsigned, Indices...> /*is*/)
+    {
+        using function_t = crow::utility::FunctionTraits<Func>;
+
+        auto ret = detail::routing_handler_call_helper::Wrapped<
+            Func, typename function_t::template arg<Indices>...>();
+        ret.template set<typename function_t::template arg<Indices>...>(
+            std::move(f));
+        return ret;
+    }
+
+  private:
+    std::function<void(const Request&,
+                       const std::shared_ptr<bmcweb::AsyncResp>&,
+                       const std::vector<std::string>&)>
+        erasedHandler;
+};
+
+} // namespace crow