Merge pull request #42 from an-tao/dev
Optimize filters and controllers
This commit is contained in:
commit
26e3cff668
|
@ -15,5 +15,9 @@ class TestController : public drogon::HttpSimpleController<TestController>
|
|||
PATH_ADD("/tpost", Post);
|
||||
PATH_ADD("/slow", "TimeFilter", Get);
|
||||
PATH_LIST_END
|
||||
TestController()
|
||||
{
|
||||
LOG_DEBUG << "TestController constructor";
|
||||
}
|
||||
};
|
||||
} // namespace example
|
||||
|
|
|
@ -13,4 +13,8 @@ class TimeFilter : public drogon::HttpFilter<TimeFilter>
|
|||
virtual void doFilter(const HttpRequestPtr &req,
|
||||
const FilterCallback &cb,
|
||||
const FilterChainCallback &ccb) override;
|
||||
TimeFilter()
|
||||
{
|
||||
LOG_DEBUG << "TimeFilter constructor";
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
|
|||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(ApiTest::rootGet, "", "TimeFilter", Get, "drogon::LocalHostFilter");
|
||||
METHOD_ADD(ApiTest::rootGet, "", "TimeFilter", Get, "drogon::LocalHostFilter", "drogon::InnerIpFilter");
|
||||
METHOD_ADD(ApiTest::rootPost, "", Post);
|
||||
METHOD_ADD(ApiTest::get, "/get/{2}/{1}", Get); //path will be /api/v1/apitest/get/{arg2}/{arg1}
|
||||
METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path will be /api/v1/apitest/{arg1}/list
|
||||
|
@ -28,6 +28,12 @@ class ApiTest : public drogon::HttpController<ApiTest>
|
|||
void rootPost(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
void jsonTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
void formTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
|
||||
|
||||
public:
|
||||
ApiTest()
|
||||
{
|
||||
LOG_DEBUG << "ApiTest constructor!";
|
||||
}
|
||||
};
|
||||
} // namespace v1
|
||||
} // namespace api
|
||||
|
|
|
@ -32,6 +32,7 @@ class DrClassMap
|
|||
public:
|
||||
static void registerClass(const std::string &className, const DrAllocFunc &func);
|
||||
static DrObjectBase *newObject(const std::string &className);
|
||||
static const std::shared_ptr<DrObjectBase> &getSingleInstance(const std::string &className);
|
||||
static std::vector<std::string> getAllClassName();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -74,6 +74,7 @@ class HttpAppFramework : public trantor::NonCopyable
|
|||
* Usually the thread calling this method is main thread of the application;
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
virtual bool isRunning() = 0;
|
||||
|
||||
///Quit the event loop
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <iostream>
|
||||
using namespace drogon;
|
||||
//std::map <std::string,DrAllocFunc> * DrClassMap::classMap=nullptr;
|
||||
|
@ -33,6 +34,17 @@ DrObjectBase *DrClassMap::newObject(const std::string &className)
|
|||
else
|
||||
return nullptr;
|
||||
}
|
||||
const std::shared_ptr<DrObjectBase> &DrClassMap::getSingleInstance(const std::string &className)
|
||||
{
|
||||
static std::unordered_map<std::string, std::shared_ptr<DrObjectBase>> singleInstanceMap;
|
||||
static std::mutex mtx;
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
auto iter = singleInstanceMap.find(className);
|
||||
if (iter != singleInstanceMap.end())
|
||||
return iter->second;
|
||||
singleInstanceMap[className] = std::shared_ptr<DrObjectBase>(newObject(className));
|
||||
return singleInstanceMap[className];
|
||||
}
|
||||
std::vector<std::string> DrClassMap::getAllClassName()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
|
|
@ -20,25 +20,26 @@
|
|||
|
||||
using namespace drogon;
|
||||
|
||||
static void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> &chain,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
|
||||
bool needSetJsessionid,
|
||||
const std::shared_ptr<std::string> &sessionIdPtr,
|
||||
std::function<void()> &&missCallback)
|
||||
static void doFilterChains(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
|
||||
size_t index,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
|
||||
bool needSetJsessionid,
|
||||
const std::shared_ptr<std::string> &sessionIdPtr,
|
||||
std::function<void()> &&missCallback)
|
||||
{
|
||||
if (chain && chain->size() > 0)
|
||||
|
||||
if (index < filters.size())
|
||||
{
|
||||
auto filter = chain->front();
|
||||
chain->pop();
|
||||
auto &filter = filters[index];
|
||||
filter->doFilter(req,
|
||||
[=](HttpResponsePtr res) {
|
||||
if (needSetJsessionid)
|
||||
res->addCookie("JSESSIONID", *sessionIdPtr);
|
||||
(*callbackPtr)(res);
|
||||
},
|
||||
[=, missCallback = std::move(missCallback)]() mutable {
|
||||
doFilterChain(chain, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
|
||||
[=, &filters, missCallback = std::move(missCallback)]() mutable {
|
||||
doFilterChains(filters, index + 1, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -46,28 +47,31 @@ static void doFilterChain(const std::shared_ptr<std::queue<std::shared_ptr<HttpF
|
|||
missCallback();
|
||||
}
|
||||
}
|
||||
void FiltersFunction::doFilters(const std::vector<std::string> &filters,
|
||||
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> FiltersFunction::createFilters(const std::vector<std::string> &filterNames)
|
||||
{
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> filters;
|
||||
for (auto const &filter : filterNames)
|
||||
{
|
||||
auto _object = DrClassMap::getSingleInstance(filter);
|
||||
auto _filter = std::dynamic_pointer_cast<HttpFilterBase>(_object);
|
||||
if (_filter)
|
||||
filters.push_back(_filter);
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "filter " << filter << " not found";
|
||||
}
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
void FiltersFunction::doFilters(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
|
||||
bool needSetJsessionid,
|
||||
const std::shared_ptr<std::string> &sessionIdPtr,
|
||||
std::function<void()> &&missCallback)
|
||||
{
|
||||
std::shared_ptr<std::queue<std::shared_ptr<HttpFilterBase>>> filterPtrs;
|
||||
if (!filters.empty())
|
||||
{
|
||||
filterPtrs = std::make_shared<std::queue<std::shared_ptr<HttpFilterBase>>>();
|
||||
for (auto const &filter : filters)
|
||||
{
|
||||
auto _object = std::shared_ptr<DrObjectBase>(DrClassMap::newObject(filter));
|
||||
auto _filter = std::dynamic_pointer_cast<HttpFilterBase>(_object);
|
||||
if (_filter)
|
||||
filterPtrs->push(_filter);
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "filter " << filter << " not found";
|
||||
}
|
||||
}
|
||||
}
|
||||
doFilterChain(filterPtrs, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
|
||||
}
|
||||
|
||||
doFilterChains(filters, 0, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback));
|
||||
}
|
||||
|
|
|
@ -15,14 +15,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "HttpRequestImpl.h"
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
|
||||
struct FiltersFunction
|
||||
{
|
||||
static void doFilters(const std::vector<std::string> &filters,
|
||||
static std::vector<std::shared_ptr<HttpFilterBase>> createFilters(const std::vector<std::string> &filterNames);
|
||||
static void doFilters(const std::vector<std::shared_ptr<HttpFilterBase>> &filters,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::shared_ptr<const std::function<void(const HttpResponsePtr &)>> &callbackPtr,
|
||||
bool needSetJsessionid,
|
||||
|
|
|
@ -278,6 +278,8 @@ void HttpAppFrameworkImpl::run()
|
|||
std::vector<std::shared_ptr<HttpServer>> servers;
|
||||
std::vector<std::shared_ptr<EventLoopThread>> loopThreads;
|
||||
_httpCtrlsRouter.init();
|
||||
_httpSimpleCtrlsRouter.init();
|
||||
_websockCtrlsRouter.init();
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
LOG_TRACE << "thread num=" << _threadNum;
|
||||
|
|
|
@ -95,7 +95,10 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
|||
_sharedLibManagerPtr.reset();
|
||||
_sessionMapPtr.reset();
|
||||
}
|
||||
|
||||
virtual bool isRunning() override
|
||||
{
|
||||
return _running;
|
||||
}
|
||||
virtual trantor::EventLoop *loop() override;
|
||||
virtual void quit() override
|
||||
{
|
||||
|
|
|
@ -29,6 +29,13 @@ void HttpControllersRouter::init()
|
|||
std::string tmp = std::regex_replace(router._pathParameterPattern, reg, "[^/]*");
|
||||
router._regex = std::regex(router._pathParameterPattern, std::regex_constants::icase);
|
||||
regString.append("(").append(tmp).append(")|");
|
||||
for(auto &binder:router._binders)
|
||||
{
|
||||
if(binder)
|
||||
{
|
||||
binder->_filters = FiltersFunction::createFilters(binder->_filterNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (regString.length() > 0)
|
||||
regString.resize(regString.length() - 1); //remove the last '|'
|
||||
|
@ -91,7 +98,7 @@ void HttpControllersRouter::addHttpPath(const std::string &path,
|
|||
}
|
||||
auto pathParameterPattern = std::regex_replace(originPath, regex, "([^/]*)");
|
||||
auto binderInfo = CtrlBinderPtr(new CtrlBinder);
|
||||
binderInfo->_filtersName = filters;
|
||||
binderInfo->_filterNames = filters;
|
||||
binderInfo->_binderPtr = binder;
|
||||
binderInfo->_parameterPlaces = std::move(places);
|
||||
binderInfo->_queryParametersPlaces = std::move(parametersPlaces);
|
||||
|
@ -168,9 +175,9 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
|
|||
callback(res);
|
||||
return;
|
||||
}
|
||||
auto &filters = binder->_filtersName;
|
||||
if (!filters.empty())
|
||||
if (!binder->_filters.empty())
|
||||
{
|
||||
auto &filters = binder->_filters;
|
||||
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
|
||||
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
|
||||
FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "HttpResponseImpl.h"
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
@ -29,7 +30,7 @@ class HttpAppFrameworkImpl;
|
|||
class HttpControllersRouter : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
HttpControllersRouter(){}
|
||||
HttpControllersRouter() {}
|
||||
void init();
|
||||
void addHttpPath(const std::string &path,
|
||||
const internal::HttpBinderBasePtr &binder,
|
||||
|
@ -44,7 +45,8 @@ class HttpControllersRouter : public trantor::NonCopyable
|
|||
struct CtrlBinder
|
||||
{
|
||||
internal::HttpBinderBasePtr _binderPtr;
|
||||
std::vector<std::string> _filtersName;
|
||||
std::vector<std::string> _filterNames;
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
|
||||
std::vector<size_t> _parameterPlaces;
|
||||
std::map<std::string, size_t> _queryParametersPlaces;
|
||||
std::mutex _binderMtx;
|
||||
|
|
|
@ -53,7 +53,7 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string
|
|||
}
|
||||
auto &item = _simpCtrlMap[path];
|
||||
item._controllerName = ctrlName;
|
||||
item._filtersName = filters;
|
||||
item._filterNames = filters;
|
||||
item._validMethodsFlags.clear(); //There may be old data, first clear
|
||||
if (validMethods.size() > 0)
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ void HttpSimpleControllersRouter::registerHttpSimpleController(const std::string
|
|||
auto controller = item._controller;
|
||||
if (!controller)
|
||||
{
|
||||
auto _object = std::shared_ptr<DrObjectBase>(DrClassMap::newObject(ctrlName));
|
||||
auto &_object = DrClassMap::getSingleInstance(ctrlName);
|
||||
controller = std::dynamic_pointer_cast<HttpSimpleControllerBase>(_object);
|
||||
item._controller = controller;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
|
|||
return;
|
||||
}
|
||||
}
|
||||
auto &filters = ctrlInfo._filtersName;
|
||||
auto &filters = ctrlInfo._filters;
|
||||
if (!filters.empty())
|
||||
{
|
||||
auto sessionIdPtr = std::make_shared<std::string>(std::move(sessionId));
|
||||
|
@ -119,7 +119,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
|
|||
bool needSetJsessionid,
|
||||
std::string &&sessionId)
|
||||
{
|
||||
const std::string &ctrlName = item._controllerName;
|
||||
const std::string &ctrlName = item._controllerName;
|
||||
auto &controller = item._controller;
|
||||
if (controller)
|
||||
{
|
||||
|
@ -183,4 +183,13 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
|
|||
|
||||
callback(res);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSimpleControllersRouter::init()
|
||||
{
|
||||
for (auto &iter : _simpCtrlMap)
|
||||
{
|
||||
auto &item = iter.second;
|
||||
item._filters = FiltersFunction::createFilters(item._filterNames);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
#include <drogon/HttpSimpleController.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <drogon/HttpBinder.h>
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
@ -40,13 +41,15 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
|
|||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
bool needSetJsessionid,
|
||||
std::string &&sessionId);
|
||||
void init();
|
||||
|
||||
private:
|
||||
HttpControllersRouter &_httpCtrlsRouter;
|
||||
struct SimpleControllerRouterItem
|
||||
{
|
||||
std::string _controllerName;
|
||||
std::vector<std::string> _filtersName;
|
||||
std::vector<std::string> _filterNames;
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
|
||||
std::vector<int> _validMethodsFlags;
|
||||
std::shared_ptr<HttpSimpleControllerBase> _controller;
|
||||
std::shared_ptr<HttpResponse> _responsePtr;
|
||||
|
|
|
@ -35,8 +35,8 @@ void WebsocketControllersRouter::registerWebSocketController(const std::string &
|
|||
assert(ctrlPtr);
|
||||
std::lock_guard<std::mutex> guard(_websockCtrlMutex);
|
||||
|
||||
_websockCtrlMap[path].controller = ctrlPtr;
|
||||
_websockCtrlMap[path].filtersName = filters;
|
||||
_websockCtrlMap[path]._controller = ctrlPtr;
|
||||
_websockCtrlMap[path]._filterNames = filters;
|
||||
}
|
||||
|
||||
void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
|
||||
|
@ -47,33 +47,30 @@ void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
|
|||
if (!wsKey.empty())
|
||||
{
|
||||
// magic="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
WebSocketControllerBasePtr ctrlPtr;
|
||||
std::vector<std::string> filtersName;
|
||||
|
||||
std::string pathLower(req->path());
|
||||
std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), tolower);
|
||||
auto iter = _websockCtrlMap.find(pathLower);
|
||||
if (iter != _websockCtrlMap.end())
|
||||
{
|
||||
std::string pathLower(req->path());
|
||||
std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), tolower);
|
||||
std::lock_guard<std::mutex> guard(_websockCtrlMutex);
|
||||
if (_websockCtrlMap.find(pathLower) != _websockCtrlMap.end())
|
||||
auto &ctrlPtr = iter->second._controller;
|
||||
auto &filters = iter->second._filters;
|
||||
if (ctrlPtr)
|
||||
{
|
||||
ctrlPtr = _websockCtrlMap[pathLower].controller;
|
||||
filtersName = _websockCtrlMap[pathLower].filtersName;
|
||||
if (!filters.empty())
|
||||
{
|
||||
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
|
||||
FiltersFunction::doFilters(filters, req, callbackPtr, false, nullptr, [=]() mutable {
|
||||
doControllerHandler(ctrlPtr, wsKey, req, std::move(*callbackPtr), wsConnPtr);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
doControllerHandler(ctrlPtr, wsKey, req, std::move(callback), wsConnPtr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ctrlPtr)
|
||||
{
|
||||
if (!filtersName.empty())
|
||||
{
|
||||
auto callbackPtr = std::make_shared<std::function<void(const HttpResponsePtr &)>>(std::move(callback));
|
||||
FiltersFunction::doFilters(filtersName, req, callbackPtr, false, nullptr, [=]() mutable {
|
||||
doControllerHandler(ctrlPtr, wsKey, req, *callbackPtr, wsConnPtr);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
doControllerHandler(ctrlPtr, wsKey, req, callback, wsConnPtr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto resp = drogon::HttpResponse::newNotFoundResponse();
|
||||
resp->setCloseConnection(true);
|
||||
|
@ -83,7 +80,7 @@ void WebsocketControllersRouter::route(const HttpRequestImplPtr &req,
|
|||
void WebsocketControllersRouter::doControllerHandler(const WebSocketControllerBasePtr &ctrlPtr,
|
||||
std::string &wsKey,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const WebSocketConnectionPtr &wsConnPtr)
|
||||
{
|
||||
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
|
@ -101,4 +98,12 @@ void WebsocketControllersRouter::doControllerHandler(const WebSocketControllerBa
|
|||
wsConnImplPtr->setController(ctrlPtr);
|
||||
ctrlPtr->handleNewConnection(req, wsConnPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
void WebsocketControllersRouter::init()
|
||||
{
|
||||
for (auto &iter : _websockCtrlMap)
|
||||
{
|
||||
iter.second._filters = FiltersFunction::createFilters(iter.second._filterNames);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#include "HttpResponseImpl.h"
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <drogon/WebSocketController.h>
|
||||
#include <drogon/HttpFilter.h>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
@ -29,19 +30,21 @@ class HttpAppFrameworkImpl;
|
|||
class WebsocketControllersRouter : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
WebsocketControllersRouter(){}
|
||||
WebsocketControllersRouter() {}
|
||||
void registerWebSocketController(const std::string &pathName,
|
||||
const std::string &ctrlName,
|
||||
const std::vector<std::string> &filters);
|
||||
void route(const HttpRequestImplPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const WebSocketConnectionPtr &wsConnPtr);
|
||||
void init();
|
||||
|
||||
private:
|
||||
struct WebSocketControllerRouterItem
|
||||
{
|
||||
WebSocketControllerBasePtr controller;
|
||||
std::vector<std::string> filtersName;
|
||||
WebSocketControllerBasePtr _controller;
|
||||
std::vector<std::string> _filterNames;
|
||||
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
|
||||
};
|
||||
std::unordered_map<std::string, WebSocketControllerRouterItem> _websockCtrlMap;
|
||||
std::mutex _websockCtrlMutex;
|
||||
|
@ -49,7 +52,7 @@ class WebsocketControllersRouter : public trantor::NonCopyable
|
|||
void doControllerHandler(const WebSocketControllerBasePtr &ctrlPtr,
|
||||
std::string &wsKey,
|
||||
const HttpRequestImplPtr &req,
|
||||
const std::function<void(const HttpResponsePtr &)> &callback,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const WebSocketConnectionPtr &wsConnPtr);
|
||||
};
|
||||
} // namespace drogon
|
2
trantor
2
trantor
|
@ -1 +1 @@
|
|||
Subproject commit 4357d2ada95b020f0573888dd9341d40286c4224
|
||||
Subproject commit 2c78af9ea6a7dac972940f61ba12c84a9915cab0
|
Loading…
Reference in New Issue