Continue to improve the api controller, not yet completed
This commit is contained in:
parent
5cc1ab00e5
commit
a8bc891209
|
@ -1,15 +1,33 @@
|
|||
#include <iostream>
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
|
||||
#include <drogon/HttpApiBinder.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
using namespace drogon;
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
void handle(const HttpRequest& req,std::function<void (HttpResponse &)>callback,int aa,const std::string &a,const std::string &b,int haha)
|
||||
{
|
||||
LOG_DEBUG<<"int aa="<<aa;
|
||||
LOG_DEBUG<<"string a="<<a;
|
||||
LOG_DEBUG<<"string b="<<b;
|
||||
LOG_DEBUG<<"int haha="<<haha;
|
||||
}
|
||||
};
|
||||
int main()
|
||||
{
|
||||
|
||||
std::cout<<banner<<std::endl;
|
||||
auto bindPtr=std::make_shared<drogon::HttpApiBinder<decltype(&A::handle)>>(&A::handle);
|
||||
//drogon::HttpApiBinder<A, decltype(&A::handle)> binder(&A::handle);
|
||||
// binder.test();
|
||||
|
||||
drogon::HttpAppFramework::instance().addListener("0.0.0.0",12345);
|
||||
drogon::HttpAppFramework::instance().addListener("0.0.0.0",8080);
|
||||
trantor::Logger::setLogLevel(trantor::Logger::INFO);
|
||||
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
|
||||
drogon::HttpAppFramework::instance().registerHttpApiController("/api/v1","",bindPtr);
|
||||
drogon::HttpAppFramework::instance().run();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
*
|
||||
* @file
|
||||
* @author An Tao
|
||||
* @section LICENSE
|
||||
*
|
||||
* Copyright 2018, An Tao. All rights reserved.
|
||||
* Use of this source code is governed by a MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/utils/FunctionTraits.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
namespace drogon{
|
||||
|
||||
class HttpApiBinderBase
|
||||
{
|
||||
public:
|
||||
virtual void handleHttpApiRequest(std::list<std::string> &pathParameter,
|
||||
const HttpRequest& req,std::function<void (HttpResponse &)>callback)
|
||||
=0;
|
||||
virtual ~HttpApiBinderBase(){}
|
||||
};
|
||||
typedef std::shared_ptr<HttpApiBinderBase> HttpApiBinderBasePtr;
|
||||
template <typename FUNCTION>
|
||||
class HttpApiBinder:public HttpApiBinderBase
|
||||
{
|
||||
public:
|
||||
virtual void handleHttpApiRequest(std::list<std::string> &pathParameter,
|
||||
const HttpRequest& req,std::function<void (HttpResponse &)>callback) 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="<<argument_count<<" "<<traits::isHTTPApiFunction<<std::endl;
|
||||
}
|
||||
private:
|
||||
FUNCTION _func;
|
||||
|
||||
typedef utility::FunctionTraits<FUNCTION> traits;
|
||||
template <
|
||||
std::size_t Index
|
||||
>
|
||||
using nth_argument_type = typename traits::template argument<Index>;
|
||||
|
||||
|
||||
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<std::string> &pathParameter,
|
||||
const HttpRequest& req,std::function<void (HttpResponse &)>callback,
|
||||
Values&&... values
|
||||
) {
|
||||
typedef typename std::remove_cv<typename std::remove_reference<nth_argument_type<sizeof...(Values)>>::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>(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<std::string> &pathParameter,
|
||||
const HttpRequest& req,std::function<void (HttpResponse &)>callback,
|
||||
Values&&... values
|
||||
)
|
||||
{
|
||||
//new object per time or create a object in constructor???
|
||||
std::unique_ptr<typename traits::class_type> ptr(new typename traits::class_type);
|
||||
(ptr.get()->*_func)(req,callback,std::move(values)...);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpApiBinder.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
|
@ -28,7 +29,6 @@
|
|||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
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<std::string> &filters=
|
||||
std::vector<std::string>())=0;
|
||||
virtual void registerHttpSimpleController(const std::string &pathName,
|
||||
const std::string &crtlName,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>())=0;
|
||||
virtual void registerHttpApiController(const std::string &pathName,
|
||||
const std::string ¶meterPattern,
|
||||
const HttpApiBinderBasePtr &binder,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>())=0;
|
||||
virtual void enableSession(const size_t timeout=0)=0;
|
||||
virtual void disableSession()=0;
|
||||
};
|
||||
|
|
|
@ -2,52 +2,72 @@
|
|||
|
||||
#include <tuple>
|
||||
#include<type_traits>
|
||||
namespace drogon{
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
namespace utility {
|
||||
|
||||
namespace utility {
|
||||
template<typename> struct FunctionTraits;
|
||||
|
||||
template<typename> struct FunctionTraits;
|
||||
template <typename Function>
|
||||
struct FunctionTraits : public FunctionTraits<
|
||||
decltype(&std::remove_reference<Function>::type::operator())
|
||||
> { };
|
||||
|
||||
template <typename Function>
|
||||
struct FunctionTraits : public FunctionTraits<
|
||||
decltype(&std::remove_reference<Function>::type::operator())
|
||||
> { };
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct FunctionTraits<
|
||||
ReturnType(ClassType::*)(Arguments...) const
|
||||
> : FunctionTraits<ReturnType(*)(Arguments...)> { };
|
||||
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct FunctionTraits<
|
||||
ReturnType(ClassType::*)(Arguments...) const
|
||||
> : FunctionTraits<ReturnType(*)(Arguments...)> { };
|
||||
/* 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<ReturnType(*)(Arguments...)> {
|
||||
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<ReturnType(*)(Arguments...)> { };
|
||||
|
||||
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::function<void (HttpResponse &)>callback,Arguments...)
|
||||
> : FunctionTraits<ReturnType(*)(Arguments...)> {
|
||||
static const bool isHTTPApiFunction=true;
|
||||
typedef ClassType class_type;
|
||||
};
|
||||
|
||||
template <std::size_t Index>
|
||||
using argument = typename std::tuple_element<
|
||||
Index,
|
||||
std::tuple<Arguments...>
|
||||
>::type;
|
||||
template <
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct FunctionTraits<
|
||||
ReturnType(*)(Arguments...)
|
||||
> {
|
||||
typedef ReturnType result_type;
|
||||
|
||||
static const std::size_t arity = sizeof...(Arguments);
|
||||
};
|
||||
template <std::size_t Index>
|
||||
using argument = typename std::tuple_element<
|
||||
Index,
|
||||
std::tuple<Arguments...>
|
||||
>::type;
|
||||
|
||||
static const std::size_t arity = sizeof...(Arguments);
|
||||
|
||||
static const bool isHTTPApiFunction=false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ namespace drogon
|
|||
virtual void run() override ;
|
||||
virtual void registerHttpSimpleController(const std::string &pathName,const std::string &crtlName,const std::vector<std::string> &filters=
|
||||
std::vector<std::string>())override ;
|
||||
virtual void registerHttpApiController(const std::string &pathName,
|
||||
const std::string ¶meterPattern,
|
||||
const HttpApiBinderBasePtr &binder,
|
||||
const std::vector<std::string> &filters=std::vector<std::string>()) 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<std::string,ControllerAndFiltersName>_simpCtrlMap;
|
||||
std::mutex _simpCtrlMutex;
|
||||
|
||||
struct ApiBinder
|
||||
{
|
||||
std::string parameterPattern;
|
||||
HttpApiBinderBasePtr binderPtr;
|
||||
std::vector<std::string> filtersName;
|
||||
};
|
||||
std::unordered_map<std::string,ApiBinder>_apiCtrlMap;
|
||||
std::mutex _apiCtrlMutex;
|
||||
|
||||
bool _enableLastModify=true;
|
||||
std::set<std::string> _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<std::string> &filters)
|
||||
{
|
||||
assert(!pathName.empty());
|
||||
assert(binder);
|
||||
std::string path(pathName);
|
||||
std::transform(pathName.begin(),pathName.end(),path.begin(),tolower);
|
||||
std::lock_guard<std::mutex> 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<v
|
|||
/*find controller*/
|
||||
std::string pathLower(req.path());
|
||||
std::transform(pathLower.begin(),pathLower.end(),pathLower.begin(),tolower);
|
||||
//fix me!need mutex;
|
||||
if(_simpCtrlMap.find(pathLower)!=_simpCtrlMap.end())
|
||||
{
|
||||
auto filters=_simpCtrlMap[pathLower].filtersName;
|
||||
|
@ -259,7 +288,17 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequest& req,std::function<v
|
|||
LOG_ERROR << "can't find controller " << ctrlName;
|
||||
}
|
||||
}
|
||||
|
||||
//find api controller
|
||||
//fix me!need mutex;
|
||||
if(_apiCtrlMap.find(pathLower)!=_apiCtrlMap.end())
|
||||
{
|
||||
//for test;
|
||||
LOG_DEBUG<<"got api controller";
|
||||
std::list<std::string> 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)
|
||||
|
|
Loading…
Reference in New Issue