diff options
author | ipknHama <ipknhama@gmail.com> | 2014-09-07 01:24:45 +0900 |
---|---|---|
committer | ipknHama <ipknhama@gmail.com> | 2014-09-07 01:24:45 +0900 |
commit | c89cafa820ec02f041c3b0e52877bc321f6a1ba9 (patch) | |
tree | 8b74deacdefd07048c230cb553efe6bb4e7352e1 | |
parent | daa3c820878f8e189120cf9359caf8b2359d61ca (diff) | |
download | crow-c89cafa820ec02f041c3b0e52877bc321f6a1ba9.tar.gz crow-c89cafa820ec02f041c3b0e52877bc321f6a1ba9.zip |
add Middlewares template to Crow main class, context implementation
-rw-r--r-- | examples/example.cpp | 2 | ||||
-rw-r--r-- | examples/example_chat.cpp | 2 | ||||
-rw-r--r-- | include/crow.h | 19 | ||||
-rw-r--r-- | include/http_request.h | 2 | ||||
-rw-r--r-- | include/middleware.h | 50 | ||||
-rw-r--r-- | include/middleware_context.h | 32 | ||||
-rw-r--r-- | include/utility.h | 73 | ||||
-rw-r--r-- | tests/unittest.cpp | 14 |
8 files changed, 184 insertions, 10 deletions
diff --git a/examples/example.cpp b/examples/example.cpp index b8e58f8..b360adb 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -12,7 +12,7 @@ class ExampleLogHandler : public crow::ILogHandler { int main() { - crow::Crow app; + crow::SimpleApp app; CROW_ROUTE(app, "/") .name("hello") diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp index b12926a..31f16c5 100644 --- a/examples/example_chat.cpp +++ b/examples/example_chat.cpp @@ -28,7 +28,7 @@ void broadcast(const string& msg) int main() { - crow::App app; + crow::SimpleApp app; crow::mustache::set_base("."); CROW_ROUTE(app, "/") diff --git a/include/crow.h b/include/crow.h index 55572bf..a018f31 100644 --- a/include/crow.h +++ b/include/crow.h @@ -13,6 +13,8 @@ #include "http_server.h" #include "utility.h" #include "routing.h" +#include "middleware_impl.h" +#include "http_request.h" // TEST #include <iostream> @@ -21,6 +23,7 @@ namespace crow { + template <typename ... Middlewares> class Crow { public: @@ -78,12 +81,26 @@ namespace crow router_.debug_print(); } + // middleware + using context_t = detail::context<Middlewares...>; + template <typename T> + T& get_middleware_context(request& req) + { + static_assert(black_magic::contains<T, Middlewares...>::value, "App doesn't have the specified middleware type."); + auto& ctx = *reinterpret_cast<context_t*>(req.middleware_context); + return ctx.get<T>(); + } + private: uint16_t port_ = 80; uint16_t concurrency_ = 1; + std::tuple<Middlewares...> middlewares_; + Router router_; }; - using App = Crow; + template <typename ... Middlewares> + using App = Crow<Middlewares...>; + using SimpleApp = Crow<>; }; diff --git a/include/http_request.h b/include/http_request.h index 83b6059..77b3ecb 100644 --- a/include/http_request.h +++ b/include/http_request.h @@ -10,5 +10,7 @@ namespace crow std::string url; std::unordered_map<std::string, std::string> headers; std::string body; + + void* middleware_context; }; } diff --git a/include/middleware.h b/include/middleware.h new file mode 100644 index 0000000..270e026 --- /dev/null +++ b/include/middleware.h @@ -0,0 +1,50 @@ +#pragma once +#include "http_request.h" +#include "http_response.h" + +namespace crow +{ + class CookieParser + { + struct context + { + std::unordered_map<std::string, std::string> jar; + }; + + template <typename AllContext> + void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx) + { + // ctx == all_ctx.bind<CookieParser>() + // ctx.jar[] = ; + } + + template <typename AllContext> + void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx) + { + } + } + + /* + App<CookieParser, AnotherJarMW> app; + A B C + A::context + int aa; + + ctx1 : public A::context + ctx2 : public ctx1, public B::context + ctx3 : public ctx2, public C::context + + C depends on A + + C::handle + context.aaa + + App::context : private CookieParser::contetx, ... + { + jar + + } + + SimpleApp + */ +} diff --git a/include/middleware_context.h b/include/middleware_context.h new file mode 100644 index 0000000..6dbf923 --- /dev/null +++ b/include/middleware_context.h @@ -0,0 +1,32 @@ +#pragma once + +#include "utility.h" + +namespace crow +{ + namespace detail + { + template <typename ... Middlewares> + struct partial_context + : public black_magic::pop_back<Middlewares...>::template rebind<partial_context> + , public black_magic::last_element_type<Middlewares...>::type::context + { + }; + + template <> + struct partial_context<> + { + }; + + template <typename ... Middlewares> + struct context : private partial_context<Middlewares...> + //struct context : private Middlewares::context... // simple but less type-safe + { + template <typename T> + typename T::context& get() + { + return static_cast<typename T::context&>(*this); + } + }; + } +} diff --git a/include/utility.h b/include/utility.h index a46d577..35ea848 100644 --- a/include/utility.h +++ b/include/utility.h @@ -2,6 +2,8 @@ #include <cstdint> #include <stdexcept> +#include <tuple> +#include <type_traits> namespace crow { @@ -211,5 +213,76 @@ template <typename F, typename Set> using type = S<>; }; + template <typename ... T> + struct last_element_type + { + using type = typename std::tuple_element<sizeof...(T)-1, std::tuple<T...>>::type; + }; + + + template <> + struct last_element_type<> + { + }; + + + // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth + template<class T> using Invoke = typename T::type; + + template<unsigned...> struct seq{ using type = seq; }; + + template<class S1, class S2> struct concat; + + template<unsigned... I1, unsigned... I2> + struct concat<seq<I1...>, seq<I2...>> + : seq<I1..., (sizeof...(I1)+I2)...>{}; + + template<class S1, class S2> + using Concat = Invoke<concat<S1, S2>>; + + template<unsigned N> struct gen_seq; + template<unsigned N> using GenSeq = Invoke<gen_seq<N>>; + + template<unsigned N> + struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{}; + + template<> struct gen_seq<0> : seq<>{}; + template<> struct gen_seq<1> : seq<0>{}; + + template <typename Seq, typename Tuple> + struct pop_back_helper; + + template <unsigned ... N, typename Tuple> + struct pop_back_helper<seq<N...>, Tuple> + { + template <template <typename ... Args> class U> + using rebind = U<std::tuple_element<N, Tuple>...>; + }; + + template <typename ... T> + struct pop_back : public pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>> + { + }; + + template <> + struct pop_back<> + { + template <template <typename ... Args> class U> + using rebind = U<>; + }; + + // from http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type + template < typename Tp, typename... List > + struct contains : std::true_type {}; + + template < typename Tp, typename Head, typename... Rest > + struct contains<Tp, Head, Rest...> + : std::conditional< std::is_same<Tp, Head>::value, + std::true_type, + contains<Tp, Rest...> + >::type {}; + + template < typename Tp > + struct contains<Tp> : std::false_type {}; } } diff --git a/tests/unittest.cpp b/tests/unittest.cpp index 918d027..17bc53c 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -112,7 +112,7 @@ TEST(ParameterTagging) TEST(RoutingTest) { - Crow app; + SimpleApp app; int A{}; uint32_t B{}; double C{}; @@ -238,7 +238,7 @@ TEST(simple_response_routing_params) TEST(handler_with_response) { - Crow app; + SimpleApp app; CROW_ROUTE(app, "/")([](const crow::request&, crow::response&) { }); @@ -247,9 +247,9 @@ TEST(handler_with_response) TEST(server_handling_error_request) { static char buf[2048]; - Crow app; + SimpleApp app; CROW_ROUTE(app, "/")([]{return "A";}); - Server<Crow> server(&app, 45451); + Server<SimpleApp> server(&app, 45451); auto _ = async(launch::async, [&]{server.run();}); std::string sendmsg = "POX"; asio::io_service is; @@ -276,12 +276,12 @@ TEST(server_handling_error_request) TEST(multi_server) { static char buf[2048]; - Crow app1, app2; + SimpleApp app1, app2; CROW_ROUTE(app1, "/")([]{return "A";}); CROW_ROUTE(app2, "/")([]{return "B";}); - Server<Crow> server1(&app1, 45451); - Server<Crow> server2(&app2, 45452); + Server<SimpleApp> server1(&app1, 45451); + Server<SimpleApp> server2(&app2, 45452); auto _ = async(launch::async, [&]{server1.run();}); auto _2 = async(launch::async, [&]{server2.run();}); |