summaryrefslogtreecommitdiff
path: root/http/routing/dynamicrule.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'http/routing/dynamicrule.hpp')
-rw-r--r--http/routing/dynamicrule.hpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/http/routing/dynamicrule.hpp b/http/routing/dynamicrule.hpp
new file mode 100644
index 0000000000..746765cf78
--- /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