From a8bc89120943e80e7087ece924d890a098eb7dfb Mon Sep 17 00:00:00 2001 From: an-tao <20741618@qq.com> Date: Mon, 4 Jun 2018 19:00:35 +0800 Subject: [PATCH] Continue to improve the api controller, not yet completed --- examples/static_link_example/main.cc | 24 +++++- lib/inc/drogon/HttpApiBinder.h | 102 ++++++++++++++++++++++++++ lib/inc/drogon/HttpAppFramework.h | 11 ++- lib/inc/drogon/utils/FunctionTraits.h | 98 +++++++++++++++---------- lib/src/HttpAppFramework.cc | 41 ++++++++++- 5 files changed, 230 insertions(+), 46 deletions(-) create mode 100755 lib/inc/drogon/HttpApiBinder.h diff --git a/examples/static_link_example/main.cc b/examples/static_link_example/main.cc index 155caccf..d0ee77b3 100755 --- a/examples/static_link_example/main.cc +++ b/examples/static_link_example/main.cc @@ -1,15 +1,33 @@ #include #include #include - +#include +#include +#include using namespace drogon; - +class A +{ +public: + void handle(const HttpRequest& req,std::functioncallback,int aa,const std::string &a,const std::string &b,int haha) + { + LOG_DEBUG<<"int aa="< +#include +#include +#include +#include +#include +#include +namespace drogon{ + + class HttpApiBinderBase + { + public: + virtual void handleHttpApiRequest(std::list &pathParameter, + const HttpRequest& req,std::functioncallback) + =0; + virtual ~HttpApiBinderBase(){} + }; + typedef std::shared_ptr HttpApiBinderBasePtr; + template + class HttpApiBinder:public HttpApiBinderBase + { + public: + virtual void handleHttpApiRequest(std::list &pathParameter, + const HttpRequest& req,std::functioncallback) override + { + run(pathParameter,req,callback); + } + HttpApiBinder(FUNCTION func): + _func(func) + { + static_assert(traits::isHTTPApiFunction,"Your API handler function interface is wrong!"); + } + void test(){ + std::cout<<"argument_count="< traits; + template < + std::size_t Index + > + using nth_argument_type = typename traits::template argument; + + + static const size_t argument_count = traits::arity; + + template< + typename... Values, + std::size_t Boundary = argument_count + > + typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run( + std::list &pathParameter, + const HttpRequest& req,std::functioncallback, + Values&&... values + ) { + typedef typename std::remove_cv>::type>::type ValueType; + ValueType value; + if(!pathParameter.empty()) + { + std::string v=std::move(pathParameter.front()); + pathParameter.pop_front(); + + std::stringstream ss(std::move(v)); + ss>>value; + + } + + run(pathParameter,req,callback, std::forward(values)..., std::move(value)); + } + template< + typename... Values, + std::size_t Boundary = argument_count + > + typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run( + std::list &pathParameter, + const HttpRequest& req,std::functioncallback, + Values&&... values + ) + { + //new object per time or create a object in constructor??? + std::unique_ptr ptr(new typename traits::class_type); + (ptr.get()->*_func)(req,callback,std::move(values)...); + } + }; +} \ No newline at end of file diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index 381bac68..fd130840 100755 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -14,6 +14,7 @@ #pragma once +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include - namespace drogon { //the drogon banner @@ -53,8 +53,13 @@ namespace drogon virtual void addListener(const std::string &ip,uint16_t port)=0; virtual void run()=0; virtual ~HttpAppFramework(); - virtual void registerHttpSimpleController(const std::string &pathName,const std::string &crtlName,const std::vector &filters= - std::vector())=0; + virtual void registerHttpSimpleController(const std::string &pathName, + const std::string &crtlName, + const std::vector &filters=std::vector())=0; + virtual void registerHttpApiController(const std::string &pathName, + const std::string ¶meterPattern, + const HttpApiBinderBasePtr &binder, + const std::vector &filters=std::vector())=0; virtual void enableSession(const size_t timeout=0)=0; virtual void disableSession()=0; }; diff --git a/lib/inc/drogon/utils/FunctionTraits.h b/lib/inc/drogon/utils/FunctionTraits.h index a23abd67..9d43f2eb 100755 --- a/lib/inc/drogon/utils/FunctionTraits.h +++ b/lib/inc/drogon/utils/FunctionTraits.h @@ -2,52 +2,72 @@ #include #include +namespace drogon{ + class HttpRequest; + class HttpResponse; + namespace utility { -namespace utility { + template struct FunctionTraits; - template struct FunctionTraits; + template + struct FunctionTraits : public FunctionTraits< + decltype(&std::remove_reference::type::operator()) + > { }; - template - struct FunctionTraits : public FunctionTraits< - decltype(&std::remove_reference::type::operator()) - > { }; + template < + typename ClassType, + typename ReturnType, + typename... Arguments + > + struct FunctionTraits< + ReturnType(ClassType::*)(Arguments...) const + > : FunctionTraits { }; - template < - typename ClassType, - typename ReturnType, - typename... Arguments - > - struct FunctionTraits< - ReturnType(ClassType::*)(Arguments...) const - > : FunctionTraits { }; + /* support the non-const operator () + * this will work with user defined functors */ + template < + typename ClassType, + typename ReturnType, + typename... Arguments + > + struct FunctionTraits< + ReturnType(ClassType::*)(Arguments...) + > : FunctionTraits { + static const bool isClassFunction=true; + }; - /* support the non-const operator () - * this will work with user defined functors */ - template < - typename ClassType, - typename ReturnType, - typename... Arguments - > - struct FunctionTraits< - ReturnType(ClassType::*)(Arguments...) - > : FunctionTraits { }; - template < - typename ReturnType, - typename... Arguments - > - struct FunctionTraits< - ReturnType(*)(Arguments...) - > { - typedef ReturnType result_type; + template < + typename ClassType, + typename ReturnType, + typename... Arguments + > + struct FunctionTraits< + ReturnType(ClassType::*)(const HttpRequest& req,std::functioncallback,Arguments...) + > : FunctionTraits { + static const bool isHTTPApiFunction=true; + typedef ClassType class_type; + }; - template - using argument = typename std::tuple_element< - Index, - std::tuple - >::type; + template < + typename ReturnType, + typename... Arguments + > + struct FunctionTraits< + ReturnType(*)(Arguments...) + > { + typedef ReturnType result_type; - static const std::size_t arity = sizeof...(Arguments); - }; + template + using argument = typename std::tuple_element< + Index, + std::tuple + >::type; + static const std::size_t arity = sizeof...(Arguments); + + static const bool isHTTPApiFunction=false; + }; + + } } diff --git a/lib/src/HttpAppFramework.cc b/lib/src/HttpAppFramework.cc index 15c7ef95..d0f1c5ea 100755 --- a/lib/src/HttpAppFramework.cc +++ b/lib/src/HttpAppFramework.cc @@ -40,6 +40,10 @@ namespace drogon virtual void run() override ; virtual void registerHttpSimpleController(const std::string &pathName,const std::string &crtlName,const std::vector &filters= std::vector())override ; + virtual void registerHttpApiController(const std::string &pathName, + const std::string ¶meterPattern, + const HttpApiBinderBasePtr &binder, + const std::vector &filters=std::vector()) override ; virtual void enableSession(const size_t timeout) override { _useSession=true;_sessionTimeout=timeout;} virtual void disableSession() override { _useSession=false;} ~HttpAppFrameworkImpl(){} @@ -64,6 +68,15 @@ namespace drogon std::unordered_map_simpCtrlMap; std::mutex _simpCtrlMutex; + struct ApiBinder + { + std::string parameterPattern; + HttpApiBinderBasePtr binderPtr; + std::vector filtersName; + }; + std::unordered_map_apiCtrlMap; + std::mutex _apiCtrlMutex; + bool _enableLastModify=true; std::set _fileTypeSet={"html","jpg"}; std::string _rootPath; @@ -92,6 +105,21 @@ void HttpAppFrameworkImpl::registerHttpSimpleController(const std::string &pathN _simpCtrlMap[path].controllerName=crtlName; _simpCtrlMap[path].filtersName=filters; } +void HttpAppFrameworkImpl::registerHttpApiController(const std::string &pathName, + const std::string ¶meterPattern, + const HttpApiBinderBasePtr &binder, + const std::vector &filters) +{ + assert(!pathName.empty()); + assert(binder); + std::string path(pathName); + std::transform(pathName.begin(),pathName.end(),path.begin(),tolower); + std::lock_guard guard(_apiCtrlMutex); + + _apiCtrlMap[path].parameterPattern=parameterPattern; + _apiCtrlMap[path].binderPtr=binder; + _apiCtrlMap[path].filtersName=filters; +} void HttpAppFrameworkImpl::addListener(const std::string &ip, uint16_t port) { _listeners.push_back(std::make_pair(ip,port)); @@ -217,6 +245,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequest& req,std::function para={"1","2","3","4.5","5"}; + auto binder=_apiCtrlMap[pathLower]; + binder.binderPtr->handleHttpApiRequest(para,req,callback); + return; + } auto res=drogon::HttpResponse::notFoundResponse(); if(needSetJsessionid)