From 3f4baf15f1431ed878739c46090e025c81fef9fd Mon Sep 17 00:00:00 2001 From: antao Date: Fri, 25 Jan 2019 16:46:20 +0800 Subject: [PATCH] Optimize filters and controllers --- examples/simple_example/TestController.h | 4 ++ examples/simple_example/TimeFilter.h | 4 ++ examples/simple_example/api_v1_ApiTest.h | 8 ++- lib/inc/drogon/DrClassMap.h | 1 + lib/inc/drogon/HttpAppFramework.h | 1 + lib/src/DrClassMap.cc | 12 +++++ lib/src/FiltersFunction.cc | 64 +++++++++++++----------- lib/src/FiltersFunction.h | 6 ++- lib/src/HttpAppFrameworkImpl.cc | 2 + lib/src/HttpAppFrameworkImpl.h | 5 +- lib/src/HttpControllersRouter.cc | 13 +++-- lib/src/HttpControllersRouter.h | 6 ++- lib/src/HttpSimpleControllersRouter.cc | 17 +++++-- lib/src/HttpSimpleControllersRouter.h | 5 +- lib/src/WebsocketControllersRouter.cc | 57 +++++++++++---------- lib/src/WebsocketControllersRouter.h | 11 ++-- trantor | 2 +- 17 files changed, 144 insertions(+), 74 deletions(-) diff --git a/examples/simple_example/TestController.h b/examples/simple_example/TestController.h index ac4f364b..c22aa358 100755 --- a/examples/simple_example/TestController.h +++ b/examples/simple_example/TestController.h @@ -15,5 +15,9 @@ class TestController : public drogon::HttpSimpleController PATH_ADD("/tpost", Post); PATH_ADD("/slow", "TimeFilter", Get); PATH_LIST_END + TestController() + { + LOG_DEBUG << "TestController constructor"; + } }; } // namespace example diff --git a/examples/simple_example/TimeFilter.h b/examples/simple_example/TimeFilter.h index 40ce461a..3693c677 100755 --- a/examples/simple_example/TimeFilter.h +++ b/examples/simple_example/TimeFilter.h @@ -13,4 +13,8 @@ class TimeFilter : public drogon::HttpFilter virtual void doFilter(const HttpRequestPtr &req, const FilterCallback &cb, const FilterChainCallback &ccb) override; + TimeFilter() + { + LOG_DEBUG << "TimeFilter constructor"; + } }; diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index 8028df49..75508f27 100755 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -10,7 +10,7 @@ class ApiTest : public drogon::HttpController 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 void rootPost(const HttpRequestPtr &req, const std::function &callback); void jsonTest(const HttpRequestPtr &req, const std::function &callback); void formTest(const HttpRequestPtr &req, const std::function &callback); + + public: + ApiTest() + { + LOG_DEBUG << "ApiTest constructor!"; + } }; } // namespace v1 } // namespace api diff --git a/lib/inc/drogon/DrClassMap.h b/lib/inc/drogon/DrClassMap.h index a6a3f93f..0b08a703 100755 --- a/lib/inc/drogon/DrClassMap.h +++ b/lib/inc/drogon/DrClassMap.h @@ -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 &getSingleInstance(const std::string &className); static std::vector getAllClassName(); protected: diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index 5af366cd..aed33edc 100755 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -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 /** diff --git a/lib/src/DrClassMap.cc b/lib/src/DrClassMap.cc index 8eafe7bc..1d0475f2 100755 --- a/lib/src/DrClassMap.cc +++ b/lib/src/DrClassMap.cc @@ -13,6 +13,7 @@ */ #include +#include #include using namespace drogon; //std::map * DrClassMap::classMap=nullptr; @@ -33,6 +34,17 @@ DrObjectBase *DrClassMap::newObject(const std::string &className) else return nullptr; } +const std::shared_ptr &DrClassMap::getSingleInstance(const std::string &className) +{ + static std::unordered_map> singleInstanceMap; + static std::mutex mtx; + std::lock_guard lock(mtx); + auto iter = singleInstanceMap.find(className); + if (iter != singleInstanceMap.end()) + return iter->second; + singleInstanceMap[className] = std::shared_ptr(newObject(className)); + return singleInstanceMap[className]; +} std::vector DrClassMap::getAllClassName() { std::vector ret; diff --git a/lib/src/FiltersFunction.cc b/lib/src/FiltersFunction.cc index e037fa8f..39aad82a 100644 --- a/lib/src/FiltersFunction.cc +++ b/lib/src/FiltersFunction.cc @@ -20,25 +20,26 @@ using namespace drogon; -static void doFilterChain(const std::shared_ptr>> &chain, - const HttpRequestImplPtr &req, - const std::shared_ptr> &callbackPtr, - bool needSetJsessionid, - const std::shared_ptr &sessionIdPtr, - std::function &&missCallback) +static void doFilterChains(const std::vector> &filters, + size_t index, + const HttpRequestImplPtr &req, + const std::shared_ptr> &callbackPtr, + bool needSetJsessionid, + const std::shared_ptr &sessionIdPtr, + std::function &&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 &filters, + +std::vector> FiltersFunction::createFilters(const std::vector &filterNames) +{ + std::vector> filters; + for (auto const &filter : filterNames) + { + auto _object = DrClassMap::getSingleInstance(filter); + auto _filter = std::dynamic_pointer_cast(_object); + if (_filter) + filters.push_back(_filter); + else + { + LOG_ERROR << "filter " << filter << " not found"; + } + } + return filters; +} + +void FiltersFunction::doFilters(const std::vector> &filters, const HttpRequestImplPtr &req, const std::shared_ptr> &callbackPtr, bool needSetJsessionid, const std::shared_ptr &sessionIdPtr, std::function &&missCallback) { - std::shared_ptr>> filterPtrs; - if (!filters.empty()) - { - filterPtrs = std::make_shared>>(); - for (auto const &filter : filters) - { - auto _object = std::shared_ptr(DrClassMap::newObject(filter)); - auto _filter = std::dynamic_pointer_cast(_object); - if (_filter) - filterPtrs->push(_filter); - else - { - LOG_ERROR << "filter " << filter << " not found"; - } - } - } - doFilterChain(filterPtrs, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback)); -} \ No newline at end of file + + doFilterChains(filters, 0, req, callbackPtr, needSetJsessionid, sessionIdPtr, std::move(missCallback)); +} diff --git a/lib/src/FiltersFunction.h b/lib/src/FiltersFunction.h index 97d0e2b1..2f4c9e79 100644 --- a/lib/src/FiltersFunction.h +++ b/lib/src/FiltersFunction.h @@ -15,14 +15,18 @@ #pragma once #include "HttpRequestImpl.h" +#include #include #include +#include + namespace drogon { struct FiltersFunction { - static void doFilters(const std::vector &filters, + static std::vector> createFilters(const std::vector &filterNames); + static void doFilters(const std::vector> &filters, const HttpRequestImplPtr &req, const std::shared_ptr> &callbackPtr, bool needSetJsessionid, diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 1690db76..763a1cef 100755 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -278,6 +278,8 @@ void HttpAppFrameworkImpl::run() std::vector> servers; std::vector> loopThreads; _httpCtrlsRouter.init(); + _httpSimpleCtrlsRouter.init(); + _websockCtrlsRouter.init(); for (auto const &listener : _listeners) { LOG_TRACE << "thread num=" << _threadNum; diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index 88c1c4bb..3f91d090 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -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 { diff --git a/lib/src/HttpControllersRouter.cc b/lib/src/HttpControllersRouter.cc index a618fb05..e717aba8 100644 --- a/lib/src/HttpControllersRouter.cc +++ b/lib/src/HttpControllersRouter.cc @@ -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::move(sessionId)); auto callbackPtr = std::make_shared>(std::move(callback)); FiltersFunction::doFilters(filters, req, callbackPtr, needSetJsessionid, sessionIdPtr, [=, &binder, &routerItem]() { diff --git a/lib/src/HttpControllersRouter.h b/lib/src/HttpControllersRouter.h index 2d2582b1..e047e608 100644 --- a/lib/src/HttpControllersRouter.h +++ b/lib/src/HttpControllersRouter.h @@ -17,6 +17,7 @@ #include "HttpResponseImpl.h" #include #include +#include #include #include #include @@ -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 _filtersName; + std::vector _filterNames; + std::vector> _filters; std::vector _parameterPlaces; std::map _queryParametersPlaces; std::mutex _binderMtx; diff --git a/lib/src/HttpSimpleControllersRouter.cc b/lib/src/HttpSimpleControllersRouter.cc index 6bdfecb7..d5f75275 100644 --- a/lib/src/HttpSimpleControllersRouter.cc +++ b/lib/src/HttpSimpleControllersRouter.cc @@ -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(DrClassMap::newObject(ctrlName)); + auto &_object = DrClassMap::getSingleInstance(ctrlName); controller = std::dynamic_pointer_cast(_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::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); + } } \ No newline at end of file diff --git a/lib/src/HttpSimpleControllersRouter.h b/lib/src/HttpSimpleControllersRouter.h index 782479ac..3fd7cd43 100644 --- a/lib/src/HttpSimpleControllersRouter.h +++ b/lib/src/HttpSimpleControllersRouter.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -40,13 +41,15 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable std::function &&callback, bool needSetJsessionid, std::string &&sessionId); + void init(); private: HttpControllersRouter &_httpCtrlsRouter; struct SimpleControllerRouterItem { std::string _controllerName; - std::vector _filtersName; + std::vector _filterNames; + std::vector> _filters; std::vector _validMethodsFlags; std::shared_ptr _controller; std::shared_ptr _responsePtr; diff --git a/lib/src/WebsocketControllersRouter.cc b/lib/src/WebsocketControllersRouter.cc index 20eb21be..6756efe7 100644 --- a/lib/src/WebsocketControllersRouter.cc +++ b/lib/src/WebsocketControllersRouter.cc @@ -35,8 +35,8 @@ void WebsocketControllersRouter::registerWebSocketController(const std::string & assert(ctrlPtr); std::lock_guard 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 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 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::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::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 &callback, + std::function &&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); + } } \ No newline at end of file diff --git a/lib/src/WebsocketControllersRouter.h b/lib/src/WebsocketControllersRouter.h index 4b633132..2c0db1a7 100644 --- a/lib/src/WebsocketControllersRouter.h +++ b/lib/src/WebsocketControllersRouter.h @@ -17,6 +17,7 @@ #include "HttpResponseImpl.h" #include #include +#include #include #include #include @@ -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 &filters); void route(const HttpRequestImplPtr &req, std::function &&callback, const WebSocketConnectionPtr &wsConnPtr); + void init(); private: struct WebSocketControllerRouterItem { - WebSocketControllerBasePtr controller; - std::vector filtersName; + WebSocketControllerBasePtr _controller; + std::vector _filterNames; + std::vector> _filters; }; std::unordered_map _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 &callback, + std::function &&callback, const WebSocketConnectionPtr &wsConnPtr); }; } // namespace drogon \ No newline at end of file diff --git a/trantor b/trantor index 4357d2ad..2c78af9e 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit 4357d2ada95b020f0573888dd9341d40286c4224 +Subproject commit 2c78af9ea6a7dac972940f61ba12c84a9915cab0