diff --git a/.clang-format b/.clang-format index 234f6b5830..0f2775cdeb 100644 --- a/.clang-format +++ b/.clang-format @@ -124,6 +124,7 @@ RawStringFormats: CanonicalDelimiter: '' BasedOnStyle: google ReflowComments: true +SeparateDefinitionBlocks: Always SortIncludes: false SortUsingDeclarations: true SpaceAfterCStyleCast: false diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 2149c377b3..837cf8f16b 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -67,25 +67,20 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-20.04 - buildname: 'ubuntu-20.04/gcc' + - os: ubuntu-22.04 + buildname: 'ubuntu-22.04/gcc' link: SHARED triplet: x64-linux compiler: gcc_64 - - os: ubuntu-20.04 - buildname: 'ubuntu-20.04/gcc' + - os: ubuntu-22.04 + buildname: 'ubuntu-22.04/gcc' link: STATIC triplet: x64-linux compiler: gcc_64 - - os: ubuntu-20.04 - buildname: 'ubuntu-20.04/gcc-10' + - os: ubuntu-22.04 + buildname: 'ubuntu-22.04/gcc-10' link: STATIC triplet: x64-linux - - os: ubuntu-20.04 - buildname: 'ubuntu-20.04/c++14' - link: STATIC - triplet: x64-linux - compiler: gcc_64 - os: macos-latest buildname: 'macos/clang' link: STATIC @@ -112,18 +107,14 @@ jobs: sudo apt-get install -y libjsoncpp-dev uuid-dev libssl-dev zlib1g-dev libsqlite3-dev sudo apt-get install -y libbrotli-dev - name: (Linux) Install gcc-10 - if: matrix.buildname == 'ubuntu-20.04/gcc-10' + if: matrix.buildname == 'ubuntu-22.04/gcc-10' run: sudo apt-get install -y gcc-10 g++-10 - - name: (Linux) Install boost - if: matrix.buildname == 'ubuntu-20.04/c++14' - run: | - sudo apt-get update - sudo apt-get -y install libboost-all-dev - name: (Linux) Install postgresql - if: matrix.os == 'ubuntu-20.04' - run: sudo apt-get -y install postgresql-all - + if: matrix.os == 'ubuntu-22.04' + run: | + sudo apt-get --purge remove postgresql postgresql-doc postgresql-common postgresql-client-common + sudo apt-get -y install postgresql-all - name: Export `shared` run: | [[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF" @@ -132,7 +123,7 @@ jobs: - name: Create Build Environment & Configure Cmake # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands - if: matrix.buildname != 'ubuntu-20.04/gcc-10' && matrix.buildname != 'ubuntu-20.04/c++14' + if: matrix.buildname != 'ubuntu-22.04/gcc-10' run: | cmake -B build \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ @@ -142,7 +133,7 @@ jobs: - name: Create Build Environment & Configure Cmake (gcc-10) # Some projects don't allow in-source building, so create a separate build directory # We'll use this as our working directory for all subsequent commands - if: matrix.buildname == 'ubuntu-20.04/gcc-10' + if: matrix.buildname == 'ubuntu-22.04/gcc-10' run: | cmake -B build \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ @@ -153,17 +144,6 @@ jobs: CC: gcc-10 CXX: g++-10 - - name: Create Build Environment & Configure Cmake (C++14) - # Some projects don't allow in-source building, so create a separate build directory - # We'll use this as our working directory for all subsequent commands - if: matrix.buildname == 'ubuntu-20.04/C++14' - run: | - cmake -B build \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DBUILD_TESTING=on \ - -DCMAKE_CXX_STANDARD=14 \ - -DBUILD_SHARED_LIBS=$shared - - name: Build working-directory: ./build # Execute the build. You can specify a specific target with "--target " @@ -197,7 +177,7 @@ jobs: run: ./test.sh -t - name: Lint - if: matrix.os == 'ubuntu-20.04' + if: matrix.os == 'ubuntu-22.04' run: | sudo apt install -y dos2unix ./format.sh && git diff --exit-code diff --git a/CMakeLists.txt b/CMakeLists.txt index fbe2288e8f..356fe2fad2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,10 +88,8 @@ if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "") set(DROGON_CXX_STANDARD ${CMAKE_CXX_STANDARD}) elseif (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE) set(DROGON_CXX_STANDARD 20) -elseif (HAS_ANY AND HAS_STRING_VIEW) - set(DROGON_CXX_STANDARD 17) else () - set(DROGON_CXX_STANDARD 14) + set(DROGON_CXX_STANDARD 17) endif () if(USE_SUBMODULE) target_include_directories( @@ -135,69 +133,37 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/) find_package(Filesystem COMPONENTS Final) if(CXX_FILESYSTEM_HAVE_FS) message(STATUS "Found std::filesystem") +else () + message(FATAL_ERROR "Not found std::filesystem, please use a newer compiler") endif() -# Check for C++ filesystem support -set(NEED_BOOST_FS 0) -if (DROGON_CXX_STANDARD EQUAL 14) - # With C++14, use Boost to support any and string_view - message(STATUS "use c++14") - find_package(Boost 1.61.0 REQUIRED) - message(STATUS "Using Boost filesystem, string_view and any") - message(STATUS "Boost include dir: " ${Boost_INCLUDE_DIR}) - target_link_libraries(${PROJECT_NAME} PUBLIC Boost::boost) - list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${Boost_INCLUDE_DIR}) - set(NEED_BOOST_FS 1) -elseif (DROGON_CXX_STANDARD EQUAL 17) - # With C++17, use Boost if std::filesystem::path is missing +if (DROGON_CXX_STANDARD EQUAL 17) message(STATUS "use c++17") - # Check for partial implementation of c++17 (Windows/OSX only?) - if (CXX_FILESYSTEM_HAVE_FS) - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - try_compile(check_filesystem_path ${CMAKE_BINARY_DIR}/cmaketest - ${PROJECT_SOURCE_DIR}/cmake/tests/check_has_std_filesystem_path.cc - CXX_STANDARD 17) - set(CMAKE_TRY_COMPILE_TARGET_TYPE) - if (NOT check_filesystem_path) - message(STATUS "The std::filesystem seems to be a partial implementation" - " Falling back to boost::filesystem") - set(NEED_BOOST_FS 1) - endif() - else() - set(NEED_BOOST_FS 1) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + try_compile(check_filesystem_path ${CMAKE_BINARY_DIR}/cmaketest + ${PROJECT_SOURCE_DIR}/cmake/tests/check_has_std_filesystem_path.cc + CXX_STANDARD 17) + set(CMAKE_TRY_COMPILE_TARGET_TYPE) + if (NOT check_filesystem_path) + message(FATAL_ERROR "The std::filesystem seems to be a partial implementation," + " please use a newer compiler") endif() else () message(STATUS "use c++20") endif () -# Workaround: 2021-08-09 Android NDK does not provide proper std::filesystem -# support. Force boost::filesystem instead. -if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") - message(STATUS "WORKAROUND: Forcing boost::filesystem on Android") - set(NEED_BOOST_FS 1) -endif () -if(NEED_BOOST_FS) - find_package(Boost 1.49.0 COMPONENTS filesystem system REQUIRED) - message(STATUS "Using Boost filesytem::path") - message(STATUS "Boost include dir: " ${Boost_INCLUDE_DIR}) - include_directories(${BOOST_INCLUDE_DIRS}) - message(STATUS "Boost libraries: " ${Boost_LIBRARIES}) - target_link_libraries(${PROJECT_NAME} PUBLIC Boost::filesystem Boost::system) - list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${Boost_INCLUDE_DIR}) - option(HAS_STD_FILESYSTEM_PATH "use boost::filesystem" OFF) -else() - option(HAS_STD_FILESYSTEM_PATH "use std::filesystem" ON) - # HACK: Needed to be compiled on Yocto Linux - if(TARGET std::filesystem) - get_property(CAN_LINK_FS TARGET std::filesystem PROPERTY INTERFACE_LINK_LIBRARIES SET) - if ( CAN_LINK_FS ) - target_link_libraries(${PROJECT_NAME} PUBLIC std::filesystem) - endif() - endif() +option(HAS_STD_FILESYSTEM_PATH "use std::filesystem" ON) +# HACK: Needed to be compiled on Yocto Linux +if(TARGET std::filesystem) + get_property(CAN_LINK_FS TARGET std::filesystem PROPERTY INTERFACE_LINK_LIBRARIES SET) + if ( CAN_LINK_FS ) + target_link_libraries(${PROJECT_NAME} PUBLIC std::filesystem) + endif() endif() + # jsoncpp find_package(Jsoncpp REQUIRED) target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_lib) @@ -316,7 +282,6 @@ set(private_headers lib/src/AOPAdvice.h lib/src/CacheFile.h lib/src/ConfigLoader.h - lib/src/filesystem.h lib/src/FiltersFunction.h lib/src/HttpAppFrameworkImpl.h lib/src/HttpClientImpl.h @@ -720,14 +685,11 @@ set(NOSQL_HEADERS install(FILES ${NOSQL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/nosql) set(DROGON_UTIL_HEADERS - lib/inc/drogon/utils/any.h lib/inc/drogon/utils/apply.h lib/inc/drogon/utils/coroutine.h lib/inc/drogon/utils/FunctionTraits.h lib/inc/drogon/utils/HttpConstraint.h - lib/inc/drogon/utils/optional.h lib/inc/drogon/utils/OStringStream.h - lib/inc/drogon/utils/string_view.h lib/inc/drogon/utils/Utilities.h) install(FILES ${DROGON_UTIL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils) diff --git a/README.md b/README.md index d200fb1a16..1a0eaa9baa 100755 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md) ### Overview -**Drogon** is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like. +**Drogon** is a C++17/20 based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like. Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows. Its main features are as follows: diff --git a/cmake/templates/DrogonConfig.cmake.in b/cmake/templates/DrogonConfig.cmake.in index 171d90182d..c1696349cd 100644 --- a/cmake/templates/DrogonConfig.cmake.in +++ b/cmake/templates/DrogonConfig.cmake.in @@ -27,10 +27,6 @@ endif() if(@MySQL_FOUND@) find_dependency(MySQL) endif() -if(@Boost_FOUND@) -find_dependency(Boost) -find_package(Boost COMPONENTS filesystem system) -endif() if(@Brotli_FOUND@) find_dependency(Brotli) endif() diff --git a/drogon_ctl/CommandHandler.h b/drogon_ctl/CommandHandler.h index 872dcec9ae..6908b2dc01 100644 --- a/drogon_ctl/CommandHandler.h +++ b/drogon_ctl/CommandHandler.h @@ -22,18 +22,22 @@ class CommandHandler : public virtual drogon::DrObjectBase { public: virtual void handleCommand(std::vector ¶meters) = 0; + virtual bool isTopCommand() { return false; } + virtual std::string script() { return ""; } + virtual std::string detail() { return ""; } + virtual ~CommandHandler() { } diff --git a/drogon_ctl/create.cc b/drogon_ctl/create.cc index 67a2da4fa9..7a24a199d8 100644 --- a/drogon_ctl/create.cc +++ b/drogon_ctl/create.cc @@ -18,6 +18,7 @@ #include #include using namespace drogon_ctl; + std::string create::detail() { return "Use create command to create some source files of drogon webapp\n\n" diff --git a/drogon_ctl/create.h b/drogon_ctl/create.h index ba72bfaea7..6b55aae5b9 100644 --- a/drogon_ctl/create.h +++ b/drogon_ctl/create.h @@ -17,21 +17,25 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create some source files(Use 'drogon_ctl help create' for more " "information)"; } + bool isTopCommand() override { return true; } + std::string detail() override; }; } // namespace drogon_ctl diff --git a/drogon_ctl/create_controller.cc b/drogon_ctl/create_controller.cc index 3e484418d2..fb4d6acbfd 100644 --- a/drogon_ctl/create_controller.cc +++ b/drogon_ctl/create_controller.cc @@ -135,6 +135,7 @@ void create_controller::newSimpleControllerHeaderFile( file << "}\n"; } } + void create_controller::newSimpleControllerSourceFile( std::ofstream &file, const std::string &className, @@ -207,6 +208,7 @@ void create_controller::newWebsockControllerHeaderFile( file << "}\n"; } } + void create_controller::newWebsockControllerSourceFile( std::ofstream &file, const std::string &className, @@ -303,6 +305,7 @@ void create_controller::newHttpControllerHeaderFile( file << "}\n"; } } + void create_controller::newHttpControllerSourceFile( std::ofstream &file, const std::string &className, diff --git a/drogon_ctl/create_controller.h b/drogon_ctl/create_controller.h index ed6191df70..f0339a3ffe 100644 --- a/drogon_ctl/create_controller.h +++ b/drogon_ctl/create_controller.h @@ -18,6 +18,7 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create_controller : public DrObject, @@ -25,6 +26,7 @@ class create_controller : public DrObject, { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create controller files"; diff --git a/drogon_ctl/create_filter.cc b/drogon_ctl/create_filter.cc index 3d909544b8..33dac3350c 100644 --- a/drogon_ctl/create_filter.cc +++ b/drogon_ctl/create_filter.cc @@ -69,6 +69,7 @@ static void createFilterSourceFile(std::ofstream &file, data.insert("filename", fileName); file << templ->genText(data); } + void create_filter::handleCommand(std::vector ¶meters) { if (parameters.size() < 1) diff --git a/drogon_ctl/create_filter.h b/drogon_ctl/create_filter.h index 141e60b374..5af6cd3df0 100644 --- a/drogon_ctl/create_filter.h +++ b/drogon_ctl/create_filter.h @@ -17,12 +17,14 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create_filter : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create filter class files"; diff --git a/drogon_ctl/create_model.cc b/drogon_ctl/create_model.cc index 5b62fc25a4..e3b88c2aca 100644 --- a/drogon_ctl/create_model.cc +++ b/drogon_ctl/create_model.cc @@ -36,6 +36,7 @@ using namespace std::chrono_literals; using namespace drogon_ctl; + static std::string toLower(const std::string &str) { auto ret = str; @@ -389,6 +390,7 @@ void create_model::createModelClassFromPG( sourceFile << templ->genText(data); createRestfulAPIController(data, restfulApiConfig); } + void create_model::createModelFromPG( const std::string &path, const DbClientPtr &client, @@ -584,6 +586,7 @@ void create_model::createModelClassFromMysql( sourceFile << templ->genText(data); createRestfulAPIController(data, restfulApiConfig); } + void create_model::createModelFromMysql( const std::string &path, const DbClientPtr &client, @@ -1112,6 +1115,7 @@ void create_model::createModel(const std::string &path, exit(1); } } + void create_model::createModel(const std::string &path, const std::string &singleModelName) { diff --git a/drogon_ctl/create_model.h b/drogon_ctl/create_model.h index dfdf088eee..577ad5e340 100644 --- a/drogon_ctl/create_model.h +++ b/drogon_ctl/create_model.h @@ -77,10 +77,12 @@ inline std::string nameTransform(const std::string &origName, bool isType) ret[0] += ('A' - 'a'); return ret; } + class PivotTable { public: PivotTable() = default; + PivotTable(const Json::Value &json) : tableName_(json.get("table_name", "").asString()) { @@ -99,6 +101,7 @@ class PivotTable throw std::runtime_error("target_key can't be empty"); } } + PivotTable reverse() const { PivotTable pivot; @@ -107,14 +110,17 @@ class PivotTable pivot.targetKey_ = originalKey_; return pivot; } + const std::string &tableName() const { return tableName_; } + const std::string &originalKey() const { return originalKey_; } + const std::string &targetKey() const { return targetKey_; @@ -160,6 +166,7 @@ class ConvertMethod includeFiles_.push_back(i.asString()); } // for } + ConvertMethod() = default; bool shouldConvert(const std::string &tableName, @@ -169,18 +176,22 @@ class ConvertMethod { return tableName_; } + const std::string &colName() const { return colName_; } + const std::string &methodBeforeDbWrite() const { return methodBeforeDbWrite_; } + const std::string &methodAfterDbRead() const { return methodAfterDbRead_; } + const std::vector &includeFiles() const { return includeFiles_; @@ -203,6 +214,7 @@ class Relationship HasMany, ManyToMany }; + Relationship(const Json::Value &relationship) { auto type = relationship.get("type", "has one").asString(); @@ -264,7 +276,9 @@ class Relationship pivotTable_ = PivotTable(pivot); } } + Relationship() = default; + Relationship reverse() const { Relationship r; @@ -286,38 +300,47 @@ class Relationship r.pivotTable_ = pivotTable_.reverse(); return r; } + Type type() const { return type_; } + bool enableReverse() const { return enableReverse_; } + const std::string &originalTableName() const { return originalTableName_; } + const std::string &originalTableAlias() const { return originalTableAlias_; } + const std::string &originalKey() const { return originalKey_; } + const std::string &targetTableName() const { return targetTableName_; } + const std::string &targetTableAlias() const { return targetTableAlias_; } + const std::string &targetKey() const { return targetKey_; } + const PivotTable &pivotTable() const { return pivotTable_; @@ -334,10 +357,12 @@ class Relationship bool enableReverse_{false}; PivotTable pivotTable_; }; + class create_model : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create Model classes files"; diff --git a/drogon_ctl/create_plugin.cc b/drogon_ctl/create_plugin.cc index 4d4f4ce221..b9b09e87e5 100644 --- a/drogon_ctl/create_plugin.cc +++ b/drogon_ctl/create_plugin.cc @@ -69,6 +69,7 @@ static void createPluginSourceFile(std::ofstream &file, data.insert("filename", fileName); file << templ->genText(data); } + void create_plugin::handleCommand(std::vector ¶meters) { if (parameters.size() < 1) diff --git a/drogon_ctl/create_plugin.h b/drogon_ctl/create_plugin.h index c16d3efe80..de72c13e7f 100644 --- a/drogon_ctl/create_plugin.h +++ b/drogon_ctl/create_plugin.h @@ -17,12 +17,14 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create_plugin : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create plugin class files"; diff --git a/drogon_ctl/create_project.cc b/drogon_ctl/create_project.cc index 4f24200707..d9b706aac6 100644 --- a/drogon_ctl/create_project.cc +++ b/drogon_ctl/create_project.cc @@ -38,6 +38,7 @@ void create_project::handleCommand(std::vector ¶meters) auto pName = parameters[0]; createProject(pName); } + static void newCmakeFile(std::ofstream &cmakeFile, const std::string &projectName) { @@ -46,11 +47,13 @@ static void newCmakeFile(std::ofstream &cmakeFile, auto templ = DrTemplateBase::newTemplate("cmake.csp"); cmakeFile << templ->genText(data); } + static void newMainFile(std::ofstream &mainFile) { auto templ = DrTemplateBase::newTemplate("demoMain"); mainFile << templ->genText(); } + static void newGitIgFile(std::ofstream &gitFile) { auto templ = DrTemplateBase::newTemplate("gitignore.csp"); @@ -62,21 +65,25 @@ static void newConfigJsonFile(std::ofstream &configJsonFile) auto templ = DrTemplateBase::newTemplate("config_json"); configJsonFile << templ->genText(); } + static void newConfigYamlFile(std::ofstream &configYamlFile) { auto templ = DrTemplateBase::newTemplate("config_yaml"); configYamlFile << templ->genText(); } + static void newModelConfigFile(std::ofstream &configFile) { auto templ = DrTemplateBase::newTemplate("model_json"); configFile << templ->genText(); } + static void newTestMainFile(std::ofstream &mainFile) { auto templ = DrTemplateBase::newTemplate("test_main"); mainFile << templ->genText(); } + static void newTestCmakeFile(std::ofstream &testCmakeFile, const std::string &projectName) { @@ -85,6 +92,7 @@ static void newTestCmakeFile(std::ofstream &testCmakeFile, auto templ = DrTemplateBase::newTemplate("test_cmake"); testCmakeFile << templ->genText(data); } + void create_project::createProject(const std::string &projectName) { #ifdef _WIN32 diff --git a/drogon_ctl/create_project.h b/drogon_ctl/create_project.h index 72e8c73b40..bad9c39d61 100644 --- a/drogon_ctl/create_project.h +++ b/drogon_ctl/create_project.h @@ -16,12 +16,14 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create_project : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create a project"; diff --git a/drogon_ctl/create_view.cc b/drogon_ctl/create_view.cc index aadec07f29..7f5f599b05 100644 --- a/drogon_ctl/create_view.cc +++ b/drogon_ctl/create_view.cc @@ -53,6 +53,7 @@ static std::string &replace_all(std::string &str, } return str; } + static void parseCxxLine(std::ofstream &oSrcFile, const std::string &line, const std::string &streamName, @@ -66,6 +67,7 @@ static void parseCxxLine(std::ofstream &oSrcFile, oSrcFile << tmp << "\n"; } } + static void outputVal(std::ofstream &oSrcFile, const std::string &streamName, const std::string &viewDataName, @@ -76,12 +78,12 @@ static void outputVal(std::ofstream &oSrcFile, << "\"];\n"; oSrcFile << " if(val.type()==typeid(const char *)){\n"; oSrcFile << " " << streamName - << "<<*any_cast(&val);\n"; + << "<<*(std::any_cast(&val));\n"; oSrcFile << " }else " "if(val.type()==typeid(std::string)||val.type()==typeid(const " "std::string)){\n"; oSrcFile << " " << streamName - << "<<*any_cast(&val);\n"; + << "<<*(std::any_cast(&val));\n"; oSrcFile << " }\n"; oSrcFile << "}\n"; } @@ -286,6 +288,7 @@ void create_view::handleCommand(std::vector ¶meters) } createViewFiles(parameters); } + void create_view::createViewFiles(std::vector &cspFileNames) { for (auto const &file : cspFileNames) @@ -295,6 +298,7 @@ void create_view::createViewFiles(std::vector &cspFileNames) exit(1); } } + int create_view::createViewFile(const std::string &script_filename) { std::cout << "create HttpView Class file by " << script_filename @@ -374,6 +378,7 @@ int create_view::createViewFile(const std::string &script_filename) } return 0; } + void create_view::newViewHeaderFile(std::ofstream &file, const std::string &className) { diff --git a/drogon_ctl/create_view.h b/drogon_ctl/create_view.h index 60efe6b416..ee4648d9bd 100644 --- a/drogon_ctl/create_view.h +++ b/drogon_ctl/create_view.h @@ -17,12 +17,14 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class create_view : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "create view class files"; diff --git a/drogon_ctl/help.cc b/drogon_ctl/help.cc index 559cc06a38..81836eee9e 100644 --- a/drogon_ctl/help.cc +++ b/drogon_ctl/help.cc @@ -17,6 +17,7 @@ #include #include using namespace drogon_ctl; + void help::handleCommand(std::vector ¶meters) { if (parameters.size() == 0) diff --git a/drogon_ctl/help.h b/drogon_ctl/help.h index 15e46fa8be..c934381619 100644 --- a/drogon_ctl/help.h +++ b/drogon_ctl/help.h @@ -17,16 +17,19 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class help : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "display this message"; } + bool isTopCommand() override { return true; diff --git a/drogon_ctl/press.cc b/drogon_ctl/press.cc index e8093b2d8e..96d0fb8eb0 100644 --- a/drogon_ctl/press.cc +++ b/drogon_ctl/press.cc @@ -24,6 +24,7 @@ #endif using namespace drogon_ctl; + std::string press::detail() { return "Use press command to do stress testing\n" @@ -37,11 +38,12 @@ std::string press::detail() "http://localhost:8080/index.html\n"; } -void outputErrorAndExit(const string_view &err) +void outputErrorAndExit(const std::string_view &err) { std::cout << err << std::endl; exit(1); } + void press::handleCommand(std::vector ¶meters) { for (auto iter = parameters.begin(); iter != parameters.end(); iter++) diff --git a/drogon_ctl/press.h b/drogon_ctl/press.h index e5ee4a1c40..cb65030a6f 100644 --- a/drogon_ctl/press.h +++ b/drogon_ctl/press.h @@ -39,19 +39,23 @@ struct Statistics trantor::Date startDate_; trantor::Date endDate_; }; + class press : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "Do stress testing(Use 'drogon_ctl help press' for more " "information)"; } + bool isTopCommand() override { return true; } + std::string detail() override; private: diff --git a/drogon_ctl/templates/cmake.csp b/drogon_ctl/templates/cmake.csp index 5a5c4bacc8..5d541fafd8 100644 --- a/drogon_ctl/templates/cmake.csp +++ b/drogon_ctl/templates/cmake.csp @@ -34,10 +34,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) # ############################################################################## if (CMAKE_CXX_STANDARD LESS 17) - # With C++14, use boost to support any, string_view and filesystem - message(STATUS "use c++14") - find_package(Boost 1.61.0 REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC Boost::boost) + message(FATAL_ERROR "c++17 or higher is required") elseif (CMAKE_CXX_STANDARD LESS 20) message(STATUS "use c++17") else () diff --git a/drogon_ctl/templates/model_cc.csp b/drogon_ctl/templates/model_cc.csp index 2175d1751d..fd90fc80e2 100644 --- a/drogon_ctl/templates/model_cc.csp +++ b/drogon_ctl/templates/model_cc.csp @@ -180,7 +180,7 @@ const std::string &[[className]]::getColumnName(size_t index) noexcept(false) } else if(col.colDatabaseType_=="bytea") { - $$<<" auto str = r[\""<();\n"; + $$<<" auto str = r[\""<();\n"; $$<<" if(str.length()>=2&&\n"; $$<<" str[0]=='\\\\'&&str[1]=='x')\n"; $$<<" {\n"; @@ -271,7 +271,7 @@ const std::string &[[className]]::getColumnName(size_t index) noexcept(false) } else if(col.colDatabaseType_=="bytea") { - $$<<" auto str = r[index].as();\n"; + $$<<" auto str = r[index].as();\n"; $$<<" if(str.length()>=2&&\n"; $$<<" str[0]=='\\\\'&&str[1]=='x')\n"; $$<<" {\n"; diff --git a/drogon_ctl/templates/model_h.csp b/drogon_ctl/templates/model_h.csp index d02f9eaeb1..a8ded7863d 100644 --- a/drogon_ctl/templates/model_h.csp +++ b/drogon_ctl/templates/model_h.csp @@ -22,6 +22,7 @@ using namespace drogon_ctl; #include #include #include +#include #include #include #include diff --git a/drogon_ctl/version.cc b/drogon_ctl/version.cc index bdba5c904c..d5ca2172fe 100644 --- a/drogon_ctl/version.cc +++ b/drogon_ctl/version.cc @@ -53,11 +53,6 @@ void version::handleCommand(std::vector ¶meters) #else std::cout << " brotli: no\n"; #endif -#ifdef Boost_FOUND - std::cout << " boost: yes\n"; -#else - std::cout << " boost: no\n"; -#endif #ifdef USE_REDIS std::cout << " hiredis: yes\n"; #else diff --git a/drogon_ctl/version.h b/drogon_ctl/version.h index 66ab863d7b..b492ba7d33 100644 --- a/drogon_ctl/version.h +++ b/drogon_ctl/version.h @@ -17,20 +17,24 @@ #include #include "CommandHandler.h" using namespace drogon; + namespace drogon_ctl { class version : public DrObject, public CommandHandler { public: void handleCommand(std::vector ¶meters) override; + std::string script() override { return "display version of this tool"; } + bool isTopCommand() override { return true; } + version() { } diff --git a/examples/benchmark/BenchmarkCtrl.cc b/examples/benchmark/BenchmarkCtrl.cc index 2f92f3f82b..23afbe6298 100644 --- a/examples/benchmark/BenchmarkCtrl.cc +++ b/examples/benchmark/BenchmarkCtrl.cc @@ -1,4 +1,5 @@ #include "BenchmarkCtrl.h" + void BenchmarkCtrl::asyncHandleHttpRequest( const HttpRequestPtr &, std::function &&callback) diff --git a/examples/benchmark/BenchmarkCtrl.h b/examples/benchmark/BenchmarkCtrl.h index 9e3f5eb6ba..4ea8f70205 100644 --- a/examples/benchmark/BenchmarkCtrl.h +++ b/examples/benchmark/BenchmarkCtrl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class BenchmarkCtrl : public drogon::HttpSimpleController { public: diff --git a/examples/benchmark/JsonCtrl.cc b/examples/benchmark/JsonCtrl.cc index 397197a72d..ef3ed2d3dd 100644 --- a/examples/benchmark/JsonCtrl.cc +++ b/examples/benchmark/JsonCtrl.cc @@ -1,4 +1,5 @@ #include "JsonCtrl.h" + void JsonCtrl::asyncHandleHttpRequest( const HttpRequestPtr &, std::function &&callback) diff --git a/examples/benchmark/JsonCtrl.h b/examples/benchmark/JsonCtrl.h index 4f1dad7c82..74f89c7251 100644 --- a/examples/benchmark/JsonCtrl.h +++ b/examples/benchmark/JsonCtrl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class JsonCtrl : public drogon::HttpSimpleController { public: diff --git a/examples/benchmark/main.cc b/examples/benchmark/main.cc index 038a7a6e9f..f858ac18ab 100644 --- a/examples/benchmark/main.cc +++ b/examples/benchmark/main.cc @@ -1,6 +1,7 @@ #include using namespace drogon; + int main() { app() diff --git a/examples/redis/CMakeLists.txt b/examples/redis/CMakeLists.txt index 0e059f806b..a61120c024 100644 --- a/examples/redis/CMakeLists.txt +++ b/examples/redis/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) # ############################################################################## if (CMAKE_CXX_STANDARD LESS 17) - # With C++14, use boost to support any and string_view + # With C++14, use boost to support any and std::string_view message(STATUS "use c++14") find_package(Boost 1.61.0 REQUIRED) target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) diff --git a/examples/redis/controllers/Client.h b/examples/redis/controllers/Client.h index 508c5562f2..77e3aa632d 100644 --- a/examples/redis/controllers/Client.h +++ b/examples/redis/controllers/Client.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class Client : public drogon::HttpController { public: diff --git a/examples/redis_cache/DateFuncs.h b/examples/redis_cache/DateFuncs.h index 149aae3f82..cd5f59e432 100644 --- a/examples/redis_cache/DateFuncs.h +++ b/examples/redis_cache/DateFuncs.h @@ -6,6 +6,7 @@ inline trantor::Date fromString(const std::string &str) { return trantor::Date(std::atoll(str.data())); } + template <> inline std::string toString(const trantor::Date &date) { diff --git a/examples/redis_cache/controllers/SlowCtrl.cc b/examples/redis_cache/controllers/SlowCtrl.cc index 6319c2d77d..73e02b6dc7 100644 --- a/examples/redis_cache/controllers/SlowCtrl.cc +++ b/examples/redis_cache/controllers/SlowCtrl.cc @@ -3,6 +3,7 @@ #include "DateFuncs.h" #include #define VDate "visitDate" + void SlowCtrl::hello(const HttpRequestPtr &req, std::function &&callback, std::string &&userid) diff --git a/examples/redis_cache/controllers/SlowCtrl.h b/examples/redis_cache/controllers/SlowCtrl.h index 8f714868bc..f5d8dc9c75 100644 --- a/examples/redis_cache/controllers/SlowCtrl.h +++ b/examples/redis_cache/controllers/SlowCtrl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class SlowCtrl : public drogon::HttpController { public: diff --git a/examples/redis_cache/filters/TimeFilter.h b/examples/redis_cache/filters/TimeFilter.h index bcd75851d7..67e2c1ac4d 100644 --- a/examples/redis_cache/filters/TimeFilter.h +++ b/examples/redis_cache/filters/TimeFilter.h @@ -13,6 +13,7 @@ class TimeFilter : public drogon::HttpFilter virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&cb, FilterChainCallback &&ccb) override; + TimeFilter() { LOG_DEBUG << "TimeFilter constructor"; diff --git a/examples/redis_cache/main.cc b/examples/redis_cache/main.cc index 4ee286d37e..35a0dd2a88 100644 --- a/examples/redis_cache/main.cc +++ b/examples/redis_cache/main.cc @@ -1,4 +1,5 @@ #include + int main() { drogon::app().loadConfigFile("../config.json"); diff --git a/examples/redis_chat/CMakeLists.txt b/examples/redis_chat/CMakeLists.txt index 061c05ca01..ea0267ba76 100644 --- a/examples/redis_chat/CMakeLists.txt +++ b/examples/redis_chat/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) # ############################################################################## if (CMAKE_CXX_STANDARD LESS 17) - # With C++14, use boost to support any and string_view + # With C++14, use boost to support any and std::string_view message(STATUS "use c++14") find_package(Boost 1.61.0 REQUIRED) target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) diff --git a/examples/simple_reverse_proxy/main.cc b/examples/simple_reverse_proxy/main.cc index e460b50139..1def749546 100644 --- a/examples/simple_reverse_proxy/main.cc +++ b/examples/simple_reverse_proxy/main.cc @@ -1,4 +1,5 @@ #include + int main() { // Set HTTP listener address and port diff --git a/examples/simple_reverse_proxy/plugins/SimpleReverseProxy.h b/examples/simple_reverse_proxy/plugins/SimpleReverseProxy.h index 4b80ff5224..fd42790d15 100644 --- a/examples/simple_reverse_proxy/plugins/SimpleReverseProxy.h +++ b/examples/simple_reverse_proxy/plugins/SimpleReverseProxy.h @@ -19,6 +19,7 @@ class SimpleReverseProxy : public drogon::Plugin SimpleReverseProxy() { } + /// This method must be called by drogon to initialize and start the plugin. /// It must be implemented by the user. void initAndStart(const Json::Value &config) override; diff --git a/examples/websocket_client/WebSocketClient.cc b/examples/websocket_client/WebSocketClient.cc index 0fe63d4315..2ed0e17b2f 100644 --- a/examples/websocket_client/WebSocketClient.cc +++ b/examples/websocket_client/WebSocketClient.cc @@ -10,7 +10,7 @@ int main(int argc, char *argv[]) { std::string server; std::string path; - optional port; + std::optional port; // Connect to a public echo server if (argc > 1 && std::string(argv[1]) == "-p") { diff --git a/examples/websocket_server/WebSocketServer.cc b/examples/websocket_server/WebSocketServer.cc index 61a54bbe41..8541dc2222 100644 --- a/examples/websocket_server/WebSocketServer.cc +++ b/examples/websocket_server/WebSocketServer.cc @@ -25,6 +25,7 @@ struct Subscriber std::string chatRoomName_; drogon::SubscriberID id_; }; + void WebSocketChat::handleNewMessage(const WebSocketConnectionPtr &wsConnPtr, std::string &&message, const WebSocketMessageType &type) diff --git a/lib/inc/drogon/Attribute.h b/lib/inc/drogon/Attribute.h index 1a50f332a6..63acb94d30 100644 --- a/lib/inc/drogon/Attribute.h +++ b/lib/inc/drogon/Attribute.h @@ -14,10 +14,10 @@ #pragma once -#include #include #include #include +#include namespace drogon { @@ -45,7 +45,7 @@ class Attributes { if (typeid(T) == it->second.type()) { - return *(any_cast(&(it->second))); + return *(std::any_cast(&(it->second))); } else { @@ -58,7 +58,7 @@ class Attributes /** * @brief Get the 'any' object identified by the given key */ - any &operator[](const std::string &key) + std::any &operator[](const std::string &key) { return attributesMap_[key]; } @@ -70,7 +70,7 @@ class Attributes attributesPtr->insert("user name", userNameString); @endcode */ - void insert(const std::string &key, const any &obj) + void insert(const std::string &key, const std::any &obj) { attributesMap_[key] = obj; } @@ -82,7 +82,7 @@ class Attributes attributesPtr->insert("user name", userNameString); @endcode */ - void insert(const std::string &key, any &&obj) + void insert(const std::string &key, std::any &&obj) { attributesMap_[key] = std::move(obj); } @@ -121,7 +121,7 @@ class Attributes Attributes() = default; private: - using AttributesMap = std::map; + using AttributesMap = std::map; AttributesMap attributesMap_; }; diff --git a/lib/inc/drogon/CacheMap.h b/lib/inc/drogon/CacheMap.h index 3c5e291004..8f90bd44f9 100644 --- a/lib/inc/drogon/CacheMap.h +++ b/lib/inc/drogon/CacheMap.h @@ -42,6 +42,7 @@ class CallbackEntry CallbackEntry(std::function cb) : cb_(std::move(cb)) { } + ~CallbackEntry() { cb_(); @@ -139,6 +140,7 @@ class CacheMap noWheels_ = true; } }; + ~CacheMap() { std::lock_guard lock(ctrlBlockPtr_->mtx); @@ -154,6 +156,7 @@ class CacheMap } LOG_TRACE << "CacheMap destruct!"; } + struct MapValue { MapValue(const T2 &value, @@ -164,26 +167,32 @@ class CacheMap timeoutCallback_(std::move(callback)) { } + MapValue(T2 &&value, size_t timeout, std::function &&callback) : value_(std::move(value)), timeout_(timeout), timeoutCallback_(std::move(callback)) { } + MapValue(T2 &&value, size_t timeout) : value_(std::move(value)), timeout_(timeout) { } + MapValue(const T2 &value, size_t timeout) : value_(value), timeout_(timeout) { } + MapValue(T2 &&value) : value_(std::move(value)) { } + MapValue(const T2 &value) : value_(value) { } + MapValue() = default; T2 value_; size_t timeout_{0}; @@ -222,6 +231,7 @@ class CacheMap if (fnOnInsert_) fnOnInsert_(key); } + /** * @brief Insert a key-value pair into the cache. * @@ -380,6 +390,7 @@ class CacheMap if (fnOnErase_) fnOnErase_(key); } + /** * @brief Get the event loop object * @@ -404,6 +415,7 @@ class CacheMap std::lock_guard lock(bucketMutex_); insertEntry(delay, std::make_shared(std::move(task))); } + void runAfter(size_t delay, const std::function &task) { std::lock_guard lock(bucketMutex_); @@ -425,10 +437,12 @@ class CacheMap ControlBlock() : destructed(false), loopEnded(false) { } + bool destructed; bool loopEnded; std::mutex mtx; }; + std::unordered_map map_; std::vector wheels_; @@ -486,6 +500,7 @@ class CacheMap t = t / bucketsNumPerWheel_; } } + void eraseAfter(size_t delay, const T1 &key) { if (noWheels_) diff --git a/lib/inc/drogon/Cookie.h b/lib/inc/drogon/Cookie.h index 1cfe46414e..20dedaab93 100644 --- a/lib/inc/drogon/Cookie.h +++ b/lib/inc/drogon/Cookie.h @@ -14,13 +14,14 @@ #pragma once #include -#include -#include #include #include +#include #include #include #include +#include +#include namespace drogon { @@ -39,10 +40,12 @@ class DROGON_EXPORT Cookie : key_(key), value_(value) { } + Cookie(std::string &&key, std::string &&value) : key_(std::move(key)), value_(std::move(value)) { } + Cookie() = default; enum class SameSite { @@ -51,6 +54,7 @@ class DROGON_EXPORT Cookie kStrict, kNone }; + /** * @brief Set the Expires Date * @@ -84,6 +88,7 @@ class DROGON_EXPORT Cookie { domain_ = domain; } + void setDomain(std::string &&domain) { domain_ = std::move(domain); @@ -96,6 +101,7 @@ class DROGON_EXPORT Cookie { path_ = path; } + void setPath(std::string &&path) { path_ = std::move(path); @@ -108,10 +114,12 @@ class DROGON_EXPORT Cookie { key_ = key; } + void setKey(std::string &&key) { key_ = std::move(key); } + /** * @brief Set the value of the cookie. */ @@ -119,10 +127,12 @@ class DROGON_EXPORT Cookie { value_ = value; } + void setValue(std::string &&value) { value_ = std::move(value); } + /** * @brief Set the max-age of the cookie. */ @@ -130,6 +140,7 @@ class DROGON_EXPORT Cookie { maxAge_ = value; } + /** * @brief Set the same site of the cookie. */ @@ -267,7 +278,7 @@ class DROGON_EXPORT Cookie /** * @brief Get the max-age of the cookie */ - optional maxAge() const + std::optional maxAge() const { return maxAge_; } @@ -275,7 +286,7 @@ class DROGON_EXPORT Cookie /** * @brief Get the max-age of the cookie */ - optional getMaxAge() const + std::optional getMaxAge() const { return maxAge_; } @@ -307,49 +318,46 @@ class DROGON_EXPORT Cookie * str2. so the function doesn't apply tolower to the second argument * str2 as it's always in lower case. * - * @return 0 if both strings are equall ignoring case, negative value if lhs - * is smaller than rhs and vice versa + * @return true if both strings are equall ignoring case */ - static int stricmp(const string_view str1, const string_view str2) + static bool stricmp(const std::string_view str1, + const std::string_view str2) { auto str1Len{str1.length()}; auto str2Len{str2.length()}; - if (str1Len != str2Len) - return str1Len - str2Len; - + return false; for (size_t idx{0}; idx < str1Len; ++idx) { auto lowerChar{tolower(str1[idx])}; if (lowerChar != str2[idx]) { - return lowerChar - str2[idx]; + return false; } } - - return 0; + return true; } /** * @brief Converts a string value to its associated enum class SameSite * value */ - static SameSite convertString2SameSite(const string_view &sameSite) + static SameSite convertString2SameSite(const std::string_view &sameSite) { - if (stricmp(sameSite, "lax") == 0) + if (stricmp(sameSite, "lax")) { return Cookie::SameSite::kLax; } - else if (stricmp(sameSite, "strict") == 0) + else if (stricmp(sameSite, "strict")) { return Cookie::SameSite::kStrict; } - else if (stricmp(sameSite, "none") == 0) + else if (stricmp(sameSite, "none")) { return Cookie::SameSite::kNone; } - else if (stricmp(sameSite, "null") != 0) + else if (!stricmp(sameSite, "null")) { LOG_WARN << "'" << sameSite @@ -357,7 +365,6 @@ class DROGON_EXPORT Cookie "or " "'None' are proper values. Return value is SameSite::kNull."; } - return Cookie::SameSite::kNull; } @@ -365,33 +372,33 @@ class DROGON_EXPORT Cookie * @brief Converts an enum class SameSite value to its associated string * value */ - static const string_view &convertSameSite2String(SameSite sameSite) + static const std::string_view &convertSameSite2String(SameSite sameSite) { switch (sameSite) { case SameSite::kLax: { - static string_view sv{"Lax"}; + static std::string_view sv{"Lax"}; return sv; } case SameSite::kStrict: { - static string_view sv{"Strict"}; + static std::string_view sv{"Strict"}; return sv; } case SameSite::kNone: { - static string_view sv{"None"}; + static std::string_view sv{"None"}; return sv; } case SameSite::kNull: { - static string_view sv{"Null"}; + static std::string_view sv{"Null"}; return sv; } } { - static string_view sv{"UNDEFINED"}; + static std::string_view sv{"UNDEFINED"}; return sv; } } @@ -404,7 +411,7 @@ class DROGON_EXPORT Cookie std::string path_; std::string key_; std::string value_; - optional maxAge_; + std::optional maxAge_; SameSite sameSite_{SameSite::kNull}; }; diff --git a/lib/inc/drogon/DrObject.h b/lib/inc/drogon/DrObject.h index 72b25f1abe..30a01ef892 100644 --- a/lib/inc/drogon/DrObject.h +++ b/lib/inc/drogon/DrObject.h @@ -51,6 +51,7 @@ class DROGON_EXPORT DrObjectBase { return (className() == class_name); } + virtual ~DrObjectBase() { } @@ -68,6 +69,7 @@ class DrObject : public virtual DrObjectBase { return alloc_.className(); } + static const std::string &classTypeName() { return alloc_.className(); @@ -91,12 +93,14 @@ class DrObject : public virtual DrObjectBase { registerClass(); } + const std::string &className() const { static std::string className = DrClassMap::demangle(typeid(T).name()); return className; } + template typename std::enable_if::value, void>::type @@ -109,6 +113,7 @@ class DrObject : public virtual DrObjectBase return std::make_shared(); }); } + template typename std::enable_if::value, void>::type @@ -120,6 +125,7 @@ class DrObject : public virtual DrObjectBase // use static val to register allocator function for class T; static DrAllocator alloc_; }; + template typename DrObject::DrAllocator DrObject::alloc_; diff --git a/lib/inc/drogon/DrTemplate.h b/lib/inc/drogon/DrTemplate.h index ee244fbc8e..81c9dc8d5c 100644 --- a/lib/inc/drogon/DrTemplate.h +++ b/lib/inc/drogon/DrTemplate.h @@ -16,6 +16,7 @@ #include #include + namespace drogon { template diff --git a/lib/inc/drogon/HttpAppFramework.h b/lib/inc/drogon/HttpAppFramework.h index 8891119634..63924bbddc 100644 --- a/lib/inc/drogon/HttpAppFramework.h +++ b/lib/inc/drogon/HttpAppFramework.h @@ -68,6 +68,7 @@ using DefaultHandler = std::function &&)>; #ifdef __cpp_impl_coroutine class HttpAppFramework; + namespace internal { struct [[nodiscard]] ForwardAwaiter @@ -84,6 +85,7 @@ struct [[nodiscard]] ForwardAwaiter app_(app) { } + void await_suspend(std::coroutine_handle<> handle) noexcept; private: @@ -538,6 +540,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable pathPattern, binder, validMethods, filters, handlerName); return *this; } + /** * @brief Register a handler into the framework via a regular expression. * diff --git a/lib/inc/drogon/HttpBinder.h b/lib/inc/drogon/HttpBinder.h index 107f0b562a..d53c49036f 100644 --- a/lib/inc/drogon/HttpBinder.h +++ b/lib/inc/drogon/HttpBinder.h @@ -39,26 +39,31 @@ struct BinderArgTypeTraits { static const bool isValid = true; }; + template struct BinderArgTypeTraits { static const bool isValid = false; }; + template struct BinderArgTypeTraits { static const bool isValid = false; }; + template struct BinderArgTypeTraits { static const bool isValid = true; }; + template struct BinderArgTypeTraits { static const bool isValid = false; }; + template struct BinderArgTypeTraits { @@ -74,6 +79,7 @@ class HttpBinderBase std::function &&callback) = 0; virtual size_t paramCount() = 0; virtual const std::string &handlerName() const = 0; + virtual ~HttpBinderBase() { } @@ -96,12 +102,14 @@ DROGON_EXPORT void handleException( std::function &&); using HttpBinderBasePtr = std::shared_ptr; + template class HttpBinder : public HttpBinderBase { public: using traits = FunctionTraits; using FunctionType = FUNCTION; + void handleHttpRequest( std::deque &pathArguments, const HttpRequestPtr &req, @@ -109,25 +117,30 @@ class HttpBinder : public HttpBinderBase { run(pathArguments, req, std::move(callback)); } + size_t paramCount() override { return traits::arity; } + HttpBinder(FUNCTION &&func) : func_(std::forward(func)) { static_assert(traits::isHTTPFunction, "Your API handler function interface is wrong!"); handlerName_ = DrClassMap::demangle(typeid(FUNCTION).name()); } + void test() { std::cout << "argument_count=" << argument_count << " " << traits::isHTTPFunction << std::endl; } + const std::string &handlerName() const override { return handlerName_; } + template typename std::enable_if::type @@ -137,6 +150,7 @@ class HttpBinder : public HttpBinderBase DrClassMap::getSingleInstance(); LOG_TRACE << "create handler class object: " << objPtr.get(); } + template typename std::enable_if::type @@ -145,6 +159,7 @@ class HttpBinder : public HttpBinderBase auto &obj = getControllerObj(); LOG_TRACE << "create handler class object: " << &obj; } + template typename std::enable_if::type createHandlerInstance() @@ -279,6 +294,7 @@ class HttpBinder : public HttpBinderBase std::forward(values)..., std::move(value)); } + template @@ -366,6 +382,7 @@ class HttpBinder : public HttpBinderBase static auto &obj = getControllerObj(); return (obj.*func_)(req, std::move(values)...); } + template (); return (*objPtr.*func_)(req, std::move(values)...); } + template (); return (obj.*func_)((*req), std::move(values)...); } + template (); return (*objPtr.*func_)((*req), std::move(values)...); } + template , public HttpControllerBase T::initPathRouting(); } }; + // use static value to register controller method in framework before // main(); static methodRegistrator registrator_; + virtual void *touch() { return ®istrator_; } }; + template typename HttpController::methodRegistrator HttpController::registrator_; diff --git a/lib/inc/drogon/HttpFilter.h b/lib/inc/drogon/HttpFilter.h index 5abbeafbc0..1614db0c00 100644 --- a/lib/inc/drogon/HttpFilter.h +++ b/lib/inc/drogon/HttpFilter.h @@ -80,6 +80,7 @@ class HttpCoroFilter : public DrObject, public HttpFilterBase public: static constexpr bool isAutoCreation{AutoCreation}; ~HttpCoroFilter() override = default; + void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) final diff --git a/lib/inc/drogon/HttpRequest.h b/lib/inc/drogon/HttpRequest.h index 619e562ad4..34f5c03abf 100644 --- a/lib/inc/drogon/HttpRequest.h +++ b/lib/inc/drogon/HttpRequest.h @@ -15,8 +15,6 @@ #pragma once #include -#include -#include #include #include #include @@ -30,6 +28,8 @@ #include #include #include +#include +#include namespace drogon { @@ -65,6 +65,7 @@ template <> HttpRequestPtr toRequest(const Json::Value &pJson); template <> HttpRequestPtr toRequest(Json::Value &&pJson); + template <> inline HttpRequestPtr toRequest(Json::Value &pJson) { @@ -108,6 +109,7 @@ class DROGON_EXPORT HttpRequest /// Return the method string of the request, such as GET, POST, etc. virtual const char *methodString() const = 0; + const char *getMethodString() const { return methodString(); @@ -115,6 +117,7 @@ class DROGON_EXPORT HttpRequest /// Return the enum type method of the request. virtual HttpMethod method() const = 0; + HttpMethod getMethod() const { return method(); @@ -188,17 +191,18 @@ class DROGON_EXPORT HttpRequest /// Get the content string of the request, which is the body part of the /// request. - string_view body() const + std::string_view body() const { - return string_view(bodyData(), bodyLength()); + return std::string_view(bodyData(), bodyLength()); } /// Get the content string of the request, which is the body part of the /// request. - string_view getBody() const + std::string_view getBody() const { return body(); } + virtual const char *bodyData() const = 0; virtual size_t bodyLength() const = 0; @@ -221,23 +225,25 @@ class DROGON_EXPORT HttpRequest } /// Get the matched path pattern after routing - string_view getMatchedPathPattern() const + std::string_view getMatchedPathPattern() const { return matchedPathPattern(); } /// Get the matched path pattern after routing - string_view matchedPathPattern() const + std::string_view matchedPathPattern() const { - return string_view(matchedPathPatternData(), - matchedPathPatternLength()); + return std::string_view(matchedPathPatternData(), + matchedPathPatternLength()); } + virtual const char *matchedPathPatternData() const = 0; virtual size_t matchedPathPatternLength() const = 0; /// Return the string of http version of request, such as HTTP/1.0, /// HTTP/1.1, etc. virtual const char *versionString() const = 0; + const char *getVersionString() const { return versionString(); @@ -302,7 +308,7 @@ class DROGON_EXPORT HttpRequest * @return optional */ template - optional getOptionalParameter(const std::string &key) + std::optional getOptionalParameter(const std::string &key) { auto ¶ms = getParameters(); auto it = params.find(key); @@ -310,22 +316,24 @@ class DROGON_EXPORT HttpRequest { try { - return optional(drogon::utils::fromString(it->second)); + return std::optional( + drogon::utils::fromString(it->second)); } catch (const std::exception &e) { LOG_ERROR << e.what(); - return optional{}; + return std::optional{}; } } else { - return optional{}; + return std::optional{}; } } /// Return the remote IP address and port virtual const trantor::InetAddress &peerAddr() const = 0; + const trantor::InetAddress &getPeerAddr() const { return peerAddr(); @@ -333,6 +341,7 @@ class DROGON_EXPORT HttpRequest /// Return the local IP address and port virtual const trantor::InetAddress &localAddr() const = 0; + const trantor::InetAddress &getLocalAddr() const { return localAddr(); @@ -340,6 +349,7 @@ class DROGON_EXPORT HttpRequest /// Return the creation timestamp set by the framework. virtual const trantor::Date &creationDate() const = 0; + const trantor::Date &getCreationDate() const { return creationDate(); @@ -347,6 +357,7 @@ class DROGON_EXPORT HttpRequest // Return the peer certificate (if any) virtual const trantor::CertificatePtr &peerCertificate() const = 0; + const trantor::CertificatePtr &getPeerCertificate() const { return peerCertificate(); @@ -377,6 +388,7 @@ class DROGON_EXPORT HttpRequest /// Get the content type virtual ContentType contentType() const = 0; + ContentType getContentType() const { return contentType(); @@ -409,7 +421,7 @@ class DROGON_EXPORT HttpRequest /// CRLF. Or just the MIME type // /// For example, "content-type: text/plain\r\n" or "text/plain" - void setContentTypeString(const string_view &typeString) + void setContentTypeString(const std::string_view &typeString) { setContentTypeString(typeString.data(), typeString.size()); } diff --git a/lib/inc/drogon/HttpResponse.h b/lib/inc/drogon/HttpResponse.h index a92f57a359..ed9778f847 100644 --- a/lib/inc/drogon/HttpResponse.h +++ b/lib/inc/drogon/HttpResponse.h @@ -14,7 +14,6 @@ #pragma once #include -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include namespace drogon { @@ -56,10 +56,12 @@ HttpResponsePtr toResponse(T &&) << DrClassMap::demangle(typeid(T).name()); exit(1); } + template <> HttpResponsePtr toResponse(const Json::Value &pJson); template <> HttpResponsePtr toResponse(Json::Value &&pJson); + template <> inline HttpResponsePtr toResponse(Json::Value &pJson) { @@ -99,6 +101,7 @@ class DROGON_EXPORT HttpResponse /// Get the status code such as 200, 404 virtual HttpStatusCode statusCode() const = 0; + HttpStatusCode getStatusCode() const { return statusCode(); @@ -107,13 +110,15 @@ class DROGON_EXPORT HttpResponse /// Set the status code of the response. virtual void setStatusCode(HttpStatusCode code) = 0; - void setCustomStatusCode(int code, string_view message = string_view{}) + void setCustomStatusCode(int code, + std::string_view message = std::string_view{}) { setCustomStatusCode(code, message.data(), message.length()); } /// Get the creation timestamp of the response. virtual const trantor::Date &creationDate() const = 0; + const trantor::Date &getCreationDate() const { return creationDate(); @@ -142,7 +147,7 @@ class DROGON_EXPORT HttpResponse /// Set the content-type string, The string may contain the header name and /// CRLF. Or just the MIME type For example, "content-type: text/plain\r\n" /// or "text/plain" - void setContentTypeString(const string_view &typeString) + void setContentTypeString(const std::string_view &typeString) { setContentTypeString(typeString.data(), typeString.size()); } @@ -151,12 +156,13 @@ class DROGON_EXPORT HttpResponse /// may contain the header name and CRLF. Or just the MIME type /// For example, "content-type: text/plain\r\n" or "text/plain" void setContentTypeCodeAndCustomString(ContentType type, - const string_view &typeString) + const std::string_view &typeString) { setContentTypeCodeAndCustomString(type, typeString.data(), typeString.length()); } + template void setContentTypeCodeAndCustomString(ContentType type, const char (&typeString)[N]) @@ -171,6 +177,7 @@ class DROGON_EXPORT HttpResponse /// Get the response content type. virtual ContentType contentType() const = 0; + ContentType getContentType() const { return contentType(); @@ -260,13 +267,13 @@ class DROGON_EXPORT HttpResponse } /// Get the response body. - string_view body() const + std::string_view body() const { - return string_view{getBodyData(), getBodyLength()}; + return std::string_view{getBodyData(), getBodyLength()}; } /// Get the response body. - string_view getBody() const + std::string_view getBody() const { return body(); } @@ -274,6 +281,7 @@ class DROGON_EXPORT HttpResponse /// Return the string of http version of request, such as HTTP/1.0, /// HTTP/1.1, etc. virtual const char *versionString() const = 0; + const char *getVersionString() const { return versionString(); @@ -302,6 +310,7 @@ class DROGON_EXPORT HttpResponse /// Get the expiration time of the response. virtual ssize_t expiredTime() const = 0; + ssize_t getExpiredTime() const { return expiredTime(); @@ -311,6 +320,7 @@ class DROGON_EXPORT HttpResponse /// If the response is not in json format, then a empty shared_ptr is /// retured. virtual const std::shared_ptr &jsonObject() const = 0; + const std::shared_ptr &getJsonObject() const { return jsonObject(); @@ -342,6 +352,7 @@ class DROGON_EXPORT HttpResponse * @return The certificate of the peer. nullptr is none. */ virtual const trantor::CertificatePtr &peerCertificate() const = 0; + const trantor::CertificatePtr &getPeerCertificate() const { return peerCertificate(); @@ -525,6 +536,7 @@ class DROGON_EXPORT HttpResponse const char *message, size_t messageLength) = 0; }; + template <> inline HttpResponsePtr toResponse(const Json::Value &pJson) { diff --git a/lib/inc/drogon/HttpSimpleController.h b/lib/inc/drogon/HttpSimpleController.h index d311345fdf..ae62b5f9a9 100644 --- a/lib/inc/drogon/HttpSimpleController.h +++ b/lib/inc/drogon/HttpSimpleController.h @@ -26,6 +26,7 @@ { #define PATH_ADD(path, ...) registerSelf__(path, {__VA_ARGS__}) #define PATH_LIST_END } + namespace drogon { /** @@ -45,6 +46,7 @@ class HttpSimpleControllerBase : public virtual DrObjectBase virtual void asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) = 0; + virtual ~HttpSimpleControllerBase() { } @@ -62,6 +64,7 @@ class HttpSimpleController : public DrObject, public HttpSimpleControllerBase { public: static const bool isAutoCreation = AutoCreation; + virtual ~HttpSimpleController() { } @@ -70,6 +73,7 @@ class HttpSimpleController : public DrObject, public HttpSimpleControllerBase HttpSimpleController() { } + static void registerSelf__( const std::string &path, const std::vector &filtersAndMethods) @@ -95,13 +99,16 @@ class HttpSimpleController : public DrObject, public HttpSimpleControllerBase } } }; + friend pathRegistrator; static pathRegistrator registrator_; + virtual void *touch() { return ®istrator_; } }; + template typename HttpSimpleController::pathRegistrator HttpSimpleController::registrator_; diff --git a/lib/inc/drogon/HttpTypes.h b/lib/inc/drogon/HttpTypes.h index 72a8d42c66..0e14196809 100644 --- a/lib/inc/drogon/HttpTypes.h +++ b/lib/inc/drogon/HttpTypes.h @@ -15,8 +15,9 @@ #include #include #include -#include +#include #include +#include namespace drogon { @@ -174,7 +175,7 @@ enum class WebSocketMessageType Unknown }; -inline string_view to_string_view(drogon::ReqResult result) +inline std::string_view to_string_view(drogon::ReqResult result) { switch (result) { diff --git a/lib/inc/drogon/HttpViewData.h b/lib/inc/drogon/HttpViewData.h index a1efb48c74..1deeb1a09b 100644 --- a/lib/inc/drogon/HttpViewData.h +++ b/lib/inc/drogon/HttpViewData.h @@ -15,8 +15,6 @@ #pragma once #include -#include -#include #include #include #include @@ -25,6 +23,8 @@ #include #include #include +#include +#include namespace drogon { @@ -43,7 +43,7 @@ class DROGON_EXPORT HttpViewData { if (typeid(T) == it->second.type()) { - return *(any_cast(&(it->second))); + return *(std::any_cast(&(it->second))); } else { @@ -54,11 +54,12 @@ class DROGON_EXPORT HttpViewData } /// Insert an item identified by the key parameter into the data set; - void insert(const std::string &key, any &&obj) + void insert(const std::string &key, std::any &&obj) { viewData_[key] = std::move(obj); } - void insert(const std::string &key, const any &obj) + + void insert(const std::string &key, const std::any &obj) { viewData_[key] = obj; } @@ -126,7 +127,7 @@ class DROGON_EXPORT HttpViewData } /// Get the 'any' object by the key parameter. - any &operator[](const std::string &key) const + std::any &operator[](const std::string &key) const { return viewData_[key]; } @@ -142,12 +143,13 @@ class DROGON_EXPORT HttpViewData @endcode */ static std::string htmlTranslate(const char *str, size_t length); - static std::string htmlTranslate(const string_view &str) + + static std::string htmlTranslate(const std::string_view &str) { return htmlTranslate(str.data(), str.length()); } - static bool needTranslation(const string_view &str) + static bool needTranslation(const std::string_view &str) { for (auto const &c : str) { @@ -166,7 +168,7 @@ class DROGON_EXPORT HttpViewData } protected: - using ViewDataMap = std::unordered_map; + using ViewDataMap = std::unordered_map; mutable ViewDataMap viewData_; }; diff --git a/lib/inc/drogon/IOThreadStorage.h b/lib/inc/drogon/IOThreadStorage.h index 929de7814f..17675d17ad 100644 --- a/lib/inc/drogon/IOThreadStorage.h +++ b/lib/inc/drogon/IOThreadStorage.h @@ -154,6 +154,7 @@ class IOThreadStorage : public trantor::NonCopyable private: std::vector storage_; }; + inline trantor::EventLoop *getIOThreadStorageLoop(size_t index) noexcept(false) { if (index > drogon::app().getThreadNum()) diff --git a/lib/inc/drogon/IntranetIpFilter.h b/lib/inc/drogon/IntranetIpFilter.h index 69c2f43bae..5304caf012 100644 --- a/lib/inc/drogon/IntranetIpFilter.h +++ b/lib/inc/drogon/IntranetIpFilter.h @@ -28,6 +28,7 @@ class DROGON_EXPORT IntranetIpFilter : public HttpFilter IntranetIpFilter() { } + virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override; diff --git a/lib/inc/drogon/LocalHostFilter.h b/lib/inc/drogon/LocalHostFilter.h index b3ca791956..124c77a07d 100644 --- a/lib/inc/drogon/LocalHostFilter.h +++ b/lib/inc/drogon/LocalHostFilter.h @@ -28,6 +28,7 @@ class DROGON_EXPORT LocalHostFilter : public HttpFilter LocalHostFilter() { } + void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override; diff --git a/lib/inc/drogon/MultiPart.h b/lib/inc/drogon/MultiPart.h index 87ed6604a5..ce5ed85ed9 100644 --- a/lib/inc/drogon/MultiPart.h +++ b/lib/inc/drogon/MultiPart.h @@ -16,16 +16,17 @@ #include #include -#include #include #include #include #include #include +#include namespace drogon { class HttpFileImpl; + /** * @brief This class represents a uploaded file by a HTTP request. * @@ -39,8 +40,8 @@ class DROGON_EXPORT HttpFile /// Return the file extension; /// Note: After the HttpFile object is destroyed, do not use this - /// string_view object. - string_view getFileExtension() const noexcept; + /// std::string_view object. + std::string_view getFileExtension() const noexcept; /// Return the name of the item in multiple parts. const std::string &getItemName() const noexcept; @@ -82,11 +83,11 @@ class DROGON_EXPORT HttpFile /** * @brief return the content of the file. * - * @return string_view + * @return std::string_view */ - string_view fileContent() const noexcept + std::string_view fileContent() const noexcept { - return string_view{fileData(), fileLength()}; + return std::string_view{fileData(), fileLength()}; } /// Return the file length. diff --git a/lib/inc/drogon/NotFound.h b/lib/inc/drogon/NotFound.h index 8b73fde56d..519705a67f 100644 --- a/lib/inc/drogon/NotFound.h +++ b/lib/inc/drogon/NotFound.h @@ -17,6 +17,7 @@ #include #include + namespace drogon { /** @@ -29,6 +30,7 @@ class DROGON_EXPORT NotFound final : public drogon::DrTemplate NotFound() { } + std::string genText(const drogon::HttpViewData &) override; }; } // namespace drogon diff --git a/lib/inc/drogon/PubSubService.h b/lib/inc/drogon/PubSubService.h index 15a4f690fd..c7d8530fe8 100644 --- a/lib/inc/drogon/PubSubService.h +++ b/lib/inc/drogon/PubSubService.h @@ -102,6 +102,7 @@ class Topic : public trantor::NonCopyable std::shared_lock lock(mutex_); return handlersMap_.empty(); } + /** * @brief Remove all subscribers from the topic. * @@ -247,6 +248,7 @@ class PubSubService : public trantor::NonCopyable topicMap_; mutable SharedMutex mutex_; SubscriberID subID_ = 0; + SubscriberID subscribeToTopic( const std::string &topicName, typename Topic::MessageHandler &&handler) diff --git a/lib/inc/drogon/RateLimiter.h b/lib/inc/drogon/RateLimiter.h index 2c5f039ee9..691edcdbc7 100644 --- a/lib/inc/drogon/RateLimiter.h +++ b/lib/inc/drogon/RateLimiter.h @@ -13,6 +13,7 @@ enum class DROGON_EXPORT RateLimiterType kSlidingWindow, kTokenBucket }; + inline RateLimiterType stringToRateLimiterType(const std::string &type) { if (type == "fixedWindow" || type == "fixed_window") @@ -23,6 +24,7 @@ inline RateLimiterType stringToRateLimiterType(const std::string &type) } class DROGON_EXPORT RateLimiter; using RateLimiterPtr = std::shared_ptr; + /** * @brief This class is used to limit the number of requests per second * @@ -50,17 +52,20 @@ class DROGON_EXPORT RateLimiter virtual bool isAllowed() = 0; virtual ~RateLimiter() noexcept = default; }; + class DROGON_EXPORT SafeRateLimiter : public RateLimiter { public: SafeRateLimiter(RateLimiterPtr limiter) : limiter_(limiter) { } + bool isAllowed() override { std::lock_guard lock(mutex_); return limiter_->isAllowed(); } + ~SafeRateLimiter() noexcept override = default; private: diff --git a/lib/inc/drogon/Session.h b/lib/inc/drogon/Session.h index 3456b8ee61..e3dc0d19e5 100644 --- a/lib/inc/drogon/Session.h +++ b/lib/inc/drogon/Session.h @@ -14,13 +14,13 @@ #pragma once -#include -#include #include #include #include #include #include +#include +#include namespace drogon { @@ -31,7 +31,8 @@ namespace drogon class Session { public: - using SessionMap = std::map; + using SessionMap = std::map; + /** * @brief Get the data identified by the key parameter. * @note if the data is not found, a default value is returned. @@ -50,7 +51,7 @@ class Session { if (typeid(T) == it->second.type()) { - return *(any_cast(&(it->second))); + return *(std::any_cast(&(it->second))); } else { @@ -70,7 +71,7 @@ class Session * @return optional */ template - optional getOptional(const std::string &key) const + std::optional getOptional(const std::string &key) const { { std::lock_guard lck(mutex_); @@ -79,7 +80,7 @@ class Session { if (typeid(T) == it->second.type()) { - return *(any_cast(&(it->second))); + return *(std::any_cast(&(it->second))); } else { @@ -87,8 +88,9 @@ class Session } } } - return nullopt; + return std::nullopt; } + /** * @brief Modify or visit the data identified by the key parameter. * @@ -111,7 +113,7 @@ class Session { if (typeid(T) == it->second.type()) { - handler(*(any_cast(&(it->second)))); + handler(*(std::any_cast(&(it->second)))); } else { @@ -122,9 +124,10 @@ class Session { auto item = T(); handler(item); - sessionMap_.insert(std::make_pair(key, any(std::move(item)))); + sessionMap_.insert(std::make_pair(key, std::any(std::move(item)))); } } + /** * @brief Modify or visit the session data. * @@ -149,7 +152,7 @@ class Session @endcode * @note If the key already exists, the element is not inserted. */ - void insert(const std::string &key, const any &obj) + void insert(const std::string &key, const std::any &obj) { std::lock_guard lck(mutex_); sessionMap_.insert(std::make_pair(key, obj)); @@ -163,7 +166,7 @@ class Session @endcode * @note If the key already exists, the element is not inserted. */ - void insert(const std::string &key, any &&obj) + void insert(const std::string &key, std::any &&obj) { std::lock_guard lck(mutex_); sessionMap_.insert(std::make_pair(key, std::move(obj))); @@ -219,6 +222,7 @@ class Session needToChange_ = true; needToSet_ = true; } + Session() = delete; private: @@ -229,6 +233,7 @@ class Session bool needToChange_{false}; friend class SessionManager; friend class HttpAppFrameworkImpl; + /** * @brief Constructor, usually called by the framework */ @@ -236,6 +241,7 @@ class Session : sessionId_(id), needToSet_(needToSet) { } + /** * @brief Change the state of the session, usually called by the framework */ @@ -243,6 +249,7 @@ class Session { needToSet_ = false; } + /** * @brief If the session ID needs to be changed. * @@ -251,6 +258,7 @@ class Session { return needToChange_; } + /** * @brief If the session ID needs to be set to the client through cookie, * return true @@ -259,6 +267,7 @@ class Session { return needToSet_; } + void setSessionId(const std::string &id) { std::lock_guard lck(mutex_); diff --git a/lib/inc/drogon/UploadFile.h b/lib/inc/drogon/UploadFile.h index f9cf87bd8d..7121b7bd3c 100644 --- a/lib/inc/drogon/UploadFile.h +++ b/lib/inc/drogon/UploadFile.h @@ -56,18 +56,22 @@ class UploadFile } } } + const std::string &path() const { return path_; } + const std::string &fileName() const { return fileName_; } + const std::string &itemName() const { return itemName_; } + ContentType contentType() const { return contentType_; diff --git a/lib/inc/drogon/WebSocketConnection.h b/lib/inc/drogon/WebSocketConnection.h index 12b1cb82df..24defa1c04 100644 --- a/lib/inc/drogon/WebSocketConnection.h +++ b/lib/inc/drogon/WebSocketConnection.h @@ -19,6 +19,7 @@ #include #include #include + namespace drogon { enum class CloseCode @@ -81,6 +82,7 @@ enum class CloseCode be verified).*/ kTLSFailed = 1015 }; + /** * @brief The WebSocket connection abstract class. * @@ -217,5 +219,6 @@ class WebSocketConnection private: std::shared_ptr contextPtr_; }; + using WebSocketConnectionPtr = std::shared_ptr; } // namespace drogon diff --git a/lib/inc/drogon/WebSocketController.h b/lib/inc/drogon/WebSocketController.h index 438e701820..92349d5c93 100644 --- a/lib/inc/drogon/WebSocketController.h +++ b/lib/inc/drogon/WebSocketController.h @@ -71,6 +71,7 @@ class WebSocketController : public DrObject, public WebSocketControllerBase { public: static const bool isAutoCreation = AutoCreation; + virtual ~WebSocketController() { } @@ -79,6 +80,7 @@ class WebSocketController : public DrObject, public WebSocketControllerBase WebSocketController() { } + static void registerSelf__( const std::string &path, const std::vector &filtersAndMethods) @@ -104,13 +106,16 @@ class WebSocketController : public DrObject, public WebSocketControllerBase } } }; + friend pathRegistrator; static pathRegistrator registrator_; + virtual void *touch() { return ®istrator_; } }; + template typename WebSocketController::pathRegistrator WebSocketController::registrator_; diff --git a/lib/inc/drogon/drogon_test.h b/lib/inc/drogon/drogon_test.h index 1a8e43d9eb..62823f8c8b 100644 --- a/lib/inc/drogon/drogon_test.h +++ b/lib/inc/drogon/drogon_test.h @@ -1,14 +1,15 @@ #pragma once #include #include -#include #include #include #include #include #include +#include #include + /** * @brief Drogon Test is a minimal effort test framework developed because the * major C++ test frameworks doesn't handle async programs well. Drogon Test's @@ -76,7 +77,7 @@ struct is_printable<_Tp, { }; -inline std::string escapeString(const string_view sv) +inline std::string escapeString(const std::string_view sv) { std::string result; result.reserve(sv.size()); @@ -104,7 +105,7 @@ inline std::string escapeString(const string_view sv) return result; } -DROGON_EXPORT std::string prettifyString(const string_view sv, +DROGON_EXPORT std::string prettifyString(const std::string_view sv, size_t maxLength = 120); #ifdef __cpp_fold_expressions @@ -119,6 +120,7 @@ inline void outputReason(Head&& head) { std::cout << std::forward(head); } + template inline void outputReason(Head&& head, Tail&&... tail) { @@ -151,7 +153,7 @@ struct AttemptPrintViaStream struct StringPrinter { - std::string operator()(const string_view& v) + std::string operator()(const std::string_view& v) { return prettifyString(v); } @@ -165,9 +167,10 @@ inline std::string attemptPrint(T&& v) // Poor man's if constexpr because SFINAE don't disambiguate between // possible resolutions - return typename std::conditional::value, - internal::StringPrinter, - DefaultPrinter>::type()(v); + return typename std::conditional< + std::is_convertible::value, + internal::StringPrinter, + DefaultPrinter>::type()(v); } // Specializations to reduce template construction @@ -225,6 +228,7 @@ struct Lhs Lhs(const T& lhs) : ref_(lhs) { } + const T& ref_; template @@ -348,13 +352,16 @@ class CaseBase : public trantor::NonCopyable { public: CaseBase() = default; + CaseBase(const std::string& name) : name_(name) { } + CaseBase(std::shared_ptr parent, const std::string& name) : parent_(parent), name_(name) { } + virtual ~CaseBase() = default; std::string fullname() const @@ -421,6 +428,7 @@ struct TestCase : public CaseBase TestCase(const std::string& name) : CaseBase(name) { } + virtual ~TestCase() = default; virtual void doTest_(std::shared_ptr) = 0; }; diff --git a/lib/inc/drogon/plugins/AccessLogger.h b/lib/inc/drogon/plugins/AccessLogger.h index 373cacb776..a9cda5d8d3 100644 --- a/lib/inc/drogon/plugins/AccessLogger.h +++ b/lib/inc/drogon/plugins/AccessLogger.h @@ -102,6 +102,7 @@ class DROGON_EXPORT AccessLogger : public drogon::Plugin AccessLogger() { } + void initAndStart(const Json::Value &config) override; void shutdown() override; diff --git a/lib/inc/drogon/plugins/GlobalFilters.h b/lib/inc/drogon/plugins/GlobalFilters.h index a94da2c2d8..3d450f6b96 100644 --- a/lib/inc/drogon/plugins/GlobalFilters.h +++ b/lib/inc/drogon/plugins/GlobalFilters.h @@ -42,6 +42,7 @@ class DROGON_EXPORT GlobalFilters GlobalFilters() { } + void initAndStart(const Json::Value &config) override; void shutdown() override; diff --git a/lib/inc/drogon/plugins/Hodor.h b/lib/inc/drogon/plugins/Hodor.h index 174efd9d22..81f88a5784 100644 --- a/lib/inc/drogon/plugins/Hodor.h +++ b/lib/inc/drogon/plugins/Hodor.h @@ -15,9 +15,9 @@ #include #include #include -#include #include #include +#include namespace drogon { @@ -85,18 +85,21 @@ class DROGON_EXPORT Hodor : public drogon::Plugin Hodor() { } + void initAndStart(const Json::Value &config) override; void shutdown() override; + /** * @brief the method is used to set a function to get the user id from the * request. users should call this method after calling the app().run() * method. etc. use the beginning advice of AOP. * */ void setUserIdGetter( - std::function(const HttpRequestPtr &)> func) + std::function(const HttpRequestPtr &)> func) { userIdGetter_ = std::move(func); } + /** * @brief the method is used to set a function to create the response when * the rate limit is exceeded. users should call this method after calling @@ -121,6 +124,7 @@ class DROGON_EXPORT Hodor : public drogon::Plugin std::unique_ptr> userLimiterMapPtr; }; + LimitStrategy makeLimitStrategy(const Json::Value &config); std::vector limitStrategies_; RateLimiterType algorithm_{RateLimiterType::kTokenBucket}; @@ -128,7 +132,7 @@ class DROGON_EXPORT Hodor : public drogon::Plugin bool multiThreads_{true}; bool useRealIpResolver_{false}; size_t limiterExpireTime_{600}; - std::function(const drogon::HttpRequestPtr &)> + std::function(const drogon::HttpRequestPtr &)> userIdGetter_; std::function rejectResponseFactory_; @@ -139,7 +143,7 @@ class DROGON_EXPORT Hodor : public drogon::Plugin bool checkLimit(const drogon::HttpRequestPtr &req, const LimitStrategy &strategy, const std::string &ip, - const drogon::optional &userId); + const std::optional &userId); HttpResponsePtr rejectResponse_; }; } // namespace plugin diff --git a/lib/inc/drogon/plugins/Plugin.h b/lib/inc/drogon/plugins/Plugin.h index 5b044c6ed3..25310055eb 100644 --- a/lib/inc/drogon/plugins/Plugin.h +++ b/lib/inc/drogon/plugins/Plugin.h @@ -82,18 +82,22 @@ class DROGON_EXPORT PluginBase : public virtual DrObjectBase, private: PluginStatus status_{PluginStatus::None}; friend class PluginsManager; + void setConfig(const Json::Value &config) { config_ = config; } + void addDependency(PluginBase *dp) { dependencies_.push_back(dp); } + void setInitializedCallback(const std::function &cb) { initializedCallback_ = cb; } + Json::Value config_; std::vector dependencies_; std::function initializedCallback_; @@ -109,10 +113,12 @@ struct IsPlugin { return 0; } + static char test(PluginBase *) { return 0; } + static constexpr bool value = (sizeof(test((TYPE *)nullptr)) == sizeof(char)); }; diff --git a/lib/inc/drogon/plugins/RealIpResolver.h b/lib/inc/drogon/plugins/RealIpResolver.h index c4d68168f4..4b415b3496 100644 --- a/lib/inc/drogon/plugins/RealIpResolver.h +++ b/lib/inc/drogon/plugins/RealIpResolver.h @@ -47,6 +47,7 @@ class DROGON_EXPORT RealIpResolver : public drogon::Plugin RealIpResolver() { } + void initAndStart(const Json::Value &config) override; void shutdown() override; diff --git a/lib/inc/drogon/plugins/SecureSSLRedirector.h b/lib/inc/drogon/plugins/SecureSSLRedirector.h index bd079436da..704ee011bf 100644 --- a/lib/inc/drogon/plugins/SecureSSLRedirector.h +++ b/lib/inc/drogon/plugins/SecureSSLRedirector.h @@ -54,6 +54,7 @@ class DROGON_EXPORT SecureSSLRedirector SecureSSLRedirector() { } + /// This method must be called by drogon to initialize and start the plugin. /// It must be implemented by the user. void initAndStart(const Json::Value &config) override; diff --git a/lib/inc/drogon/plugins/SlashRemover.h b/lib/inc/drogon/plugins/SlashRemover.h index c05d6a0ea1..db5e91caad 100644 --- a/lib/inc/drogon/plugins/SlashRemover.h +++ b/lib/inc/drogon/plugins/SlashRemover.h @@ -51,6 +51,7 @@ class DROGON_EXPORT SlashRemover : public drogon::Plugin SlashRemover() { } + void initAndStart(const Json::Value &config) override; void shutdown() override; diff --git a/lib/inc/drogon/utils/FunctionTraits.h b/lib/inc/drogon/utils/FunctionTraits.h index 9f066393ad..4bc5d0aa42 100644 --- a/lib/inc/drogon/utils/FunctionTraits.h +++ b/lib/inc/drogon/utils/FunctionTraits.h @@ -48,12 +48,14 @@ struct FunctionTraits; // functor,lambda,std::function... template -struct FunctionTraits : public FunctionTraits::type::operator())> +struct FunctionTraits + : public FunctionTraits< + decltype(&std::remove_reference::type::operator())> { static const bool isClassFunction = false; static const bool isDrObjectClass = false; using class_type = void; + static const std::string name() { return std::string("Functor"); @@ -69,6 +71,7 @@ struct FunctionTraits static const bool isDrObjectClass = std::is_base_of, ClassType>::value; using class_type = ClassType; + static const std::string name() { return std::string("Class Function"); @@ -84,6 +87,7 @@ struct FunctionTraits static const bool isDrObjectClass = std::is_base_of, ClassType>::value; using class_type = ClassType; + static const std::string name() { return std::string("Class Function"); @@ -127,6 +131,7 @@ struct FunctionTraits< using first_param_type = HttpRequestPtr; using return_type = AsyncTask; }; + template struct FunctionTraits< Task<> (*)(HttpRequestPtr req, @@ -139,6 +144,7 @@ struct FunctionTraits< using first_param_type = HttpRequestPtr; using return_type = Task<>; }; + template struct FunctionTraits (*)(HttpRequestPtr req, Arguments...)> @@ -193,6 +199,7 @@ struct FunctionTraits static const bool isClassFunction = false; static const bool isDrObjectClass = false; static const bool isCoroutine = false; + static const std::string name() { return std::string("Normal or Static Function"); diff --git a/lib/inc/drogon/utils/HttpConstraint.h b/lib/inc/drogon/utils/HttpConstraint.h index c1af00f465..43af185266 100644 --- a/lib/inc/drogon/utils/HttpConstraint.h +++ b/lib/inc/drogon/utils/HttpConstraint.h @@ -16,6 +16,7 @@ #include #include + namespace drogon { namespace internal @@ -34,22 +35,27 @@ class HttpConstraint : type_(ConstraintType::HttpMethod), method_(method) { } + HttpConstraint(const std::string &filterName) : type_(ConstraintType::HttpFilter), filterName_(filterName) { } + HttpConstraint(const char *filterName) : type_(ConstraintType::HttpFilter), filterName_(filterName) { } + ConstraintType type() const { return type_; } + HttpMethod getHttpMethod() const { return method_; } + const std::string &getFilterName() const { return filterName_; diff --git a/lib/inc/drogon/utils/OStringStream.h b/lib/inc/drogon/utils/OStringStream.h index 2e90ceadf4..f108d04132 100644 --- a/lib/inc/drogon/utils/OStringStream.h +++ b/lib/inc/drogon/utils/OStringStream.h @@ -15,7 +15,7 @@ #pragma once #include #include -#include +#include namespace drogon { @@ -41,14 +41,17 @@ struct CanConvertToString std::is_same(0)), yes>::value; }; } // namespace internal + class OStringStream { public: OStringStream() = default; + void reserve(size_t size) { buffer_.reserve(size); } + template std::enable_if_t::value, OStringStream&> operator<<(T&& value) @@ -58,6 +61,7 @@ class OStringStream buffer_.append(ss.str()); return *this; } + template std::enable_if_t::value, OStringStream&> operator<<(T&& value) @@ -65,18 +69,21 @@ class OStringStream buffer_.append(std::to_string(std::forward(value))); return *this; } + template OStringStream& operator<<(const char (&buf)[N]) { buffer_.append(buf, N - 1); return *this; } - OStringStream& operator<<(const string_view& str) + + OStringStream& operator<<(const std::string_view& str) { buffer_.append(str.data(), str.length()); return *this; } - OStringStream& operator<<(string_view&& str) + + OStringStream& operator<<(std::string_view&& str) { buffer_.append(str.data(), str.length()); return *this; @@ -87,6 +94,7 @@ class OStringStream buffer_.append(str); return *this; } + OStringStream& operator<<(std::string&& str) { buffer_.append(std::move(str)); @@ -129,6 +137,7 @@ class OStringStream { return buffer_; } + const std::string& str() const { return buffer_; diff --git a/lib/inc/drogon/utils/Utilities.h b/lib/inc/drogon/utils/Utilities.h index 9e2123516b..44e1e92d4b 100644 --- a/lib/inc/drogon/utils/Utilities.h +++ b/lib/inc/drogon/utils/Utilities.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,6 +26,8 @@ #include #include #include +#include +#include #ifdef _WIN32 #include DROGON_EXPORT char *strptime(const char *s, const char *f, struct tm *tm); @@ -55,17 +57,18 @@ struct CanConvertFromStringStream yes>::value; }; } // namespace internal + namespace utils { /// Determine if the string is an integer DROGON_EXPORT bool isInteger(const std::string &str); /// Determine if the string is an integer -DROGON_EXPORT bool isInteger(string_view str); +DROGON_EXPORT bool isInteger(std::string_view str); /// Determine if the string is base64 encoded DROGON_EXPORT bool isBase64(const std::string &str); /// Determine if the string is base64 encoded -DROGON_EXPORT bool isBase64(string_view str); +DROGON_EXPORT bool isBase64(std::string_view str); /// Generate random a string /** @@ -106,19 +109,19 @@ DROGON_EXPORT std::set splitStringToSet( DROGON_EXPORT std::string getUuid(); /// Get the encoded length of base64. -constexpr size_t base64EncodedLength(unsigned int in_len, bool padded = true) +constexpr size_t base64EncodedLength(size_t in_len, bool padded = true) { return padded ? ((in_len + 3 - 1) / 3) * 4 : (in_len * 8 + 6 - 1) / 6; } /// Encode the string to base64 format. DROGON_EXPORT std::string base64Encode(const unsigned char *bytes_to_encode, - unsigned int in_len, + size_t in_len, bool url_safe = false, bool padded = true); /// Encode the string to base64 format. -inline std::string base64Encode(string_view data, +inline std::string base64Encode(std::string_view data, bool url_safe = false, bool padded = true) { @@ -130,40 +133,43 @@ inline std::string base64Encode(string_view data, /// Encode the string to base64 format with no padding. inline std::string base64EncodeUnpadded(const unsigned char *bytes_to_encode, - unsigned int in_len, + size_t in_len, bool url_safe = false) { return base64Encode(bytes_to_encode, in_len, url_safe, false); } /// Encode the string to base64 format with no padding. -inline std::string base64EncodeUnpadded(string_view data, bool url_safe = false) +inline std::string base64EncodeUnpadded(std::string_view data, + bool url_safe = false) { return base64Encode(data, url_safe, false); } /// Get the decoded length of base64. -constexpr size_t base64DecodedLength(unsigned int in_len) +constexpr size_t base64DecodedLength(size_t in_len) { return (in_len * 3) / 4; } /// Decode the base64 format string. -DROGON_EXPORT std::string base64Decode(string_view encoded_string); +DROGON_EXPORT std::string base64Decode(std::string_view encoded_string); DROGON_EXPORT std::vector base64DecodeToVector( - string_view encoded_string); + std::string_view encoded_string); /// Check if the string need decoding DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end); /// Decode from or encode to the URL format string DROGON_EXPORT std::string urlDecode(const char *begin, const char *end); + inline std::string urlDecode(const std::string &szToDecode) { auto begin = szToDecode.data(); return urlDecode(begin, begin + szToDecode.length()); } -inline std::string urlDecode(const string_view &szToDecode) + +inline std::string urlDecode(const std::string_view &szToDecode) { auto begin = szToDecode.data(); return urlDecode(begin, begin + szToDecode.length()); @@ -174,30 +180,35 @@ DROGON_EXPORT std::string urlEncodeComponent(const std::string &); /// Get the MD5 digest of a string. DROGON_EXPORT std::string getMd5(const char *data, const size_t dataLen); + inline std::string getMd5(const std::string &originalString) { return getMd5(originalString.data(), originalString.length()); } DROGON_EXPORT std::string getSha1(const char *data, const size_t dataLen); + inline std::string getSha1(const std::string &originalString) { return getSha1(originalString.data(), originalString.length()); } DROGON_EXPORT std::string getSha256(const char *data, const size_t dataLen); + inline std::string getSha256(const std::string &originalString) { return getSha256(originalString.data(), originalString.length()); } DROGON_EXPORT std::string getSha3(const char *data, const size_t dataLen); + inline std::string getSha3(const std::string &originalString) { return getSha3(originalString.data(), originalString.length()); } DROGON_EXPORT std::string getBlake2b(const char *data, const size_t dataLen); + inline std::string getBlake2b(const std::string &originalString) { return getBlake2b(originalString.data(), originalString.length()); @@ -312,6 +323,7 @@ inline std::wstring toNativePath(const std::string &strPath) { return trantor::utils::toNativePath(strPath); } + inline const std::wstring &toNativePath(const std::wstring &strPath) { return trantor::utils::toNativePath(strPath); @@ -321,6 +333,7 @@ inline const std::string &toNativePath(const std::string &strPath) { return trantor::utils::toNativePath(strPath); } + inline std::string toNativePath(const std::wstring &strPath) { return trantor::utils::toNativePath(strPath); @@ -347,6 +360,7 @@ inline const std::string &fromNativePath(const std::string &strPath) { return trantor::utils::fromNativePath(strPath); } + // Convert on all systems inline std::string fromNativePath(const std::wstring &strPath) { @@ -489,6 +503,7 @@ DROGON_EXPORT bool supportsTls() noexcept; namespace internal { DROGON_EXPORT extern const size_t fixedRandomNumber; + struct SafeStringHash { size_t operator()(const std::string &str) const @@ -504,3 +519,17 @@ struct SafeStringHash } // namespace internal } // namespace utils } // namespace drogon + +namespace trantor +{ +inline LogStream &operator<<(LogStream &ls, const std::string_view &v) +{ + ls.append(v.data(), v.length()); + return ls; +} + +inline LogStream &operator<<(LogStream &ls, const std::filesystem::path &p) +{ + return ls << p.string(); +} +} // namespace trantor diff --git a/lib/inc/drogon/utils/any.h b/lib/inc/drogon/utils/any.h deleted file mode 100644 index 52a249f05f..0000000000 --- a/lib/inc/drogon/utils/any.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * - * any.h - * An Tao - * - * Copyright 2018, An Tao. All rights reserved. - * https://github.com/an-tao/drogon - * Use of this source code is governed by a MIT license - * that can be found in the License file. - * - * Drogon - * - */ - -#pragma once -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#include -#else -#include -#endif - -namespace drogon -{ -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -using std::any; -using std::any_cast; -#else -using boost::any; -using boost::any_cast; -#endif -} // namespace drogon diff --git a/lib/inc/drogon/utils/apply.h b/lib/inc/drogon/utils/apply.h index 137f39262d..c1e36e0217 100644 --- a/lib/inc/drogon/utils/apply.h +++ b/lib/inc/drogon/utils/apply.h @@ -17,6 +17,7 @@ #include #else #include + namespace { template diff --git a/lib/inc/drogon/utils/coroutine.h b/lib/inc/drogon/utils/coroutine.h index 509ca2aadc..3f398ba6e1 100644 --- a/lib/inc/drogon/utils/coroutine.h +++ b/lib/inc/drogon/utils/coroutine.h @@ -13,7 +13,6 @@ */ #pragma once -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include namespace drogon { @@ -90,11 +90,13 @@ struct final_awaiter { return false; } + template auto await_suspend(std::coroutine_handle handle) noexcept { return handle.promise().continuation_; } + void await_resume() noexcept { } @@ -109,18 +111,23 @@ struct [[nodiscard]] Task Task(handle_type h) : coro_(h) { } + Task(const Task &) = delete; + Task(Task &&other) { coro_ = other.coro_; other.coro_ = nullptr; } + ~Task() { if (coro_) coro_.destroy(); } + Task &operator=(const Task &) = delete; + Task &operator=(Task &&other) { if (std::addressof(other) == this) @@ -139,14 +146,17 @@ struct [[nodiscard]] Task { return Task{handle_type::from_promise(*this)}; } + std::suspend_always initial_suspend() { return {}; } + void return_value(const T &v) { value = v; } + void return_value(T &&v) { value = std::move(v); @@ -183,7 +193,7 @@ struct [[nodiscard]] Task continuation_ = handle; } - optional value; + std::optional value; std::exception_ptr exception_; std::coroutine_handle<> continuation_; }; @@ -196,15 +206,18 @@ struct [[nodiscard]] Task explicit awaiter(handle_type coro) : coro_(coro) { } + bool await_ready() noexcept { return !coro_ || coro_.done(); } + auto await_suspend(std::coroutine_handle<> handle) noexcept { coro_.promise().setContinuation(handle); return coro_; } + T await_resume() { auto &&v = coro_.promise().result(); @@ -214,6 +227,7 @@ struct [[nodiscard]] Task private: handle_type coro_; }; + return awaiter(coro_); } @@ -225,15 +239,18 @@ struct [[nodiscard]] Task explicit awaiter(handle_type coro) : coro_(coro) { } + bool await_ready() noexcept { return !coro_ || coro_.done(); } + auto await_suspend(std::coroutine_handle<> handle) noexcept { coro_.promise().setContinuation(handle); return coro_; } + T await_resume() { return std::move(coro_.promise().result()); @@ -242,8 +259,10 @@ struct [[nodiscard]] Task private: handle_type coro_; }; + return awaiter(coro_); } + handle_type coro_; }; @@ -256,18 +275,23 @@ struct [[nodiscard]] Task Task(handle_type handle) : coro_(handle) { } + Task(const Task &) = delete; + Task(Task &&other) { coro_ = other.coro_; other.coro_ = nullptr; } + ~Task() { if (coro_) coro_.destroy(); } + Task &operator=(const Task &) = delete; + Task &operator=(Task &&other) { if (std::addressof(other) == this) @@ -286,30 +310,37 @@ struct [[nodiscard]] Task { return Task<>{handle_type::from_promise(*this)}; } + std::suspend_always initial_suspend() { return {}; } + void return_void() { } + auto final_suspend() noexcept { return final_awaiter{}; } + void unhandled_exception() { exception_ = std::current_exception(); } + void result() { if (exception_ != nullptr) std::rethrow_exception(exception_); } + void setContinuation(std::coroutine_handle<> handle) { continuation_ = handle; } + std::exception_ptr exception_; std::coroutine_handle<> continuation_; }; @@ -322,15 +353,18 @@ struct [[nodiscard]] Task explicit awaiter(handle_type coro) : coro_(coro) { } + bool await_ready() noexcept { return !coro_ || coro_.done(); } + auto await_suspend(std::coroutine_handle<> handle) noexcept { coro_.promise().setContinuation(handle); return coro_; } + auto await_resume() { coro_.promise().result(); @@ -339,6 +373,7 @@ struct [[nodiscard]] Task private: handle_type coro_; }; + return awaiter(coro_); } @@ -350,15 +385,18 @@ struct [[nodiscard]] Task explicit awaiter(handle_type coro) : coro_(coro) { } + bool await_ready() noexcept { return false; } + auto await_suspend(std::coroutine_handle<> handle) noexcept { coro_.promise().setContinuation(handle); return coro_; } + void await_resume() { coro_.promise().result(); @@ -367,8 +405,10 @@ struct [[nodiscard]] Task private: handle_type coro_; }; + return awaiter(coro_); } + handle_type coro_; }; @@ -388,6 +428,7 @@ struct AsyncTask } AsyncTask(const AsyncTask &) = delete; + AsyncTask(AsyncTask &&other) { coro_ = other.coro_; @@ -395,6 +436,7 @@ struct AsyncTask } AsyncTask &operator=(const AsyncTask &) = delete; + AsyncTask &operator=(AsyncTask &&other) { if (std::addressof(other) == this) @@ -454,9 +496,11 @@ struct AsyncTask { } }; + return awaiter{}; } }; + bool await_ready() const noexcept { return coro_.done(); @@ -502,7 +546,7 @@ struct CallbackAwaiter : public trantor::NonCopyable // HACK: Not all desired types are default constructable. But we need the // entire struct to be constructed for awaiting. std::optional takes care of // that. - optional result_; + std::optional result_; std::exception_ptr exception_{nullptr}; protected: @@ -510,10 +554,12 @@ struct CallbackAwaiter : public trantor::NonCopyable { exception_ = e; } + void setValue(const T &v) { result_.emplace(v); } + void setValue(T &&v) { result_.emplace(std::move(v)); @@ -581,7 +627,7 @@ auto sync_wait(Await &&await) } else { - optional value; + std::optional value; auto task = [&]() -> AsyncTask { try { @@ -644,10 +690,12 @@ struct [[nodiscard]] TimerAwaiter : CallbackAwaiter : loop_(loop), delay_(delay.count()) { } + TimerAwaiter(trantor::EventLoop *loop, double delay) : loop_(loop), delay_(delay) { } + void await_suspend(std::coroutine_handle<> handle) { loop_->runAfter(delay_, [handle]() { handle.resume(); }); @@ -669,6 +717,7 @@ struct [[nodiscard]] LoopAwaiter : CallbackAwaiter { assert(workLoop); } + void await_suspend(std::coroutine_handle<> handle) { workLoop_->queueInLoop([handle, this]() { @@ -702,6 +751,7 @@ struct [[nodiscard]] SwitchThreadAwaiter : CallbackAwaiter explicit SwitchThreadAwaiter(trantor::EventLoop *loop) : loop_(loop) { } + void await_suspend(std::coroutine_handle<> handle) { loop_->runInLoop([handle]() { handle.resume(); }); @@ -710,12 +760,14 @@ struct [[nodiscard]] SwitchThreadAwaiter : CallbackAwaiter private: trantor::EventLoop *loop_; }; + struct [[nodiscard]] EndAwaiter : CallbackAwaiter { EndAwaiter(trantor::EventLoop *loop) : loop_(loop) { assert(loop); } + void await_suspend(std::coroutine_handle<> handle) { loop_->runOnQuit([handle]() { handle.resume(); }); @@ -816,6 +868,7 @@ std::function async_func(Coro &&coro) async_run(std::move(coro)); }; } + namespace internal { template @@ -825,6 +878,7 @@ struct [[nodiscard]] EventLoopAwaiter : public drogon::CallbackAwaiter : task_(std::move(task)), loop_(loop) { } + void await_suspend(std::coroutine_handle<> handle) { loop_->queueInLoop([this, handle]() { diff --git a/lib/inc/drogon/utils/optional.h b/lib/inc/drogon/utils/optional.h deleted file mode 100644 index 7700402c1a..0000000000 --- a/lib/inc/drogon/utils/optional.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * - * optional.h - * An Tao - * - * Copyright 2018, An Tao. All rights reserved. - * https://github.com/an-tao/drogon - * Use of this source code is governed by a MIT license - * that can be found in the License file. - * - * Drogon - * - */ - -#pragma once -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#include -#else -#include -#endif - -namespace drogon -{ -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -using std::nullopt; -using std::optional; -#else -const boost::none_t nullopt = boost::none; -using boost::optional; -#endif -} // namespace drogon diff --git a/lib/inc/drogon/utils/string_view.h b/lib/inc/drogon/utils/string_view.h deleted file mode 100644 index c145f83490..0000000000 --- a/lib/inc/drogon/utils/string_view.h +++ /dev/null @@ -1,330 +0,0 @@ -/** - * - * @file string_view.h - * @author An Tao - * - * Copyright 2018, An Tao. All rights reserved. - * https://github.com/an-tao/drogon - * Use of this source code is governed by a MIT license - * that can be found in the License file. - * - * Drogon - * - */ - -#pragma once -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#include -#else -#include -#include -#include -#endif - -#include - -namespace drogon -{ -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -using std::string_view; -#else -using boost::string_view; -#endif -} // namespace drogon -namespace trantor -{ -inline LogStream &operator<<(LogStream &ls, const drogon::string_view &v) -{ - ls.append(v.data(), v.length()); - return ls; -} -} // namespace trantor -#if __cplusplus < 201703L && !(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -namespace drogon -{ -#ifndef _MSC_VER -template -struct StringViewHasher; - -template <> -struct StringViewHasher<4> -{ - size_t operator()(const drogon::string_view &__str) const noexcept - { - // Take from the memory header file - //===-------------------------- memory - //------------------------------------===// - // - // The LLVM Compiler Infrastructure - // - // This file is dual licensed under the MIT and the University of - // Illinois Open Source Licenses. See LICENSE.TXT for details. - // - //===----------------------------------------------------------------------===// - const uint32_t __m = 0x5bd1e995; - const uint32_t __r = 24; - uint32_t __h = __str.length(); - auto __len = __h; - const unsigned char *__data = (const unsigned char *)(__str.data()); - for (; __len >= 4; __data += 4, __len -= 4) - { - uint32_t __k = *((uint32_t *)__data); - __k *= __m; - __k ^= __k >> __r; - __k *= __m; - __h *= __m; - __h ^= __k; - } - switch (__len) - { - case 3: - __h ^= __data[2] << 16; - case 2: - __h ^= __data[1] << 8; - case 1: - __h ^= __data[0]; - __h *= __m; - } - __h ^= __h >> 13; - __h *= __m; - __h ^= __h >> 15; - return __h; - } -}; - -template <> -struct StringViewHasher<8> -{ - static const size_t __k0 = 0xc3a5c85c97cb3127ULL; - static const size_t __k1 = 0xb492b66fbe98f273ULL; - static const size_t __k2 = 0x9ae16a3b2f90404fULL; - static const size_t __k3 = 0xc949d7c7509e6557ULL; - - static size_t __rotate(size_t __val, int __shift) - { - return __shift == 0 ? __val - : ((__val >> __shift) | (__val << (64 - __shift))); - } - - static size_t __rotate_by_at_least_1(size_t __val, int __shift) - { - return (__val >> __shift) | (__val << (64 - __shift)); - } - - static size_t __shift_mix(size_t __val) - { - return __val ^ (__val >> 47); - } - - static size_t __hash_len_16(size_t __u, size_t __v) - { - const size_t __mul = 0x9ddfea08eb382d69ULL; - size_t __a = (__u ^ __v) * __mul; - __a ^= (__a >> 47); - size_t __b = (__v ^ __a) * __mul; - __b ^= (__b >> 47); - __b *= __mul; - return __b; - } - template - inline static Size __loadword(const void *__p) - { - Size __r; - std::memcpy(&__r, __p, sizeof(__r)); - return __r; - } - - static size_t __hash_len_0_to_16(const char *__s, size_t __len) - { - if (__len > 8) - { - const size_t __a = __loadword(__s); - const size_t __b = __loadword(__s + __len - 8); - return __hash_len_16(__a, - __rotate_by_at_least_1(__b + __len, __len)) ^ - __b; - } - if (__len >= 4) - { - const uint32_t __a = __loadword(__s); - const uint32_t __b = __loadword(__s + __len - 4); - return __hash_len_16(__len + (__a << 3), __b); - } - if (__len > 0) - { - const unsigned char __a = __s[0]; - const unsigned char __b = __s[__len >> 1]; - const unsigned char __c = __s[__len - 1]; - const uint32_t __y = - static_cast(__a) + (static_cast(__b) << 8); - const uint32_t __z = __len + (static_cast(__c) << 2); - return __shift_mix(__y * __k2 ^ __z * __k3) * __k2; - } - return __k2; - } - - static size_t __hash_len_17_to_32(const char *__s, size_t __len) - { - const size_t __a = __loadword(__s) * __k1; - const size_t __b = __loadword(__s + 8); - const size_t __c = __loadword(__s + __len - 8) * __k2; - const size_t __d = __loadword(__s + __len - 16) * __k0; - return __hash_len_16(__rotate(__a - __b, 43) + __rotate(__c, 30) + __d, - __a + __rotate(__b ^ __k3, 20) - __c + __len); - } - - // Return a 16-byte hash for 48 bytes. Quick and dirty. - // Callers do best to use "random-looking" values for a and b. - static std::pair __weak_hash_len_32_with_seeds(size_t __w, - size_t __x, - size_t __y, - size_t __z, - size_t __a, - size_t __b) - { - __a += __w; - __b = __rotate(__b + __a + __z, 21); - const size_t __c = __a; - __a += __x; - __a += __y; - __b += __rotate(__a, 44); - return std::pair(__a + __z, __b + __c); - } - - // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. - static std::pair __weak_hash_len_32_with_seeds( - const char *__s, - size_t __a, - size_t __b) - { - return __weak_hash_len_32_with_seeds(__loadword(__s), - __loadword(__s + 8), - __loadword(__s + 16), - __loadword(__s + 24), - __a, - __b); - } - - // Return an 8-byte hash for 33 to 64 bytes. - static size_t __hash_len_33_to_64(const char *__s, size_t __len) - { - size_t __z = __loadword(__s + 24); - size_t __a = __loadword(__s) + - (__len + __loadword(__s + __len - 16)) * __k0; - size_t __b = __rotate(__a + __z, 52); - size_t __c = __rotate(__a, 37); - __a += __loadword(__s + 8); - __c += __rotate(__a, 7); - __a += __loadword(__s + 16); - size_t __vf = __a + __z; - size_t __vs = __b + __rotate(__a, 31) + __c; - __a = - __loadword(__s + 16) + __loadword(__s + __len - 32); - __z += __loadword(__s + __len - 8); - __b = __rotate(__a + __z, 52); - __c = __rotate(__a, 37); - __a += __loadword(__s + __len - 24); - __c += __rotate(__a, 7); - __a += __loadword(__s + __len - 16); - size_t __wf = __a + __z; - size_t __ws = __b + __rotate(__a, 31) + __c; - size_t __r = __shift_mix((__vf + __ws) * __k2 + (__wf + __vs) * __k0); - return __shift_mix(__r * __k0 + __vs) * __k2; - } - size_t operator()(const drogon::string_view &__str) const noexcept - { - size_t __len = __str.length(); - const char *__s = static_cast(__str.data()); - if (__len <= 32) - { - if (__len <= 16) - { - return __hash_len_0_to_16(__s, __len); - } - else - { - return __hash_len_17_to_32(__s, __len); - } - } - else if (__len <= 64) - { - return __hash_len_33_to_64(__s, __len); - } - - // For strings over 64 bytes we hash the end first, and then as we - // loop we keep 56 bytes of state: v, w, x, y, and z. - size_t __x = __loadword(__s + __len - 40); - size_t __y = __loadword(__s + __len - 16) + - __loadword(__s + __len - 56); - size_t __z = __hash_len_16(__loadword(__s + __len - 48) + __len, - __loadword(__s + __len - 24)); - std::pair __v = - __weak_hash_len_32_with_seeds(__s + __len - 64, __len, __z); - std::pair __w = - __weak_hash_len_32_with_seeds(__s + __len - 32, __y + __k1, __x); - __x = __x * __k1 + __loadword(__s); - - // Decrease len to the nearest multiple of 64, and operate on 64-byte - // chunks. - __len = (__len - 1) & ~static_cast(63); - do - { - __x = __rotate(__x + __y + __v.first + __loadword(__s + 8), - 37) * - __k1; - __y = - __rotate(__y + __v.second + __loadword(__s + 48), 42) * - __k1; - __x ^= __w.second; - __y += __v.first + __loadword(__s + 40); - __z = __rotate(__z + __w.first, 33) * __k1; - __v = __weak_hash_len_32_with_seeds(__s, - __v.second * __k1, - __x + __w.first); - __w = __weak_hash_len_32_with_seeds( - __s + 32, __z + __w.second, __y + __loadword(__s + 16)); - std::swap(__z, __x); - __s += 64; - __len -= 64; - } while (__len != 0); - return __hash_len_16(__hash_len_16(__v.first, __w.first) + - __shift_mix(__y) * __k1 + __z, - __hash_len_16(__v.second, __w.second) + __x); - } -}; -#else - -// Taken and modified from https://stackoverflow.com/a/8317622/3687637 -struct ShortStringViewHasher -{ - size_t operator()(const string_view &sv) const - { - const size_t initValue = 1049039; - const size_t A = 6665339; - const size_t B = 2534641; - size_t h = initValue; - for (char ch : sv) - h = (h * A) ^ (ch * B); - return h; - } -}; -#endif -} // namespace drogon -namespace std -{ -template <> -struct hash -{ - size_t operator()(const drogon::string_view &__str) const noexcept - { - // MSVC is having problems with non-aligned strings -#ifndef _MSC_VER - return drogon::StringViewHasher()(__str); -#else - return drogon::ShortStringViewHasher(__str); -#endif - } -}; -} // namespace std - -#endif diff --git a/lib/src/AccessLogger.cc b/lib/src/AccessLogger.cc index 952dc5a514..2a00b98cb9 100644 --- a/lib/src/AccessLogger.cc +++ b/lib/src/AccessLogger.cc @@ -331,6 +331,7 @@ void AccessLogger::outputReqQuery(trantor::LogStream &stream, { stream << req->query(); } + //$request_url void AccessLogger::outputReqURL(trantor::LogStream &stream, const drogon::HttpRequestPtr &req, @@ -407,6 +408,7 @@ void AccessLogger::outputRespLength(trantor::LogStream &stream, { stream << resp->body().length(); } + void AccessLogger::outputMethod(trantor::LogStream &stream, const drogon::HttpRequestPtr &req, const drogon::HttpResponsePtr &) @@ -484,6 +486,7 @@ void AccessLogger::outputStatusString(trantor::LogStream &stream, int code = resp->getStatusCode(); stream << code << " " << statusCodeToString(code); } + //$status_code void AccessLogger::outputStatusCode(trantor::LogStream &stream, const drogon::HttpRequestPtr &, @@ -491,6 +494,7 @@ void AccessLogger::outputStatusCode(trantor::LogStream &stream, { stream << resp->getStatusCode(); } + //$processing_time void AccessLogger::outputProcessingTime(trantor::LogStream &stream, const drogon::HttpRequestPtr &req, diff --git a/lib/src/CacheFile.h b/lib/src/CacheFile.h index b1aebb10dc..899b9b7004 100644 --- a/lib/src/CacheFile.h +++ b/lib/src/CacheFile.h @@ -14,9 +14,9 @@ #pragma once -#include #include #include +#include #include namespace drogon @@ -26,16 +26,19 @@ class CacheFile : public trantor::NonCopyable public: explicit CacheFile(const std::string &path, bool autoDelete = true); ~CacheFile(); + void append(const std::string &data) { append(data.data(), data.length()); } + void append(const char *data, size_t length); - string_view getStringView() + + std::string_view getStringView() { if (data()) - return string_view(data_, dataLength_); - return string_view(); + return std::string_view(data_, dataLength_); + return std::string_view(); } private: diff --git a/lib/src/ConfigAdapter.h b/lib/src/ConfigAdapter.h index 3f9b8a8706..c9951c0326 100644 --- a/lib/src/ConfigAdapter.h +++ b/lib/src/ConfigAdapter.h @@ -15,6 +15,7 @@ class ConfigAdapter noexcept(false) = 0; virtual std::vector getExtensions() const = 0; }; + using ConfigAdapterPtr = std::shared_ptr; } // namespace drogon \ No newline at end of file diff --git a/lib/src/ConfigAdapterManager.cc b/lib/src/ConfigAdapterManager.cc index d49f7847eb..7b89f00380 100644 --- a/lib/src/ConfigAdapterManager.cc +++ b/lib/src/ConfigAdapterManager.cc @@ -14,6 +14,7 @@ using namespace drogon; adapters_[ext] = adapterPtr; \ } \ } + ConfigAdapterManager &ConfigAdapterManager::instance() { static ConfigAdapterManager instance; diff --git a/lib/src/ConfigAdapterManager.h b/lib/src/ConfigAdapterManager.h index 94f61e260c..89a811449e 100644 --- a/lib/src/ConfigAdapterManager.h +++ b/lib/src/ConfigAdapterManager.h @@ -2,6 +2,7 @@ #include "ConfigAdapterManager.h" #include "ConfigAdapter.h" #include + namespace drogon { class ConfigAdapterManager diff --git a/lib/src/ConfigLoader.cc b/lib/src/ConfigLoader.cc index 7b5537b2eb..8d479b2885 100644 --- a/lib/src/ConfigLoader.cc +++ b/lib/src/ConfigLoader.cc @@ -35,10 +35,11 @@ #endif #include -#include "filesystem.h" #include "ConfigAdapterManager.h" +#include using namespace drogon; + static bool bytesSize(std::string &sizeStr, size_t &size) { if (sizeStr.empty()) @@ -139,16 +140,20 @@ ConfigLoader::ConfigLoader(const std::string &configFile) ": " + e.what()); } } + ConfigLoader::ConfigLoader(const Json::Value &data) : configJsonRoot_(data) { } + ConfigLoader::ConfigLoader(Json::Value &&data) : configJsonRoot_(std::move(data)) { } + ConfigLoader::~ConfigLoader() { } + static void loadLogSetting(const Json::Value &log) { if (!log) @@ -184,6 +189,7 @@ static void loadLogSetting(const Json::Value &log) auto localTime = log.get("display_local_time", false).asBool(); trantor::Logger::setDisplayLocalTime(localTime); } + static void loadControllers(const Json::Value &controllers) { if (!controllers) @@ -240,6 +246,7 @@ static void loadControllers(const Json::Value &controllers) drogon::app().registerHttpSimpleController(path, ctrlName, constraints); } } + static void loadApp(const Json::Value &app) { if (!app) @@ -515,6 +522,7 @@ static void loadApp(const Json::Value &app) app.get("enabled_compressed_request", false).asBool(); drogon::app().enableCompressedRequest(enableCompressedRequests); } + static void loadDbClients(const Json::Value &dbClients) { if (!dbClients) @@ -646,6 +654,7 @@ static void loadListeners(const Json::Value &listeners) addr, port, useSSL, cert, key, useOldTLS, sslConfCmds); } } + static void loadSSL(const Json::Value &sslConf) { if (!sslConf) @@ -670,6 +679,7 @@ static void loadSSL(const Json::Value &sslConf) } drogon::app().setSSLConfigCommands(sslConfCmds); } + void ConfigLoader::load() { // std::cout< #include using namespace drogon; + std::string Cookie::cookieString() const { std::string ret = "Set-Cookie: "; diff --git a/lib/src/DbClientManager.h b/lib/src/DbClientManager.h index 9eae788a86..2a27872b54 100644 --- a/lib/src/DbClientManager.h +++ b/lib/src/DbClientManager.h @@ -30,18 +30,22 @@ class DbClientManager : public trantor::NonCopyable { public: void createDbClients(const std::vector &ioloops); + DbClientPtr getDbClient(const std::string &name) { assert(dbClientsMap_.find(name) != dbClientsMap_.end()); return dbClientsMap_[name]; } + ~DbClientManager(); + DbClientPtr getFastDbClient(const std::string &name) { auto iter = dbFastClientsMap_.find(name); assert(iter != dbFastClientsMap_.end()); return iter->second.getThreadData(); } + void createDbClient(const std::string &dbType, const std::string &host, const unsigned short port, @@ -59,6 +63,7 @@ class DbClientManager : public trantor::NonCopyable private: std::map dbClientsMap_; + struct DbInfo { std::string name_; @@ -69,6 +74,7 @@ class DbClientManager : public trantor::NonCopyable double timeout_; bool autoBatch_; }; + std::vector dbInfos_; std::map> dbFastClientsMap_; }; diff --git a/lib/src/DrClassMap.cc b/lib/src/DrClassMap.cc index 2f4c07f7dc..9f36d4706a 100644 --- a/lib/src/DrClassMap.cc +++ b/lib/src/DrClassMap.cc @@ -73,6 +73,7 @@ std::shared_ptr DrClassMap::newSharedObject( else return nullptr; } + const std::shared_ptr &DrClassMap::getSingleInstance( const std::string &className) { diff --git a/lib/src/FixedWindowRateLimiter.cc b/lib/src/FixedWindowRateLimiter.cc index f3be3ce9cd..df02afdcfe 100644 --- a/lib/src/FixedWindowRateLimiter.cc +++ b/lib/src/FixedWindowRateLimiter.cc @@ -10,6 +10,7 @@ FixedWindowRateLimiter::FixedWindowRateLimiter( timeUnit_(timeUnit) { } + // implementation of the fixed window algorithm bool FixedWindowRateLimiter::isAllowed() diff --git a/lib/src/FixedWindowRateLimiter.h b/lib/src/FixedWindowRateLimiter.h index 3a9833b7da..28e6ef0b04 100644 --- a/lib/src/FixedWindowRateLimiter.h +++ b/lib/src/FixedWindowRateLimiter.h @@ -2,6 +2,7 @@ #include #include + namespace drogon { class FixedWindowRateLimiter : public RateLimiter diff --git a/lib/src/GlobalFilters.cc b/lib/src/GlobalFilters.cc index 363b6bf5f8..59aaa236b2 100644 --- a/lib/src/GlobalFilters.cc +++ b/lib/src/GlobalFilters.cc @@ -93,6 +93,7 @@ void GlobalFilters::initAndStart(const Json::Value &config) std::move(accb)); }); } + void GlobalFilters::shutdown() { filters_.clear(); diff --git a/lib/src/Hodor.cc b/lib/src/Hodor.cc index 2f44a63603..a4d007344e 100644 --- a/lib/src/Hodor.cc +++ b/lib/src/Hodor.cc @@ -2,6 +2,7 @@ #include using namespace drogon::plugin; + Hodor::LimitStrategy Hodor::makeLimitStrategy(const Json::Value &config) { LimitStrategy strategy; @@ -62,6 +63,7 @@ Hodor::LimitStrategy Hodor::makeLimitStrategy(const Json::Value &config) } return strategy; } + void Hodor::initAndStart(const Json::Value &config) { algorithm_ = stringToRateLimiterType( @@ -118,7 +120,7 @@ void Hodor::shutdown() bool Hodor::checkLimit(const drogon::HttpRequestPtr &req, const LimitStrategy &strategy, const std::string &ip, - const drogon::optional &userId) + const std::optional &userId) { if (strategy.regexFlag) { @@ -200,6 +202,7 @@ bool Hodor::checkLimit(const drogon::HttpRequestPtr &req, } return true; } + void Hodor::onHttpRequest(const drogon::HttpRequestPtr &req, drogon::AdviceCallback &&adviceCallback, drogon::AdviceChainCallback &&chainCallback) @@ -208,7 +211,7 @@ void Hodor::onHttpRequest(const drogon::HttpRequestPtr &req, (useRealIpResolver_ ? drogon::plugin::RealIpResolver::GetRealAddr(req) : req->peerAddr()) .toIpNetEndian(); - optional userId; + std::optional userId; if (userIdGetter_) { userId = userIdGetter_(req); diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 2fe8c3b26b..df67636a87 100644 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -39,13 +39,13 @@ #include "StaticFileRouter.h" #include "WebSocketConnectionImpl.h" #include "WebsocketControllersRouter.h" -#include "filesystem.h" #include #include #include #include #include +#include #include #include @@ -198,41 +198,49 @@ HttpAppFrameworkImpl::~HttpAppFrameworkImpl() noexcept #endif sessionManagerPtr_.reset(); } + HttpAppFramework &HttpAppFrameworkImpl::setStaticFilesCacheTime(int cacheTime) { staticFileRouterPtr_->setStaticFilesCacheTime(cacheTime); return *this; } + int HttpAppFrameworkImpl::staticFilesCacheTime() const { return staticFileRouterPtr_->staticFilesCacheTime(); } + HttpAppFramework &HttpAppFrameworkImpl::setGzipStatic(bool useGzipStatic) { staticFileRouterPtr_->setGzipStatic(useGzipStatic); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setBrStatic(bool useGzipStatic) { staticFileRouterPtr_->setBrStatic(useGzipStatic); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setImplicitPageEnable( bool useImplicitPage) { staticFileRouterPtr_->setImplicitPageEnable(useImplicitPage); return *this; } + bool HttpAppFrameworkImpl::isImplicitPageEnabled() const { return staticFileRouterPtr_->isImplicitPageEnabled(); } + HttpAppFramework &HttpAppFrameworkImpl::setImplicitPage( const std::string &implicitPageFile) { staticFileRouterPtr_->setImplicitPage(implicitPageFile); return *this; } + const std::string &HttpAppFrameworkImpl::getImplicitPage() const { return staticFileRouterPtr_->getImplicitPage(); @@ -294,6 +302,7 @@ HttpAppFramework &HttpAppFrameworkImpl::registerWebSocketController( filtersAndMethods); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::registerHttpSimpleController( const std::string &pathName, const std::string &ctrlName, @@ -344,6 +353,7 @@ HttpAppFramework &HttpAppFrameworkImpl::setThreadNum(size_t threadNum) threadNum_ = threadNum; return *this; } + PluginBase *HttpAppFrameworkImpl::getPlugin(const std::string &name) { return pluginsManagerPtr_->getPlugin(name); @@ -354,6 +364,7 @@ std::shared_ptr HttpAppFrameworkImpl::getSharedPlugin( { return pluginsManagerPtr_->getSharedPlugin(name); } + void HttpAppFrameworkImpl::addPlugin( const std::string &name, const std::vector &dependencies, @@ -372,6 +383,7 @@ void HttpAppFrameworkImpl::addPlugin( auto &plugins = jsonRuntimeConfig_["plugins"]; plugins.append(pluginConfig); } + void HttpAppFrameworkImpl::addPlugins(const Json::Value &configs) { assert(!isRunning()); @@ -382,6 +394,7 @@ void HttpAppFrameworkImpl::addPlugins(const Json::Value &configs) plugins.append(config); } } + HttpAppFramework &HttpAppFrameworkImpl::addListener( const std::string &ip, uint16_t port, @@ -396,18 +409,21 @@ HttpAppFramework &HttpAppFrameworkImpl::addListener( ip, port, useSSL, certFile, keyFile, useOldTLS, sslConfCmds); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setMaxConnectionNum( size_t maxConnections) { maxConnectionNum_ = maxConnections; return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setMaxConnectionNumPerIP( size_t maxConnectionsPerIP) { maxConnectionNumPerIP_ = maxConnectionsPerIP; return *this; } + HttpAppFramework &HttpAppFrameworkImpl::loadConfigFile( const std::string &fileName) { @@ -416,6 +432,7 @@ HttpAppFramework &HttpAppFrameworkImpl::loadConfigFile( jsonConfig_ = loader.jsonValue(); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::loadConfigJson(const Json::Value &data) { ConfigLoader loader(data); @@ -423,6 +440,7 @@ HttpAppFramework &HttpAppFrameworkImpl::loadConfigJson(const Json::Value &data) jsonConfig_ = loader.jsonValue(); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::loadConfigJson(Json::Value &&data) { ConfigLoader loader(std::move(data)); @@ -430,6 +448,7 @@ HttpAppFramework &HttpAppFrameworkImpl::loadConfigJson(Json::Value &&data) jsonConfig_ = loader.jsonValue(); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setLogPath( const std::string &logPath, const std::string &logfileBaseName, @@ -456,23 +475,27 @@ HttpAppFramework &HttpAppFrameworkImpl::setLogPath( logfileMaxNum_ = maxFiles; return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setLogLevel( trantor::Logger::LogLevel level) { trantor::Logger::setLogLevel(level); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setLogLocalTime(bool on) { trantor::Logger::setDisplayLocalTime(on); return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setSSLConfigCommands( const std::vector> &sslConfCmds) { sslConfCmds_ = sslConfCmds; return *this; } + HttpAppFramework &HttpAppFrameworkImpl::setSSLFiles(const std::string &certPath, const std::string &keyPath) { @@ -738,15 +761,16 @@ HttpAppFramework &HttpAppFrameworkImpl::setUploadPath( { assert(!uploadPath.empty()); - filesystem::path fsUploadPath(utils::toNativePath(uploadPath)); + std::filesystem::path fsUploadPath(utils::toNativePath(uploadPath)); if (!fsUploadPath.is_absolute()) { - filesystem::path fsRoot(utils::toNativePath(rootPath_)); + std::filesystem::path fsRoot(utils::toNativePath(rootPath_)); fsUploadPath = fsRoot / fsUploadPath; } uploadPath_ = utils::fromNativePath(fsUploadPath.native()); return *this; } + void HttpAppFrameworkImpl::findSessionForRequest(const HttpRequestImplPtr &req) { if (useSession_) @@ -762,6 +786,7 @@ void HttpAppFrameworkImpl::findSessionForRequest(const HttpRequestImplPtr &req) sessionManagerPtr_->getSession(sessionId, needSetJsessionid)); } } + void HttpAppFrameworkImpl::onNewWebsockRequest( const HttpRequestImplPtr &req, std::function &&callback, @@ -811,6 +836,7 @@ HttpAppFrameworkImpl::getHandlersInfo() const ret.insert(ret.end(), v.begin(), v.end()); return ret; } + void HttpAppFrameworkImpl::callCallback( const HttpRequestImplPtr &req, const HttpResponsePtr &resp, @@ -882,6 +908,7 @@ void HttpAppFrameworkImpl::callCallback( } } } + void HttpAppFrameworkImpl::onAsyncRequest( const HttpRequestImplPtr &req, std::function &&callback) @@ -970,6 +997,7 @@ void HttpAppFrameworkImpl::forward( hostString, timeout); } + void HttpAppFrameworkImpl::forward( const HttpRequestImplPtr &req, std::function &&callback, @@ -1026,20 +1054,24 @@ orm::DbClientPtr HttpAppFrameworkImpl::getDbClient(const std::string &name) { return dbClientManagerPtr_->getDbClient(name); } + orm::DbClientPtr HttpAppFrameworkImpl::getFastDbClient(const std::string &name) { return dbClientManagerPtr_->getFastDbClient(name); } + nosql::RedisClientPtr HttpAppFrameworkImpl::getRedisClient( const std::string &name) { return redisClientManagerPtr_->getRedisClient(name); } + nosql::RedisClientPtr HttpAppFrameworkImpl::getFastRedisClient( const std::string &name) { return redisClientManagerPtr_->getFastRedisClient(name); } + HttpAppFramework &HttpAppFrameworkImpl::createDbClient( const std::string &dbType, const std::string &host, @@ -1088,6 +1120,7 @@ HttpAppFramework &HttpAppFrameworkImpl::createRedisClient( name, ip, port, username, password, connectionNum, isFast, timeout, db); return *this; } + void HttpAppFrameworkImpl::quit() { if (getLoop()->isRunning()) @@ -1190,6 +1223,7 @@ std::vector HttpAppFrameworkImpl::getListeners() const { return listenerManagerPtr_->getListeners(); } + HttpAppFramework &HttpAppFrameworkImpl::setDefaultHandler( DefaultHandler handler) { diff --git a/lib/src/HttpAppFrameworkImpl.h b/lib/src/HttpAppFrameworkImpl.h index 4f689eb5d9..3aa928edfd 100644 --- a/lib/src/HttpAppFrameworkImpl.h +++ b/lib/src/HttpAppFrameworkImpl.h @@ -73,10 +73,12 @@ class HttpAppFrameworkImpl final : public HttpAppFramework const std::vector> &sslConfCmds) override; HttpAppFramework &setThreadNum(size_t threadNum) override; + size_t getThreadNum() const override { return threadNum_; } + HttpAppFramework &setSSLConfigCommands( const std::vector> &sslConfCmds) override; @@ -157,6 +159,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework syncAdvices_.emplace_back(advice); return *this; } + HttpAppFramework ®isterPreRoutingAdvice( const std::function &advice) override { postRoutingObservers_.emplace_back(advice); return *this; } + HttpAppFramework ®isterPreHandlingAdvice( const std::function &advice) override { preHandlingObservers_.emplace_back(advice); return *this; } + HttpAppFramework ®isterPostHandlingAdvice( const std::function &advice) override @@ -207,6 +215,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework postHandlingAdvices_.emplace_back(advice); return *this; } + HttpAppFramework ®isterPreSendingAdvice( const std::function &advice) override @@ -214,6 +223,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework preSendingAdvices_.emplace_back(advice); return *this; } + HttpAppFramework &setDefaultHandler(DefaultHandler handler) override; HttpAppFramework &setupFileLogger() override; @@ -227,6 +237,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework sessionSameSite_ = sameSite; return *this; } + HttpAppFramework &disableSession() override { useSession_ = false; @@ -251,6 +262,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework { return rootPath_; } + HttpAppFramework &setDocumentRoot(const std::string &rootPath) override { rootPath_ = rootPath; @@ -274,11 +286,13 @@ class HttpAppFrameworkImpl final : public HttpAppFramework { return uploadPath_; } + const std::shared_ptr &getResolver() const override { static auto resolver = trantor::Resolver::newResolver(getLoop()); return resolver; } + HttpAppFramework &setUploadPath(const std::string &uploadPath) override; HttpAppFramework &setFileTypes( const std::vector &types) override; @@ -296,130 +310,158 @@ class HttpAppFrameworkImpl final : public HttpAppFramework false) override; HttpAppFramework &loadConfigJson(Json::Value &&data) noexcept( false) override; + HttpAppFramework &enableRunAsDaemon() override { runAsDaemon_ = true; return *this; } + HttpAppFramework &disableSigtermHandling() override { handleSigterm_ = false; return *this; } + HttpAppFramework &enableRelaunchOnError() override { relaunchOnError_ = true; return *this; } + HttpAppFramework &setLogPath(const std::string &logPath, const std::string &logfileBaseName, size_t logfileSize, size_t maxFiles) override; HttpAppFramework &setLogLevel(trantor::Logger::LogLevel level) override; HttpAppFramework &setLogLocalTime(bool on) override; + HttpAppFramework &enableSendfile(bool sendFile) override { useSendfile_ = sendFile; return *this; } + HttpAppFramework &enableGzip(bool useGzip) override { useGzip_ = useGzip; return *this; } + bool isGzipEnabled() const override { return useGzip_; } + HttpAppFramework &enableBrotli(bool useBrotli) override { useBrotli_ = useBrotli; return *this; } + bool isBrotliEnabled() const override { return useBrotli_; } + HttpAppFramework &setStaticFilesCacheTime(int cacheTime) override; int staticFilesCacheTime() const override; + HttpAppFramework &setIdleConnectionTimeout(size_t timeout) override { idleConnectionTimeout_ = timeout; return *this; } + HttpAppFramework &setKeepaliveRequestsNumber(const size_t number) override { keepaliveRequestsNumber_ = number; return *this; } + HttpAppFramework &setPipeliningRequestsNumber(const size_t number) override { pipeliningRequestsNumber_ = number; return *this; } + HttpAppFramework &setGzipStatic(bool useGzipStatic) override; HttpAppFramework &setBrStatic(bool useGzipStatic) override; + HttpAppFramework &setClientMaxBodySize(size_t maxSize) override { clientMaxBodySize_ = maxSize; return *this; } + HttpAppFramework &setClientMaxMemoryBodySize(size_t maxSize) override { clientMaxMemoryBodySize_ = maxSize; return *this; } + HttpAppFramework &setClientMaxWebSocketMessageSize(size_t maxSize) override { clientMaxWebSocketMessageSize_ = maxSize; return *this; } + HttpAppFramework &setHomePage(const std::string &homePageFile) override { homePageFile_ = homePageFile; return *this; } + const std::string &getHomePage() const override { return homePageFile_; } + HttpAppFramework &setTermSignalHandler( const std::function &handler) override { termSignalHandler_ = handler; return *this; } + const std::function &getTermSignalHandler() const { return termSignalHandler_; } + HttpAppFramework &setIntSignalHandler( const std::function &handler) override { intSignalHandler_ = handler; return *this; } + const std::function &getIntSignalHandler() const { return intSignalHandler_; } + HttpAppFramework &setImplicitPageEnable(bool useImplicitPage) override; bool isImplicitPageEnabled() const override; HttpAppFramework &setImplicitPage( const std::string &implicitPageFile) override; const std::string &getImplicitPage() const override; + size_t getClientMaxBodySize() const { return clientMaxBodySize_; } + size_t getClientMaxMemoryBodySize() const { return clientMaxMemoryBodySize_; } + size_t getClientMaxWebSocketMessageSize() const { return clientMaxWebSocketMessageSize_; } + std::vector> getHandlersInfo() const override; @@ -427,12 +469,14 @@ class HttpAppFrameworkImpl final : public HttpAppFramework { return keepaliveRequestsNumber_; } + size_t pipeliningRequestsNumber() const { return pipeliningRequestsNumber_; } ~HttpAppFrameworkImpl() noexcept override; + bool isRunning() override { return running_; @@ -459,6 +503,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework { return usingUnicodeEscaping_; } + HttpAppFramework &setFloatPrecisionInJson( unsigned int precision, const std::string &precisionType) noexcept override @@ -472,6 +517,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework { return floatPrecisionInJson_; } + trantor::EventLoop *getLoop() const override; trantor::EventLoop *getIOLoop(size_t id) const override; @@ -491,19 +537,23 @@ class HttpAppFrameworkImpl final : public HttpAppFramework enableServerHeader_ = flag; return *this; } + HttpAppFramework &enableDateHeader(bool flag) override { enableDateHeader_ = flag; return *this; } + bool sendServerHeader() const { return enableServerHeader_; } + bool sendDateHeader() const { return enableDateHeader_; } + const std::string &getServerHeaderString() const { return serverHeader_; @@ -536,15 +586,18 @@ class HttpAppFrameworkImpl final : public HttpAppFramework nosql::RedisClientPtr getRedisClient(const std::string &name) override; nosql::RedisClientPtr getFastRedisClient(const std::string &name) override; std::vector getListeners() const override; + inline static HttpAppFrameworkImpl &instance() { static HttpAppFrameworkImpl instance; return instance; } + bool useSendfile() const { return useSendfile_; } + void callCallback( const HttpRequestImplPtr &req, const HttpResponsePtr &resp, @@ -568,14 +621,17 @@ class HttpAppFrameworkImpl final : public HttpAppFramework bool areAllDbClientsAvailable() const noexcept override; const std::function &getCustomErrorHandler() const override; + bool isUsingCustomErrorHandler() const { return usingCustomErrorHandler_; } + void enableReusePort(bool enable) override { reusePort_ = enable; } + bool reusePort() const override { return reusePort_; diff --git a/lib/src/HttpClientImpl.cc b/lib/src/HttpClientImpl.cc index 69bb9e4969..ac2716d7fd 100644 --- a/lib/src/HttpClientImpl.cc +++ b/lib/src/HttpClientImpl.cc @@ -601,6 +601,7 @@ void HttpClientImpl::handleResponse( } } } + void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, trantor::MsgBuffer *msg) { diff --git a/lib/src/HttpClientImpl.h b/lib/src/HttpClientImpl.h index 287af8c3c0..f330d22c37 100644 --- a/lib/src/HttpClientImpl.h +++ b/lib/src/HttpClientImpl.h @@ -46,14 +46,17 @@ class HttpClientImpl final : public HttpClient, void sendRequest(const HttpRequestPtr &req, HttpReqCallback &&callback, double timeout = 0) override; + trantor::EventLoop *getLoop() override { return loop_; } + void setPipeliningDepth(size_t depth) override { pipeliningDepth_ = depth; } + ~HttpClientImpl(); void enableCookies(bool flag = true) override @@ -75,10 +78,12 @@ class HttpClientImpl final : public HttpClient, { return bytesSent_; } + size_t bytesReceived() const override { return bytesReceived_; } + void setUserAgent(const std::string &userAgent) override { userAgent_ = userAgent; @@ -148,5 +153,6 @@ class HttpClientImpl final : public HttpClient, std::string clientKeyPath_; std::function sockOptCallback_; }; + using HttpClientImplPtr = std::shared_ptr; } // namespace drogon diff --git a/lib/src/HttpControllersRouter.cc b/lib/src/HttpControllersRouter.cc index 88d10577ad..1c1d428baf 100644 --- a/lib/src/HttpControllersRouter.cc +++ b/lib/src/HttpControllersRouter.cc @@ -162,6 +162,7 @@ void HttpControllersRouter::addHttpRegex( } ctrlVector_.push_back(std::move(router)); } + void HttpControllersRouter::addHttpPath( const std::string &path, const internal::HttpBinderBasePtr &binder, diff --git a/lib/src/HttpControllersRouter.h b/lib/src/HttpControllersRouter.h index 5ad26b0078..d19d186342 100644 --- a/lib/src/HttpControllersRouter.h +++ b/lib/src/HttpControllersRouter.h @@ -58,6 +58,7 @@ class HttpControllersRouter : public trantor::NonCopyable postHandlingAdvices_(postHandlingAdvices) { } + void init(const std::vector &ioLoops); void addHttpPath(const std::string &path, const internal::HttpBinderBasePtr &binder, @@ -76,6 +77,7 @@ class HttpControllersRouter : public trantor::NonCopyable private: StaticFileRouter &fileRouter_; + struct CtrlBinder { internal::HttpBinderBasePtr binderPtr_; @@ -87,7 +89,9 @@ class HttpControllersRouter : public trantor::NonCopyable IOThreadStorage responseCache_; bool isCORS_{false}; }; + using CtrlBinderPtr = std::shared_ptr; + struct HttpControllerRouterItem { std::string pathParameterPattern_; @@ -96,6 +100,7 @@ class HttpControllersRouter : public trantor::NonCopyable CtrlBinderPtr binders_[Invalid]{ nullptr}; // The enum value of Invalid is the http methods number }; + std::unordered_map ctrlMap_; std::vector ctrlVector_; diff --git a/lib/src/HttpFileImpl.cc b/lib/src/HttpFileImpl.cc index 28722a80af..57323ca347 100644 --- a/lib/src/HttpFileImpl.cc +++ b/lib/src/HttpFileImpl.cc @@ -14,11 +14,12 @@ #include "HttpFileImpl.h" #include "HttpAppFrameworkImpl.h" -#include "filesystem.h" #include +#include #include #include #include +#include using namespace drogon; @@ -32,7 +33,7 @@ int HttpFileImpl::save(const std::string &path) const noexcept assert(!path.empty()); if (fileName_.empty()) return -1; - filesystem::path fsUploadDir(utils::toNativePath(path)); + std::filesystem::path fsUploadDir(utils::toNativePath(path)); if (fsUploadDir.is_absolute()) { // do nothing @@ -47,16 +48,16 @@ int HttpFileImpl::save(const std::string &path) const noexcept } else { - fsUploadDir = filesystem::current_path() / fsUploadDir; + fsUploadDir = std::filesystem::current_path() / fsUploadDir; } - fsUploadDir = filesystem::weakly_canonical(fsUploadDir); + fsUploadDir = std::filesystem::weakly_canonical(fsUploadDir); - if (!filesystem::exists(fsUploadDir)) + if (!std::filesystem::exists(fsUploadDir)) { LOG_TRACE << "create path:" << fsUploadDir; - drogon::error_code err; - filesystem::create_directories(fsUploadDir, err); + std::error_code err; + std::filesystem::create_directories(fsUploadDir, err); if (err) { LOG_SYSERR; @@ -64,7 +65,7 @@ int HttpFileImpl::save(const std::string &path) const noexcept } } - filesystem::path fsSaveToPath(filesystem::weakly_canonical( + std::filesystem::path fsSaveToPath(std::filesystem::weakly_canonical( fsUploadDir / utils::toNativePath(fileName_))); LOG_TRACE << "save to path:" << fsSaveToPath; if (!std::equal(fsUploadDir.begin(), @@ -79,24 +80,25 @@ int HttpFileImpl::save(const std::string &path) const noexcept return saveTo(fsSaveToPath); } + int HttpFileImpl::saveAs(const std::string &fileName) const noexcept { assert(!fileName.empty()); - filesystem::path fsFileName(utils::toNativePath(fileName)); + std::filesystem::path fsFileName(utils::toNativePath(fileName)); if (!fsFileName.is_absolute() && (!fsFileName.has_parent_path() || (fsFileName.begin()->string() != "." && fsFileName.begin()->string() != ".."))) { - filesystem::path fsUploadPath(utils::toNativePath( + std::filesystem::path fsUploadPath(utils::toNativePath( HttpAppFrameworkImpl::instance().getUploadPath())); fsFileName = fsUploadPath / fsFileName; } if (fsFileName.has_parent_path() && - !filesystem::exists(fsFileName.parent_path())) + !std::filesystem::exists(fsFileName.parent_path())) { LOG_TRACE << "create path:" << fsFileName.parent_path(); - drogon::error_code err; - filesystem::create_directories(fsFileName.parent_path(), err); + std::error_code err; + std::filesystem::create_directories(fsFileName.parent_path(), err); if (err) { LOG_SYSERR; @@ -105,7 +107,9 @@ int HttpFileImpl::saveAs(const std::string &fileName) const noexcept } return saveTo(fsFileName); } -int HttpFileImpl::saveTo(const filesystem::path &pathAndFileName) const noexcept + +int HttpFileImpl::saveTo( + const std::filesystem::path &pathAndFileName) const noexcept { LOG_TRACE << "save uploaded file:" << pathAndFileName; auto wPath = utils::toNativePath(pathAndFileName.native()); @@ -148,7 +152,7 @@ void HttpFile::setFileName(const std::string &fileName) noexcept implPtr_->setFileName(fileName); } -string_view HttpFile::getFileExtension() const noexcept +std::string_view HttpFile::getFileExtension() const noexcept { return implPtr_->getFileExtension(); } @@ -197,10 +201,12 @@ std::string HttpFile::getMd5() const noexcept { return implPtr_->getMd5(); } + const std::string &HttpFile::getContentTransferEncoding() const noexcept { return implPtr_->getContentTransferEncoding(); } + HttpFile::HttpFile(std::shared_ptr &&implPtr) noexcept : implPtr_(std::move(implPtr)) { diff --git a/lib/src/HttpFileImpl.h b/lib/src/HttpFileImpl.h index b3c2e11af4..cd05c9fd5c 100644 --- a/lib/src/HttpFileImpl.h +++ b/lib/src/HttpFileImpl.h @@ -14,14 +14,14 @@ #pragma once #include "HttpUtils.h" -#include -#include "filesystem.h" #include #include #include #include #include +#include +#include namespace drogon { @@ -39,12 +39,14 @@ class HttpFileImpl { fileName_ = fileName; } + void setFileName(std::string &&fileName) noexcept { fileName_ = std::move(fileName); } + /// Return the file extension; - string_view getFileExtension() const noexcept + std::string_view getFileExtension() const noexcept { return drogon::getFileExtension(fileName_); } @@ -53,7 +55,7 @@ class HttpFileImpl /// parser. void setFile(const char *data, size_t length) noexcept { - fileContent_ = string_view{data, length}; + fileContent_ = std::string_view{data, length}; } /// Save the file to the file system. @@ -91,7 +93,7 @@ class HttpFileImpl return fileContent_.data(); } - const string_view &fileContent() const noexcept + const std::string_view &fileContent() const noexcept { return fileContent_; } @@ -106,10 +108,12 @@ class HttpFileImpl { itemName_ = itemName; } + void setItemName(std::string &&itemName) noexcept { itemName_ = std::move(itemName); } + /// Return the type of file. FileType getFileType() const noexcept { @@ -123,29 +127,35 @@ class HttpFileImpl // Return sha512 hash of the file std::string getSha3() const noexcept; // int saveTo(const std::string &pathAndFileName) const; - int saveTo(const filesystem::path &pathAndFileName) const noexcept; + int saveTo(const std::filesystem::path &pathAndFileName) const noexcept; + void setRequest(const HttpRequestPtr &req) noexcept { requestPtr_ = req; } + drogon::ContentType getContentType() const noexcept { return contentType_; } + void setContentType(drogon::ContentType contentType) noexcept { contentType_ = contentType; } + void setContentTransferEncoding( const std::string &contentTransferEncoding) noexcept { transferEncoding_ = contentTransferEncoding; } + void setContentTransferEncoding( std::string &&contentTransferEncoding) noexcept { transferEncoding_ = std::move(contentTransferEncoding); } + const std::string &getContentTransferEncoding() const noexcept { return transferEncoding_; @@ -155,7 +165,7 @@ class HttpFileImpl std::string fileName_; std::string itemName_; std::string transferEncoding_; - string_view fileContent_; + std::string_view fileContent_; HttpRequestPtr requestPtr_; drogon::ContentType contentType_{drogon::CT_NONE}; }; diff --git a/lib/src/HttpFileUploadRequest.h b/lib/src/HttpFileUploadRequest.h index 86bff2f2fe..d6d4074d26 100644 --- a/lib/src/HttpFileUploadRequest.h +++ b/lib/src/HttpFileUploadRequest.h @@ -26,10 +26,12 @@ class HttpFileUploadRequest : public HttpRequestImpl { return boundary_; } + const std::vector &files() const { return files_; } + explicit HttpFileUploadRequest(const std::vector &files); private: diff --git a/lib/src/HttpMessageBody.h b/lib/src/HttpMessageBody.h index 8eec70a1c9..c753e771a8 100644 --- a/lib/src/HttpMessageBody.h +++ b/lib/src/HttpMessageBody.h @@ -13,7 +13,7 @@ */ #pragma once -#include +#include #include #include @@ -28,26 +28,33 @@ class HttpMessageBody kString, kStringView }; + BodyType bodyType() { return type_; } + virtual const char *data() const { return nullptr; } + virtual char *data() { return nullptr; } + virtual size_t length() const { return 0; } - virtual string_view getString() const = 0; + + virtual std::string_view getString() const = 0; + virtual void append(const char * /*buf*/, size_t /*len*/) { } + virtual ~HttpMessageBody() { } @@ -55,6 +62,7 @@ class HttpMessageBody protected: BodyType type_{BodyType::kNone}; }; + class HttpMessageStringBody : public HttpMessageBody { public: @@ -62,30 +70,37 @@ class HttpMessageStringBody : public HttpMessageBody { type_ = BodyType::kString; } + HttpMessageStringBody(const std::string &body) : body_(body) { type_ = BodyType::kString; } + HttpMessageStringBody(std::string &&body) : body_(std::move(body)) { type_ = BodyType::kString; } + const char *data() const override { return body_.data(); } + char *data() override { return const_cast(body_.data()); } + size_t length() const override { return body_.length(); } - string_view getString() const override + + std::string_view getString() const override { - return string_view{body_.data(), body_.length()}; + return std::string_view{body_.data(), body_.length()}; } + void append(const char *buf, size_t len) override { body_.append(buf, len); @@ -102,25 +117,29 @@ class HttpMessageStringViewBody : public HttpMessageBody { type_ = BodyType::kStringView; } + const char *data() const override { return body_.data(); } + char *data() override { return const_cast(body_.data()); } + size_t length() const override { return body_.length(); } - string_view getString() const override + + std::string_view getString() const override { return body_; } private: - string_view body_; + std::string_view body_; }; } // namespace drogon diff --git a/lib/src/HttpRequestImpl.cc b/lib/src/HttpRequestImpl.cc index 448e9b7929..ed5db244a6 100644 --- a/lib/src/HttpRequestImpl.cc +++ b/lib/src/HttpRequestImpl.cc @@ -29,6 +29,7 @@ #endif using namespace drogon; + void HttpRequestImpl::parseJson() const { auto input = contentView(); @@ -70,12 +71,13 @@ void HttpRequestImpl::parseJson() const std::make_unique("content type error"); } } + void HttpRequestImpl::parseParameters() const { auto input = queryView(); if (!input.empty()) { - string_view::size_type pos = 0; + std::string_view::size_type pos = 0; while ((input[pos] == '?' || isspace(static_cast(input[pos]))) && pos < input.length()) @@ -83,14 +85,14 @@ void HttpRequestImpl::parseParameters() const ++pos; } auto value = input.substr(pos); - while ((pos = value.find('&')) != string_view::npos) + while ((pos = value.find('&')) != std::string_view::npos) { auto coo = value.substr(0, pos); auto epos = coo.find('='); - if (epos != string_view::npos) + if (epos != std::string_view::npos) { auto key = coo.substr(0, epos); - string_view::size_type cpos = 0; + std::string_view::size_type cpos = 0; while (cpos < key.length() && isspace(static_cast(key[cpos]))) ++cpos; @@ -106,10 +108,10 @@ void HttpRequestImpl::parseParameters() const { auto &coo = value; auto epos = coo.find('='); - if (epos != string_view::npos) + if (epos != std::string_view::npos) { auto key = coo.substr(0, epos); - string_view::size_type cpos = 0; + std::string_view::size_type cpos = 0; while (cpos < key.length() && isspace(static_cast(key[cpos]))) ++cpos; @@ -132,7 +134,7 @@ void HttpRequestImpl::parseParameters() const if (type.empty() || type.find("application/x-www-form-urlencoded") != std::string::npos) { - string_view::size_type pos = 0; + std::string_view::size_type pos = 0; while ((input[pos] == '?' || isspace(static_cast(input[pos]))) && pos < input.length()) @@ -140,14 +142,14 @@ void HttpRequestImpl::parseParameters() const ++pos; } auto value = input.substr(pos); - while ((pos = value.find('&')) != string_view::npos) + while ((pos = value.find('&')) != std::string_view::npos) { auto coo = value.substr(0, pos); auto epos = coo.find('='); - if (epos != string_view::npos) + if (epos != std::string_view::npos) { auto key = coo.substr(0, epos); - string_view::size_type cpos = 0; + std::string_view::size_type cpos = 0; while (cpos < key.length() && isspace(static_cast(key[cpos]))) ++cpos; @@ -163,10 +165,10 @@ void HttpRequestImpl::parseParameters() const { auto &coo = value; auto epos = coo.find('='); - if (epos != string_view::npos) + if (epos != std::string_view::npos) { auto key = coo.substr(0, epos); - string_view::size_type cpos = 0; + std::string_view::size_type cpos = 0; while (cpos < key.length() && isspace(static_cast(key[cpos]))) ++cpos; @@ -637,7 +639,7 @@ const char *HttpRequestImpl::methodString() const bool HttpRequestImpl::setMethod(const char *start, const char *end) { assert(method_ == Invalid); - string_view m(start, end - start); + std::string_view m(start, end - start); switch (m.length()) { case 3: @@ -808,7 +810,7 @@ StreamDecompressStatus HttpRequestImpl::decompressBodyBrotli() noexcept auto minVal = [](size_t a, size_t b) { return a < b ? a : b; }; std::unique_ptr cacheFileHolder; std::string contentHolder; - string_view compressed; + std::string_view compressed; if (cacheFilePtr_) { cacheFileHolder = std::move(cacheFilePtr_); @@ -880,7 +882,7 @@ StreamDecompressStatus HttpRequestImpl::decompressBodyGzip() noexcept auto minVal = [](size_t a, size_t b) { return a < b ? a : b; }; std::unique_ptr cacheFileHolder; std::string contentHolder; - string_view compressed; + std::string_view compressed; if (cacheFilePtr_) { cacheFileHolder = std::move(cacheFilePtr_); diff --git a/lib/src/HttpRequestImpl.h b/lib/src/HttpRequestImpl.h index e138f202e5..8de059a4ad 100644 --- a/lib/src/HttpRequestImpl.h +++ b/lib/src/HttpRequestImpl.h @@ -51,6 +51,7 @@ class HttpRequestImpl : public HttpRequest : creationDate_(trantor::Date::now()), loop_(loop) { } + void reset() { method_ = Invalid; @@ -78,6 +79,7 @@ class HttpRequestImpl : public HttpRequest jsonParsingErrorPtr_.reset(); peerCertificate_.reset(); } + trantor::EventLoop *getLoop() { return loop_; @@ -100,6 +102,7 @@ class HttpRequestImpl : public HttpRequest const char *versionString() const override; bool setMethod(const char *start, const char *end); + void setSecure(bool secure) { isOnSecureConnection_ = secure; @@ -179,7 +182,7 @@ class HttpRequestImpl : public HttpRequest query_ = query; } - string_view bodyView() const + std::string_view bodyView() const { if (cacheFilePtr_) { @@ -187,6 +190,7 @@ class HttpRequestImpl : public HttpRequest } return content_; } + const char *bodyData() const override { if (cacheFilePtr_) @@ -195,6 +199,7 @@ class HttpRequestImpl : public HttpRequest } return content_.data(); } + size_t bodyLength() const override { if (cacheFilePtr_) @@ -208,12 +213,12 @@ class HttpRequestImpl : public HttpRequest void reserveBodySize(size_t length); - string_view queryView() const + std::string_view queryView() const { return query_; } - string_view contentView() const + std::string_view contentView() const { if (cacheFilePtr_) return cacheFilePtr_->getStringView(); @@ -434,6 +439,7 @@ class HttpRequestImpl : public HttpRequest contentTypeString_ = std::string(type.begin() + (haveHeader ? 14 : 0), type.end() - endOffset); } + void setContentTypeCode(const ContentType type) override { contentType_ = type; @@ -462,6 +468,7 @@ class HttpRequestImpl : public HttpRequest { return matchedPathPattern_.data(); } + size_t matchedPathPatternLength() const override { return matchedPathPattern_.length(); @@ -471,6 +478,7 @@ class HttpRequestImpl : public HttpRequest { matchedPathPattern_ = pathPattern; } + const std::string &expect() const { const static std::string none{""}; @@ -478,14 +486,17 @@ class HttpRequestImpl : public HttpRequest return *expectPtr_; return none; } + bool keepAlive() const { return keepAlive_; } + bool isOnSecureConnection() const noexcept override { return isOnSecureConnection_; } + const std::string &getJsonError() const override { const static std::string none{""}; @@ -493,16 +504,19 @@ class HttpRequestImpl : public HttpRequest return *jsonParsingErrorPtr_; return none; } + StreamDecompressStatus decompressBody(); ~HttpRequestImpl(); protected: friend class HttpRequest; + void setContentType(const std::string &contentType) { contentTypeString_ = contentType; } + void setContentType(std::string &&contentType) { contentTypeString_ = std::move(contentType); @@ -524,12 +538,12 @@ class HttpRequestImpl : public HttpRequest if (pos != std::string::npos) { contentType_ = parseContentType( - string_view(contentTypeString.data(), pos)); + std::string_view(contentTypeString.data(), pos)); } else { contentType_ = - parseContentType(string_view(contentTypeString)); + parseContentType(std::string_view(contentTypeString)); } if (contentType_ == CT_NONE) @@ -541,6 +555,7 @@ class HttpRequestImpl : public HttpRequest private: void parseParameters() const; + void parseParametersOnce() const { // Not multi-thread safe but good, because we basically call this @@ -551,6 +566,7 @@ class HttpRequestImpl : public HttpRequest parseParameters(); } } + void createTmpFile(); void parseJson() const; #ifdef USE_BROTLI @@ -564,7 +580,7 @@ class HttpRequestImpl : public HttpRequest std::string path_; std::string originalPath_; bool pathEncode_{true}; - string_view matchedPathPattern_{""}; + std::string_view matchedPathPattern_{""}; std::string query_; std:: unordered_map diff --git a/lib/src/HttpRequestParser.cc b/lib/src/HttpRequestParser.cc index b3f76cd68a..b9c6375e0b 100644 --- a/lib/src/HttpRequestParser.cc +++ b/lib/src/HttpRequestParser.cc @@ -96,6 +96,7 @@ bool HttpRequestParser::processRequestLine(const char *begin, const char *end) } return succeed; } + HttpRequestImplPtr HttpRequestParser::makeRequestForPool(HttpRequestImpl *ptr) { std::weak_ptr weakPtr = shared_from_this(); @@ -124,6 +125,7 @@ HttpRequestImplPtr HttpRequestParser::makeRequestForPool(HttpRequestImpl *ptr) } }); } + void HttpRequestParser::reset() { assert(loop_->isInLoopThread()); diff --git a/lib/src/HttpRequestParser.h b/lib/src/HttpRequestParser.h index ee91a70275..71d4dd10bf 100644 --- a/lib/src/HttpRequestParser.h +++ b/lib/src/HttpRequestParser.h @@ -67,42 +67,52 @@ class HttpRequestParser : public trantor::NonCopyable, } return false; } + const WebSocketConnectionImplPtr &webSocketConn() const { return websockConnPtr_; } + void setWebsockConnection(const WebSocketConnectionImplPtr &conn) { websockConnPtr_ = conn; } + // to support request pipelining(rfc2616-8.1.2.2) void pushRequestToPipelining(const HttpRequestPtr &, bool isHeadMethod); bool pushResponseToPipelining(const HttpRequestPtr &, HttpResponsePtr); void popReadyResponses(std::vector> &); + size_t numberOfRequestsInPipelining() const { return requestPipelining_.size(); } + bool emptyPipelining() { return requestPipelining_.empty(); } + bool isStop() const { return stopWorking_; } + void stop() { stopWorking_ = true; } + size_t numberOfRequestsParsed() const { return requestsCounter_; } + trantor::MsgBuffer &getBuffer() { return sendBuffer_; } + std::vector> &getResponseBuffer() { assert(loop_->isInLoopThread()); @@ -114,6 +124,7 @@ class HttpRequestParser : public trantor::NonCopyable, } return *responseBuffer_; } + std::vector &getRequestBuffer() { assert(loop_->isInLoopThread()); diff --git a/lib/src/HttpResponseImpl.cc b/lib/src/HttpResponseImpl.cc index 46d725a629..be565a700f 100644 --- a/lib/src/HttpResponseImpl.cc +++ b/lib/src/HttpResponseImpl.cc @@ -17,7 +17,7 @@ #include "HttpUtils.h" #include #include -#include "filesystem.h" +#include #include #include #include @@ -37,6 +37,7 @@ namespace drogon { // "Fri, 23 Aug 2019 12:58:03 GMT" length = 29 static const size_t httpFullDateStringLength = 29; + static inline void doResponseCreateAdvices( const HttpResponseImplPtr &responsePtr) { @@ -50,6 +51,7 @@ static inline void doResponseCreateAdvices( } } } + static inline HttpResponsePtr genHttpResponse(const std::string &viewName, const HttpViewData &data) { @@ -202,6 +204,7 @@ HttpResponsePtr HttpResponse::newNotFoundResponse() } } } + HttpResponsePtr HttpResponse::newRedirectionResponse( const std::string &location, HttpStatusCode status) @@ -585,6 +588,7 @@ void HttpResponseImpl::makeHeaderString(trantor::MsgBuffer &buffer) buffer.append("\r\n"); } } + void HttpResponseImpl::renderToBuffer(trantor::MsgBuffer &buffer) { if (expriedTime_ >= 0) @@ -628,6 +632,7 @@ void HttpResponseImpl::renderToBuffer(trantor::MsgBuffer &buffer) if (bodyPtr_) buffer.append(bodyPtr_->data(), bodyPtr_->length()); } + std::shared_ptr HttpResponseImpl::renderToBuffer() { if (expriedTime_ >= 0) @@ -701,7 +706,8 @@ std::shared_ptr HttpResponseImpl::renderToBuffer() } LOG_TRACE << "reponse(no body):" - << string_view{httpString->peek(), httpString->readableBytes()}; + << std::string_view{httpString->peek(), + httpString->readableBytes()}; if (bodyPtr_) httpString->append(bodyPtr_->data(), bodyPtr_->length()); if (expriedTime_ >= 0) @@ -884,7 +890,7 @@ void HttpResponseImpl::clear() { statusCode_ = kUnknown; version_ = Version::kHttp11; - statusMessage_ = string_view{}; + statusMessage_ = std::string_view{}; fullHeaderString_.reset(); jsonParsingErrorPtr_.reset(); sendfileName_.clear(); diff --git a/lib/src/HttpResponseImpl.h b/lib/src/HttpResponseImpl.h index 2ffd55713f..0d5514867e 100644 --- a/lib/src/HttpResponseImpl.h +++ b/lib/src/HttpResponseImpl.h @@ -38,6 +38,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse HttpResponseImpl() : creationDate_(trantor::Date::now()) { } + HttpResponseImpl(HttpStatusCode code, ContentType type) : statusCode_(code), statusMessage_(statusCodeToString(code)), @@ -47,10 +48,12 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse contentTypeString_(contentTypeToMime(type)) { } + void setPassThrough(bool flag) override { passThrough_ = flag; } + HttpStatusCode statusCode() const override { return statusCode_; @@ -222,6 +225,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse addHeader("content-length", std::to_string(bodyPtr_->length())); } } + void setBody(std::string &&body) override { bodyPtr_ = std::make_shared(std::move(body)); @@ -235,6 +239,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse { headers_["location"] = url; } + std::shared_ptr renderToBuffer(); void renderToBuffer(trantor::MsgBuffer &buffer); std::shared_ptr renderHeaderForHeadMethod(); @@ -267,6 +272,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse } return bodyPtr_->data(); } + size_t getBodyLength() const override { if (bodyPtr_) @@ -276,6 +282,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse void swap(HttpResponseImpl &that) noexcept; void parseJson() const; + const std::shared_ptr &jsonObject() const override { // Not multi-thread safe but good, because we basically call this @@ -287,6 +294,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse } return jsonPtr_; } + const std::string &getJsonError() const override { const static std::string none; @@ -294,55 +302,67 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse return *jsonParsingErrorPtr_; return none; } + void setJsonObject(const Json::Value &pJson) { flagForParsingJson_ = true; flagForSerializingJson_ = false; jsonPtr_ = std::make_shared(pJson); } + void setJsonObject(Json::Value &&pJson) { flagForParsingJson_ = true; flagForSerializingJson_ = false; jsonPtr_ = std::make_shared(std::move(pJson)); } + bool shouldBeCompressed() const; void generateBodyFromJson() const; + const std::string &sendfileName() const override { return sendfileName_; } + const SendfileRange &sendfileRange() const override { return sendfileRange_; } + const trantor::CertificatePtr &peerCertificate() const override { return peerCertificate_; } + void setPeerCertificate(const trantor::CertificatePtr &cert) { peerCertificate_ = cert; } + void setSendfile(const std::string &filename) { sendfileName_ = filename; } + void setSendfileRange(size_t offset, size_t len) { sendfileRange_.first = offset; sendfileRange_.second = len; } + const std::function &streamCallback() const override { return streamCallback_; } + void setStreamCallback( const std::function &callback) { streamCallback_ = callback; } + void makeHeaderString() { fullHeaderString_ = std::make_shared(128); @@ -402,12 +422,12 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse if (pos != std::string::npos) { contentType_ = parseContentType( - string_view(contentTypeString.data(), pos)); + std::string_view(contentTypeString.data(), pos)); } else { contentType_ = - parseContentType(string_view(contentTypeString)); + parseContentType(std::string_view(contentTypeString)); } if (contentType_ == CT_NONE) @@ -426,6 +446,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse addHeader("content-length", std::to_string(bodyPtr_->length())); } } + void setContentTypeCodeAndCustomString(ContentType type, const char *typeString, size_t typeStringLength) override @@ -433,7 +454,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse contentType_ = type; flagForParsingContentType_ = true; - string_view sv(typeString, typeStringLength); + std::string_view sv(typeString, typeStringLength); bool haveHeader = sv.find("content-type: ") == 0; bool haveCRLF = sv.rfind("\r\n") == sv.size() - 2; @@ -442,8 +463,8 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse endOffset += 14; if (haveCRLF) endOffset += 2; - setContentType(string_view{typeString + (haveHeader ? 14 : 0), - typeStringLength - endOffset}); + setContentType(std::string_view{typeString + (haveHeader ? 14 : 0), + typeStringLength - endOffset}); } void setContentTypeString(const char *typeString, @@ -455,7 +476,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse { assert(code >= 0); customStatusCode_ = code; - statusMessage_ = string_view{message, messageLength}; + statusMessage_ = std::string_view{message, messageLength}; } std:: @@ -466,7 +487,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse int customStatusCode_{-1}; HttpStatusCode statusCode_{kUnknown}; - string_view statusMessage_; + std::string_view statusMessage_; trantor::Date creationDate_; Version version_{Version::kHttp11}; @@ -491,16 +512,19 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse mutable std::shared_ptr jsonParsingErrorPtr_; mutable std::string contentTypeString_{"text/html; charset=utf-8"}; bool passThrough_{false}; - void setContentType(const string_view &contentType) + + void setContentType(const std::string_view &contentType) { contentTypeString_ = std::string(contentType.data(), contentType.size()); } - void setStatusMessage(const string_view &message) + + void setStatusMessage(const std::string_view &message) { statusMessage_ = message; } }; + using HttpResponseImplPtr = std::shared_ptr; inline void swap(HttpResponseImpl &one, HttpResponseImpl &two) noexcept diff --git a/lib/src/HttpResponseParser.cc b/lib/src/HttpResponseParser.cc index f074a2789d..4e0d3ad7c1 100644 --- a/lib/src/HttpResponseParser.cc +++ b/lib/src/HttpResponseParser.cc @@ -72,6 +72,7 @@ bool HttpResponseParser::processResponseLine(const char *begin, const char *end) } return false; } + bool HttpResponseParser::parseResponseOnClose() { if (status_ == HttpResponseParseStatus::kExpectClose) @@ -81,6 +82,7 @@ bool HttpResponseParser::parseResponseOnClose() } return false; } + // return false if any error bool HttpResponseParser::parseResponse(MsgBuffer *buf) { diff --git a/lib/src/HttpServer.cc b/lib/src/HttpServer.cc index 0a0b79014b..246e15dfb2 100644 --- a/lib/src/HttpServer.cc +++ b/lib/src/HttpServer.cc @@ -109,10 +109,12 @@ void HttpServer::start() << server_.ipPort(); server_.start(); } + void HttpServer::stop() { server_.stop(); } + void HttpServer::onConnection(const TcpConnectionPtr &conn) { if (conn->connected()) @@ -230,6 +232,7 @@ struct CallbackParamPack isHeadMethod_(isHeadMethod) { } + trantor::TcpConnectionPtr conn_; HttpRequestImplPtr req_; std::shared_ptr loopFlag_; @@ -422,9 +425,11 @@ void HttpServer::handleResponse( struct ChunkingParams { using DataCallback = std::function; + explicit ChunkingParams(DataCallback cb) : dataCallback(std::move(cb)) { } + DataCallback dataCallback; bool bFinished{false}; #ifndef NDEBUG // defined by CMake for release build @@ -460,6 +465,7 @@ static std::size_t chunkingCallback( #endif return 0; } + // Reserve size to prepend the chunk size & append cr/lf, and get data struct { @@ -468,6 +474,7 @@ static std::size_t chunkingCallback( return n == 0 ? 0 : 1 + (*this)(n >> 4); } } neededDigits; + auto nHeaderSize = neededDigits(nSize) + 2; auto nDataSize = cbParams->dataCallback(pBuffer + nHeaderSize, nSize - nHeaderSize - 2); diff --git a/lib/src/HttpServer.h b/lib/src/HttpServer.h index 8b17506e47..edac8b0f37 100644 --- a/lib/src/HttpServer.h +++ b/lib/src/HttpServer.h @@ -23,6 +23,7 @@ #include "impl_forwards.h" struct CallbackParamPack; + namespace drogon { class HttpServer : trantor::NonCopyable @@ -49,39 +50,48 @@ class HttpServer : trantor::NonCopyable { httpAsyncCallback_ = cb; } + void setNewWebsocketCallback(const WebSocketNewAsyncCallback &cb) { newWebsocketCallback_ = cb; } + void setConnectionCallback(const trantor::ConnectionCallback &cb) { connectionCallback_ = cb; } + void setIoLoopThreadPool( const std::shared_ptr &pool) { server_.setIoLoopThreadPool(pool); } + void setIoLoopNum(int numThreads) { server_.setIoLoopNum(numThreads); } + void setIoLoops(const std::vector &ioLoops) { server_.setIoLoops(ioLoops); } + void kickoffIdleConnections(size_t timeout) { server_.kickoffIdleConnections(timeout); } + trantor::EventLoop *getLoop() { return server_.getLoop(); } + std::vector getIoLoops() { return server_.getIoLoops(); } + void start(); void stop(); diff --git a/lib/src/HttpSimpleControllersRouter.h b/lib/src/HttpSimpleControllersRouter.h index cb73eb1554..4cf107b5c7 100644 --- a/lib/src/HttpSimpleControllersRouter.h +++ b/lib/src/HttpSimpleControllersRouter.h @@ -89,6 +89,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable const std::vector< std::function> &postHandlingAdvices_; + struct CtrlBinder { std::shared_ptr controller_; @@ -105,6 +106,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable { CtrlBinderPtr binders_[Invalid]; }; + std::unordered_map simpleCtrlMap_; std::mutex simpleCtrlMutex_; diff --git a/lib/src/HttpUtils.cc b/lib/src/HttpUtils.cc index 94d60b9224..4fad29b736 100644 --- a/lib/src/HttpUtils.cc +++ b/lib/src/HttpUtils.cc @@ -21,354 +21,354 @@ namespace drogon { static std::unordered_map customMime; -const string_view &statusCodeToString(int code) +const std::string_view &statusCodeToString(int code) { switch (code) { case 100: { - static string_view sv = "Continue"; + static std::string_view sv = "Continue"; return sv; } case 101: { - static string_view sv = "Switching Protocols"; + static std::string_view sv = "Switching Protocols"; return sv; } case 102: { - static string_view sv = "Processing"; + static std::string_view sv = "Processing"; return sv; } case 103: { - static string_view sv = "Early Hints"; + static std::string_view sv = "Early Hints"; return sv; } case 200: { - static string_view sv = "OK"; + static std::string_view sv = "OK"; return sv; } case 201: { - static string_view sv = "Created"; + static std::string_view sv = "Created"; return sv; } case 202: { - static string_view sv = "Accepted"; + static std::string_view sv = "Accepted"; return sv; } case 203: { - static string_view sv = "Non-Authoritative Information"; + static std::string_view sv = "Non-Authoritative Information"; return sv; } case 204: { - static string_view sv = "No Content"; + static std::string_view sv = "No Content"; return sv; } case 205: { - static string_view sv = "Reset Content"; + static std::string_view sv = "Reset Content"; return sv; } case 206: { - static string_view sv = "Partial Content"; + static std::string_view sv = "Partial Content"; return sv; } case 207: { - static string_view sv = "Multi-Status"; + static std::string_view sv = "Multi-Status"; return sv; } case 208: { - static string_view sv = "Already Reported"; + static std::string_view sv = "Already Reported"; return sv; } case 226: { - static string_view sv = "IM Used"; + static std::string_view sv = "IM Used"; return sv; } case 300: { - static string_view sv = "Multiple Choices"; + static std::string_view sv = "Multiple Choices"; return sv; } case 301: { - static string_view sv = "Moved Permanently"; + static std::string_view sv = "Moved Permanently"; return sv; } case 302: { - static string_view sv = "Found"; + static std::string_view sv = "Found"; return sv; } case 303: { - static string_view sv = "See Other"; + static std::string_view sv = "See Other"; return sv; } case 304: { - static string_view sv = "Not Modified"; + static std::string_view sv = "Not Modified"; return sv; } case 305: { - static string_view sv = "Use Proxy"; + static std::string_view sv = "Use Proxy"; return sv; } case 306: { - static string_view sv = "(Unused)"; + static std::string_view sv = "(Unused)"; return sv; } case 307: { - static string_view sv = "Temporary Redirect"; + static std::string_view sv = "Temporary Redirect"; return sv; } case 308: { - static string_view sv = "Permanent Redirect"; + static std::string_view sv = "Permanent Redirect"; return sv; } case 400: { - static string_view sv = "Bad Request"; + static std::string_view sv = "Bad Request"; return sv; } case 401: { - static string_view sv = "Unauthorized"; + static std::string_view sv = "Unauthorized"; return sv; } case 402: { - static string_view sv = "Payment Required"; + static std::string_view sv = "Payment Required"; return sv; } case 403: { - static string_view sv = "Forbidden"; + static std::string_view sv = "Forbidden"; return sv; } case 404: { - static string_view sv = "Not Found"; + static std::string_view sv = "Not Found"; return sv; } case 405: { - static string_view sv = "Method Not Allowed"; + static std::string_view sv = "Method Not Allowed"; return sv; } case 406: { - static string_view sv = "Not Acceptable"; + static std::string_view sv = "Not Acceptable"; return sv; } case 407: { - static string_view sv = "Proxy Authentication Required"; + static std::string_view sv = "Proxy Authentication Required"; return sv; } case 408: { - static string_view sv = "Request Time-out"; + static std::string_view sv = "Request Time-out"; return sv; } case 409: { - static string_view sv = "Conflict"; + static std::string_view sv = "Conflict"; return sv; } case 410: { - static string_view sv = "Gone"; + static std::string_view sv = "Gone"; return sv; } case 411: { - static string_view sv = "Length Required"; + static std::string_view sv = "Length Required"; return sv; } case 412: { - static string_view sv = "Precondition Failed"; + static std::string_view sv = "Precondition Failed"; return sv; } case 413: { - static string_view sv = "Request Entity Too Large"; + static std::string_view sv = "Request Entity Too Large"; return sv; } case 414: { - static string_view sv = "Request-URI Too Large"; + static std::string_view sv = "Request-URI Too Large"; return sv; } case 415: { - static string_view sv = "Unsupported Media Type"; + static std::string_view sv = "Unsupported Media Type"; return sv; } case 416: { - static string_view sv = "Requested Range Not Satisfiable"; + static std::string_view sv = "Requested Range Not Satisfiable"; return sv; } case 417: { - static string_view sv = "Expectation Failed"; + static std::string_view sv = "Expectation Failed"; return sv; } case 418: { - static string_view sv = "I'm a Teapot"; + static std::string_view sv = "I'm a Teapot"; return sv; } case 421: { - static string_view sv = "Misdirected Request"; + static std::string_view sv = "Misdirected Request"; return sv; } case 422: { - static string_view sv = "Unprocessable Entity"; + static std::string_view sv = "Unprocessable Entity"; return sv; } case 423: { - static string_view sv = "Locked"; + static std::string_view sv = "Locked"; return sv; } case 424: { - static string_view sv = "Failed Dependency"; + static std::string_view sv = "Failed Dependency"; return sv; } case 425: { - static string_view sv = "Too Early"; + static std::string_view sv = "Too Early"; return sv; } case 426: { - static string_view sv = "Upgrade Required"; + static std::string_view sv = "Upgrade Required"; return sv; } case 428: { - static string_view sv = "Precondition Required"; + static std::string_view sv = "Precondition Required"; return sv; } case 429: { - static string_view sv = "Too Many Requests"; + static std::string_view sv = "Too Many Requests"; return sv; } case 431: { - static string_view sv = "Request Header Fields Too Large"; + static std::string_view sv = "Request Header Fields Too Large"; return sv; } case 451: { - static string_view sv = "Unavailable For Legal Reasons"; + static std::string_view sv = "Unavailable For Legal Reasons"; return sv; } case 500: { - static string_view sv = "Internal Server Error"; + static std::string_view sv = "Internal Server Error"; return sv; } case 501: { - static string_view sv = "Not Implemented"; + static std::string_view sv = "Not Implemented"; return sv; } case 502: { - static string_view sv = "Bad Gateway"; + static std::string_view sv = "Bad Gateway"; return sv; } case 503: { - static string_view sv = "Service Unavailable"; + static std::string_view sv = "Service Unavailable"; return sv; } case 504: { - static string_view sv = "Gateway Time-out"; + static std::string_view sv = "Gateway Time-out"; return sv; } case 505: { - static string_view sv = "HTTP Version Not Supported"; + static std::string_view sv = "HTTP Version Not Supported"; return sv; } case 506: { - static string_view sv = "Variant Also Negotiates"; + static std::string_view sv = "Variant Also Negotiates"; return sv; } case 507: { - static string_view sv = "Insufficient Storage"; + static std::string_view sv = "Insufficient Storage"; return sv; } case 508: { - static string_view sv = "Loop Detected"; + static std::string_view sv = "Loop Detected"; return sv; } case 510: { - static string_view sv = "Not Extended"; + static std::string_view sv = "Not Extended"; return sv; } case 511: { - static string_view sv = "Network Authentication Required"; + static std::string_view sv = "Network Authentication Required"; return sv; } default: if (code >= 100 && code < 200) { - static string_view sv = "Informational"; + static std::string_view sv = "Informational"; return sv; } else if (code >= 200 && code < 300) { - static string_view sv = "Successful"; + static std::string_view sv = "Successful"; return sv; } else if (code >= 300 && code < 400) { - static string_view sv = "Redirection"; + static std::string_view sv = "Redirection"; return sv; } else if (code >= 400 && code < 500) { - static string_view sv = "Bad Request"; + static std::string_view sv = "Bad Request"; return sv; } else if (code >= 500 && code < 600) { - static string_view sv = "Server Error"; + static std::string_view sv = "Server Error"; return sv; } else { - static string_view sv = "Undefined Error"; + static std::string_view sv = "Undefined Error"; return sv; } } @@ -484,12 +484,9 @@ ContentType getContentType(const std::string &fileName) } } -ContentType parseContentType(const string_view &contentType) +ContentType parseContentType(const std::string_view &contentType) { - // When using C++14. boost::string_view have a different idea of hashing. - // For boost. only string_view referencing the same underlying string and - // range have the same hash. Use a custom hash to avoid it - static const std::unordered_map map_{ + static const std::unordered_map map_{ {"text/html", CT_TEXT_HTML}, {"application/x-www-form-urlencoded", CT_APPLICATION_X_FORM}, {"application/xml", CT_APPLICATION_XML}, @@ -524,10 +521,10 @@ ContentType parseContentType(const string_view &contentType) return iter->second; } -FileType parseFileType(const string_view &fileExtension) +FileType parseFileType(const std::string_view &fileExtension) { // https://en.wikipedia.org/wiki/List_of_file_formats - static const std::unordered_map map_{ + static const std::unordered_map map_{ {"", FT_UNKNOWN}, {"html", FT_DOCUMENT}, {"docx", FT_DOCUMENT}, {"zip", FT_ARCHIVE}, {"rar", FT_ARCHIVE}, {"xz", FT_ARCHIVE}, {"7z", FT_ARCHIVE}, {"tgz", FT_ARCHIVE}, {"gz", FT_ARCHIVE}, @@ -541,149 +538,150 @@ FileType parseFileType(const string_view &fileExtension) return iter->second; } -const string_view &contentTypeToMime(ContentType contenttype) +const std::string_view &contentTypeToMime(ContentType contenttype) { switch (contenttype) { case CT_TEXT_HTML: { - static string_view sv = "text/html; charset=utf-8"; + static std::string_view sv = "text/html; charset=utf-8"; return sv; } case CT_APPLICATION_X_FORM: { - static string_view sv = "application/x-www-form-urlencoded"; + static std::string_view sv = "application/x-www-form-urlencoded"; return sv; } case CT_APPLICATION_XML: { - static string_view sv = "application/xml; charset=utf-8"; + static std::string_view sv = "application/xml; charset=utf-8"; return sv; } case CT_APPLICATION_JSON: { - static string_view sv = "application/json; charset=utf-8"; + static std::string_view sv = "application/json; charset=utf-8"; return sv; } case CT_APPLICATION_X_JAVASCRIPT: { - static string_view sv = "application/x-javascript; charset=utf-8"; + static std::string_view sv = + "application/x-javascript; charset=utf-8"; return sv; } case CT_TEXT_JAVASCRIPT: { - static string_view sv = "text/javascript; charset=utf-8"; + static std::string_view sv = "text/javascript; charset=utf-8"; return sv; } case CT_TEXT_CSS: { - static string_view sv = "text/css; charset=utf-8"; + static std::string_view sv = "text/css; charset=utf-8"; return sv; } case CT_TEXT_XML: { - static string_view sv = "text/xml; charset=utf-8"; + static std::string_view sv = "text/xml; charset=utf-8"; return sv; } case CT_TEXT_XSL: { - static string_view sv = "text/xsl; charset=utf-8"; + static std::string_view sv = "text/xsl; charset=utf-8"; return sv; } case CT_APPLICATION_OCTET_STREAM: { - static string_view sv = "application/octet-stream"; + static std::string_view sv = "application/octet-stream"; return sv; } case CT_IMAGE_SVG_XML: { - static string_view sv = "image/svg+xml"; + static std::string_view sv = "image/svg+xml"; return sv; } case CT_APPLICATION_X_FONT_TRUETYPE: { - static string_view sv = "application/x-font-truetype"; + static std::string_view sv = "application/x-font-truetype"; return sv; } case CT_APPLICATION_X_FONT_OPENTYPE: { - static string_view sv = "application/x-font-opentype"; + static std::string_view sv = "application/x-font-opentype"; return sv; } case CT_APPLICATION_FONT_WOFF: { - static string_view sv = "application/font-woff"; + static std::string_view sv = "application/font-woff"; return sv; } case CT_APPLICATION_FONT_WOFF2: { - static string_view sv = "application/font-woff2"; + static std::string_view sv = "application/font-woff2"; return sv; } case CT_APPLICATION_VND_MS_FONTOBJ: { - static string_view sv = "application/vnd.ms-fontobject"; + static std::string_view sv = "application/vnd.ms-fontobject"; return sv; } case CT_APPLICATION_PDF: { - static string_view sv = "application/pdf"; + static std::string_view sv = "application/pdf"; return sv; } case CT_IMAGE_PNG: { - static string_view sv = "image/png"; + static std::string_view sv = "image/png"; return sv; } case CT_IMAGE_AVIF: { - static string_view sv = "image/avif"; + static std::string_view sv = "image/avif"; return sv; } case CT_IMAGE_WEBP: { - static string_view sv = "image/webp"; + static std::string_view sv = "image/webp"; return sv; } case CT_IMAGE_JPG: { - static string_view sv = "image/jpeg"; + static std::string_view sv = "image/jpeg"; return sv; } case CT_IMAGE_GIF: { - static string_view sv = "image/gif"; + static std::string_view sv = "image/gif"; return sv; } case CT_IMAGE_XICON: { - static string_view sv = "image/x-icon"; + static std::string_view sv = "image/x-icon"; return sv; } case CT_IMAGE_BMP: { - static string_view sv = "image/bmp"; + static std::string_view sv = "image/bmp"; return sv; } case CT_IMAGE_ICNS: { - static string_view sv = "image/icns"; + static std::string_view sv = "image/icns"; return sv; } case CT_APPLICATION_WASM: { - static string_view sv = "application/wasm"; + static std::string_view sv = "application/wasm"; return sv; } case CT_NONE: { - static string_view sv = ""; + static std::string_view sv = ""; return sv; } default: case CT_TEXT_PLAIN: { - static string_view sv = "text/plain; charset=utf-8"; + static std::string_view sv = "text/plain; charset=utf-8"; return sv; } } @@ -703,7 +701,7 @@ void registerCustomExtensionMime(const std::string &ext, mimeStr = mime; } -const string_view fileNameToMime(const std::string &fileName) +const std::string_view fileNameToMime(const std::string &fileName) { ContentType intenalContentType = getContentType(fileName); if (intenalContentType != CT_APPLICATION_OCTET_STREAM) @@ -724,7 +722,8 @@ const string_view fileNameToMime(const std::string &fileName) return ""; return it->second; } -std::pair fileNameToContentTypeAndMime( + +std::pair fileNameToContentTypeAndMime( const std::string &fileName) { ContentType intenalContentType = getContentType(fileName); diff --git a/lib/src/HttpUtils.h b/lib/src/HttpUtils.h index cabb7d3e8a..882823d533 100644 --- a/lib/src/HttpUtils.h +++ b/lib/src/HttpUtils.h @@ -14,29 +14,30 @@ #pragma once -#include +#include #include #include -#include +#include namespace drogon { -const string_view &contentTypeToMime(ContentType contentType); -const string_view &statusCodeToString(int code); +const std::string_view &contentTypeToMime(ContentType contentType); +const std::string_view &statusCodeToString(int code); ContentType getContentType(const std::string &fileName); -ContentType parseContentType(const string_view &contentType); -FileType parseFileType(const string_view &fileExtension); +ContentType parseContentType(const std::string_view &contentType); +FileType parseFileType(const std::string_view &fileExtension); void registerCustomExtensionMime(const std::string &ext, const std::string &mime); -const string_view fileNameToMime(const std::string &fileName); -std::pair fileNameToContentTypeAndMime( +const std::string_view fileNameToMime(const std::string &fileName); +std::pair fileNameToContentTypeAndMime( const std::string &filename); -inline string_view getFileExtension(const std::string &fileName) + +inline std::string_view getFileExtension(const std::string &fileName) { auto pos = fileName.rfind('.'); if (pos == std::string::npos) return ""; - return string_view(&fileName[pos + 1], fileName.length() - pos - 1); + return std::string_view(&fileName[pos + 1], fileName.length() - pos - 1); } template @@ -44,26 +45,31 @@ inline constexpr const char *contentLengthFormatString() { return "content-length: %d\r\n"; } + template <> inline constexpr const char *contentLengthFormatString() { return "content-length: %u\r\n"; } + template <> inline constexpr const char *contentLengthFormatString() { return "content-length: %ld\r\n"; } + template <> inline constexpr const char *contentLengthFormatString() { return "content-length: %lu\r\n"; } + template <> inline constexpr const char *contentLengthFormatString() { return "content-length: %lld\r\n"; } + template <> inline constexpr const char *contentLengthFormatString() { diff --git a/lib/src/IntranetIpFilter.cc b/lib/src/IntranetIpFilter.cc index c0f787390b..e7f1ea2e36 100644 --- a/lib/src/IntranetIpFilter.cc +++ b/lib/src/IntranetIpFilter.cc @@ -15,6 +15,7 @@ #include "HttpResponseImpl.h" #include using namespace drogon; + void IntranetIpFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) diff --git a/lib/src/JsonConfigAdapter.cc b/lib/src/JsonConfigAdapter.cc index 3505ac7d4e..6ddab71e88 100644 --- a/lib/src/JsonConfigAdapter.cc +++ b/lib/src/JsonConfigAdapter.cc @@ -3,6 +3,7 @@ #include using namespace drogon; + Json::Value JsonConfigAdapter::getJson(const std::string &content) const noexcept(false) { @@ -19,6 +20,7 @@ Json::Value JsonConfigAdapter::getJson(const std::string &content) const } return root; } + std::vector JsonConfigAdapter::getExtensions() const { return {"json"}; diff --git a/lib/src/JsonConfigAdapter.h b/lib/src/JsonConfigAdapter.h index aca59b47a7..6a27f0f762 100644 --- a/lib/src/JsonConfigAdapter.h +++ b/lib/src/JsonConfigAdapter.h @@ -1,5 +1,6 @@ #pragma once #include "ConfigAdapter.h" + namespace drogon { class JsonConfigAdapter : public ConfigAdapter diff --git a/lib/src/ListenerManager.cc b/lib/src/ListenerManager.cc index be2bfd3596..2651508213 100644 --- a/lib/src/ListenerManager.cc +++ b/lib/src/ListenerManager.cc @@ -34,6 +34,7 @@ class DrogonFileLocker : public trantor::NonCopyable fd_ = open("/tmp/drogon.lock", O_TRUNC | O_CREAT, 0666); flock(fd_, LOCK_EX); } + ~DrogonFileLocker() { close(fd_); diff --git a/lib/src/ListenerManager.h b/lib/src/ListenerManager.h index 1ac5ce4cdc..cc187c7465 100644 --- a/lib/src/ListenerManager.h +++ b/lib/src/ListenerManager.h @@ -27,6 +27,7 @@ namespace trantor { class InetAddress; } + namespace drogon { class ListenerManager : public trantor::NonCopyable @@ -80,6 +81,7 @@ class ListenerManager : public trantor::NonCopyable sslConfCmds_(std::move(sslConfCmds)) { } + std::string ip_; uint16_t port_; bool useSSL_; @@ -88,6 +90,7 @@ class ListenerManager : public trantor::NonCopyable bool useOldTLS_; std::vector> sslConfCmds_; }; + std::vector listeners_; std::vector> servers_; diff --git a/lib/src/LocalHostFilter.cc b/lib/src/LocalHostFilter.cc index f1350a0d4c..f8f9b668f1 100644 --- a/lib/src/LocalHostFilter.cc +++ b/lib/src/LocalHostFilter.cc @@ -15,6 +15,7 @@ #include "HttpResponseImpl.h" #include using namespace drogon; + void LocalHostFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) diff --git a/lib/src/MultiPart.cc b/lib/src/MultiPart.cc index e3a81847dd..ba43af51d6 100644 --- a/lib/src/MultiPart.cc +++ b/lib/src/MultiPart.cc @@ -34,6 +34,7 @@ const std::vector &MultiPartParser::getFiles() const { return files_; } + std::unordered_map MultiPartParser::getFilesMap() const { std::unordered_map result; @@ -43,6 +44,7 @@ std::unordered_map MultiPartParser::getFilesMap() const } return result; } + const std::map &MultiPartParser::getParameters() const { return parameters_; @@ -76,8 +78,10 @@ int MultiPartParser::parse(const HttpRequestPtr &req) pos2 = contentType.size(); return parse(req, contentType.data() + (pos + 9), pos2 - (pos + 9)); } -static std::pair parseLine(const char *begin, - const char *end) + +static std::pair parseLine( + const char *begin, + const char *end) { auto p = begin; while (p != end) @@ -86,19 +90,20 @@ static std::pair parseLine(const char *begin, { if (p + 1 != end && *(p + 1) == ' ') { - return std::make_pair(string_view(begin, p - begin), - string_view(p + 2, end - p - 2)); + return std::make_pair(std::string_view(begin, p - begin), + std::string_view(p + 2, end - p - 2)); } else { - return std::make_pair(string_view(begin, p - begin), - string_view(p + 1, end - p - 1)); + return std::make_pair(std::string_view(begin, p - begin), + std::string_view(p + 1, end - p - 1)); } } ++p; } - return std::make_pair(string_view(), string_view()); + return std::make_pair(std::string_view(), std::string_view()); } + int MultiPartParser::parseEntity(const char *begin, const char *end) { static const char entityName[] = "name="; @@ -181,7 +186,8 @@ int MultiPartParser::parseEntity(const char *begin, const char *end) auto value = keyAndValue.second; auto semiColonPos = std::find(value.data(), value.data() + value.length(), ';'); - string_view contentType(value.data(), semiColonPos - value.data()); + std::string_view contentType(value.data(), + semiColonPos - value.data()); filePtr->setContentType(parseContentType(contentType)); } else if (key == "content-transfer-encoding") @@ -209,24 +215,24 @@ int MultiPartParser::parse(const HttpRequestPtr &req, const char *boundaryData, size_t boundaryLen) { - string_view boundary{boundaryData, boundaryLen}; + std::string_view boundary{boundaryData, boundaryLen}; if (boundary.size() > 2 && boundary[0] == '\"') boundary = boundary.substr(1, boundary.size() - 2); requestPtr_ = req; - string_view::size_type pos1, pos2; + std::string_view::size_type pos1, pos2; pos1 = 0; auto content = static_cast(req.get())->bodyView(); pos2 = content.find(boundary); while (true) { pos1 = pos2; - if (pos1 == string_view::npos) + if (pos1 == std::string_view::npos) break; pos1 += boundary.length(); if (content[pos1] == '\r' && content[pos1 + 1] == '\n') pos1 += 2; pos2 = content.find(boundary, pos1); - if (pos2 == string_view::npos) + if (pos2 == std::string_view::npos) break; bool flag = false; if (content[pos2 - 4] == '\r' && content[pos2 - 3] == '\n' && diff --git a/lib/src/PluginsManager.cc b/lib/src/PluginsManager.cc index ac9650ec0f..c343744890 100644 --- a/lib/src/PluginsManager.cc +++ b/lib/src/PluginsManager.cc @@ -86,6 +86,7 @@ void PluginsManager::initializeAllPlugins( forEachCallback(plugin); } } + void PluginsManager::createPlugin(const std::string &pluginName) { auto pluginPtr = std::dynamic_pointer_cast( @@ -97,6 +98,7 @@ void PluginsManager::createPlugin(const std::string &pluginName) } pluginsMap_[pluginName] = pluginPtr; } + PluginBase *PluginsManager::getPlugin(const std::string &pluginName) { auto iter = pluginsMap_.find(pluginName); diff --git a/lib/src/RangeParser.cc b/lib/src/RangeParser.cc index afce1241ce..1af15175a9 100644 --- a/lib/src/RangeParser.cc +++ b/lib/src/RangeParser.cc @@ -29,6 +29,7 @@ static constexpr size_t MAX_DIGIT = MAX_SIZE % 10; (static_cast(base) > MAX_TEN || \ (static_cast(base) >= MAX_TEN && \ static_cast(digit) - '0' > MAX_DIGIT)) + // clang-format on /** Following formats are valid range header according to rfc7233` diff --git a/lib/src/RedisClientManager.h b/lib/src/RedisClientManager.h index d53874fa26..bc2f9b2c23 100644 --- a/lib/src/RedisClientManager.h +++ b/lib/src/RedisClientManager.h @@ -30,6 +30,7 @@ class RedisClientManager : public trantor::NonCopyable { public: void createRedisClients(const std::vector &ioLoops); + RedisClientPtr getRedisClient(const std::string &name) { assert(redisClientsMap_.find(name) != redisClientsMap_.end()); @@ -42,6 +43,7 @@ class RedisClientManager : public trantor::NonCopyable assert(iter != redisFastClientsMap_.end()); return iter->second.getThreadData(); } + void createRedisClient(const std::string &name, const std::string &host, unsigned short port, @@ -58,6 +60,7 @@ class RedisClientManager : public trantor::NonCopyable private: std::map redisClientsMap_; std::map> redisFastClientsMap_; + struct RedisInfo { std::string name_; @@ -70,6 +73,7 @@ class RedisClientManager : public trantor::NonCopyable double timeout_; unsigned int db_; }; + std::vector redisInfos_; }; } // namespace nosql diff --git a/lib/src/RedisResultSkipped.cc b/lib/src/RedisResultSkipped.cc index 80bf176c2f..c3ec10071e 100644 --- a/lib/src/RedisResultSkipped.cc +++ b/lib/src/RedisResultSkipped.cc @@ -54,12 +54,14 @@ std::vector RedisResult::asArray() const noexcept(false) "hiredis library first."; abort(); } + long long RedisResult::asInteger() const noexcept(false) { LOG_FATAL << "Redis is not supported by drogon, please install the " "hiredis library first."; abort(); } + bool RedisResult::isNil() const noexcept { LOG_FATAL << "Redis is not supported by drogon, please install the " diff --git a/lib/src/SessionManager.h b/lib/src/SessionManager.h index d45b28e671..9a968f0145 100644 --- a/lib/src/SessionManager.h +++ b/lib/src/SessionManager.h @@ -34,10 +34,12 @@ class SessionManager : public trantor::NonCopyable size_t timeout, const std::vector &startAdvices, const std::vector &destroyAdvices); + ~SessionManager() { sessionMapPtr_.reset(); } + SessionPtr getSession(const std::string &sessionID, bool needToSet); void changeSessionId(const SessionPtr &sessionPtr); diff --git a/lib/src/SharedLibManager.cc b/lib/src/SharedLibManager.cc index f2cca07c87..bf67b4f2f9 100644 --- a/lib/src/SharedLibManager.cc +++ b/lib/src/SharedLibManager.cc @@ -20,6 +20,7 @@ #include #include #include + static void forEachFileIn( const std::string &path, const std::function &cb) @@ -70,6 +71,7 @@ static void forEachFileIn( } using namespace drogon; + SharedLibManager::SharedLibManager(const std::vector &libPaths, const std::string &outputPath) : libPaths_(libPaths), outputPath_(outputPath) @@ -78,10 +80,12 @@ SharedLibManager::SharedLibManager(const std::vector &libPaths, timeId_ = workingThread_.getLoop()->runEvery(5.0, [this]() { managerLibs(); }); } + SharedLibManager::~SharedLibManager() { workingThread_.getLoop()->invalidateTimer(timeId_); } + void SharedLibManager::managerLibs() { for (auto const &libPath : libPaths_) diff --git a/lib/src/SharedLibManager.h b/lib/src/SharedLibManager.h index e1c05caffe..901bb617be 100644 --- a/lib/src/SharedLibManager.h +++ b/lib/src/SharedLibManager.h @@ -33,11 +33,13 @@ class SharedLibManager : public trantor::NonCopyable void managerLibs(); std::vector libPaths_; std::string outputPath_; + struct DLStat { void *handle{nullptr}; struct timespec mTime = {0, 0}; }; + std::unordered_map dlMap_; void *compileAndLoadLib(const std::string &sourceFile, void *oldHld); void *loadLib(const std::string &soFile, void *oldHld); diff --git a/lib/src/SlashRemover.cc b/lib/src/SlashRemover.cc index 9bd33f4f66..d52f77103a 100644 --- a/lib/src/SlashRemover.cc +++ b/lib/src/SlashRemover.cc @@ -35,6 +35,7 @@ static inline bool removeTrailingSlashes(string& url) url.resize(notSlashIndex + 1); return false; } + static inline void removeDuplicateSlashes(string& url) { size_t a = 1, len = url.size(); @@ -51,6 +52,7 @@ static inline void removeDuplicateSlashes(string& url) } url.resize(a + 1); } + static inline void removeExcessiveSlashes(string& url) { if (url.back() == '/' && // This check is so we don't search if there is no diff --git a/lib/src/SlidingWindowRateLimiter.cc b/lib/src/SlidingWindowRateLimiter.cc index 5f485327ee..a9fe2432e6 100644 --- a/lib/src/SlidingWindowRateLimiter.cc +++ b/lib/src/SlidingWindowRateLimiter.cc @@ -12,6 +12,7 @@ SlidingWindowRateLimiter::SlidingWindowRateLimiter( timeUnit_(timeUnit) { } + // implementation of the sliding window algorithm bool SlidingWindowRateLimiter::isAllowed() { @@ -20,11 +21,12 @@ bool SlidingWindowRateLimiter::isAllowed() unitStartTime_ + std::chrono::duration_cast( std::chrono::duration( - static_cast((uint64_t)( - std::chrono::duration_cast>( - now - unitStartTime_) - .count() / - timeUnit_.count())) * + static_cast( + (uint64_t)(std::chrono::duration_cast< + std::chrono::duration>( + now - unitStartTime_) + .count() / + timeUnit_.count())) * timeUnit_.count())); if (unitStartTime_ > lastTime_) diff --git a/lib/src/SpinLock.h b/lib/src/SpinLock.h index 3b3b867bac..ee572ee448 100644 --- a/lib/src/SpinLock.h +++ b/lib/src/SpinLock.h @@ -53,6 +53,7 @@ class SpinLock std::this_thread::yield(); } } + inline ~SpinLock() { flag_.store(false, std::memory_order_release); @@ -73,6 +74,7 @@ class SimpleSpinLock _mm_pause(); } } + inline ~SimpleSpinLock() { flag_.clear(std::memory_order_release); diff --git a/lib/src/StaticFileRouter.cc b/lib/src/StaticFileRouter.cc index d1b3761501..e0d0e24ac3 100644 --- a/lib/src/StaticFileRouter.cc +++ b/lib/src/StaticFileRouter.cc @@ -30,8 +30,7 @@ #define S_ISDIR(m) (((m)&0170000) == (0040000)) #endif #include -// Switch between native c++17 or boost for c++14 -#include "filesystem.h" +#include using namespace drogon; @@ -140,10 +139,11 @@ void StaticFileRouter::route( tmpPath.begin() + URI.length(), URI.begin())) { - string_view restOfThePath{path.data() + URI.length(), - path.length() - URI.length()}; + std::string_view restOfThePath{path.data() + URI.length(), + path.length() - URI.length()}; auto pos = restOfThePath.rfind('/'); - if (pos != 0 && pos != string_view::npos && !location.isRecursive_) + if (pos != 0 && pos != std::string_view::npos && + !location.isRecursive_) { callback(app().getCustomErrorHandler()(k403Forbidden)); return; @@ -151,14 +151,14 @@ void StaticFileRouter::route( std::string filePath = location.realLocation_ + std::string{restOfThePath.data(), restOfThePath.length()}; - filesystem::path fsFilePath(utils::toNativePath(filePath)); - drogon::error_code err; - if (!filesystem::exists(fsFilePath, err)) + std::filesystem::path fsFilePath(utils::toNativePath(filePath)); + std::error_code err; + if (!std::filesystem::exists(fsFilePath, err)) { defaultHandler_(req, std::move(callback)); return; } - if (filesystem::is_directory(fsFilePath, err)) + if (std::filesystem::is_directory(fsFilePath, err)) { // Check if path is eligible for an implicit index.html if (implicitPageEnable_) @@ -176,7 +176,7 @@ void StaticFileRouter::route( if (!location.allowAll_) { pos = restOfThePath.rfind('.'); - if (pos == string_view::npos) + if (pos == std::string_view::npos) { callback(app().getCustomErrorHandler()(k403Forbidden)); return; @@ -200,7 +200,7 @@ void StaticFileRouter::route( sendStaticFileResponse(filePath, req, std::move(callback), - string_view{ + std::string_view{ location.defaultContentType_}); } else @@ -220,7 +220,7 @@ void StaticFileRouter::route( sendStaticFileResponse(filePath, req, std::move(*callbackPtr), - string_view{contentType}); + std::string_view{contentType}); }); } @@ -230,11 +230,11 @@ void StaticFileRouter::route( std::string directoryPath = HttpAppFrameworkImpl::instance().getDocumentRoot() + path; - filesystem::path fsDirectoryPath(utils::toNativePath(directoryPath)); - drogon::error_code err; - if (filesystem::exists(fsDirectoryPath, err)) + std::filesystem::path fsDirectoryPath(utils::toNativePath(directoryPath)); + std::error_code err; + if (std::filesystem::exists(fsDirectoryPath, err)) { - if (filesystem::is_directory(fsDirectoryPath, err)) + if (std::filesystem::is_directory(fsDirectoryPath, err)) { // Check if path is eligible for an implicit index.html if (implicitPageEnable_) @@ -317,7 +317,7 @@ void StaticFileRouter::sendStaticFileResponse( const std::string &filePath, const HttpRequestImplPtr &req, std::function &&callback, - const string_view &defaultContentType) + const std::string_view &defaultContentType) { if (req->method() != Get) { @@ -479,10 +479,10 @@ void StaticFileRouter::sendStaticFileResponse( // Check existence if (!fileExists) { - filesystem::path fsFilePath(utils::toNativePath(filePath)); - drogon::error_code err; - if (!filesystem::exists(fsFilePath, err) || - !filesystem::is_regular_file(fsFilePath, err)) + std::filesystem::path fsFilePath(utils::toNativePath(filePath)); + std::error_code err; + if (!std::filesystem::exists(fsFilePath, err) || + !std::filesystem::is_regular_file(fsFilePath, err)) { defaultHandler_(req, std::move(callback)); return; @@ -496,10 +496,10 @@ void StaticFileRouter::sendStaticFileResponse( { // Find compressed file first. auto brFileName = filePath + ".br"; - filesystem::path fsBrFile(utils::toNativePath(brFileName)); - drogon::error_code err; - if (filesystem::exists(fsBrFile, err) && - filesystem::is_regular_file(fsBrFile, err)) + std::filesystem::path fsBrFile(utils::toNativePath(brFileName)); + std::error_code err; + if (std::filesystem::exists(fsBrFile, err) && + std::filesystem::is_regular_file(fsBrFile, err)) { auto ct = fileNameToContentTypeAndMime(filePath); resp = HttpResponse::newFileResponse(brFileName, @@ -514,10 +514,10 @@ void StaticFileRouter::sendStaticFileResponse( { // Find compressed file first. auto gzipFileName = filePath + ".gz"; - filesystem::path fsGzipFile(utils::toNativePath(gzipFileName)); - drogon::error_code err; - if (filesystem::exists(fsGzipFile, err) && - filesystem::is_regular_file(fsGzipFile, err)) + std::filesystem::path fsGzipFile(utils::toNativePath(gzipFileName)); + std::error_code err; + if (std::filesystem::exists(fsGzipFile, err) && + std::filesystem::is_regular_file(fsGzipFile, err)) { auto ct = fileNameToContentTypeAndMime(filePath); resp = HttpResponse::newFileResponse(gzipFileName, diff --git a/lib/src/StaticFileRouter.h b/lib/src/StaticFileRouter.h index 6515afb7a5..c3d4e90fb9 100644 --- a/lib/src/StaticFileRouter.h +++ b/lib/src/StaticFileRouter.h @@ -31,29 +31,34 @@ class StaticFileRouter void route(const HttpRequestImplPtr &req, std::function &&callback); void setFileTypes(const std::vector &types); + void setStaticFilesCacheTime(int cacheTime) { staticFilesCacheTime_ = cacheTime; } + int staticFilesCacheTime() const { return staticFilesCacheTime_; } + void setGzipStatic(bool useGzipStatic) { gzipStaticFlag_ = useGzipStatic; } + void setBrStatic(bool useBrStatic) { brStaticFlag_ = useBrStatic; } + void init(const std::vector &ioLoops); void sendStaticFileResponse( const std::string &filePath, const HttpRequestImplPtr &req, std::function &&callback, - const string_view &defaultContentType); + const std::string_view &defaultContentType); void addALocation(const std::string &uriPrefix, const std::string &defaultContentType, @@ -77,22 +82,27 @@ class StaticFileRouter { headers_ = headers; } + void setImplicitPageEnable(bool useImplicitPage) { implicitPageEnable_ = useImplicitPage; } + bool isImplicitPageEnabled() const { return implicitPageEnable_; } + void setImplicitPage(const std::string &implicitPageFile) { implicitPage_ = implicitPageFile; } + const std::string &getImplicitPage() const { return implicitPage_; } + void setDefaultHandler(DefaultHandler &&handler) { defaultHandler_ = std::move(handler); @@ -138,6 +148,7 @@ class StaticFileRouter bool implicitPageEnable_{true}; std::string implicitPage_{"index.html"}; DefaultHandler defaultHandler_ = StaticFileRouter::defaultHandler; + struct Location { std::string uriPrefix_; @@ -148,6 +159,7 @@ class StaticFileRouter bool allowAll_; bool isRecursive_; std::vector> filters_; + Location(const std::string &uriPrefix, const std::string &defaultContentType, const std::string &alias, @@ -169,6 +181,7 @@ class StaticFileRouter } } }; + std::shared_ptr>> ioLocationsPtr_; std::vector locations_; }; diff --git a/lib/src/TaskTimeoutFlag.cc b/lib/src/TaskTimeoutFlag.cc index af147a092e..b8eba8a23c 100644 --- a/lib/src/TaskTimeoutFlag.cc +++ b/lib/src/TaskTimeoutFlag.cc @@ -21,6 +21,7 @@ TaskTimeoutFlag::TaskTimeoutFlag(trantor::EventLoop *loop, : loop_(loop), timeout_(timeout), timeoutFunc_(timeoutCallback) { } + void TaskTimeoutFlag::runTimer() { std::weak_ptr weakPtr = shared_from_this(); @@ -33,6 +34,7 @@ void TaskTimeoutFlag::runTimer() thisPtr->timeoutFunc_(); }); } + bool TaskTimeoutFlag::done() { return isDone_.exchange(true); diff --git a/lib/src/Utilities.cc b/lib/src/Utilities.cc index 7b83ecaf15..9305b90175 100644 --- a/lib/src/Utilities.cc +++ b/lib/src/Utilities.cc @@ -13,7 +13,6 @@ */ #include -#include "filesystem.h" #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +60,7 @@ char *strptime(const char *s, const char *f, struct tm *tm) } return (char *)(s + input.tellg()); } + time_t timegm(struct tm *tm) { struct tm my_tm; @@ -91,6 +92,7 @@ static const std::string urlBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; + class Base64CharMap { public: @@ -115,6 +117,7 @@ class Base64CharMap index; charMap_[0] = char(0xff); } + char getIndex(const char c) const noexcept { return charMap_[static_cast(c)]; @@ -123,6 +126,7 @@ class Base64CharMap private: char charMap_[256]{0}; }; + const static Base64CharMap base64CharMap; static inline bool isBase64(unsigned char c) @@ -140,7 +144,7 @@ static inline bool isBase64(unsigned char c) return false; } -bool isInteger(string_view str) +bool isInteger(std::string_view str) { for (auto c : str) if (c < '0' || c > '9') @@ -148,7 +152,7 @@ bool isInteger(string_view str) return true; } -bool isBase64(string_view str) +bool isBase64(std::string_view str) { for (auto c : str) if (!isBase64(c)) @@ -234,6 +238,7 @@ std::vector hexToBinaryVector(const char *ptr, size_t length) } return ret; } + std::string hexToBinaryString(const char *ptr, size_t length) { assert(length % 2 == 0); @@ -395,7 +400,7 @@ std::string getUuid() } std::string base64Encode(const unsigned char *bytes_to_encode, - unsigned int in_len, + size_t in_len, bool url_safe, bool padded) { @@ -447,7 +452,7 @@ std::string base64Encode(const unsigned char *bytes_to_encode, return ret; } -std::vector base64DecodeToVector(string_view encoded_string) +std::vector base64DecodeToVector(std::string_view encoded_string) { auto in_len = encoded_string.size(); int i = 0; @@ -509,7 +514,7 @@ std::vector base64DecodeToVector(string_view encoded_string) return ret; } -std::string base64Decode(string_view encoded_string) +std::string base64Decode(std::string_view encoded_string) { auto in_len = encoded_string.size(); int i = 0; @@ -569,6 +574,7 @@ std::string base64Decode(string_view encoded_string) return ret; } + static std::string charToHex(char c) { std::string result; @@ -584,6 +590,7 @@ static std::string charToHex(char c) return result; } + std::string urlEncodeComponent(const std::string &src) { std::string result; @@ -680,6 +687,7 @@ std::string urlEncodeComponent(const std::string &src) return result; } + std::string urlEncode(const std::string &src) { std::string result; @@ -782,12 +790,14 @@ std::string urlEncode(const std::string &src) return result; } + bool needUrlDecoding(const char *begin, const char *end) { return std::find_if(begin, end, [](const char c) { return c == '+' || c == '%'; }) != end; } + std::string urlDecode(const char *begin, const char *end) { std::string result; @@ -993,6 +1003,7 @@ char *getHttpFullDate(const trantor::Date &date) sizeof(lastTimeString)); return lastTimeString; } + trantor::Date getHttpDate(const std::string &httpFullDateString) { static const std::array formats = { @@ -1017,6 +1028,7 @@ trantor::Date getHttpDate(const std::string &httpFullDateString) LOG_WARN << "invalid datetime format: '" << httpFullDateString << "'"; return trantor::Date((std::numeric_limits::max)()); } + std::string formattedString(const char *format, ...) { std::string strBuffer(128, 0); @@ -1070,11 +1082,11 @@ int createPath(const std::string &path) if (path.empty()) return 0; auto osPath{toNativePath(path)}; - if (osPath.back() != filesystem::path::preferred_separator) - osPath.push_back(filesystem::path::preferred_separator); - filesystem::path fsPath(osPath); - drogon::error_code err; - filesystem::create_directories(fsPath, err); + if (osPath.back() != std::filesystem::path::preferred_separator) + osPath.push_back(std::filesystem::path::preferred_separator); + std::filesystem::path fsPath(osPath); + std::error_code err; + std::filesystem::create_directories(fsPath, err); if (err) { LOG_ERROR << "Error " << err.value() << " creating path " << osPath @@ -1104,6 +1116,7 @@ std::string brotliCompress(const char *data, const size_t ndata) ret.resize(encodedSize); return ret; } + std::string brotliDecompress(const char *data, const size_t ndata) { if (ndata == 0) @@ -1149,6 +1162,7 @@ std::string brotliCompress(const char * /*data*/, const size_t /*ndata*/) "use brotliCompress()"; abort(); } + std::string brotliDecompress(const char * /*data*/, const size_t /*ndata*/) { LOG_ERROR << "If you do not have the brotli package installed, you cannot " @@ -1208,7 +1222,7 @@ std::string secureRandomString(size_t size) return std::string(); std::string ret(size, 0); - const string_view chars = + const std::string_view chars = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" diff --git a/lib/src/WebSocketClientImpl.cc b/lib/src/WebSocketClientImpl.cc index 2d52c8bdee..79d23aaddc 100644 --- a/lib/src/WebSocketClientImpl.cc +++ b/lib/src/WebSocketClientImpl.cc @@ -30,10 +30,12 @@ using namespace trantor; WebSocketClientImpl::~WebSocketClientImpl() { } + WebSocketConnectionPtr WebSocketClientImpl::getConnection() { return websockConnPtr_; } + void WebSocketClientImpl::stop() { stop_ = true; @@ -44,6 +46,7 @@ void WebSocketClientImpl::stop() } tcpClientPtr_.reset(); } + void WebSocketClientImpl::createTcpClient() { LOG_TRACE << "New TcpClient," << serverAddr_.toIpPort(); @@ -110,6 +113,7 @@ void WebSocketClientImpl::createTcpClient() }); tcpClientPtr_->connect(); } + void WebSocketClientImpl::connectToServerInLoop() { loop_->assertInLoopThread(); diff --git a/lib/src/WebSocketConnectionImpl.cc b/lib/src/WebSocketConnectionImpl.cc index 40ea211745..864ebd815d 100644 --- a/lib/src/WebSocketConnectionImpl.cc +++ b/lib/src/WebSocketConnectionImpl.cc @@ -17,6 +17,7 @@ #include using namespace drogon; + WebSocketConnectionImpl::WebSocketConnectionImpl( const trantor::TcpConnectionPtr &conn, bool isServer) @@ -27,10 +28,12 @@ WebSocketConnectionImpl::WebSocketConnectionImpl( usingMask_(false) { } + WebSocketConnectionImpl::~WebSocketConnectionImpl() { shutdown(); } + void WebSocketConnectionImpl::send(const char *msg, uint64_t len, const WebSocketMessageType type) @@ -155,15 +158,18 @@ void WebSocketConnectionImpl::sendWsData(const char *msg, } tcpConnectionPtr_->send(std::move(bytesFormatted)); } + void WebSocketConnectionImpl::send(const std::string &msg, const WebSocketMessageType type) { send(msg.data(), msg.length(), type); } + const trantor::InetAddress &WebSocketConnectionImpl::localAddr() const { return localAddr_; } + const trantor::InetAddress &WebSocketConnectionImpl::peerAddr() const { return peerAddr_; @@ -173,10 +179,12 @@ bool WebSocketConnectionImpl::connected() const { return tcpConnectionPtr_->connected(); } + bool WebSocketConnectionImpl::disconnected() const { return tcpConnectionPtr_->disconnected(); } + void WebSocketConnectionImpl::WebSocketConnectionImpl::shutdown( const CloseCode code, const std::string &reason) @@ -193,6 +201,7 @@ void WebSocketConnectionImpl::WebSocketConnectionImpl::shutdown( send(message, WebSocketMessageType::Close); tcpConnectionPtr_->shutdown(); } + void WebSocketConnectionImpl::WebSocketConnectionImpl::forceClose() { tcpConnectionPtr_->forceClose(); diff --git a/lib/src/WebSocketConnectionImpl.h b/lib/src/WebSocketConnectionImpl.h index f7147b47dd..1970884084 100644 --- a/lib/src/WebSocketConnectionImpl.h +++ b/lib/src/WebSocketConnectionImpl.h @@ -28,6 +28,7 @@ class WebSocketMessageParser { public: bool parse(trantor::MsgBuffer *buffer); + bool gotAll(std::string &message, WebSocketMessageType &type) { assert(message.empty()); diff --git a/lib/src/WebsocketControllersRouter.h b/lib/src/WebsocketControllersRouter.h index 7ddb88b3cc..bc23733209 100644 --- a/lib/src/WebsocketControllersRouter.h +++ b/lib/src/WebsocketControllersRouter.h @@ -29,6 +29,7 @@ namespace drogon { class HttpAppFrameworkImpl; + class WebsocketControllersRouter : public trantor::NonCopyable { public: @@ -55,6 +56,7 @@ class WebsocketControllersRouter : public trantor::NonCopyable postHandlingAdvices_(postHandlingAdvices) { } + void registerWebSocketController( const std::string &pathName, const std::string &ctrlName, @@ -83,6 +85,7 @@ class WebsocketControllersRouter : public trantor::NonCopyable { CtrlBinderPtr binders_[Invalid]; }; + std::unordered_map wsCtrlMap_; const std::vector -#include - -#if HAS_STD_FILESYSTEM_PATH -#include -#include -#else -#include -#include -#endif - -namespace drogon -{ -#if HAS_STD_FILESYSTEM_PATH -namespace filesystem = std::filesystem; -using std::error_code; -#else -namespace filesystem = boost::filesystem; -using boost::system::error_code; -#endif -} // namespace drogon - -namespace trantor -{ -inline LogStream &operator<<(LogStream &ls, const drogon::filesystem::path &v) -{ -#if defined(_WIN32) && defined(__cpp_char8_t) - // Convert UCS-2 to UTF-8, not ASCII - not needed on other OSes - auto u8path{v.u8string()}; - ls.append((const char *)u8path.data(), u8path.length()); -#else - // No need to convert - ls.append(v.string().data(), v.string().length()); -#endif - return ls; -} -} // namespace trantor diff --git a/lib/src/impl_forwards.h b/lib/src/impl_forwards.h index dd7e266a16..70ccdd44b1 100644 --- a/lib/src/impl_forwards.h +++ b/lib/src/impl_forwards.h @@ -42,6 +42,7 @@ class DbClient; using DbClientPtr = std::shared_ptr; class DbClientManager; } // namespace orm + namespace nosql { class RedisClient; diff --git a/lib/tests/integration_test/client/WebSocketTest.cc b/lib/tests/integration_test/client/WebSocketTest.cc index 30362124a1..e0ce72f2df 100644 --- a/lib/tests/integration_test/client/WebSocketTest.cc +++ b/lib/tests/integration_test/client/WebSocketTest.cc @@ -14,6 +14,7 @@ struct DataPack }; static WebSocketClientPtr wsPtr_; + DROGON_TEST(WebSocketTest) { wsPtr_ = WebSocketClient::newWebSocketClient("127.0.0.1", 8848); diff --git a/lib/tests/integration_test/server/BeginAdviceTest.h b/lib/tests/integration_test/server/BeginAdviceTest.h index b94d60beec..0dd0d96190 100644 --- a/lib/tests/integration_test/server/BeginAdviceTest.h +++ b/lib/tests/integration_test/server/BeginAdviceTest.h @@ -14,6 +14,7 @@ class BeginAdviceTest : public drogon::HttpSimpleController // list path definations here; // PATH_ADD("/path","filter1","filter2",...); PATH_ADD("/test_begin_advice", Get); + PATH_LIST_END BeginAdviceTest() { diff --git a/lib/tests/integration_test/server/CoroFilter.h b/lib/tests/integration_test/server/CoroFilter.h index 0f0d61e528..077fcee9ab 100644 --- a/lib/tests/integration_test/server/CoroFilter.h +++ b/lib/tests/integration_test/server/CoroFilter.h @@ -10,6 +10,7 @@ class CoroFilter : public drogon::HttpCoroFilter { public: Task doFilter(const HttpRequestPtr &req) override; + CoroFilter() { LOG_DEBUG << "CoroFilter constructor"; diff --git a/lib/tests/integration_test/server/CustomCtrl.cc b/lib/tests/integration_test/server/CustomCtrl.cc index a69bfb6332..57e68023a2 100644 --- a/lib/tests/integration_test/server/CustomCtrl.cc +++ b/lib/tests/integration_test/server/CustomCtrl.cc @@ -1,4 +1,5 @@ #include "CustomCtrl.h" + // add definition of your processing function here void CustomCtrl::hello(const HttpRequestPtr &req, diff --git a/lib/tests/integration_test/server/CustomCtrl.h b/lib/tests/integration_test/server/CustomCtrl.h index 169ca1f9dd..e2cd294345 100644 --- a/lib/tests/integration_test/server/CustomCtrl.h +++ b/lib/tests/integration_test/server/CustomCtrl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class CustomCtrl : public drogon::HttpController { public: diff --git a/lib/tests/integration_test/server/CustomHeaderFilter.h b/lib/tests/integration_test/server/CustomHeaderFilter.h index eb0cbfb316..d943d03cf6 100644 --- a/lib/tests/integration_test/server/CustomHeaderFilter.h +++ b/lib/tests/integration_test/server/CustomHeaderFilter.h @@ -16,6 +16,7 @@ class CustomHeaderFilter : public HttpFilter : field_(field), value_(value) { } + virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, FilterChainCallback &&fccb) override; diff --git a/lib/tests/integration_test/server/DoNothingPlugin.h b/lib/tests/integration_test/server/DoNothingPlugin.h index a18e86d093..33b8207059 100644 --- a/lib/tests/integration_test/server/DoNothingPlugin.h +++ b/lib/tests/integration_test/server/DoNothingPlugin.h @@ -15,6 +15,7 @@ class DoNothingPlugin : public Plugin DoNothingPlugin() { } + /// This method must be called by drogon to initialize and start the plugin. /// It must be implemented by the user. void initAndStart(const Json::Value &config) override; diff --git a/lib/tests/integration_test/server/ForwardCtrl.cc b/lib/tests/integration_test/server/ForwardCtrl.cc index 482c5f55db..9dba50fe49 100644 --- a/lib/tests/integration_test/server/ForwardCtrl.cc +++ b/lib/tests/integration_test/server/ForwardCtrl.cc @@ -1,4 +1,5 @@ #include "ForwardCtrl.h" + void ForwardCtrl::asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/ForwardCtrl.h b/lib/tests/integration_test/server/ForwardCtrl.h index edf99f23b0..82de2d02f0 100644 --- a/lib/tests/integration_test/server/ForwardCtrl.h +++ b/lib/tests/integration_test/server/ForwardCtrl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class ForwardCtrl : public drogon::HttpSimpleController { public: diff --git a/lib/tests/integration_test/server/JsonTestController.cc b/lib/tests/integration_test/server/JsonTestController.cc index bb5ddc27ee..e99d57ec4d 100644 --- a/lib/tests/integration_test/server/JsonTestController.cc +++ b/lib/tests/integration_test/server/JsonTestController.cc @@ -1,5 +1,6 @@ #include "JsonTestController.h" #include + void JsonTestController::asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/ListParaCtl.cc b/lib/tests/integration_test/server/ListParaCtl.cc index 5545801aa9..413f3cf913 100644 --- a/lib/tests/integration_test/server/ListParaCtl.cc +++ b/lib/tests/integration_test/server/ListParaCtl.cc @@ -1,4 +1,5 @@ #include "ListParaCtl.h" + void ListParaCtl::asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/ListParaCtl.h b/lib/tests/integration_test/server/ListParaCtl.h index bf2bae3ae9..3f10e2189e 100644 --- a/lib/tests/integration_test/server/ListParaCtl.h +++ b/lib/tests/integration_test/server/ListParaCtl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class ListParaCtl : public drogon::HttpSimpleController { public: diff --git a/lib/tests/integration_test/server/MethodTest.cc b/lib/tests/integration_test/server/MethodTest.cc index 691b644bb7..25af36398f 100644 --- a/lib/tests/integration_test/server/MethodTest.cc +++ b/lib/tests/integration_test/server/MethodTest.cc @@ -1,4 +1,5 @@ #include "MethodTest.h" + static void makeGetRespose( const std::function &callback) { @@ -17,6 +18,7 @@ void MethodTest::get(const HttpRequestPtr &req, LOG_DEBUG; makeGetRespose(callback); } + void MethodTest::post(const HttpRequestPtr &req, std::function &&callback, std::string str) @@ -32,6 +34,7 @@ void MethodTest::getReg(const HttpRequestPtr &req, LOG_DEBUG << regStr; makeGetRespose(callback); } + void MethodTest::postReg( const HttpRequestPtr &req, std::function &&callback, diff --git a/lib/tests/integration_test/server/MethodTest.h b/lib/tests/integration_test/server/MethodTest.h index 1462494547..0c7533c653 100644 --- a/lib/tests/integration_test/server/MethodTest.h +++ b/lib/tests/integration_test/server/MethodTest.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class MethodTest : public drogon::HttpController { public: diff --git a/lib/tests/integration_test/server/PipeliningTest.h b/lib/tests/integration_test/server/PipeliningTest.h index d304f5acae..5369d3c690 100644 --- a/lib/tests/integration_test/server/PipeliningTest.h +++ b/lib/tests/integration_test/server/PipeliningTest.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + // class PipeliningTest : public drogon::HttpSimpleController //{ // public: diff --git a/lib/tests/integration_test/server/RangeTestController.h b/lib/tests/integration_test/server/RangeTestController.h index 56abdeafc4..fd8f3f174e 100644 --- a/lib/tests/integration_test/server/RangeTestController.h +++ b/lib/tests/integration_test/server/RangeTestController.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class RangeTestController : public drogon::HttpController { public: diff --git a/lib/tests/integration_test/server/TestController.cc b/lib/tests/integration_test/server/TestController.cc index 0cbf5d7723..9f08736283 100644 --- a/lib/tests/integration_test/server/TestController.cc +++ b/lib/tests/integration_test/server/TestController.cc @@ -1,5 +1,6 @@ #include "TestController.h" using namespace example; + void TestController::asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/TestController.h b/lib/tests/integration_test/server/TestController.h index 9d7dd35c66..c2eaaffdae 100644 --- a/lib/tests/integration_test/server/TestController.h +++ b/lib/tests/integration_test/server/TestController.h @@ -2,6 +2,7 @@ #include #include using namespace drogon; + namespace example { class TestController : public drogon::HttpSimpleController @@ -17,6 +18,7 @@ class TestController : public drogon::HttpSimpleController PATH_ADD("/Test", "nonFilter"); PATH_ADD("/tpost", Post, Options); PATH_ADD("/slow", "TimeFilter", Get); + PATH_LIST_END TestController() { diff --git a/lib/tests/integration_test/server/TestPlugin.h b/lib/tests/integration_test/server/TestPlugin.h index f1af2e40d6..84eb7861c1 100644 --- a/lib/tests/integration_test/server/TestPlugin.h +++ b/lib/tests/integration_test/server/TestPlugin.h @@ -15,6 +15,7 @@ class TestPlugin : public Plugin TestPlugin() { } + /// This method must be called by drogon to initialize and start the plugin. /// It must be implemented by the user. void initAndStart(const Json::Value &config) override; diff --git a/lib/tests/integration_test/server/TestViewCtl.cc b/lib/tests/integration_test/server/TestViewCtl.cc index d7e2fd331b..7d638ae2eb 100644 --- a/lib/tests/integration_test/server/TestViewCtl.cc +++ b/lib/tests/integration_test/server/TestViewCtl.cc @@ -1,4 +1,5 @@ #include "TestViewCtl.h" + void TestViewCtl::asyncHandleHttpRequest( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/TestViewCtl.h b/lib/tests/integration_test/server/TestViewCtl.h index 81c9e1d973..244bc231c2 100644 --- a/lib/tests/integration_test/server/TestViewCtl.h +++ b/lib/tests/integration_test/server/TestViewCtl.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + class TestViewCtl : public drogon::HttpSimpleController { public: diff --git a/lib/tests/integration_test/server/TimeFilter.cc b/lib/tests/integration_test/server/TimeFilter.cc index 2e45859612..5a4555d3ef 100644 --- a/lib/tests/integration_test/server/TimeFilter.cc +++ b/lib/tests/integration_test/server/TimeFilter.cc @@ -4,6 +4,7 @@ #include "TimeFilter.h" #define VDate "visitDate" + void TimeFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&cb, FilterChainCallback &&ccb) diff --git a/lib/tests/integration_test/server/TimeFilter.h b/lib/tests/integration_test/server/TimeFilter.h index bcd75851d7..67e2c1ac4d 100644 --- a/lib/tests/integration_test/server/TimeFilter.h +++ b/lib/tests/integration_test/server/TimeFilter.h @@ -13,6 +13,7 @@ class TimeFilter : public drogon::HttpFilter virtual void doFilter(const HttpRequestPtr &req, FilterCallback &&cb, FilterChainCallback &&ccb) override; + TimeFilter() { LOG_DEBUG << "TimeFilter constructor"; diff --git a/lib/tests/integration_test/server/WebSocketTest.cc b/lib/tests/integration_test/server/WebSocketTest.cc index 8bc555721d..bd3871fa18 100644 --- a/lib/tests/integration_test/server/WebSocketTest.cc +++ b/lib/tests/integration_test/server/WebSocketTest.cc @@ -1,10 +1,12 @@ #include "WebSocketTest.h" using namespace example; + struct Subscriber { std::string chatRoomName_; drogon::SubscriberID id_; }; + void WebSocketTest::handleNewMessage(const WebSocketConnectionPtr &wsConnPtr, std::string &&message, const WebSocketMessageType &type) diff --git a/lib/tests/integration_test/server/WebSocketTest.h b/lib/tests/integration_test/server/WebSocketTest.h index 40f09dd7ef..d295855a95 100644 --- a/lib/tests/integration_test/server/WebSocketTest.h +++ b/lib/tests/integration_test/server/WebSocketTest.h @@ -2,6 +2,7 @@ #include #include using namespace drogon; + namespace example { class WebSocketTest : public drogon::WebSocketController diff --git a/lib/tests/integration_test/server/api_Attachment.cc b/lib/tests/integration_test/server/api_Attachment.cc index 89f657297b..39a346ee51 100644 --- a/lib/tests/integration_test/server/api_Attachment.cc +++ b/lib/tests/integration_test/server/api_Attachment.cc @@ -2,6 +2,7 @@ #include using namespace api; + // add definition of your processing function here void Attachment::get(const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/api_Attachment.h b/lib/tests/integration_test/server/api_Attachment.h index c61937449e..939cca970d 100644 --- a/lib/tests/integration_test/server/api_Attachment.h +++ b/lib/tests/integration_test/server/api_Attachment.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + namespace api { class Attachment : public drogon::HttpController diff --git a/lib/tests/integration_test/server/api_v1_ApiTest.cc b/lib/tests/integration_test/server/api_v1_ApiTest.cc index d64cdcde2d..e52fa9f4a3 100644 --- a/lib/tests/integration_test/server/api_v1_ApiTest.cc +++ b/lib/tests/integration_test/server/api_v1_ApiTest.cc @@ -1,5 +1,6 @@ #include "api_v1_ApiTest.h" using namespace api::v1; + // add definition of your processing function here void ApiTest::rootGet(const HttpRequestPtr &req, std::function &&callback) @@ -8,6 +9,7 @@ void ApiTest::rootGet(const HttpRequestPtr &req, res->setBody("ROOT Get!!!"); callback(res); } + void ApiTest::rootPost(const HttpRequestPtr &req, std::function &&callback) { @@ -17,6 +19,7 @@ void ApiTest::rootPost(const HttpRequestPtr &req, callback(res); }).detach(); } + void ApiTest::get(const HttpRequestPtr &req, std::function &&callback, int p1, @@ -48,13 +51,14 @@ void ApiTest::your_method_name( para; para["p1"] = std::to_string(p1); para["p2"] = std::to_string(p2); - para["p3"] = HttpViewData::htmlTranslate(string_view( + para["p3"] = HttpViewData::htmlTranslate(std::string_view( "")); data.insert("parameters", para); auto res = HttpResponse::newHttpViewResponse("ListParaView", data); callback(res); } + void ApiTest::staticApi(const HttpRequestPtr &req, std::function &&callback) { @@ -460,6 +464,7 @@ void ApiTest::regexTest(const HttpRequestPtr &req, } static std::mutex cacheTestMtx; + void ApiTest::cacheTest(const HttpRequestPtr &req, std::function &&callback) { @@ -476,6 +481,7 @@ void ApiTest::cacheTest(const HttpRequestPtr &req, } static std::mutex cacheTest2Mtx; + void ApiTest::cacheTest2( const HttpRequestPtr &req, std::function &&callback) @@ -495,6 +501,7 @@ void ApiTest::cacheTest2( } static std::mutex regexCacheApiMtx; + void ApiTest::cacheTestRegex( const HttpRequestPtr &req, std::function &&callback) diff --git a/lib/tests/integration_test/server/api_v1_ApiTest.h b/lib/tests/integration_test/server/api_v1_ApiTest.h index f13b09d355..8750beb445 100644 --- a/lib/tests/integration_test/server/api_v1_ApiTest.h +++ b/lib/tests/integration_test/server/api_v1_ApiTest.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + namespace api { namespace v1 @@ -74,11 +75,13 @@ class ApiTest : public drogon::HttpController std::function &&callback, int p1, std::string &&p2); + void shutdown(const HttpRequestPtr &req, std::function &&callback) { app().quit(); } + void cacheTest(const HttpRequestPtr &req, std::function &&callback); void cacheTest2(const HttpRequestPtr &req, diff --git a/lib/tests/integration_test/server/api_v1_CoroTest.h b/lib/tests/integration_test/server/api_v1_CoroTest.h index 1ccb07fec1..fe215227f4 100644 --- a/lib/tests/integration_test/server/api_v1_CoroTest.h +++ b/lib/tests/integration_test/server/api_v1_CoroTest.h @@ -1,6 +1,7 @@ #pragma once #include using namespace drogon; + namespace api { namespace v1 diff --git a/lib/tests/integration_test/server/main.cc b/lib/tests/integration_test/server/main.cc index 537b5915a3..deefa07049 100644 --- a/lib/tests/integration_test/server/main.cc +++ b/lib/tests/integration_test/server/main.cc @@ -8,9 +8,11 @@ #include #include #include +#include using namespace drogon; using namespace std::chrono_literals; + class A : public DrObjectBase { public: @@ -36,6 +38,7 @@ class A : public DrObjectBase auto res = HttpResponse::newHttpViewResponse("ListParaView", data); callback(res); } + static void staticHandle( const HttpRequestPtr &req, std::function &&callback, @@ -60,6 +63,7 @@ class A : public DrObjectBase callback(res); } }; + class B : public DrObjectBase { public: @@ -87,6 +91,7 @@ class C : public drogon::HttpController public: METHOD_LIST_BEGIN ADD_METHOD_TO(C::priv, "/priv/resource", Get, "DigestAuthFilter"); + METHOD_LIST_END void priv(const HttpRequestPtr &req, std::function &&callback) const @@ -111,6 +116,7 @@ class Test : public HttpController METHOD_ADD(Test::list, "/{2}/info", Get); // path is /api/v1/test/{arg2}/info + METHOD_LIST_END void get(const HttpRequestPtr &req, std::function &&callback, @@ -129,6 +135,7 @@ class Test : public HttpController auto res = HttpResponse::newHttpViewResponse("ListParaView", data); callback(res); } + void list(const HttpRequestPtr &req, std::function &&callback, int p1, @@ -156,7 +163,7 @@ using namespace drogon; namespace drogon { template <> -string_view fromRequest(const HttpRequest &req) +std::string_view fromRequest(const HttpRequest &req) { return req.body(); } @@ -190,8 +197,8 @@ int main() // parameter in the path. float b, // here the `b` parameter is converted from the number 2 // parameter in the path. - string_view &&body, // here the `body` parameter is converted from - // req->as(); + std::string_view &&body, // here the `body` parameter is converted + // from req->as(); const std::shared_ptr &jsonPtr // here the `jsonPtr` parameter is converted from // req->as>(); diff --git a/lib/tests/unittests/BrotliTest.cc b/lib/tests/unittests/BrotliTest.cc index 3ff25db6b6..7e2a975478 100644 --- a/lib/tests/unittests/BrotliTest.cc +++ b/lib/tests/unittests/BrotliTest.cc @@ -3,6 +3,7 @@ #include #include using namespace drogon::utils; + DROGON_TEST(BrotliTest) { SUBSECTION(shortText) diff --git a/lib/tests/unittests/ClassNameTest.cc b/lib/tests/unittests/ClassNameTest.cc index 56606d99ec..387c938b55 100644 --- a/lib/tests/unittests/ClassNameTest.cc +++ b/lib/tests/unittests/ClassNameTest.cc @@ -13,6 +13,7 @@ class handler : public drogon::DrObject return handler::classTypeName(); } }; + class hh : public handler { }; diff --git a/lib/tests/unittests/CoroutineTest.cc b/lib/tests/unittests/CoroutineTest.cc index 39fa0b327a..349bef242b 100644 --- a/lib/tests/unittests/CoroutineTest.cc +++ b/lib/tests/unittests/CoroutineTest.cc @@ -14,6 +14,7 @@ struct SomeStruct { beenDestructed = true; } + static bool beenDestructed; }; diff --git a/lib/tests/unittests/DrObjectTest.cc b/lib/tests/unittests/DrObjectTest.cc index 248d95410c..cc24b35670 100644 --- a/lib/tests/unittests/DrObjectTest.cc +++ b/lib/tests/unittests/DrObjectTest.cc @@ -6,6 +6,7 @@ using namespace drogon; class TestA : public DrObject { }; + namespace test { class TestB : public DrObject diff --git a/lib/tests/unittests/HttpFullDateTest.cc b/lib/tests/unittests/HttpFullDateTest.cc index 9461737645..6b891bf0f0 100644 --- a/lib/tests/unittests/HttpFullDateTest.cc +++ b/lib/tests/unittests/HttpFullDateTest.cc @@ -4,6 +4,7 @@ #include using namespace drogon; + DROGON_TEST(HttpFullDateTest) { auto str = utils::getHttpFullDate(); diff --git a/lib/tests/unittests/HttpHeaderTest.cc b/lib/tests/unittests/HttpHeaderTest.cc index 522ee7a47b..4a46bb193a 100644 --- a/lib/tests/unittests/HttpHeaderTest.cc +++ b/lib/tests/unittests/HttpHeaderTest.cc @@ -15,6 +15,7 @@ DROGON_TEST(HttpHeaderRequest) req->removeHeader("Abc"); CHECK(req->getHeader("abc") == ""); } + DROGON_TEST(HttpHeaderResponse) { auto resp = std::dynamic_pointer_cast( diff --git a/lib/tests/unittests/MainLoopTest.cc b/lib/tests/unittests/MainLoopTest.cc index 4271bc09b0..727aac6390 100644 --- a/lib/tests/unittests/MainLoopTest.cc +++ b/lib/tests/unittests/MainLoopTest.cc @@ -10,6 +10,7 @@ struct TestCookie TestCookie(std::shared_ptr ctx) : TEST_CTX(ctx) { } + ~TestCookie() { if (!taken) @@ -17,6 +18,7 @@ struct TestCookie else SUCCESS(); } + void take() { taken = true; diff --git a/lib/tests/unittests/MsgBufferTest.cc b/lib/tests/unittests/MsgBufferTest.cc index 23abea8a24..28670c8e42 100644 --- a/lib/tests/unittests/MsgBufferTest.cc +++ b/lib/tests/unittests/MsgBufferTest.cc @@ -4,6 +4,7 @@ #include using namespace trantor; + DROGON_TEST(MsgBufferTest) { SUBSECTION(readableTest) diff --git a/lib/tests/unittests/OStringStreamTest.cc b/lib/tests/unittests/OStringStreamTest.cc index 52305ca9e4..232458e2d2 100644 --- a/lib/tests/unittests/OStringStreamTest.cc +++ b/lib/tests/unittests/OStringStreamTest.cc @@ -29,11 +29,11 @@ DROGON_TEST(OStringStreamTest) CHECK(ss.str() == "hello world"); } - SUBSECTION(string_view) + SUBSECTION(std::string_view) { drogon::OStringStream ss; - ss << drogon::string_view("hello"); - ss << drogon::string_view(" world"); + ss << std::string_view("hello"); + ss << std::string_view(" world"); CHECK(ss.str() == "hello world"); } @@ -49,7 +49,7 @@ DROGON_TEST(OStringStreamTest) { drogon::OStringStream ss; ss << std::string("hello"); - ss << drogon::string_view(" world"); + ss << std::string_view(" world"); ss << "!"; ss << 123; ss << 3.14f; diff --git a/lib/tests/unittests/StringOpsTest.cc b/lib/tests/unittests/StringOpsTest.cc index 4eaa058212..92bf89bfb2 100644 --- a/lib/tests/unittests/StringOpsTest.cc +++ b/lib/tests/unittests/StringOpsTest.cc @@ -33,6 +33,7 @@ inline bool operator==(const Container1& a, const SameContent& wrapper) } using namespace drogon; + DROGON_TEST(StringOpsTest) { SUBSECTION(SplitString) diff --git a/lib/tests/unittests/UrlCodecTest.cc b/lib/tests/unittests/UrlCodecTest.cc index 8a54865ad8..9fdaa14d0c 100644 --- a/lib/tests/unittests/UrlCodecTest.cc +++ b/lib/tests/unittests/UrlCodecTest.cc @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/nosql_lib/redis/inc/drogon/nosql/RedisClient.h b/nosql_lib/redis/inc/drogon/nosql/RedisClient.h index eaf240aca1..97615c0cf4 100644 --- a/nosql_lib/redis/inc/drogon/nosql/RedisClient.h +++ b/nosql_lib/redis/inc/drogon/nosql/RedisClient.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,16 +34,19 @@ namespace nosql #ifdef __cpp_impl_coroutine class RedisClient; class RedisTransaction; + namespace internal { struct [[nodiscard]] RedisAwaiter : public CallbackAwaiter { using RedisFunction = std::function; + explicit RedisAwaiter(RedisFunction &&function) : function_(std::move(function)) { } + void await_suspend(std::coroutine_handle<> handle) { function_( @@ -78,6 +81,7 @@ struct [[nodiscard]] RedisTransactionAwaiter #endif class RedisTransaction; + /** * @brief This class represents a redis client that contains several connections * to a redis server. @@ -123,7 +127,7 @@ class DROGON_EXPORT RedisClient */ virtual void execCommandAsync(RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept = 0; /** @@ -157,7 +161,7 @@ class DROGON_EXPORT RedisClient */ template T execCommandSync(std::function &&processFunc, - string_view command, + std::string_view command, Args &&...args) { std::shared_ptr> pro(new std::promise); @@ -254,7 +258,7 @@ class DROGON_EXPORT RedisClient @endcode */ template - internal::RedisAwaiter execCommandCoro(string_view command, + internal::RedisAwaiter execCommandCoro(std::string_view command, Arguments... args) { return internal::RedisAwaiter( @@ -268,6 +272,7 @@ class DROGON_EXPORT RedisClient args...); }); } + /** * @brief await a RedisTransactionPtr in a coroutine. * @@ -292,6 +297,7 @@ class DROGON_EXPORT RedisClient } #endif }; + class DROGON_EXPORT RedisTransaction : public RedisClient { public: @@ -333,6 +339,7 @@ class DROGON_EXPORT RedisTransaction : public RedisClient { } }; + using RedisClientPtr = std::shared_ptr; using RedisTransactionPtr = std::shared_ptr; diff --git a/nosql_lib/redis/inc/drogon/nosql/RedisException.h b/nosql_lib/redis/inc/drogon/nosql/RedisException.h index 51f71b42d9..dbb8dc0ffe 100644 --- a/nosql_lib/redis/inc/drogon/nosql/RedisException.h +++ b/nosql_lib/redis/inc/drogon/nosql/RedisException.h @@ -15,6 +15,7 @@ #include #include +#include namespace drogon { @@ -32,6 +33,7 @@ enum class RedisErrorCode kBadType, kTimeout }; + class RedisException final : public std::exception { public: @@ -39,24 +41,29 @@ class RedisException final : public std::exception { return message_.data(); } + RedisErrorCode code() const { return code_; } + RedisException(RedisErrorCode code, const std::string &message) : message_(message), code_(code) { } + RedisException(RedisErrorCode code, std::string &&message) : message_(std::move(message)), code_(code) { } + RedisException() = delete; private: std::string message_; RedisErrorCode code_{RedisErrorCode::kNone}; }; + using RedisExceptionCallback = std::function; } // namespace nosql } // namespace drogon \ No newline at end of file diff --git a/nosql_lib/redis/inc/drogon/nosql/RedisResult.h b/nosql_lib/redis/inc/drogon/nosql/RedisResult.h index f82a3560e7..69239d4d5c 100644 --- a/nosql_lib/redis/inc/drogon/nosql/RedisResult.h +++ b/nosql_lib/redis/inc/drogon/nosql/RedisResult.h @@ -21,6 +21,7 @@ #include struct redisReply; + namespace drogon { namespace nosql @@ -47,6 +48,7 @@ class DROGON_EXPORT RedisResult explicit RedisResult(redisReply *result) : result_(result) { } + ~RedisResult() = default; /** diff --git a/nosql_lib/redis/src/RedisClientImpl.cc b/nosql_lib/redis/src/RedisClientImpl.cc index 3d84629328..1015c7cec8 100644 --- a/nosql_lib/redis/src/RedisClientImpl.cc +++ b/nosql_lib/redis/src/RedisClientImpl.cc @@ -174,7 +174,7 @@ RedisConnectionPtr RedisClientImpl::newSubscribeConnection( void RedisClientImpl::execCommandAsync( RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept { if (timeout_ > 0.0) @@ -250,6 +250,7 @@ void RedisClientImpl::closeAll() readyConnections_.clear(); connections_.clear(); } + void RedisClientImpl::newTransactionAsync( const std::function &)> &callback) @@ -376,8 +377,9 @@ void RedisClientImpl::handleNextTask(const RedisConnectionPtr &connPtr) (*taskPtr)(connPtr); } } + void RedisClientImpl::execCommandAsyncWithTimeout( - string_view command, + std::string_view command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, va_list ap) diff --git a/nosql_lib/redis/src/RedisClientImpl.h b/nosql_lib/redis/src/RedisClientImpl.h index 9a9b752b0c..6427f92d02 100644 --- a/nosql_lib/redis/src/RedisClientImpl.h +++ b/nosql_lib/redis/src/RedisClientImpl.h @@ -30,6 +30,7 @@ namespace nosql { class RedisConnection; using RedisConnectionPtr = std::shared_ptr; + class RedisClientImpl final : public RedisClient, public trantor::NonCopyable, @@ -43,10 +44,11 @@ class RedisClientImpl final unsigned int db = 0); void execCommandAsync(RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept override; ~RedisClientImpl() override; std::shared_ptr newSubscriber() noexcept override; + RedisTransactionPtr newTransaction() noexcept(false) override { std::promise prom; @@ -63,13 +65,16 @@ class RedisClientImpl final } return trans; } + void newTransactionAsync( const std::function &callback) override; + void setTimeout(double timeout) override { timeout_ = timeout; } + void init(); void closeAll() override; @@ -96,7 +101,7 @@ class RedisClientImpl final std::shared_ptr makeTransaction( const RedisConnectionPtr &connPtr); void handleNextTask(const RedisConnectionPtr &connPtr); - void execCommandAsyncWithTimeout(string_view command, + void execCommandAsyncWithTimeout(std::string_view command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, va_list ap); diff --git a/nosql_lib/redis/src/RedisClientLockFree.cc b/nosql_lib/redis/src/RedisClientLockFree.cc index 97d1c0b1bc..e268fee10d 100644 --- a/nosql_lib/redis/src/RedisClientLockFree.cc +++ b/nosql_lib/redis/src/RedisClientLockFree.cc @@ -142,7 +142,7 @@ RedisConnectionPtr RedisClientLockFree::newSubscribeConnection( void RedisClientLockFree::execCommandAsync( RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept { loop_->assertInLoopThread(); @@ -339,7 +339,7 @@ void RedisClientLockFree::handleNextTask(const RedisConnectionPtr &connPtr) } void RedisClientLockFree::execCommandAsyncWithTimeout( - string_view command, + std::string_view command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, va_list ap) diff --git a/nosql_lib/redis/src/RedisClientLockFree.h b/nosql_lib/redis/src/RedisClientLockFree.h index 32a50bbb89..8df7ac5877 100644 --- a/nosql_lib/redis/src/RedisClientLockFree.h +++ b/nosql_lib/redis/src/RedisClientLockFree.h @@ -29,6 +29,7 @@ namespace nosql { class RedisConnection; using RedisConnectionPtr = std::shared_ptr; + class RedisClientLockFree final : public RedisClient, public trantor::NonCopyable, @@ -43,10 +44,11 @@ class RedisClientLockFree final unsigned int db = 0); void execCommandAsync(RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept override; ~RedisClientLockFree() override; std::shared_ptr newSubscriber() noexcept override; + RedisTransactionPtr newTransaction() override { LOG_ERROR @@ -56,6 +58,7 @@ class RedisClientLockFree final assert(0); return nullptr; } + void newTransactionAsync( const std::function &callback) override; @@ -87,7 +90,7 @@ class RedisClientLockFree final std::shared_ptr makeTransaction( const RedisConnectionPtr &connPtr); void handleNextTask(const RedisConnectionPtr &connPtr); - void execCommandAsyncWithTimeout(string_view command, + void execCommandAsyncWithTimeout(std::string_view command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, va_list ap); diff --git a/nosql_lib/redis/src/RedisConnection.cc b/nosql_lib/redis/src/RedisConnection.cc index 0a680e387e..87403c047e 100644 --- a/nosql_lib/redis/src/RedisConnection.cc +++ b/nosql_lib/redis/src/RedisConnection.cc @@ -22,6 +22,7 @@ #endif using namespace drogon::nosql; + RedisConnection::RedisConnection(const trantor::InetAddress &serverAddress, const std::string &username, const std::string &password, @@ -262,30 +263,35 @@ void RedisConnection::handleDisconnect() redisContext_->ev.cleanup = nullptr; redisContext_->ev.data = nullptr; } + void RedisConnection::addWrite(void *userData) { auto thisPtr = static_cast(userData); assert(thisPtr->channel_); thisPtr->channel_->enableWriting(); } + void RedisConnection::delWrite(void *userData) { auto thisPtr = static_cast(userData); assert(thisPtr->channel_); thisPtr->channel_->disableWriting(); } + void RedisConnection::addRead(void *userData) { auto thisPtr = static_cast(userData); assert(thisPtr->channel_); thisPtr->channel_->enableReading(); } + void RedisConnection::delRead(void *userData) { auto thisPtr = static_cast(userData); assert(thisPtr->channel_); thisPtr->channel_->disableReading(); } + void RedisConnection::cleanup(void * /*userData*/) { LOG_TRACE << "cleanup"; diff --git a/nosql_lib/redis/src/RedisConnection.h b/nosql_lib/redis/src/RedisConnection.h index d37136fae4..ff821807ae 100644 --- a/nosql_lib/redis/src/RedisConnection.h +++ b/nosql_lib/redis/src/RedisConnection.h @@ -13,9 +13,10 @@ */ #pragma once -#include +#include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ enum class ConnectStatus kConnected, kEnd }; + class RedisConnection : public trantor::NonCopyable, public std::enable_shared_from_this { @@ -47,25 +49,29 @@ class RedisConnection : public trantor::NonCopyable, const std::string &password, unsigned int db, trantor::EventLoop *loop); + void setConnectCallback( const std::function &&)> &callback) { connectCallback_ = callback; } + void setDisconnectCallback( const std::function &&)> &callback) { disconnectCallback_ = callback; } + void setIdleCallback( const std::function &)> &callback) { idleCallback_ = callback; } - static std::string getFormattedCommand(const string_view &command, + + static std::string getFormattedCommand(const std::string_view &command, va_list ap) noexcept(false) { char *cmd; @@ -89,6 +95,7 @@ class RedisConnection : public trantor::NonCopyable, free(cmd); return fullCommand; } + void sendFormattedCommand(std::string &&command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback) @@ -112,7 +119,8 @@ class RedisConnection : public trantor::NonCopyable, }); } } - void sendvCommand(string_view command, + + void sendvCommand(std::string_view command, RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, va_list ap) @@ -155,10 +163,12 @@ class RedisConnection : public trantor::NonCopyable, if (redisContext_ && status_ != ConnectStatus::kEnd) redisAsyncDisconnect(redisContext_); } + void disconnect(); + void sendCommand(RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) { va_list args; @@ -169,6 +179,7 @@ class RedisConnection : public trantor::NonCopyable, args); va_end(args); } + trantor::EventLoop *getLoop() const { return loop_; @@ -212,6 +223,7 @@ class RedisConnection : public trantor::NonCopyable, void handleDisconnect(); }; + using RedisConnectionPtr = std::shared_ptr; } // namespace nosql } // namespace drogon diff --git a/nosql_lib/redis/src/RedisResult.cc b/nosql_lib/redis/src/RedisResult.cc index 130388d9f9..ea889ad1a9 100644 --- a/nosql_lib/redis/src/RedisResult.cc +++ b/nosql_lib/redis/src/RedisResult.cc @@ -115,12 +115,14 @@ std::vector RedisResult::asArray() const noexcept(false) } throw RedisException(RedisErrorCode::kBadType, "bad type"); } + long long RedisResult::asInteger() const noexcept(false) { if (type() == RedisResultType::kInteger) return result_->integer; throw RedisException(RedisErrorCode::kBadType, "bad type"); } + bool RedisResult::isNil() const noexcept { return type() == RedisResultType::kNil; diff --git a/nosql_lib/redis/src/RedisTransactionImpl.cc b/nosql_lib/redis/src/RedisTransactionImpl.cc index 2c8081ba32..a0eacaacb3 100644 --- a/nosql_lib/redis/src/RedisTransactionImpl.cc +++ b/nosql_lib/redis/src/RedisTransactionImpl.cc @@ -34,10 +34,11 @@ void RedisTransactionImpl::execute(RedisResultCallback &&resultCallback, std::move(exceptionCallback), "EXEC"); } + void RedisTransactionImpl::execCommandAsync( RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept { if (isExecutedOrCancelled_) diff --git a/nosql_lib/redis/src/RedisTransactionImpl.h b/nosql_lib/redis/src/RedisTransactionImpl.h index d9a5030d98..2f65367134 100644 --- a/nosql_lib/redis/src/RedisTransactionImpl.h +++ b/nosql_lib/redis/src/RedisTransactionImpl.h @@ -32,28 +32,33 @@ class RedisTransactionImpl final RedisExceptionCallback &&exceptionCallback) override; void execCommandAsync(RedisResultCallback &&resultCallback, RedisExceptionCallback &&exceptionCallback, - string_view command, + std::string_view command, ...) noexcept override; + std::shared_ptr newSubscriber() noexcept override { LOG_ERROR << "You can't create subscriber from redis transaction"; assert(0); return nullptr; } + std::shared_ptr newTransaction() override { return shared_from_this(); } + void newTransactionAsync( const std::function &)> &callback) override { callback(shared_from_this()); } + void setTimeout(double timeout) override { timeout_ = timeout; } + void doBegin(); ~RedisTransactionImpl() override; diff --git a/nosql_lib/redis/tests/redis_subscriber_test.cc b/nosql_lib/redis/tests/redis_subscriber_test.cc index 66685dbc11..d61669ee4f 100644 --- a/nosql_lib/redis/tests/redis_subscriber_test.cc +++ b/nosql_lib/redis/tests/redis_subscriber_test.cc @@ -12,6 +12,7 @@ static std::atomic_int nPmsgRecv{0}; static std::atomic_int nMsgSent{0}; RedisClientPtr redisClient; + DROGON_TEST(RedisSubscriberTest) { redisClient = drogon::nosql::RedisClient::newRedisClient( diff --git a/nosql_lib/redis/tests/redis_test.cc b/nosql_lib/redis/tests/redis_test.cc index b33be6f746..552b2065c7 100644 --- a/nosql_lib/redis/tests/redis_test.cc +++ b/nosql_lib/redis/tests/redis_test.cc @@ -9,6 +9,7 @@ using namespace std::chrono_literals; using namespace drogon::nosql; RedisClientPtr redisClient; + DROGON_TEST(RedisTest) { redisClient = drogon::nosql::RedisClient::newRedisClient( diff --git a/orm_lib/inc/drogon/orm/BaseBuilder.h b/orm_lib/inc/drogon/orm/BaseBuilder.h index 66052a2bae..b8047663bf 100644 --- a/orm_lib/inc/drogon/orm/BaseBuilder.h +++ b/orm_lib/inc/drogon/orm/BaseBuilder.h @@ -16,14 +16,14 @@ #include #include -#include -#include +#include #include #include #include #include #include #include +#include #define unimplemented() assert(false && "unimplemented") @@ -87,8 +87,8 @@ class BaseBuilder std::string from_; std::string columns_; std::vector filters_; - optional limit_; - optional offset_; + std::optional limit_; + std::optional offset_; // The order is important; use vector instead of unordered_map and // map. std::vector> orders_; @@ -207,6 +207,7 @@ class BaseBuilder { return T(r[0]); } + template = nullptr, @@ -220,6 +221,7 @@ class BaseBuilder } return ret; } + template = nullptr, @@ -228,6 +230,7 @@ class BaseBuilder { return r[0]; } + template = nullptr, diff --git a/orm_lib/inc/drogon/orm/CoroMapper.h b/orm_lib/inc/drogon/orm/CoroMapper.h index 0ad412cd7e..e1c8747588 100644 --- a/orm_lib/inc/drogon/orm/CoroMapper.h +++ b/orm_lib/inc/drogon/orm/CoroMapper.h @@ -19,6 +19,7 @@ #ifdef __cpp_impl_coroutine #include #include + namespace drogon { namespace orm @@ -31,10 +32,12 @@ struct [[nodiscard]] MapperAwaiter : public CallbackAwaiter using MapperFunction = std::function &&, std::function &&)>; + explicit MapperAwaiter(MapperFunction &&function) : function_(std::move(function)) { } + void await_suspend(std::coroutine_handle<> handle) { function_( @@ -72,7 +75,9 @@ class CoroMapper : public Mapper explicit CoroMapper(DbClientPtr client) : Mapper(std::move(client)) { } + using TraitsPKType = typename Mapper::TraitsPKType; + inline internal::MapperAwaiter findByPrimaryKey(const TraitsPKType &key) { if constexpr (!std::is_same::value) @@ -213,6 +218,7 @@ class CoroMapper : public Mapper { return findBy(Criteria()); } + inline internal::MapperAwaiter count( const Criteria &criteria = Criteria()) { @@ -238,6 +244,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter(std::move(lb)); } + inline internal::MapperAwaiter findOne(const Criteria &criteria) { auto lb = [this, criteria](SingleRowCallback &&callback, @@ -297,6 +304,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter(std::move(lb)); } + inline internal::MapperAwaiter> findBy( const Criteria &criteria) { @@ -348,6 +356,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter>(std::move(lb)); } + inline internal::MapperAwaiter insert(const T &obj) { auto lb = [this, obj](SingleRowCallback &&callback, @@ -402,6 +411,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter(std::move(lb)); } + inline internal::MapperAwaiter update(const T &obj) { auto lb = [this, obj](CountCallback &&callback, @@ -539,6 +549,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter(std::move(lb)); } + inline internal::MapperAwaiter deleteBy(const Criteria &criteria) { auto lb = [this, criteria](CountCallback &&callback, @@ -569,6 +580,7 @@ class CoroMapper : public Mapper }; return internal::MapperAwaiter(std::move(lb)); } + inline internal::MapperAwaiter deleteByPrimaryKey( const TraitsPKType &key) { diff --git a/orm_lib/inc/drogon/orm/Criteria.h b/orm_lib/inc/drogon/orm/Criteria.h index d3c7e068ea..5216f3e83b 100644 --- a/orm_lib/inc/drogon/orm/Criteria.h +++ b/orm_lib/inc/drogon/orm/Criteria.h @@ -27,6 +27,7 @@ namespace Json { class Value; } + namespace drogon { namespace orm @@ -55,6 +56,7 @@ struct CustomSql explicit CustomSql(std::string content) : content_(std::move(content)) { } + std::string content_; }; @@ -308,10 +310,12 @@ class DROGON_EXPORT Criteria break; } } + Criteria(const std::string &colName, CompareOperator &opera) : Criteria(colName, (const CompareOperator &)opera) { } + Criteria(const std::string &colName, CompareOperator &&opera) : Criteria(colName, (const CompareOperator &)opera) { diff --git a/orm_lib/inc/drogon/orm/DbClient.h b/orm_lib/inc/drogon/orm/DbClient.h index 9d646ac671..5bcb0e0f74 100644 --- a/orm_lib/inc/drogon/orm/DbClient.h +++ b/orm_lib/inc/drogon/orm/DbClient.h @@ -218,12 +218,14 @@ class DROGON_EXPORT DbClient : public trantor::NonCopyable /// wiki page. internal::SqlBinder operator<<(const std::string &sql); internal::SqlBinder operator<<(std::string &&sql); + template internal::SqlBinder operator<<(const char (&sql)[N]) { return internal::SqlBinder(sql, N - 1, *this, type_); } - internal::SqlBinder operator<<(const string_view &sql) + + internal::SqlBinder operator<<(const std::string_view &sql) { return internal::SqlBinder(sql.data(), sql.length(), *this, type_); } @@ -273,6 +275,7 @@ class DROGON_EXPORT DbClient : public trantor::NonCopyable { return type_; } + const std::string &connectionInfo() const { return connectionInfo_; @@ -352,6 +355,7 @@ class DROGON_EXPORT DbClient : public trantor::NonCopyable ClientType type_; std::string connectionInfo_; }; + using DbClientPtr = std::shared_ptr; class Transaction : public DbClient @@ -361,6 +365,7 @@ class Transaction : public DbClient // virtual void commit() = 0; virtual void setCommitCallback( const std::function &commitCallback) = 0; + void closeAll() override { } diff --git a/orm_lib/inc/drogon/orm/Field.h b/orm_lib/inc/drogon/orm/Field.h index 7854d486f7..7f933ba532 100644 --- a/orm_lib/inc/drogon/orm/Field.h +++ b/orm_lib/inc/drogon/orm/Field.h @@ -18,7 +18,7 @@ #pragma once #include -#include +#include #include #include #include @@ -118,6 +118,7 @@ class DROGON_EXPORT Field { return ArrayParser(result_.getValue(row_, column_)); } + template std::vector> asArray() const { @@ -159,6 +160,7 @@ class DROGON_EXPORT Field private: const Result result_; }; + template <> DROGON_EXPORT std::string Field::as() const; template <> @@ -167,8 +169,9 @@ template <> DROGON_EXPORT char *Field::as() const; template <> DROGON_EXPORT std::vector Field::as>() const; + template <> -inline drogon::string_view Field::as() const +inline std::string_view Field::as() const { auto first = result_.getValue(row_, column_); auto length = result_.getLength(row_, column_); diff --git a/orm_lib/inc/drogon/orm/FunctionTraits.h b/orm_lib/inc/drogon/orm/FunctionTraits.h index c758ff9b0a..91cd5625b8 100644 --- a/orm_lib/inc/drogon/orm/FunctionTraits.h +++ b/orm_lib/inc/drogon/orm/FunctionTraits.h @@ -24,10 +24,12 @@ namespace orm { class Result; class DrogonDbException; + namespace internal { template struct FunctionTraits; + template <> struct FunctionTraits { @@ -39,10 +41,12 @@ struct FunctionTraits static const bool isSqlCallback = false; static const bool isExceptCallback = false; }; + // functor,lambda template -struct FunctionTraits : public FunctionTraits::type::operator())> +struct FunctionTraits + : public FunctionTraits< + decltype(&std::remove_reference::type::operator())> { }; diff --git a/orm_lib/inc/drogon/orm/Mapper.h b/orm_lib/inc/drogon/orm/Mapper.h index e307a9f529..f553a1d55c 100644 --- a/orm_lib/inc/drogon/orm/Mapper.h +++ b/orm_lib/inc/drogon/orm/Mapper.h @@ -33,6 +33,7 @@ enum class SortOrder ASC, DESC }; + namespace internal { template @@ -40,11 +41,13 @@ struct Traits { using type = typename T::PrimaryKeyType; }; + template struct Traits { using type = int; }; + template struct has_sqlForFindingByPrimaryKey { @@ -62,6 +65,7 @@ struct has_sqlForFindingByPrimaryKey static constexpr bool value = std::is_same(0)), yes>::value; }; + template struct has_sqlForDeletingByPrimaryKey { @@ -288,6 +292,7 @@ class Mapper }; binder >> ecb; } + template inline typename std::enable_if< std::is_same::value, @@ -686,6 +691,7 @@ class Mapper size_t offset_{0}; std::string orderByString_; bool forUpdate_{false}; + void clear() { limit_ = 0; @@ -693,6 +699,7 @@ class Mapper orderByString_.clear(); forUpdate_ = false; } + template typename std::enable_if::value, void>::type @@ -702,6 +709,7 @@ class Mapper sql += T::primaryKeyName; sql += " = $?"; } + template typename std::enable_if< std::is_same, PKType>::value, @@ -719,6 +727,7 @@ class Mapper } } } + template typename std::enable_if::value, void>::type @@ -727,6 +736,7 @@ class Mapper { binder << pk; } + template typename std::enable_if< std::is_same, PKType>::value, @@ -745,6 +755,7 @@ class Mapper tupleToBinder(t, binder); binder << std::get(t); } + template ::value> typename std::enable_if<(N == 1), void>::type tupleToBinder( const TP &t, @@ -927,6 +938,7 @@ inline std::future Mapper::findFutureOne( binder.exec(); return prom->get_future(); } + template inline std::vector Mapper::findBy(const Criteria &criteria) noexcept( false) @@ -978,6 +990,7 @@ inline std::vector Mapper::findBy(const Criteria &criteria) noexcept( } return ret; } + template inline void Mapper::findBy(const Criteria &criteria, const MultipleRowsCallback &rcb, @@ -1027,6 +1040,7 @@ inline void Mapper::findBy(const Criteria &criteria, }; binder >> ecb; } + template inline std::future> Mapper::findFutureBy( const Criteria &criteria) noexcept @@ -1079,22 +1093,26 @@ inline std::future> Mapper::findFutureBy( binder.exec(); return prom->get_future(); } + template inline std::vector Mapper::findAll() noexcept(false) { return findBy(Criteria()); } + template inline void Mapper::findAll(const MultipleRowsCallback &rcb, const ExceptionCallback &ecb) noexcept { findBy(Criteria(), rcb, ecb); } + template inline std::future> Mapper::findFutureAll() noexcept { return findFutureBy(Criteria()); } + template inline size_t Mapper::count(const Criteria &criteria) noexcept(false) { @@ -1119,6 +1137,7 @@ inline size_t Mapper::count(const Criteria &criteria) noexcept(false) assert(r.size() == 1); return r[0][(Row::SizeType)0].as(); } + template inline void Mapper::count(const Criteria &criteria, const CountCallback &rcb, @@ -1142,6 +1161,7 @@ inline void Mapper::count(const Criteria &criteria, }; binder >> ecb; } + template inline std::future Mapper::countFuture( const Criteria &criteria) noexcept @@ -1169,6 +1189,7 @@ inline std::future Mapper::countFuture( binder.exec(); return prom->get_future(); } + template inline void Mapper::insert(T &obj) noexcept(false) { @@ -1201,6 +1222,7 @@ inline void Mapper::insert(T &obj) noexcept(false) } } } + template inline void Mapper::insert(const T &obj, const SingleRowCallback &rcb, @@ -1243,6 +1265,7 @@ inline void Mapper::insert(const T &obj, }; binder >> ecb; } + template inline std::future Mapper::insertFuture(const T &obj) noexcept { @@ -1324,6 +1347,7 @@ inline size_t Mapper::update(const T &obj) noexcept(false) } return r.affectedRows(); } + template template size_t Mapper::updateBy(const std::vector &colNames, @@ -1391,6 +1415,7 @@ inline void Mapper::update(const T &obj, binder >> [rcb](const Result &r) { rcb(r.affectedRows()); }; binder >> ecb; } + template template void Mapper::updateBy(const std::vector &colNames, @@ -1458,6 +1483,7 @@ inline std::future Mapper::updateFuture(const T &obj) noexcept binder.exec(); return prom->get_future(); } + template template inline std::future Mapper::updateFutureBy( @@ -1523,6 +1549,7 @@ inline size_t Mapper::deleteOne(const T &obj) noexcept(false) } return r.affectedRows(); } + template inline void Mapper::deleteOne(const T &obj, const CountCallback &rcb, @@ -1543,6 +1570,7 @@ inline void Mapper::deleteOne(const T &obj, binder >> [rcb](const Result &r) { rcb(r.affectedRows()); }; binder >> ecb; } + template inline std::future Mapper::deleteFutureOne(const T &obj) noexcept { @@ -1596,6 +1624,7 @@ inline size_t Mapper::deleteBy(const Criteria &criteria) noexcept(false) } return r.affectedRows(); } + template inline void Mapper::deleteBy(const Criteria &criteria, const CountCallback &rcb, @@ -1622,6 +1651,7 @@ inline void Mapper::deleteBy(const Criteria &criteria, binder >> [rcb](const Result &r) { rcb(r.affectedRows()); }; binder >> ecb; } + template inline std::future Mapper::deleteFutureBy( const Criteria &criteria) noexcept @@ -1658,12 +1688,14 @@ inline Mapper &Mapper::limit(size_t limit) limit_ = limit; return *this; } + template inline Mapper &Mapper::offset(size_t offset) { offset_ = offset; return *this; } + template inline Mapper &Mapper::orderBy(const std::string &colName, const SortOrder &order) @@ -1688,6 +1720,7 @@ inline Mapper &Mapper::orderBy(const std::string &colName, } return *this; } + template inline Mapper &Mapper::orderBy(size_t colIndex, const SortOrder &order) { @@ -1695,18 +1728,21 @@ inline Mapper &Mapper::orderBy(size_t colIndex, const SortOrder &order) assert(!colName.empty()); return orderBy(colName, order); } + template inline Mapper &Mapper::paginate(size_t page, size_t perPage) { assert(page > 0 && perPage > 0); return limit(perPage).offset((page - 1) * perPage); } + template inline Mapper &Mapper::forUpdate() { forUpdate_ = true; return *this; } + template inline std::string Mapper::replaceSqlPlaceHolder( const std::string &sqlStr, diff --git a/orm_lib/inc/drogon/orm/RestfulController.h b/orm_lib/inc/drogon/orm/RestfulController.h index 84022f22a6..569447f1a3 100644 --- a/orm_lib/inc/drogon/orm/RestfulController.h +++ b/orm_lib/inc/drogon/orm/RestfulController.h @@ -42,6 +42,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable std::pair{masqueradingVector_[i], i}); } } + void disableMasquerading() { masquerading_ = false; @@ -52,6 +53,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable std::pair{masqueradingVector_[i], i}); } } + void registerAJsonValidator( const std::string &fieldName, const std::function @@ -59,6 +61,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable { validators_.emplace_back(fieldName, validator); } + void registerAJsonValidator( const std::string &fieldName, std::function &&validator) @@ -93,6 +96,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable : columnsVector_(columnsVector) { } + std::vector fieldsSelector(const std::set &fields) { std::vector ret; @@ -109,6 +113,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable } return ret; } + template Json::Value makeJson(const HttpRequestPtr &req, const T &obj) { @@ -139,6 +144,7 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable } } } + bool doCustomValidations(const Json::Value &pJson, std::string &err) { for (auto &validator : validators_) @@ -153,10 +159,12 @@ class DROGON_EXPORT RestfulController : trantor::NonCopyable } return true; } + bool isMasquerading() const { return masquerading_; } + const std::vector &masqueradingVector() const { return masqueradingVector_; diff --git a/orm_lib/inc/drogon/orm/Result.h b/orm_lib/inc/drogon/orm/Result.h index 759b3d9d34..23039c0fc0 100644 --- a/orm_lib/inc/drogon/orm/Result.h +++ b/orm_lib/inc/drogon/orm/Result.h @@ -60,6 +60,7 @@ class DROGON_EXPORT Result explicit Result(ResultImplPtr ptr) : resultPtr_(std::move(ptr)) { } + Result(const Result &r) noexcept = default; Result(Result &&) noexcept = default; Result &operator=(const Result &r) noexcept; @@ -87,10 +88,12 @@ class DROGON_EXPORT Result using const_reverse_iterator = ConstReverseIterator; SizeType size() const noexcept; + SizeType capacity() const noexcept { return size(); } + ConstIterator begin() const noexcept; ConstIterator cbegin() const noexcept; ConstIterator end() const noexcept; @@ -147,11 +150,13 @@ class DROGON_EXPORT Result friend class Row; /// Number of given column (throws exception if it doesn't exist). RowSizeType columnNumber(const char colName[]) const; + /// Number of given column (throws exception if it doesn't exist). RowSizeType columnNumber(const std::string &name) const { return columnNumber(name.c_str()); } + /// Get the column oid, for postgresql database int oid(RowSizeType column) const noexcept; @@ -159,6 +164,7 @@ class DROGON_EXPORT Result bool isNull(SizeType row, RowSizeType column) const; FieldSizeType getLength(SizeType row, RowSizeType column) const; }; + inline void swap(Result &one, Result &two) noexcept { one.swap(two); diff --git a/orm_lib/inc/drogon/orm/ResultIterator.h b/orm_lib/inc/drogon/orm/ResultIterator.h index d4f1eefdfc..62350865e4 100644 --- a/orm_lib/inc/drogon/orm/ResultIterator.h +++ b/orm_lib/inc/drogon/orm/ResultIterator.h @@ -19,6 +19,7 @@ #include #include + namespace drogon { namespace orm @@ -32,34 +33,41 @@ class ConstResultIterator : protected Row using value_type = const Row; using size_type = Result::SizeType; using difference_type = Result::DifferenceType; + // ConstResultIterator(const Row &t) noexcept : Row(t) {} pointer operator->() { return this; } + reference operator*() { return *this; } ConstResultIterator operator++(int); + ConstResultIterator &operator++() { ++index_; return *this; } + ConstResultIterator operator--(int); + ConstResultIterator &operator--() { --index_; return *this; } + ConstResultIterator &operator+=(difference_type i) { index_ += i; return *this; } + ConstResultIterator &operator-=(difference_type i) { index_ -= i; @@ -70,31 +78,38 @@ class ConstResultIterator : protected Row { return index_ == other.index_; } + bool operator!=(const ConstResultIterator &other) const { return index_ != other.index_; } + bool operator>(const ConstResultIterator &other) const { return index_ > other.index_; } + bool operator<(const ConstResultIterator &other) const { return index_ < other.index_; } + bool operator>=(const ConstResultIterator &other) const { return index_ >= other.index_; } + bool operator<=(const ConstResultIterator &other) const { return index_ <= other.index_; } + ConstResultIterator(const ConstResultIterator &) noexcept = default; ConstResultIterator(ConstResultIterator &&) noexcept = default; private: friend class Result; + ConstResultIterator(const Result &r, SizeType index) noexcept : Row(r, index) { @@ -110,12 +125,14 @@ class ConstReverseResultIterator : private ConstResultIterator using iterator_type::iterator_category; using iterator_type::pointer; using iterator_type::reference; + // using iterator_type::value_type; ConstReverseResultIterator(const ConstReverseResultIterator &rhs) : ConstResultIterator(rhs) { } + explicit ConstReverseResultIterator(const ConstResultIterator &rhs) : ConstResultIterator(rhs) { @@ -128,22 +145,27 @@ class ConstReverseResultIterator : private ConstResultIterator using iterator_type::operator*; ConstReverseResultIterator operator++(int); + ConstReverseResultIterator &operator++() { iterator_type::operator--(); return *this; } + ConstReverseResultIterator operator--(int); + ConstReverseResultIterator &operator--() { iterator_type::operator++(); return *this; } + ConstReverseResultIterator &operator+=(difference_type i) { iterator_type::operator-=(i); return *this; } + ConstReverseResultIterator &operator-=(difference_type i) { iterator_type::operator+=(i); @@ -154,22 +176,27 @@ class ConstReverseResultIterator : private ConstResultIterator { return index_ == other.index_; } + bool operator!=(const ConstReverseResultIterator &other) const { return index_ != other.index_; } + bool operator>(const ConstReverseResultIterator &other) const { return index_ < other.index_; } + bool operator<(const ConstReverseResultIterator &other) const { return index_ > other.index_; } + bool operator>=(const ConstReverseResultIterator &other) const { return index_ <= other.index_; } + bool operator<=(const ConstReverseResultIterator &other) const { return index_ >= other.index_; diff --git a/orm_lib/inc/drogon/orm/Row.h b/orm_lib/inc/drogon/orm/Row.h index a75c6e00c7..35b27a0975 100644 --- a/orm_lib/inc/drogon/orm/Row.h +++ b/orm_lib/inc/drogon/orm/Row.h @@ -20,6 +20,7 @@ #include #include #include + namespace drogon { namespace orm @@ -63,10 +64,12 @@ class DROGON_EXPORT Row Reference at(const std::string &columnName) const; SizeType size() const; + SizeType capacity() const noexcept { return size(); } + ConstIterator begin() const noexcept; ConstIterator cbegin() const noexcept; ConstIterator end() const noexcept; diff --git a/orm_lib/inc/drogon/orm/RowIterator.h b/orm_lib/inc/drogon/orm/RowIterator.h index 3015aa0743..d39f4ce973 100644 --- a/orm_lib/inc/drogon/orm/RowIterator.h +++ b/orm_lib/inc/drogon/orm/RowIterator.h @@ -19,6 +19,7 @@ #include #include + namespace drogon { namespace orm @@ -32,34 +33,41 @@ class ConstRowIterator : protected Field using size_type = Row::SizeType; using difference_type = Row::DifferenceType; using iterator_category = std::random_access_iterator_tag; + // ConstRowIterator(const Field &t) noexcept : Field(t) {} pointer operator->() { return this; } + reference operator*() { return *this; } ConstRowIterator operator++(int); + ConstRowIterator &operator++() { ++column_; return *this; } + ConstRowIterator operator--(int); + ConstRowIterator &operator--() { --column_; return *this; } + ConstRowIterator &operator+=(difference_type i) { column_ += i; return *this; } + ConstRowIterator &operator-=(difference_type i) { column_ -= i; @@ -70,22 +78,27 @@ class ConstRowIterator : protected Field { return column_ == other.column_; } + bool operator!=(const ConstRowIterator &other) const { return column_ != other.column_; } + bool operator>(const ConstRowIterator &other) const { return column_ > other.column_; } + bool operator<(const ConstRowIterator &other) const { return column_ < other.column_; } + bool operator>=(const ConstRowIterator &other) const { return column_ >= other.column_; } + bool operator<=(const ConstRowIterator &other) const { return column_ <= other.column_; @@ -93,6 +106,7 @@ class ConstRowIterator : protected Field private: friend class Row; + ConstRowIterator(const Row &r, SizeType column) noexcept : Field(r, column) { } @@ -107,12 +121,14 @@ class ConstReverseRowIterator : private ConstRowIterator using iterator_type::iterator_category; using iterator_type::pointer; using iterator_type::reference; + // using iterator_type::value_type; ConstReverseRowIterator(const ConstReverseRowIterator &rhs) : ConstRowIterator(rhs) { } + explicit ConstReverseRowIterator(const ConstRowIterator &rhs) : ConstRowIterator(rhs) { @@ -125,22 +141,27 @@ class ConstReverseRowIterator : private ConstRowIterator using iterator_type::operator*; ConstReverseRowIterator operator++(int); + ConstReverseRowIterator &operator++() { iterator_type::operator--(); return *this; } + ConstReverseRowIterator operator--(int); + ConstReverseRowIterator &operator--() { iterator_type::operator++(); return *this; } + ConstReverseRowIterator &operator+=(difference_type i) { iterator_type::operator-=(i); return *this; } + ConstReverseRowIterator &operator-=(difference_type i) { iterator_type::operator+=(i); @@ -151,22 +172,27 @@ class ConstReverseRowIterator : private ConstRowIterator { return column_ == other.column_; } + bool operator!=(const ConstReverseRowIterator &other) const { return column_ != other.column_; } + bool operator>(const ConstReverseRowIterator &other) const { return column_ < other.column_; } + bool operator<(const ConstReverseRowIterator &other) const { return column_ > other.column_; } + bool operator>=(const ConstReverseRowIterator &other) const { return column_ <= other.column_; } + bool operator<=(const ConstReverseRowIterator &other) const { return column_ >= other.column_; diff --git a/orm_lib/inc/drogon/orm/SqlBinder.h b/orm_lib/inc/drogon/orm/SqlBinder.h index d1c2e64162..628b92297a 100644 --- a/orm_lib/inc/drogon/orm/SqlBinder.h +++ b/orm_lib/inc/drogon/orm/SqlBinder.h @@ -21,8 +21,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #ifdef _WIN32 #include #else // some Unix-like OS @@ -70,10 +70,12 @@ constexpr T htonT(T value) noexcept return value; #endif } + inline uint64_t htonll(uint64_t value) { return htonT(value); } + inline uint64_t ntohll(uint64_t value) { return htonll(value); @@ -111,6 +113,7 @@ enum class Mode NonBlocking, Blocking }; + namespace internal { template @@ -120,6 +123,7 @@ struct VectorTypeTraits static const bool isPtrVector = false; using ItemsType = T; }; + template struct VectorTypeTraits>> { @@ -127,6 +131,7 @@ struct VectorTypeTraits>> static const bool isPtrVector = true; using ItemsType = T; }; + template <> struct VectorTypeTraits { @@ -142,21 +147,25 @@ struct CallbackArgTypeTraits { static const bool isValid = true; }; + template struct CallbackArgTypeTraits { static const bool isValid = false; }; + template struct CallbackArgTypeTraits { static const bool isValid = false; }; + template struct CallbackArgTypeTraits { static const bool isValid = true; }; + template struct CallbackArgTypeTraits { @@ -169,6 +178,7 @@ class CallbackHolderBase virtual ~CallbackHolderBase() = default; virtual void execCallback(const Result &result) = 0; }; + template class CallbackHolder : public CallbackHolderBase { @@ -206,6 +216,7 @@ class CallbackHolder : public CallbackHolderBase } run(nullptr, true); } + template typename std::enable_if::type run(const Result &result) { @@ -213,6 +224,7 @@ class CallbackHolder : public CallbackHolderBase "Your sql callback function type is wrong!"); function_(result); } + template typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run( const Row *const row, @@ -244,6 +256,7 @@ class CallbackHolder : public CallbackHolderBase run(row, isNull, std::forward(values)..., std::move(value)); } + template typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run( const Row *const, @@ -252,6 +265,7 @@ class CallbackHolder : public CallbackHolderBase { function_(isNull, std::move(values)...); } + template typename std::enable_if::isVector, ValueType>::type @@ -259,6 +273,7 @@ class CallbackHolder : public CallbackHolderBase { return field.asArray::ItemsType>(); } + template typename std::enable_if::isVector, ValueType>::type @@ -267,6 +282,7 @@ class CallbackHolder : public CallbackHolderBase return field.as(); } }; + class DROGON_EXPORT SqlBinder : public trantor::NonCopyable { using self = SqlBinder; @@ -280,6 +296,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable type_(type) { } + SqlBinder(std::string &&sql, DbClient &client, ClientType type) : sqlPtr_(std::make_shared(std::move(sql))), sqlViewPtr_(sqlPtr_->data()), @@ -288,6 +305,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable type_(type) { } + SqlBinder(const char *sql, size_t sqlLength, DbClient &client, @@ -298,6 +316,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable type_(type) { } + SqlBinder(SqlBinder &&that) noexcept : sqlPtr_(std::move(that.sqlPtr_)), sqlViewPtr_(that.sqlViewPtr_), @@ -320,8 +339,10 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable // set the execed_ to true to avoid the same sql being executed twice. that.execed_ = true; } + SqlBinder &operator=(SqlBinder &&that) = delete; ~SqlBinder(); + template ::type>> @@ -428,44 +449,58 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable // LOG_TRACE << "Bind parameter:" << parameter; return *this; } + // template <> self &operator<<(const char str[]) { return operator<<(std::string(str)); } + self &operator<<(char str[]) { return operator<<(std::string(str)); } - self &operator<<(const drogon::string_view &str); - self &operator<<(drogon::string_view &&str) + + self &operator<<(const std::string_view &str); + + self &operator<<(std::string_view &&str) { - return operator<<((const drogon::string_view &)str); + return operator<<((const std::string_view &)str); } - self &operator<<(drogon::string_view &str) + + self &operator<<(std::string_view &str) { - return operator<<((const drogon::string_view &)str); + return operator<<((const std::string_view &)str); } + self &operator<<(const std::string &str); + self &operator<<(std::string &str) { return operator<<((const std::string &)str); } + self &operator<<(std::string &&str); + self &operator<<(trantor::Date &&date) { return operator<<(date.toDbStringLocal()); } + self &operator<<(const trantor::Date &date) { return operator<<(date.toDbStringLocal()); } + self &operator<<(const std::vector &v); + self &operator<<(std::vector &v) { return operator<<((const std::vector &)v); } + self &operator<<(std::vector &&v); + self &operator<<(float f) { if (type_ == ClientType::Sqlite3) @@ -474,26 +509,31 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable } return operator<<(std::to_string(f)); } + self &operator<<(double f); self &operator<<(std::nullptr_t); self &operator<<(DefaultValue dv); + self &operator<<(const Mode &mode) { mode_ = mode; return *this; } + self &operator<<(Mode &mode) { mode_ = mode; return *this; } + self &operator<<(Mode &&mode) { mode_ = mode; return *this; } + template - self &operator<<(const optional ¶meter) + self &operator<<(const std::optional ¶meter) { if (parameter) { @@ -501,8 +541,9 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable } return *this << nullptr; } + template - self &operator<<(optional ¶meter) + self &operator<<(std::optional ¶meter) { if (parameter) { @@ -510,8 +551,9 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable } return *this << nullptr; } + template - self &operator<<(optional &¶meter) + self &operator<<(std::optional &¶meter) { if (parameter) { @@ -519,6 +561,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable } return *this << nullptr; } + self &operator<<(const Json::Value &j) noexcept(true) { switch (j.type()) @@ -545,14 +588,17 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable return *this << Json::writeString(jsonBuilder, j); } } + self &operator<<(Json::Value &j) noexcept(true) { return *this << static_cast(j); } + self &operator<<(Json::Value &&j) noexcept(true) { return *this << static_cast(j); } + void exec() noexcept(false); private: diff --git a/orm_lib/src/Criteria.cc b/orm_lib/src/Criteria.cc index ff9c3c0277..8840a8f60f 100644 --- a/orm_lib/src/Criteria.cc +++ b/orm_lib/src/Criteria.cc @@ -44,6 +44,7 @@ const Criteria operator&&(Criteria cond1, Criteria cond2) }; return cond; } + const Criteria operator||(Criteria cond1, Criteria cond2) { assert(cond1); diff --git a/orm_lib/src/DbClientImpl.cc b/orm_lib/src/DbClientImpl.cc index f455469969..5e154b21c9 100644 --- a/orm_lib/src/DbClientImpl.cc +++ b/orm_lib/src/DbClientImpl.cc @@ -16,7 +16,7 @@ #include "DbConnection.h" #include "../../lib/src/TaskTimeoutFlag.h" #include -#include +#include #if USE_POSTGRESQL #include "postgresql_impl/PgConnection.h" #endif @@ -71,6 +71,7 @@ DbClientImpl::DbClientImpl(const std::string &connInfo, LOG_TRACE << "type=" << (int)type; assert(connNum > 0); } + void DbClientImpl::init() { // LOG_DEBUG << loops_.getLoopNum(); @@ -161,7 +162,7 @@ void DbClientImpl::execSql( { // LOG_TRACE << "Push query to buffer"; std::shared_ptr cmd = - std::make_shared(string_view{sql, sqlLength}, + std::make_shared(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -198,6 +199,7 @@ void DbClientImpl::execSql( return; } } + void DbClientImpl::newTransactionAsync( const std::function &)> &callback) { @@ -263,6 +265,7 @@ void DbClientImpl::newTransactionAsync( callback)); } } + void DbClientImpl::makeTrans( const DbConnectionPtr &conn, std::function &)> &&callback) @@ -316,6 +319,7 @@ void DbClientImpl::makeTrans( conn->loop()->queueInLoop( [callback = std::move(callback), trans]() { callback(trans); }); } + std::shared_ptr DbClientImpl::newTransaction( const std::function &commitCallback) noexcept(false) { @@ -540,7 +544,7 @@ void DbClientImpl::execSqlWithTimeout( { // LOG_TRACE << "Push query to buffer"; auto command = - std::make_shared(string_view{sql, sqlLength}, + std::make_shared(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -561,7 +565,7 @@ void DbClientImpl::execSqlWithTimeout( } if (conn) { - conn->execSql(string_view{sql, sqlLength}, + conn->execSql(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), diff --git a/orm_lib/src/DbClientImpl.h b/orm_lib/src/DbClientImpl.h index 4244ebc617..09ad0c994d 100644 --- a/orm_lib/src/DbClientImpl.h +++ b/orm_lib/src/DbClientImpl.h @@ -57,10 +57,12 @@ class DbClientImpl : public DbClient, const std::function &)> &callback) override; bool hasAvailableConnections() const noexcept override; + void setTimeout(double timeout) override { timeout_ = timeout; } + void init(); void closeAll() override; diff --git a/orm_lib/src/DbClientLockFree.cc b/orm_lib/src/DbClientLockFree.cc index 6283183d71..427f762442 100644 --- a/orm_lib/src/DbClientLockFree.cc +++ b/orm_lib/src/DbClientLockFree.cc @@ -123,7 +123,7 @@ void DbClientLockFree::execSql( (transSet_.empty() || transSet_.find(conn) == transSet_.end())) { conn->execSql( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -153,7 +153,7 @@ void DbClientLockFree::execSql( transSet_.find(conn) == transSet_.end())) { conn->execSql( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -185,7 +185,7 @@ void DbClientLockFree::execSql( if (transSet_.empty() || transSet_.find(conn) == transSet_.end()) { - conn->execSql(string_view{sql, sqlLength}, + conn->execSql(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -211,7 +211,7 @@ void DbClientLockFree::execSql( // LOG_TRACE << "Push query to buffer"; sqlCmdBuffer_.emplace_back(std::make_shared( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -554,7 +554,7 @@ void DbClientLockFree::execSqlWithTimeout( (transSet_.empty() || transSet_.find(conn) == transSet_.end())) { conn->execSql( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -587,7 +587,7 @@ void DbClientLockFree::execSqlWithTimeout( transSet_.find(conn) == transSet_.end())) { conn->execSql( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -622,7 +622,7 @@ void DbClientLockFree::execSqlWithTimeout( if (transSet_.empty() || transSet_.find(conn) == transSet_.end()) { - conn->execSql(string_view{sql, sqlLength}, + conn->execSql(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -648,7 +648,7 @@ void DbClientLockFree::execSqlWithTimeout( // LOG_TRACE << "Push query to buffer"; auto cmdPtr = std::make_shared( - string_view{sql, sqlLength}, + std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), diff --git a/orm_lib/src/DbClientLockFree.h b/orm_lib/src/DbClientLockFree.h index a68334cf43..1e2e4d715c 100644 --- a/orm_lib/src/DbClientLockFree.h +++ b/orm_lib/src/DbClientLockFree.h @@ -60,10 +60,12 @@ class DbClientLockFree : public DbClient, const std::function &)> &callback) override; bool hasAvailableConnections() const noexcept override; + void setTimeout(double timeout) override { timeout_ = timeout; } + void closeAll() override; private: diff --git a/orm_lib/src/DbConnection.h b/orm_lib/src/DbConnection.h index 75598c274a..87bca7ba33 100644 --- a/orm_lib/src/DbConnection.h +++ b/orm_lib/src/DbConnection.h @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ enum class ConnectStatus struct SqlCmd { - string_view sql_; + std::string_view sql_; size_t parametersNumber_; std::vector parameters_; std::vector lengths_; @@ -58,7 +58,7 @@ struct SqlCmd #if LIBPQ_SUPPORTS_BATCH_MODE bool isChanging_{false}; #endif - SqlCmd(string_view &&sql, + SqlCmd(std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -78,27 +78,33 @@ struct SqlCmd class DbConnection; using DbConnectionPtr = std::shared_ptr; + class DbConnection : public trantor::NonCopyable { public: using DbConnectionCallback = std::function; + explicit DbConnection(trantor::EventLoop *loop) : loop_(loop) { } + void setOkCallback(const DbConnectionCallback &cb) { okCallback_ = cb; } + void setCloseCallback(const DbConnectionCallback &cb) { closeCallback_ = cb; } + void setIdleCallback(const std::function &cb) { idleCb_ = cb; } + virtual void execSql( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -107,19 +113,24 @@ class DbConnection : public trantor::NonCopyable std::function &&exceptCallback) = 0; virtual void batchSql( std::deque> &&sqlCommands) = 0; + virtual ~DbConnection() { LOG_TRACE << "Destruct DbConn" << this; } + ConnectStatus status() const { return status_; } + trantor::EventLoop *loop() { return loop_; } + virtual void disconnect() = 0; + bool isWorking() const { return isWorking_; diff --git a/orm_lib/src/Field.cc b/orm_lib/src/Field.cc index 2961069342..0f0089c86e 100644 --- a/orm_lib/src/Field.cc +++ b/orm_lib/src/Field.cc @@ -18,6 +18,7 @@ #include using namespace drogon::orm; + Field::Field(const Row &row, Row::SizeType columnNum) noexcept : row_(Result::SizeType(row.index_)), column_((long)columnNum), @@ -48,24 +49,27 @@ std::string Field::as() const else { // Bytea type of PostgreSQL - auto sv = as(); + auto sv = as(); if (sv.length() < 2 || sv[0] != '\\' || sv[1] != 'x') return std::string(); return utils::hexToBinaryString(sv.data() + 2, sv.length() - 2); } } + template <> const char *Field::as() const { auto data_ = result_.getValue(row_, column_); return data_; } + template <> char *Field::as() const { auto data_ = result_.getValue(row_, column_); return (char *)data_; } + template <> std::vector Field::as>() const { @@ -78,7 +82,7 @@ std::vector Field::as>() const else { // Bytea type of PostgreSQL - auto sv = as(); + auto sv = as(); if (sv.length() < 2 || sv[0] != '\\' || sv[1] != 'x') return std::vector(); return utils::hexToBinaryVector(sv.data() + 2, sv.length() - 2); @@ -89,6 +93,7 @@ const char *Field::c_str() const { return as(); } + // template <> // std::vector Field::as>() const // { diff --git a/orm_lib/src/Result.cc b/orm_lib/src/Result.cc index 93f1f2ea5f..fe45ebb314 100644 --- a/orm_lib/src/Result.cc +++ b/orm_lib/src/Result.cc @@ -180,6 +180,7 @@ Result &Result::operator=(const Result &r) noexcept resultPtr_ = r.resultPtr_; return *this; } + Result &Result::operator=(Result &&r) noexcept { resultPtr_ = std::move(r.resultPtr_); diff --git a/orm_lib/src/ResultImpl.h b/orm_lib/src/ResultImpl.h index 42508e91c3..fb8e1d0379 100644 --- a/orm_lib/src/ResultImpl.h +++ b/orm_lib/src/ResultImpl.h @@ -16,6 +16,7 @@ #include #include + namespace drogon { namespace orm @@ -40,11 +41,13 @@ class ResultImpl : public trantor::NonCopyable { return 0; } + virtual int oid(RowSizeType column) const { (void)column; return 0; } + virtual ~ResultImpl() { } diff --git a/orm_lib/src/Row.cc b/orm_lib/src/Row.cc index 2f9a59a365..a6fd1fb907 100644 --- a/orm_lib/src/Row.cc +++ b/orm_lib/src/Row.cc @@ -19,6 +19,7 @@ #include using namespace drogon::orm; + Row::Row(const Result &r, SizeType index) noexcept : result_(r), index_(long(index)), end_(r.columns()) { diff --git a/orm_lib/src/SqlBinder.cc b/orm_lib/src/SqlBinder.cc index 393ee315ef..b93a2bd716 100644 --- a/orm_lib/src/SqlBinder.cc +++ b/orm_lib/src/SqlBinder.cc @@ -124,6 +124,7 @@ void SqlBinder::exec() } } } + SqlBinder::~SqlBinder() { destructed_ = true; @@ -132,7 +133,8 @@ SqlBinder::~SqlBinder() exec(); } } -SqlBinder &SqlBinder::operator<<(const drogon::string_view &str) + +SqlBinder &SqlBinder::operator<<(const std::string_view &str) { auto obj = std::make_shared(str.data(), str.length()); parameters_.push_back(obj->data()); @@ -153,6 +155,7 @@ SqlBinder &SqlBinder::operator<<(const drogon::string_view &str) } return *this; } + SqlBinder &SqlBinder::operator<<(const std::string &str) { auto obj = std::make_shared(str); diff --git a/orm_lib/src/TransactionImpl.cc b/orm_lib/src/TransactionImpl.cc index 1d12dce84d..0f55142400 100644 --- a/orm_lib/src/TransactionImpl.cc +++ b/orm_lib/src/TransactionImpl.cc @@ -14,7 +14,7 @@ #include "TransactionImpl.h" #include "../../lib/src/TaskTimeoutFlag.h" -#include +#include #include using namespace drogon::orm; @@ -84,8 +84,9 @@ TransactionImpl::~TransactionImpl() } } } + void TransactionImpl::execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -293,7 +294,7 @@ void TransactionImpl::doBegin() } void TransactionImpl::execSqlInLoopWithTimeout( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, diff --git a/orm_lib/src/TransactionImpl.h b/orm_lib/src/TransactionImpl.h index 6f1d13768b..0be310f5c0 100644 --- a/orm_lib/src/TransactionImpl.h +++ b/orm_lib/src/TransactionImpl.h @@ -33,15 +33,18 @@ class TransactionImpl : public Transaction, std::function usedUpCallback); ~TransactionImpl() override; void rollback() override; + void setCommitCallback( const std::function &commitCallback) override { commitCallback_ = commitCallback; } + bool hasAvailableConnections() const noexcept override { return connectionPtr_->status() == ConnectStatus::Ok; } + void setTimeout(double timeout) override { timeout_ = timeout; @@ -49,6 +52,7 @@ class TransactionImpl : public Transaction, private: DbConnectionPtr connectionPtr_; + void execSql(const char *sql, size_t sqlLength, size_t paraNum, @@ -61,7 +65,7 @@ class TransactionImpl : public Transaction, { if (loop_->isInLoopThread()) { - execSqlInLoop(string_view{sql, sqlLength}, + execSqlInLoop(std::string_view{sql, sqlLength}, paraNum, std::move(parameters), std::move(length), @@ -73,7 +77,7 @@ class TransactionImpl : public Transaction, { loop_->queueInLoop( [thisPtr = shared_from_this(), - sql = string_view{sql, sqlLength}, + sql = std::string_view{sql, sqlLength}, paraNum, parameters = std::move(parameters), length = std::move(length), @@ -92,7 +96,7 @@ class TransactionImpl : public Transaction, } void execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -100,13 +104,14 @@ class TransactionImpl : public Transaction, ResultCallback &&rcb, std::function &&exceptCallback); void execSqlInLoopWithTimeout( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, std::vector &&format, ResultCallback &&rcb, std::function &&exceptCallback); + std::shared_ptr newTransaction( const std::function &) noexcept(false) override { @@ -119,13 +124,15 @@ class TransactionImpl : public Transaction, { callback(shared_from_this()); } + std::function usedUpCallback_; bool isCommitedOrRolledback_{false}; bool isWorking_{false}; void execNewTask(); + struct SqlCmd { - string_view sql_; + std::string_view sql_; size_t parametersNumber_; std::vector parameters_; std::vector lengths_; @@ -135,6 +142,7 @@ class TransactionImpl : public Transaction, bool isRollbackCmd_{false}; std::shared_ptr thisPtr_; }; + using SqlCmdPtr = std::shared_ptr; std::list sqlCmdBuffer_; // std::mutex _bufferMutex; diff --git a/orm_lib/src/mysql_impl/MysqlConnection.cc b/orm_lib/src/mysql_impl/MysqlConnection.cc index 1d25f44a5b..c71f54110c 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.cc +++ b/orm_lib/src/mysql_impl/MysqlConnection.cc @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #ifndef _WIN32 #include @@ -31,6 +31,7 @@ using namespace drogon; using namespace drogon::orm; + namespace drogon { namespace orm @@ -167,6 +168,7 @@ void MysqlConnection::handleClosed() auto thisPtr = shared_from_this(); closeCallback_(thisPtr); } + void MysqlConnection::disconnect() { auto thisPtr = shared_from_this(); @@ -181,6 +183,7 @@ void MysqlConnection::disconnect() }); f.get(); } + void MysqlConnection::handleTimeout() { int status = 0; @@ -226,6 +229,7 @@ void MysqlConnection::handleTimeout() { } } + void MysqlConnection::handleCmd(int status) { switch (execStatus_) @@ -298,6 +302,7 @@ void MysqlConnection::handleCmd(int status) return; } } + void MysqlConnection::handleEvent() { int status = 0; @@ -350,6 +355,7 @@ void MysqlConnection::handleEvent() continueSetCharacterSet(status); } } + void MysqlConnection::continueSetCharacterSet(int status) { int err; @@ -373,6 +379,7 @@ void MysqlConnection::continueSetCharacterSet(int status) } setChannel(); } + void MysqlConnection::startSetCharacterSet() { int err; @@ -402,8 +409,9 @@ void MysqlConnection::startSetCharacterSet() } setChannel(); } + void MysqlConnection::execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -526,6 +534,7 @@ void MysqlConnection::outputError() handleClosed(); } } + void MysqlConnection::startQuery() { int err; @@ -549,6 +558,7 @@ void MysqlConnection::startQuery() startStoreResult(true); } } + void MysqlConnection::startStoreResult(bool queueInLoop) { MYSQL_RES *ret; @@ -583,6 +593,7 @@ void MysqlConnection::startStoreResult(bool queueInLoop) } } } + void MysqlConnection::getResult(MYSQL_RES *res) { auto resultPtr = std::shared_ptr(res, [](MYSQL_RES *r) { diff --git a/orm_lib/src/mysql_impl/MysqlConnection.h b/orm_lib/src/mysql_impl/MysqlConnection.h index a3dd4bb0e0..7f678513e4 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.h +++ b/orm_lib/src/mysql_impl/MysqlConnection.h @@ -31,15 +31,18 @@ namespace orm { class MysqlConnection; using MysqlConnectionPtr = std::shared_ptr; + class MysqlConnection : public DbConnection, public std::enable_shared_from_this { public: MysqlConnection(trantor::EventLoop *loop, const std::string &connInfo); + ~MysqlConnection() { } - void execSql(string_view &&sql, + + void execSql(std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -80,11 +83,13 @@ class MysqlConnection : public DbConnection, }); } } + void batchSql(std::deque> &&) override { LOG_FATAL << "The mysql library does not support batch mode"; exit(1); } + void disconnect() override; private: @@ -95,11 +100,13 @@ class MysqlConnection : public DbConnection, { mysql_library_init(0, nullptr, nullptr); } + ~MysqlEnv() { mysql_library_end(); } }; + class MysqlThreadEnv { public: @@ -107,13 +114,15 @@ class MysqlConnection : public DbConnection, { mysql_thread_init(); } + ~MysqlThreadEnv() { mysql_thread_end(); } }; + void execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, diff --git a/orm_lib/src/mysql_impl/MysqlResultImpl.h b/orm_lib/src/mysql_impl/MysqlResultImpl.h index 49ff98a924..64013f0271 100644 --- a/orm_lib/src/mysql_impl/MysqlResultImpl.h +++ b/orm_lib/src/mysql_impl/MysqlResultImpl.h @@ -70,6 +70,7 @@ class MysqlResultImpl : public ResultImpl } } } + SizeType size() const noexcept override; RowSizeType columns() const noexcept override; const char *columnName(RowSizeType number) const override; diff --git a/orm_lib/src/postgresql_impl/PgBatchConnection.cc b/orm_lib/src/postgresql_impl/PgBatchConnection.cc index 8a884a684b..e29f9677df 100644 --- a/orm_lib/src/postgresql_impl/PgBatchConnection.cc +++ b/orm_lib/src/postgresql_impl/PgBatchConnection.cc @@ -29,12 +29,13 @@ namespace drogon namespace orm { static const unsigned int maxBatchCount = 256; + Result makeResult(std::shared_ptr &&r = nullptr) { return Result(std::make_shared(std::move(r))); } -bool checkSql(const string_view &sql_) +bool checkSql(const std::string_view &sql_) { if (sql_.length() > 1024) return true; @@ -75,6 +76,7 @@ int PgConnection::flush() } return ret; } + PgConnection::PgConnection(trantor::EventLoop *loop, const std::string &connInfo, bool autoBatch) @@ -214,7 +216,7 @@ void PgConnection::pgPoll() } void PgConnection::execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -238,6 +240,7 @@ void PgConnection::execSqlInLoop( [thisPtr = shared_from_this()]() { thisPtr->sendBatchedSql(); }); } } + int PgConnection::sendBatchEnd() { if (!PQpipelineSync(connectionPtr_.get())) @@ -249,6 +252,7 @@ int PgConnection::sendBatchEnd() } return 1; } + void PgConnection::sendBatchedSql() { if (isWorking_) @@ -467,8 +471,8 @@ void PgConnection::handleRead() { auto r = preparedStatements_.insert( std::string{cmd->sql_.data(), cmd->sql_.length()}); - preparedStatementsMap_[string_view{r.first->c_str(), - r.first->length()}] = { + preparedStatementsMap_[std::string_view{r.first->c_str(), + r.first->length()}] = { std::move(cmd->preparingStatement_), cmd->isChanging_}; cmd->preparingStatement_.clear(); continue; @@ -485,8 +489,8 @@ void PgConnection::handleRead() { auto r = preparedStatements_.insert( std::string{cmd->sql_.data(), cmd->sql_.length()}); - preparedStatementsMap_[string_view{r.first->c_str(), - r.first->length()}] = { + preparedStatementsMap_[std::string_view{r.first->c_str(), + r.first->length()}] = { std::move(cmd->preparingStatement_), cmd->isChanging_}; cmd->preparingStatement_.clear(); continue; diff --git a/orm_lib/src/postgresql_impl/PgConnection.cc b/orm_lib/src/postgresql_impl/PgConnection.cc index cbd4094c56..40c0b252a1 100644 --- a/orm_lib/src/postgresql_impl/PgConnection.cc +++ b/orm_lib/src/postgresql_impl/PgConnection.cc @@ -16,7 +16,7 @@ #include "PostgreSQLResultImpl.h" #include #include -#include +#include #include #include #include @@ -35,6 +35,7 @@ Result makeResult(std::shared_ptr &&r = nullptr) } // namespace orm } // namespace drogon + int PgConnection::flush() { auto ret = PQflush(connectionPtr_.get()); @@ -54,6 +55,7 @@ int PgConnection::flush() } return ret; } + PgConnection::PgConnection(trantor::EventLoop *loop, const std::string &connInfo, bool) @@ -188,7 +190,7 @@ void PgConnection::pgPoll() } void PgConnection::execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -362,7 +364,8 @@ void PgConnection::doAfterPreparing() { isPreparingStatement_ = false; auto r = preparedStatements_.insert(std::string{sql_}); - preparedStatementsMap_[string_view{r.first->data(), r.first->length()}] = + preparedStatementsMap_[std::string_view{r.first->data(), + r.first->length()}] = statementName_; if (PQsendQueryPrepared(connectionPtr_.get(), statementName_.c_str(), diff --git a/orm_lib/src/postgresql_impl/PgConnection.h b/orm_lib/src/postgresql_impl/PgConnection.h index df50fe4fd3..3c70e6a526 100644 --- a/orm_lib/src/postgresql_impl/PgConnection.h +++ b/orm_lib/src/postgresql_impl/PgConnection.h @@ -34,6 +34,7 @@ namespace orm { class PgConnection; using PgConnectionPtr = std::shared_ptr; + class PgConnection : public DbConnection, public std::enable_shared_from_this { @@ -44,7 +45,7 @@ class PgConnection : public DbConnection, const std::string &connInfo, bool autoBatch); - void execSql(string_view &&sql, + void execSql(std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -94,6 +95,7 @@ class PgConnection : public DbConnection, { return connectionPtr_; } + void setMessageCallback(MessageCallback cb) { messageCallback_ = std::move(cb); @@ -104,17 +106,19 @@ class PgConnection : public DbConnection, trantor::Channel channel_; bool isPreparingStatement_{false}; size_t preparedStatementsID_{0}; + std::string newStmtName() { loop_->assertInLoopThread(); return std::to_string(++preparedStatementsID_); } + void handleRead(); void pgPoll(); void handleClosed(); void execSqlInLoop( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -130,7 +134,7 @@ class PgConnection : public DbConnection, int flush(); void handleFatalError(); std::set preparedStatements_; - string_view sql_; + std::string_view sql_; #if LIBPQ_SUPPORTS_BATCH_MODE void handleFatalError(bool clearAll, bool isAbortPipeline = false); std::list> batchCommandsForWaitingResults_; @@ -140,10 +144,10 @@ class PgConnection : public DbConnection, bool sendBatchEnd_{false}; bool autoBatch_{false}; unsigned int batchCount_{0}; - std::unordered_map> + std::unordered_map> preparedStatementsMap_; #else - std::unordered_map preparedStatementsMap_; + std::unordered_map preparedStatementsMap_; #endif MessageCallback messageCallback_; diff --git a/orm_lib/src/postgresql_impl/PgListener.cc b/orm_lib/src/postgresql_impl/PgListener.cc index bc2c4da9e2..77327443b9 100644 --- a/orm_lib/src/postgresql_impl/PgListener.cc +++ b/orm_lib/src/postgresql_impl/PgListener.cc @@ -162,7 +162,7 @@ void PgListener::listenInLoop(const std::string& channel, return; } - // Because DbConnection::execSql() takes string_view as parameter, + // Because DbConnection::execSql() takes std::string_view as parameter, // sql must be hold until query finish. auto sql = std::make_shared( (listen ? "LISTEN " : "UNLISTEN ") + escapedChannel); diff --git a/orm_lib/src/postgresql_impl/PgListener.h b/orm_lib/src/postgresql_impl/PgListener.h index 80d152a4f5..ba5a15f022 100644 --- a/orm_lib/src/postgresql_impl/PgListener.h +++ b/orm_lib/src/postgresql_impl/PgListener.h @@ -33,6 +33,7 @@ class PgListener : public DbListener, PgListener(std::string connInfo, trantor::EventLoop* loop); ~PgListener() override; void init() noexcept; + trantor::EventLoop* loop() const { return loop_; diff --git a/orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h b/orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h index 436dc00eab..69836eee8a 100644 --- a/orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h +++ b/orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h @@ -31,6 +31,7 @@ class PostgreSQLResultImpl : public ResultImpl : result_(std::move(r)) { } + SizeType size() const noexcept override; RowSizeType columns() const noexcept override; const char *columnName(RowSizeType number) const override; diff --git a/orm_lib/src/postgresql_impl/test/test2.cc b/orm_lib/src/postgresql_impl/test/test2.cc index f41f7e9ea2..5a6f19d280 100644 --- a/orm_lib/src/postgresql_impl/test/test2.cc +++ b/orm_lib/src/postgresql_impl/test/test2.cc @@ -9,6 +9,7 @@ using namespace std::chrono_literals; using namespace drogon::orm; + class User { public: @@ -17,13 +18,16 @@ class User const static std::string tableName; using PrimaryKeyType = int; + explicit User(const Row &r) : userId_(r["user_id"].as()), userName_(r["user_name"].as()) { } + std::string userId_; std::string userName_; + static const std::string &sqlForFindingByPrimaryKey() { const static std::string sql = @@ -31,6 +35,7 @@ class User return sql; } }; + const std::string User::primaryKeyName = "user_uuid"; const bool User::hasPrimaryKey = true; const std::string User::tableName = "users"; diff --git a/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc b/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc index a20e4b3916..8ad70c7474 100644 --- a/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc +++ b/orm_lib/src/sqlite3_impl/Sqlite3Connection.cc @@ -15,7 +15,7 @@ #include "Sqlite3Connection.h" #include "Sqlite3ResultImpl.h" #include -#include +#include #include #include #include @@ -27,7 +27,7 @@ using namespace drogon::orm; std::once_flag Sqlite3Connection::once_; void Sqlite3Connection::onError( - const string_view &sql, + const std::string_view &sql, const std::function &exceptCallback) { auto exceptPtr = std::make_exception_ptr( @@ -91,7 +91,7 @@ void Sqlite3Connection::init() } void Sqlite3Connection::execSql( - string_view &&sql, + std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -115,7 +115,7 @@ void Sqlite3Connection::execSql( } void Sqlite3Connection::execSqlInQueue( - const string_view &sql, + const std::string_view &sql, size_t paraNum, const std::vector ¶meters, const std::vector &length, @@ -259,7 +259,8 @@ void Sqlite3Connection::execSqlInQueue( if (paraNum > 0 && newStmt) { auto r = stmts_.insert(std::string{sql}); - stmtsMap_[string_view{r.first->data(), r.first->length()}] = stmtPtr; + stmtsMap_[std::string_view{r.first->data(), r.first->length()}] = + stmtPtr; } rcb(Result(std::move(resultPtr))); idleCb_(); @@ -309,6 +310,7 @@ int Sqlite3Connection::stmtStep( } return r; } + void Sqlite3Connection::disconnect() { std::promise pro; diff --git a/orm_lib/src/sqlite3_impl/Sqlite3Connection.h b/orm_lib/src/sqlite3_impl/Sqlite3Connection.h index 2548ad0223..b9c284303d 100644 --- a/orm_lib/src/sqlite3_impl/Sqlite3Connection.h +++ b/orm_lib/src/sqlite3_impl/Sqlite3Connection.h @@ -35,6 +35,7 @@ namespace orm { class Sqlite3Connection; using Sqlite3ConnectionPtr = std::shared_ptr; + class Sqlite3Connection : public DbConnection, public std::enable_shared_from_this { @@ -43,7 +44,7 @@ class Sqlite3Connection : public DbConnection, const std::string &connInfo, const std::shared_ptr &sharedMutex); - void execSql(string_view &&sql, + void execSql(std::string_view &&sql, size_t paraNum, std::vector &¶meters, std::vector &&length, @@ -51,18 +52,20 @@ class Sqlite3Connection : public DbConnection, ResultCallback &&rcb, std::function &&exceptCallback) override; + void batchSql(std::deque> &&) override { LOG_FATAL << "The mysql library does not support batch mode"; exit(1); } + void disconnect() override; void init(); private: static std::once_flag once_; void execSqlInQueue( - const string_view &sql, + const std::string_view &sql, size_t paraNum, const std::vector ¶meters, const std::vector &length, @@ -70,7 +73,7 @@ class Sqlite3Connection : public DbConnection, const ResultCallback &rcb, const std::function &exceptCallback); void onError( - const string_view &sql, + const std::string_view &sql, const std::function &exceptCallback); int stmtStep(sqlite3_stmt *stmt, const std::shared_ptr &resultPtr, @@ -78,7 +81,8 @@ class Sqlite3Connection : public DbConnection, trantor::EventLoopThread loopThread_; std::shared_ptr connectionPtr_; std::shared_ptr sharedMutexPtr_; - std::unordered_map> stmtsMap_; + std::unordered_map> + stmtsMap_; std::set stmts_; std::string connInfo_; }; diff --git a/orm_lib/src/sqlite3_impl/test/Groups.cc b/orm_lib/src/sqlite3_impl/test/Groups.cc index 6ffbf372ca..0421247453 100644 --- a/orm_lib/src/sqlite3_impl/test/Groups.cc +++ b/orm_lib/src/sqlite3_impl/test/Groups.cc @@ -39,11 +39,13 @@ const std::vector Groups::metaData_ = { {"text", "std::string", "varchar(255)", 0, 0, 0, 0}, {"avatar", "std::vector", "blob", 0, 0, 0, 0}, {"is_default", "bool", "bool", 1, 0, 0, 0}}; + const std::string &Groups::getColumnName(size_t index) noexcept(false) { assert(index < metaData_.size()); return metaData_[index].colName_; } + Groups::Groups(const Row &r, const ssize_t indexOffset) noexcept { if (indexOffset < 0) @@ -623,10 +625,12 @@ const uint64_t &Groups::getValueOfGroupId() const noexcept return *groupId_; return defaultValue; } + const std::shared_ptr &Groups::getGroupId() const noexcept { return groupId_; } + const typename Groups::PrimaryKeyType &Groups::getPrimaryKey() const { assert(groupId_); @@ -640,15 +644,18 @@ const std::string &Groups::getValueOfGroupName() const noexcept return *groupName_; return defaultValue; } + const std::shared_ptr &Groups::getGroupName() const noexcept { return groupName_; } + void Groups::setGroupName(const std::string &pGroupName) noexcept { groupName_ = std::make_shared(pGroupName); dirtyFlag_[1] = true; } + void Groups::setGroupName(std::string &&pGroupName) noexcept { groupName_ = std::make_shared(std::move(pGroupName)); @@ -668,10 +675,12 @@ const uint64_t &Groups::getValueOfCreaterId() const noexcept return *createrId_; return defaultValue; } + const std::shared_ptr &Groups::getCreaterId() const noexcept { return createrId_; } + void Groups::setCreaterId(const uint64_t &pCreaterId) noexcept { createrId_ = std::make_shared(pCreaterId); @@ -691,15 +700,18 @@ const std::string &Groups::getValueOfCreateTime() const noexcept return *createTime_; return defaultValue; } + const std::shared_ptr &Groups::getCreateTime() const noexcept { return createTime_; } + void Groups::setCreateTime(const std::string &pCreateTime) noexcept { createTime_ = std::make_shared(pCreateTime); dirtyFlag_[3] = true; } + void Groups::setCreateTime(std::string &&pCreateTime) noexcept { createTime_ = std::make_shared(std::move(pCreateTime)); @@ -719,10 +731,12 @@ const uint64_t &Groups::getValueOfInviting() const noexcept return *inviting_; return defaultValue; } + const std::shared_ptr &Groups::getInviting() const noexcept { return inviting_; } + void Groups::setInviting(const uint64_t &pInviting) noexcept { inviting_ = std::make_shared(pInviting); @@ -742,10 +756,12 @@ const uint64_t &Groups::getValueOfInvitingUserId() const noexcept return *invitingUserId_; return defaultValue; } + const std::shared_ptr &Groups::getInvitingUserId() const noexcept { return invitingUserId_; } + void Groups::setInvitingUserId(const uint64_t &pInvitingUserId) noexcept { invitingUserId_ = std::make_shared(pInvitingUserId); @@ -765,15 +781,18 @@ const std::string &Groups::getValueOfAvatarId() const noexcept return *avatarId_; return defaultValue; } + const std::shared_ptr &Groups::getAvatarId() const noexcept { return avatarId_; } + void Groups::setAvatarId(const std::string &pAvatarId) noexcept { avatarId_ = std::make_shared(pAvatarId); dirtyFlag_[6] = true; } + void Groups::setAvatarId(std::string &&pAvatarId) noexcept { avatarId_ = std::make_shared(std::move(pAvatarId)); @@ -793,10 +812,12 @@ const double &Groups::getValueOfUuu() const noexcept return *uuu_; return defaultValue; } + const std::shared_ptr &Groups::getUuu() const noexcept { return uuu_; } + void Groups::setUuu(const double &pUuu) noexcept { uuu_ = std::make_shared(pUuu); @@ -816,15 +837,18 @@ const std::string &Groups::getValueOfText() const noexcept return *text_; return defaultValue; } + const std::shared_ptr &Groups::getText() const noexcept { return text_; } + void Groups::setText(const std::string &pText) noexcept { text_ = std::make_shared(pText); dirtyFlag_[8] = true; } + void Groups::setText(std::string &&pText) noexcept { text_ = std::make_shared(std::move(pText)); @@ -844,6 +868,7 @@ const std::vector &Groups::getValueOfAvatar() const noexcept return *avatar_; return defaultValue; } + std::string Groups::getValueOfAvatarAsString() const noexcept { const static std::string defaultValue = std::string(); @@ -851,10 +876,12 @@ std::string Groups::getValueOfAvatarAsString() const noexcept return std::string(avatar_->data(), avatar_->size()); return defaultValue; } + const std::shared_ptr> &Groups::getAvatar() const noexcept { return avatar_; } + void Groups::setAvatar(const std::vector &pAvatar) noexcept { avatar_ = std::make_shared>(pAvatar); @@ -882,10 +909,12 @@ const bool &Groups::getValueOfIsDefault() const noexcept return *isDefault_; return defaultValue; } + const std::shared_ptr &Groups::getIsDefault() const noexcept { return isDefault_; } + void Groups::setIsDefault(const bool &pIsDefault) noexcept { isDefault_ = std::make_shared(pIsDefault); @@ -1158,6 +1187,7 @@ void Groups::updateArgs(drogon::orm::internal::SqlBinder &binder) const } } } + Json::Value Groups::toJson() const { Json::Value ret; @@ -1541,6 +1571,7 @@ bool Groups::validateJsonForCreation(const Json::Value &pJson, std::string &err) } return true; } + bool Groups::validateMasqueradedJsonForCreation( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1685,6 +1716,7 @@ bool Groups::validateMasqueradedJsonForCreation( } return true; } + bool Groups::validateJsonForUpdate(const Json::Value &pJson, std::string &err) { if (pJson.isMember("group_id")) @@ -1754,6 +1786,7 @@ bool Groups::validateJsonForUpdate(const Json::Value &pJson, std::string &err) } return true; } + bool Groups::validateMasqueradedJsonForUpdate( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1883,6 +1916,7 @@ bool Groups::validateMasqueradedJsonForUpdate( } return true; } + bool Groups::validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, diff --git a/orm_lib/src/sqlite3_impl/test/Groups.h b/orm_lib/src/sqlite3_impl/test/Groups.h index 90f99a22e0..d9e7f0e02e 100644 --- a/orm_lib/src/sqlite3_impl/test/Groups.h +++ b/orm_lib/src/sqlite3_impl/test/Groups.h @@ -22,6 +22,7 @@ #include using namespace drogon::orm; + namespace drogon { namespace orm @@ -30,6 +31,7 @@ class DbClient; using DbClientPtr = std::shared_ptr; } // namespace orm } // namespace drogon + namespace drogon_model { namespace sqlite3 @@ -236,6 +238,7 @@ class Groups { return 11; } + static const std::string &getColumnName(size_t index) noexcept(false); Json::Value toJson() const; @@ -261,6 +264,7 @@ class Groups std::shared_ptr text_; std::shared_ptr> avatar_; std::shared_ptr isDefault_; + struct MetaData { const std::string colName_; @@ -271,6 +275,7 @@ class Groups const bool isPrimaryKey_; const bool notNull_; }; + static const std::vector metaData_; bool dirtyFlag_[11] = {false}; @@ -288,6 +293,7 @@ class Groups "delete from " + tableName + " where group_id = ?"; return sql; } + std::string sqlForInserting(bool &needSelection) const { std::string sql = "insert into " + tableName + " ("; diff --git a/orm_lib/tests/CMakeLists.txt b/orm_lib/tests/CMakeLists.txt index 28ae110d66..0611406153 100644 --- a/orm_lib/tests/CMakeLists.txt +++ b/orm_lib/tests/CMakeLists.txt @@ -1,22 +1,26 @@ link_libraries(${PROJECT_NAME}) -if(WIN32) - link_libraries(iphlpapi) -endif(WIN32) +if (WIN32) + link_libraries(iphlpapi) +endif (WIN32) add_executable(db_test - db_test.cc - postgresql/Users.cc - mysql/Users.cc - sqlite3/Users.cc -) + db_test.cc + postgresql/Users.cc + mysql/Users.cc + sqlite3/Users.cc + ) + +if (WIN32) + target_compile_options(db_test PRIVATE /bigobj) +endif (WIN32) add_executable(pipeline_test pipeline_test.cpp -) + ) add_executable(db_listener_test db_listener_test.cc -) + ) set_property(TARGET db_test PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD}) set_property(TARGET db_test PROPERTY CXX_STANDARD_REQUIRED ON) diff --git a/orm_lib/tests/db_listener_test.cc b/orm_lib/tests/db_listener_test.cc index ce3e67f8f2..c15c49cdc1 100644 --- a/orm_lib/tests/db_listener_test.cc +++ b/orm_lib/tests/db_listener_test.cc @@ -27,6 +27,7 @@ using namespace std::chrono_literals; #if USE_POSTGRESQL orm::DbClientPtr postgreClient; + DROGON_TEST(ListenNotifyTest) { auto clientPtr = postgreClient; diff --git a/orm_lib/tests/db_test.cc b/orm_lib/tests/db_test.cc index 448473737f..e5c4c52e0a 100644 --- a/orm_lib/tests/db_test.cc +++ b/orm_lib/tests/db_test.cc @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -42,6 +42,7 @@ void expFunction(const DrogonDbException &e) } #if USE_POSTGRESQL DbClientPtr postgreClient; + DROGON_TEST(PostgreTest) { auto &clientPtr = postgreClient; @@ -245,7 +246,7 @@ DROGON_TEST(PostgreTest) e.base().what()); }, 1); - /// 2.3 query, parameter binding (string_view) + /// 2.3 query, parameter binding (std::string_view) clientPtr->execSqlAsync( "select * from users where user_id = $1 and user_name = $2", [TEST_CTX](const Result &r) { MANDATE(r.size() == 1); }, @@ -253,7 +254,7 @@ DROGON_TEST(PostgreTest) FAULT("postgresql - DbClient asynchronous interface(4) what():", e.base().what()); }, - drogon::string_view("pg1"), + std::string_view("pg1"), "postgresql1"); /// 2.4 delete clientPtr->execSqlAsync( @@ -985,6 +986,7 @@ DROGON_TEST(PostgreTest) #if USE_MYSQL DbClientPtr mysqlClient; + DROGON_TEST(MySQLTest) { auto &clientPtr = mysqlClient; @@ -1754,6 +1756,7 @@ DROGON_TEST(MySQLTest) #if USE_SQLITE3 DbClientPtr sqlite3Client; + DROGON_TEST(SQLite3Test) { auto &clientPtr = sqlite3Client; @@ -2036,20 +2039,20 @@ DROGON_TEST(SQLite3Test) FAULT("sqlite3 - DbClient asynchronous interface(0) what():", e.base().what()); } - /// 3.2 insert,(string_view) + /// 3.2 insert,(std::string_view) try { - drogon::string_view sv("pg1"); - drogon::string_view sv1("postgresql1"); - drogon::string_view sv2("123"); + std::string_view sv("pg1"); + std::string_view sv1("postgresql1"); + std::string_view sv2("123"); auto r = clientPtr->execSqlSync( "insert into users " "(user_id,user_name,password,org_name,create_time) " "values(?,?,?,?,?)", sv, - (const drogon::string_view &)sv1, + (const std::string_view &)sv1, std::move(sv2), - drogon::string_view("default"), + std::string_view("default"), trantor::Date::now()); MANDATE(r.affectedRows() == 1UL); } @@ -2592,6 +2595,7 @@ DROGON_TEST(SQLite3Test) #endif using namespace drogon; + int main(int argc, char **argv) { trantor::Logger::setLogLevel(trantor::Logger::LogLevel::kDebug); diff --git a/orm_lib/tests/mysql/Users.cc b/orm_lib/tests/mysql/Users.cc index bfe01ce93a..a7283d5fba 100644 --- a/orm_lib/tests/mysql/Users.cc +++ b/orm_lib/tests/mysql/Users.cc @@ -35,11 +35,13 @@ const std::vector Users::metaData_ = { {"avatar_id", "std::string", "varchar(32)", 32, 0, 0, 0}, {"salt", "std::string", "varchar(20)", 20, 0, 0, 0}, {"admin", "int8_t", "tinyint(1)", 1, 0, 0, 0}}; + const std::string &Users::getColumnName(size_t index) noexcept(false) { assert(index < metaData_.size()); return metaData_[index].colName_; } + Users::Users(const Row &r, const ssize_t indexOffset) noexcept { if (indexOffset < 0) @@ -520,10 +522,12 @@ const int32_t &Users::getValueOfId() const noexcept return *id_; return defaultValue; } + const std::shared_ptr &Users::getId() const noexcept { return id_; } + void Users::setId(const int32_t &pId) noexcept { id_ = std::make_shared(pId); @@ -543,15 +547,18 @@ const std::string &Users::getValueOfUserId() const noexcept return *userId_; return defaultValue; } + const std::shared_ptr &Users::getUserId() const noexcept { return userId_; } + void Users::setUserId(const std::string &pUserId) noexcept { userId_ = std::make_shared(pUserId); dirtyFlag_[1] = true; } + void Users::setUserId(std::string &&pUserId) noexcept { userId_ = std::make_shared(std::move(pUserId)); @@ -571,15 +578,18 @@ const std::string &Users::getValueOfUserName() const noexcept return *userName_; return defaultValue; } + const std::shared_ptr &Users::getUserName() const noexcept { return userName_; } + void Users::setUserName(const std::string &pUserName) noexcept { userName_ = std::make_shared(pUserName); dirtyFlag_[2] = true; } + void Users::setUserName(std::string &&pUserName) noexcept { userName_ = std::make_shared(std::move(pUserName)); @@ -599,15 +609,18 @@ const std::string &Users::getValueOfPassword() const noexcept return *password_; return defaultValue; } + const std::shared_ptr &Users::getPassword() const noexcept { return password_; } + void Users::setPassword(const std::string &pPassword) noexcept { password_ = std::make_shared(pPassword); dirtyFlag_[3] = true; } + void Users::setPassword(std::string &&pPassword) noexcept { password_ = std::make_shared(std::move(pPassword)); @@ -627,15 +640,18 @@ const std::string &Users::getValueOfOrgName() const noexcept return *orgName_; return defaultValue; } + const std::shared_ptr &Users::getOrgName() const noexcept { return orgName_; } + void Users::setOrgName(const std::string &pOrgName) noexcept { orgName_ = std::make_shared(pOrgName); dirtyFlag_[4] = true; } + void Users::setOrgName(std::string &&pOrgName) noexcept { orgName_ = std::make_shared(std::move(pOrgName)); @@ -655,15 +671,18 @@ const std::string &Users::getValueOfSignature() const noexcept return *signature_; return defaultValue; } + const std::shared_ptr &Users::getSignature() const noexcept { return signature_; } + void Users::setSignature(const std::string &pSignature) noexcept { signature_ = std::make_shared(pSignature); dirtyFlag_[5] = true; } + void Users::setSignature(std::string &&pSignature) noexcept { signature_ = std::make_shared(std::move(pSignature)); @@ -683,15 +702,18 @@ const std::string &Users::getValueOfAvatarId() const noexcept return *avatarId_; return defaultValue; } + const std::shared_ptr &Users::getAvatarId() const noexcept { return avatarId_; } + void Users::setAvatarId(const std::string &pAvatarId) noexcept { avatarId_ = std::make_shared(pAvatarId); dirtyFlag_[6] = true; } + void Users::setAvatarId(std::string &&pAvatarId) noexcept { avatarId_ = std::make_shared(std::move(pAvatarId)); @@ -711,15 +733,18 @@ const std::string &Users::getValueOfSalt() const noexcept return *salt_; return defaultValue; } + const std::shared_ptr &Users::getSalt() const noexcept { return salt_; } + void Users::setSalt(const std::string &pSalt) noexcept { salt_ = std::make_shared(pSalt); dirtyFlag_[7] = true; } + void Users::setSalt(std::string &&pSalt) noexcept { salt_ = std::make_shared(std::move(pSalt)); @@ -739,10 +764,12 @@ const int8_t &Users::getValueOfAdmin() const noexcept return *admin_; return defaultValue; } + const std::shared_ptr &Users::getAdmin() const noexcept { return admin_; } + void Users::setAdmin(const int8_t &pAdmin) noexcept { admin_ = std::make_shared(pAdmin); @@ -994,6 +1021,7 @@ void Users::updateArgs(drogon::orm::internal::SqlBinder &binder) const } } } + Json::Value Users::toJson() const { Json::Value ret; @@ -1304,6 +1332,7 @@ bool Users::validateJsonForCreation(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForCreation( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1424,6 +1453,7 @@ bool Users::validateMasqueradedJsonForCreation( } return true; } + bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) { if (pJson.isMember("id")) @@ -1480,6 +1510,7 @@ bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForUpdate( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1589,6 +1620,7 @@ bool Users::validateMasqueradedJsonForUpdate( } return true; } + bool Users::validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, diff --git a/orm_lib/tests/mysql/Users.h b/orm_lib/tests/mysql/Users.h index 28160a43df..9c56fa8d9b 100644 --- a/orm_lib/tests/mysql/Users.h +++ b/orm_lib/tests/mysql/Users.h @@ -26,6 +26,7 @@ #include using namespace drogon::orm; + namespace drogon { namespace orm @@ -34,6 +35,7 @@ class DbClient; using DbClientPtr = std::shared_ptr; } // namespace orm } // namespace drogon + namespace drogon_model { namespace drogonTestMysql @@ -227,6 +229,7 @@ class Users { return 9; } + static const std::string &getColumnName(size_t index) noexcept(false); Json::Value toJson() const; @@ -257,6 +260,7 @@ class Users std::shared_ptr avatarId_; std::shared_ptr salt_; std::shared_ptr admin_; + struct MetaData { const std::string colName_; @@ -267,6 +271,7 @@ class Users const bool isPrimaryKey_; const bool notNull_; }; + static const std::vector metaData_; bool dirtyFlag_[9] = {false}; @@ -284,6 +289,7 @@ class Users "delete from " + tableName + " where id = ?"; return sql; } + std::string sqlForInserting(bool &needSelection) const { std::string sql = "insert into " + tableName + " ("; diff --git a/orm_lib/tests/postgresql/Users.cc b/orm_lib/tests/postgresql/Users.cc index 877a83e430..77b3684343 100644 --- a/orm_lib/tests/postgresql/Users.cc +++ b/orm_lib/tests/postgresql/Users.cc @@ -35,11 +35,13 @@ const std::vector Users::metaData_ = { {"id", "int32_t", "integer", 4, 1, 1, 1}, {"salt", "std::string", "character varying", 20, 0, 0, 0}, {"admin", "bool", "boolean", 1, 0, 0, 0}}; + const std::string &Users::getColumnName(size_t index) noexcept(false) { assert(index < metaData_.size()); return metaData_[index].colName_; } + Users::Users(const Row &r, const ssize_t indexOffset) noexcept { if (indexOffset < 0) @@ -520,15 +522,18 @@ const std::string &Users::getValueOfUserId() const noexcept return *userId_; return defaultValue; } + const std::shared_ptr &Users::getUserId() const noexcept { return userId_; } + void Users::setUserId(const std::string &pUserId) noexcept { userId_ = std::make_shared(pUserId); dirtyFlag_[0] = true; } + void Users::setUserId(std::string &&pUserId) noexcept { userId_ = std::make_shared(std::move(pUserId)); @@ -548,15 +553,18 @@ const std::string &Users::getValueOfUserName() const noexcept return *userName_; return defaultValue; } + const std::shared_ptr &Users::getUserName() const noexcept { return userName_; } + void Users::setUserName(const std::string &pUserName) noexcept { userName_ = std::make_shared(pUserName); dirtyFlag_[1] = true; } + void Users::setUserName(std::string &&pUserName) noexcept { userName_ = std::make_shared(std::move(pUserName)); @@ -576,15 +584,18 @@ const std::string &Users::getValueOfPassword() const noexcept return *password_; return defaultValue; } + const std::shared_ptr &Users::getPassword() const noexcept { return password_; } + void Users::setPassword(const std::string &pPassword) noexcept { password_ = std::make_shared(pPassword); dirtyFlag_[2] = true; } + void Users::setPassword(std::string &&pPassword) noexcept { password_ = std::make_shared(std::move(pPassword)); @@ -604,15 +615,18 @@ const std::string &Users::getValueOfOrgName() const noexcept return *orgName_; return defaultValue; } + const std::shared_ptr &Users::getOrgName() const noexcept { return orgName_; } + void Users::setOrgName(const std::string &pOrgName) noexcept { orgName_ = std::make_shared(pOrgName); dirtyFlag_[3] = true; } + void Users::setOrgName(std::string &&pOrgName) noexcept { orgName_ = std::make_shared(std::move(pOrgName)); @@ -632,15 +646,18 @@ const std::string &Users::getValueOfSignature() const noexcept return *signature_; return defaultValue; } + const std::shared_ptr &Users::getSignature() const noexcept { return signature_; } + void Users::setSignature(const std::string &pSignature) noexcept { signature_ = std::make_shared(pSignature); dirtyFlag_[4] = true; } + void Users::setSignature(std::string &&pSignature) noexcept { signature_ = std::make_shared(std::move(pSignature)); @@ -660,15 +677,18 @@ const std::string &Users::getValueOfAvatarId() const noexcept return *avatarId_; return defaultValue; } + const std::shared_ptr &Users::getAvatarId() const noexcept { return avatarId_; } + void Users::setAvatarId(const std::string &pAvatarId) noexcept { avatarId_ = std::make_shared(pAvatarId); dirtyFlag_[5] = true; } + void Users::setAvatarId(std::string &&pAvatarId) noexcept { avatarId_ = std::make_shared(std::move(pAvatarId)); @@ -688,10 +708,12 @@ const int32_t &Users::getValueOfId() const noexcept return *id_; return defaultValue; } + const std::shared_ptr &Users::getId() const noexcept { return id_; } + void Users::setId(const int32_t &pId) noexcept { id_ = std::make_shared(pId); @@ -711,15 +733,18 @@ const std::string &Users::getValueOfSalt() const noexcept return *salt_; return defaultValue; } + const std::shared_ptr &Users::getSalt() const noexcept { return salt_; } + void Users::setSalt(const std::string &pSalt) noexcept { salt_ = std::make_shared(pSalt); dirtyFlag_[7] = true; } + void Users::setSalt(std::string &&pSalt) noexcept { salt_ = std::make_shared(std::move(pSalt)); @@ -739,10 +764,12 @@ const bool &Users::getValueOfAdmin() const noexcept return *admin_; return defaultValue; } + const std::shared_ptr &Users::getAdmin() const noexcept { return admin_; } + void Users::setAdmin(const bool &pAdmin) noexcept { admin_ = std::make_shared(pAdmin); @@ -993,6 +1020,7 @@ void Users::updateArgs(drogon::orm::internal::SqlBinder &binder) const } } } + Json::Value Users::toJson() const { Json::Value ret; @@ -1303,6 +1331,7 @@ bool Users::validateJsonForCreation(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForCreation( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1423,6 +1452,7 @@ bool Users::validateMasqueradedJsonForCreation( } return true; } + bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) { if (pJson.isMember("user_id")) @@ -1479,6 +1509,7 @@ bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForUpdate( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1588,6 +1619,7 @@ bool Users::validateMasqueradedJsonForUpdate( } return true; } + bool Users::validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, diff --git a/orm_lib/tests/postgresql/Users.h b/orm_lib/tests/postgresql/Users.h index 2739228948..d3c3ce4fc3 100644 --- a/orm_lib/tests/postgresql/Users.h +++ b/orm_lib/tests/postgresql/Users.h @@ -26,6 +26,7 @@ #include using namespace drogon::orm; + namespace drogon { namespace orm @@ -34,6 +35,7 @@ class DbClient; using DbClientPtr = std::shared_ptr; } // namespace orm } // namespace drogon + namespace drogon_model { namespace postgres @@ -227,6 +229,7 @@ class Users { return 9; } + static const std::string &getColumnName(size_t index) noexcept(false); Json::Value toJson() const; @@ -257,6 +260,7 @@ class Users std::shared_ptr id_; std::shared_ptr salt_; std::shared_ptr admin_; + struct MetaData { const std::string colName_; @@ -267,6 +271,7 @@ class Users const bool isPrimaryKey_; const bool notNull_; }; + static const std::vector metaData_; bool dirtyFlag_[9] = {false}; @@ -284,6 +289,7 @@ class Users "delete from " + tableName + " where id = $1"; return sql; } + std::string sqlForInserting(bool &needSelection) const { std::string sql = "insert into " + tableName + " ("; diff --git a/orm_lib/tests/sqlite3/Users.cc b/orm_lib/tests/sqlite3/Users.cc index 872185afeb..00d078eaf2 100644 --- a/orm_lib/tests/sqlite3/Users.cc +++ b/orm_lib/tests/sqlite3/Users.cc @@ -38,11 +38,13 @@ const std::vector Users::metaData_ = { {"salt", "std::string", "character varchar(20)", 0, 0, 0, 0}, {"admin", "std::string", "boolean", 0, 0, 0, 0}, {"create_time", "::trantor::Date", "datetime", 0, 0, 0, 0}}; + const std::string &Users::getColumnName(size_t index) noexcept(false) { assert(index < metaData_.size()); return metaData_[index].colName_; } + Users::Users(const Row &r, const ssize_t indexOffset) noexcept { if (indexOffset < 0) @@ -681,20 +683,24 @@ const uint64_t &Users::getValueOfId() const noexcept return *id_; return defaultValue; } + const std::shared_ptr &Users::getId() const noexcept { return id_; } + void Users::setId(const uint64_t &pId) noexcept { id_ = std::make_shared(pId); dirtyFlag_[0] = true; } + void Users::setIdToNull() noexcept { id_.reset(); dirtyFlag_[0] = true; } + const typename Users::PrimaryKeyType &Users::getPrimaryKey() const { assert(id_); @@ -708,20 +714,24 @@ const std::string &Users::getValueOfUserId() const noexcept return *userId_; return defaultValue; } + const std::shared_ptr &Users::getUserId() const noexcept { return userId_; } + void Users::setUserId(const std::string &pUserId) noexcept { userId_ = std::make_shared(pUserId); dirtyFlag_[1] = true; } + void Users::setUserId(std::string &&pUserId) noexcept { userId_ = std::make_shared(std::move(pUserId)); dirtyFlag_[1] = true; } + void Users::setUserIdToNull() noexcept { userId_.reset(); @@ -735,20 +745,24 @@ const std::string &Users::getValueOfUserName() const noexcept return *userName_; return defaultValue; } + const std::shared_ptr &Users::getUserName() const noexcept { return userName_; } + void Users::setUserName(const std::string &pUserName) noexcept { userName_ = std::make_shared(pUserName); dirtyFlag_[2] = true; } + void Users::setUserName(std::string &&pUserName) noexcept { userName_ = std::make_shared(std::move(pUserName)); dirtyFlag_[2] = true; } + void Users::setUserNameToNull() noexcept { userName_.reset(); @@ -762,20 +776,24 @@ const std::string &Users::getValueOfPassword() const noexcept return *password_; return defaultValue; } + const std::shared_ptr &Users::getPassword() const noexcept { return password_; } + void Users::setPassword(const std::string &pPassword) noexcept { password_ = std::make_shared(pPassword); dirtyFlag_[3] = true; } + void Users::setPassword(std::string &&pPassword) noexcept { password_ = std::make_shared(std::move(pPassword)); dirtyFlag_[3] = true; } + void Users::setPasswordToNull() noexcept { password_.reset(); @@ -789,20 +807,24 @@ const std::string &Users::getValueOfOrgName() const noexcept return *orgName_; return defaultValue; } + const std::shared_ptr &Users::getOrgName() const noexcept { return orgName_; } + void Users::setOrgName(const std::string &pOrgName) noexcept { orgName_ = std::make_shared(pOrgName); dirtyFlag_[4] = true; } + void Users::setOrgName(std::string &&pOrgName) noexcept { orgName_ = std::make_shared(std::move(pOrgName)); dirtyFlag_[4] = true; } + void Users::setOrgNameToNull() noexcept { orgName_.reset(); @@ -816,20 +838,24 @@ const std::string &Users::getValueOfSignature() const noexcept return *signature_; return defaultValue; } + const std::shared_ptr &Users::getSignature() const noexcept { return signature_; } + void Users::setSignature(const std::string &pSignature) noexcept { signature_ = std::make_shared(pSignature); dirtyFlag_[5] = true; } + void Users::setSignature(std::string &&pSignature) noexcept { signature_ = std::make_shared(std::move(pSignature)); dirtyFlag_[5] = true; } + void Users::setSignatureToNull() noexcept { signature_.reset(); @@ -843,20 +869,24 @@ const std::string &Users::getValueOfAvatarId() const noexcept return *avatarId_; return defaultValue; } + const std::shared_ptr &Users::getAvatarId() const noexcept { return avatarId_; } + void Users::setAvatarId(const std::string &pAvatarId) noexcept { avatarId_ = std::make_shared(pAvatarId); dirtyFlag_[6] = true; } + void Users::setAvatarId(std::string &&pAvatarId) noexcept { avatarId_ = std::make_shared(std::move(pAvatarId)); dirtyFlag_[6] = true; } + void Users::setAvatarIdToNull() noexcept { avatarId_.reset(); @@ -870,20 +900,24 @@ const std::string &Users::getValueOfSalt() const noexcept return *salt_; return defaultValue; } + const std::shared_ptr &Users::getSalt() const noexcept { return salt_; } + void Users::setSalt(const std::string &pSalt) noexcept { salt_ = std::make_shared(pSalt); dirtyFlag_[7] = true; } + void Users::setSalt(std::string &&pSalt) noexcept { salt_ = std::make_shared(std::move(pSalt)); dirtyFlag_[7] = true; } + void Users::setSaltToNull() noexcept { salt_.reset(); @@ -897,20 +931,24 @@ const std::string &Users::getValueOfAdmin() const noexcept return *admin_; return defaultValue; } + const std::shared_ptr &Users::getAdmin() const noexcept { return admin_; } + void Users::setAdmin(const std::string &pAdmin) noexcept { admin_ = std::make_shared(pAdmin); dirtyFlag_[8] = true; } + void Users::setAdmin(std::string &&pAdmin) noexcept { admin_ = std::make_shared(std::move(pAdmin)); dirtyFlag_[8] = true; } + void Users::setAdminToNull() noexcept { admin_.reset(); @@ -924,15 +962,18 @@ const ::trantor::Date &Users::getValueOfCreateTime() const noexcept return *createTime_; return defaultValue; } + const std::shared_ptr<::trantor::Date> &Users::getCreateTime() const noexcept { return createTime_; } + void Users::setCreateTime(const ::trantor::Date &pCreateTime) noexcept { createTime_ = std::make_shared<::trantor::Date>(pCreateTime); dirtyFlag_[9] = true; } + void Users::setCreateTimeToNull() noexcept { createTime_.reset(); @@ -1205,6 +1246,7 @@ void Users::updateArgs(drogon::orm::internal::SqlBinder &binder) const } } } + Json::Value Users::toJson() const { Json::Value ret; @@ -1549,6 +1591,7 @@ bool Users::validateJsonForCreation(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForCreation( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1689,6 +1732,7 @@ bool Users::validateMasqueradedJsonForCreation( } return true; } + bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) { if (pJson.isMember("id")) @@ -1751,6 +1795,7 @@ bool Users::validateJsonForUpdate(const Json::Value &pJson, std::string &err) } return true; } + bool Users::validateMasqueradedJsonForUpdate( const Json::Value &pJson, const std::vector &pMasqueradingVector, @@ -1878,6 +1923,7 @@ bool Users::validateMasqueradedJsonForUpdate( } return true; } + bool Users::validJsonOfField(size_t index, const std::string &fieldName, const Json::Value &pJson, diff --git a/orm_lib/tests/sqlite3/Users.h b/orm_lib/tests/sqlite3/Users.h index d1570c213a..51372eaae2 100644 --- a/orm_lib/tests/sqlite3/Users.h +++ b/orm_lib/tests/sqlite3/Users.h @@ -33,6 +33,7 @@ class DbClient; using DbClientPtr = std::shared_ptr; } // namespace orm } // namespace drogon + namespace drogon_model { namespace sqlite3 @@ -232,6 +233,7 @@ class Users { return 10; } + static const std::string &getColumnName(size_t index) noexcept(false); Json::Value toJson() const; @@ -263,6 +265,7 @@ class Users std::shared_ptr salt_; std::shared_ptr admin_; std::shared_ptr<::trantor::Date> createTime_; + struct MetaData { const std::string colName_; @@ -273,6 +276,7 @@ class Users const bool isPrimaryKey_; const bool notNull_; }; + static const std::vector metaData_; bool dirtyFlag_[10] = {false}; @@ -290,6 +294,7 @@ class Users "delete from " + tableName + " where id = ?"; return sql; } + std::string sqlForInserting(bool &needSelection) const { std::string sql = "insert into " + tableName + " (";