drogonCMS-cmake into main branch that replaces make plus other things #1
2539
vendors/drogon/.Doxyfile
vendored
Normal file
2539
vendors/drogon/.Doxyfile
vendored
Normal file
File diff suppressed because it is too large
Load Diff
153
vendors/drogon/.clang-format
vendored
Normal file
153
vendors/drogon/.clang-format
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
AfterCaseLabel: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 2000
|
||||
PointerAlignment: Right
|
||||
ReferenceAlignment: Right
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SeparateDefinitionBlocks: Always
|
||||
SortIncludes: Never
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
50
vendors/drogon/.gitignore
vendored
Executable file
50
vendors/drogon/.gitignore
vendored
Executable file
@ -0,0 +1,50 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
build/
|
||||
cmake-build-debug/
|
||||
cmake-build-debug-visual-studio/
|
||||
.idea/
|
||||
lib/inc/drogon/version.h
|
||||
html/
|
||||
latex/
|
||||
.vscode
|
||||
*.kdev4
|
||||
.cproject
|
||||
.project
|
||||
.settings/
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
install
|
||||
trace.json
|
||||
.cache/
|
4
vendors/drogon/.gitmodules
vendored
Executable file
4
vendors/drogon/.gitmodules
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
[submodule "trantor"]
|
||||
path = trantor
|
||||
url = https://github.com/an-tao/trantor.git
|
||||
branch = master
|
845
vendors/drogon/CMakeLists.txt
vendored
Normal file
845
vendors/drogon/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,845 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(drogon)
|
||||
|
||||
message(STATUS "compiler: " ${CMAKE_CXX_COMPILER_ID})
|
||||
|
||||
option(BUILD_CTL "Build drogon_ctl" ON)
|
||||
option(BUILD_EXAMPLES "Build examples" ON)
|
||||
option(BUILD_ORM "Build orm" ON)
|
||||
option(COZ_PROFILING "Use coz for profiling" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build drogon as a shared lib" OFF)
|
||||
option(BUILD_DOC "Build Doxygen documentation" OFF)
|
||||
option(BUILD_BROTLI "Build Brotli" ON)
|
||||
option(BUILD_YAML_CONFIG "Build yaml config" ON)
|
||||
option(USE_SUBMODULE "Use trantor as a submodule" ON)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_POSTGRESQL "Build with postgresql support" ON "BUILD_ORM" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(LIBPQ_BATCH_MODE "Use batch mode for libpq" ON "BUILD_POSTGRESQL" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_MYSQL "Build with mysql support" ON "BUILD_ORM" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_SQLITE "Build with sqlite3 support" ON "BUILD_ORM" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_REDIS "Build with redis support" ON "BUILD_ORM" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(USE_SPDLOG "Allow using the spdlog logging library" OFF "USE_SUBMODULE" OFF)
|
||||
|
||||
set(DROGON_MAJOR_VERSION 1)
|
||||
set(DROGON_MINOR_VERSION 9)
|
||||
set(DROGON_PATCH_VERSION 1)
|
||||
set(DROGON_VERSION
|
||||
${DROGON_MAJOR_VERSION}.${DROGON_MINOR_VERSION}.${DROGON_PATCH_VERSION})
|
||||
set(DROGON_VERSION_STRING "${DROGON_VERSION}")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
# Offer the user the choice of overriding the installation directories
|
||||
set(INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries")
|
||||
set(INSTALL_BIN_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for executables")
|
||||
set(INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for header files")
|
||||
set(DEF_INSTALL_DROGON_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/Drogon)
|
||||
set(INSTALL_DROGON_CMAKE_DIR ${DEF_INSTALL_DROGON_CMAKE_DIR}
|
||||
CACHE PATH "Installation directory for cmake files")
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# Force MSVC to use UTF-8 because that's what we use. Otherwise it uses
|
||||
# the default of whatever Windows sets and causes encoding issues.
|
||||
message(STATUS "You are using MSVC. Forceing to use UTF-8")
|
||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
if (MSVC_VERSION GREATER_EQUAL 1914)
|
||||
# Tells Visual Studio 2017 (15.7+) and newer to correctly set the value of the standard __cplusplus macro,
|
||||
# instead of leaving it to 199711L and settings the effective c++ version in _MSVC_LANG
|
||||
# Dropping support for older versions of VS would allow to only rely on __cplusplus
|
||||
add_compile_options("/Zc:__cplusplus")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
add_library(${PROJECT_NAME})
|
||||
if (BUILD_SHARED_LIBS)
|
||||
find_package(Threads)
|
||||
# set(BUILD_EXAMPLES FALSE)
|
||||
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
|
||||
"${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" isSystemDir)
|
||||
if ("${isSystemDir}" STREQUAL "-1")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
|
||||
endif ("${isSystemDir}" STREQUAL "-1")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${DROGON_VERSION}
|
||||
SOVERSION ${DROGON_MAJOR_VERSION})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads)
|
||||
if (WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Rpcrt4 ws2_32 crypt32 Advapi32)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
|
||||
# We export class to facilitate maintenance, thus if you compile
|
||||
# drogon on windows as a shared library, you will need to use
|
||||
# exact same compiler for drogon and your app.
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC /wd4251 /wd4275)
|
||||
endif ()
|
||||
endif ()
|
||||
endif (BUILD_SHARED_LIBS)
|
||||
|
||||
if(USE_SPDLOG)
|
||||
find_package(spdlog CONFIG)
|
||||
if(spdlog_FOUND)
|
||||
message(STATUS "spdlog found!")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog_header_only)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC DROGON_SPDLOG_SUPPORT SPDLOG_FMT_EXTERNAL FMT_HEADER_ONLY)
|
||||
endif(spdlog_FOUND)
|
||||
endif(USE_SPDLOG)
|
||||
|
||||
if (NOT ${CMAKE_PLATFORM_NAME} STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror)
|
||||
endif ()
|
||||
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(${PROJECT_NAME} EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
|
||||
|
||||
include(cmake/DrogonUtilities.cmake)
|
||||
include(cmake/ParseAndAddDrogonTests.cmake)
|
||||
include(CheckIncludeFileCXX)
|
||||
|
||||
check_include_file_cxx(any HAS_ANY)
|
||||
check_include_file_cxx(string_view HAS_STRING_VIEW)
|
||||
check_include_file_cxx(coroutine HAS_COROUTINE)
|
||||
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)
|
||||
else ()
|
||||
set(DROGON_CXX_STANDARD 17)
|
||||
endif ()
|
||||
if(USE_SUBMODULE)
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/trantor>)
|
||||
endif()
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/inc>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/orm_lib/inc>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/nosql_lib/redis/inc>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/exports>
|
||||
$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>)
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/third_party/mman-win32>)
|
||||
endif (WIN32)
|
||||
|
||||
if(USE_SUBMODULE)
|
||||
add_subdirectory(trantor)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC trantor)
|
||||
else()
|
||||
find_package(Trantor CONFIG REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Trantor::Trantor)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE network)
|
||||
elseif (NOT WIN32 AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dl)
|
||||
elseif (WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi)
|
||||
endif ()
|
||||
|
||||
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()
|
||||
|
||||
if (DROGON_CXX_STANDARD EQUAL 17)
|
||||
message(STATUS "use c++17")
|
||||
# Check for partial implementation of c++17 (Windows/OSX only?)
|
||||
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 ()
|
||||
|
||||
|
||||
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)
|
||||
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${JSONCPP_INCLUDE_DIRS})
|
||||
|
||||
# yamlcpp
|
||||
if(BUILD_YAML_CONFIG)
|
||||
find_package(yaml-cpp QUIET)
|
||||
if(yaml-cpp_FOUND)
|
||||
if (NOT YAML_CPP_LIBRARIES)
|
||||
find_library(YAML_CPP_LINK_LIBRARY "yaml-cpp")
|
||||
if(NOT YAML_CPP_LINK_LIBRARY)
|
||||
message(STATUS "yaml-cpp not used")
|
||||
else()
|
||||
message(STATUS "yaml-cpp found ")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${YAML_CPP_LINK_LIBRARY})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_YAML_CPP)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "yaml-cpp found ")
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${YAML_CPP_LIBRARIES})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_YAML_CPP)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "yaml-cpp not used")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "yaml-cpp not used")
|
||||
endif(BUILD_YAML_CONFIG)
|
||||
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
|
||||
AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD"
|
||||
AND NOT WIN32)
|
||||
find_package(UUID REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE UUID_lib)
|
||||
|
||||
try_compile(normal_uuid ${CMAKE_BINARY_DIR}/cmaketest
|
||||
${PROJECT_SOURCE_DIR}/cmake/tests/normal_uuid_lib_test.cc
|
||||
LINK_LIBRARIES UUID_lib
|
||||
OUTPUT_VARIABLE NORMAL_UUID_COMPILE_OUTPUT)
|
||||
try_compile(ossp_uuid ${CMAKE_BINARY_DIR}/cmaketest
|
||||
${PROJECT_SOURCE_DIR}/cmake/tests/ossp_uuid_lib_test.cc
|
||||
LINK_LIBRARIES UUID_lib
|
||||
OUTPUT_VARIABLE OSSP_UUID_COMPILE_OUTPUT)
|
||||
if (normal_uuid)
|
||||
add_definitions(-DUSE_OSSP_UUID=0)
|
||||
elseif (ossp_uuid)
|
||||
add_definitions(-DUSE_OSSP_UUID=1)
|
||||
else ()
|
||||
message(FATAL_ERROR "uuid lib error:\n${NORMAL_UUID_COMPILE_OUTPUT}\n${OSSP_UUID_COMPILE_OUTPUT}")
|
||||
endif ()
|
||||
endif (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
|
||||
AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD"
|
||||
AND NOT WIN32)
|
||||
|
||||
if (BUILD_BROTLI)
|
||||
find_package(Brotli)
|
||||
if (Brotli_FOUND)
|
||||
message(STATUS "Brotli found")
|
||||
add_definitions(-DUSE_BROTLI)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Brotli_lib)
|
||||
endif (Brotli_FOUND)
|
||||
endif (BUILD_BROTLI)
|
||||
|
||||
set(DROGON_SOURCES
|
||||
lib/src/AOPAdvice.cc
|
||||
lib/src/AccessLogger.cc
|
||||
lib/src/CacheFile.cc
|
||||
lib/src/ConfigAdapterManager.cc
|
||||
lib/src/ConfigLoader.cc
|
||||
lib/src/Cookie.cc
|
||||
lib/src/DrClassMap.cc
|
||||
lib/src/DrTemplateBase.cc
|
||||
lib/src/FiltersFunction.cc
|
||||
lib/src/FixedWindowRateLimiter.cc
|
||||
lib/src/GlobalFilters.cc
|
||||
lib/src/Histogram.cc
|
||||
lib/src/Hodor.cc
|
||||
lib/src/HttpAppFrameworkImpl.cc
|
||||
lib/src/HttpBinder.cc
|
||||
lib/src/HttpClientImpl.cc
|
||||
lib/src/HttpConnectionLimit.cc
|
||||
lib/src/HttpControllerBinder.cc
|
||||
lib/src/HttpControllersRouter.cc
|
||||
lib/src/HttpFileImpl.cc
|
||||
lib/src/HttpFileUploadRequest.cc
|
||||
lib/src/HttpRequestImpl.cc
|
||||
lib/src/HttpRequestParser.cc
|
||||
lib/src/HttpResponseImpl.cc
|
||||
lib/src/HttpResponseParser.cc
|
||||
lib/src/HttpServer.cc
|
||||
lib/src/HttpUtils.cc
|
||||
lib/src/HttpViewData.cc
|
||||
lib/src/IntranetIpFilter.cc
|
||||
lib/src/JsonConfigAdapter.cc
|
||||
lib/src/ListenerManager.cc
|
||||
lib/src/LocalHostFilter.cc
|
||||
lib/src/MultiPart.cc
|
||||
lib/src/NotFound.cc
|
||||
lib/src/PluginsManager.cc
|
||||
lib/src/PromExporter.cc
|
||||
lib/src/RangeParser.cc
|
||||
lib/src/RateLimiter.cc
|
||||
lib/src/RealIpResolver.cc
|
||||
lib/src/SecureSSLRedirector.cc
|
||||
lib/src/Redirector.cc
|
||||
lib/src/SessionManager.cc
|
||||
lib/src/SlashRemover.cc
|
||||
lib/src/SlidingWindowRateLimiter.cc
|
||||
lib/src/StaticFileRouter.cc
|
||||
lib/src/TaskTimeoutFlag.cc
|
||||
lib/src/TokenBucketRateLimiter.cc
|
||||
lib/src/Utilities.cc
|
||||
lib/src/WebSocketClientImpl.cc
|
||||
lib/src/WebSocketConnectionImpl.cc
|
||||
lib/src/YamlConfigAdapter.cc
|
||||
lib/src/drogon_test.cc)
|
||||
set(private_headers
|
||||
lib/src/AOPAdvice.h
|
||||
lib/src/CacheFile.h
|
||||
lib/src/ConfigLoader.h
|
||||
lib/src/ControllerBinderBase.h
|
||||
lib/src/FiltersFunction.h
|
||||
lib/src/HttpAppFrameworkImpl.h
|
||||
lib/src/HttpClientImpl.h
|
||||
lib/src/HttpConnectionLimit.h
|
||||
lib/src/HttpControllerBinder.h
|
||||
lib/src/HttpControllersRouter.h
|
||||
lib/src/HttpFileImpl.h
|
||||
lib/src/HttpFileUploadRequest.h
|
||||
lib/src/HttpMessageBody.h
|
||||
lib/src/HttpRequestImpl.h
|
||||
lib/src/HttpRequestParser.h
|
||||
lib/src/HttpResponseImpl.h
|
||||
lib/src/HttpResponseParser.h
|
||||
lib/src/HttpServer.h
|
||||
lib/src/HttpUtils.h
|
||||
lib/src/impl_forwards.h
|
||||
lib/src/ListenerManager.h
|
||||
lib/src/PluginsManager.h
|
||||
lib/src/SessionManager.h
|
||||
lib/src/SpinLock.h
|
||||
lib/src/StaticFileRouter.h
|
||||
lib/src/TaskTimeoutFlag.h
|
||||
lib/src/WebSocketClientImpl.h
|
||||
lib/src/WebSocketConnectionImpl.h
|
||||
lib/src/FixedWindowRateLimiter.h
|
||||
lib/src/SlidingWindowRateLimiter.h
|
||||
lib/src/TokenBucketRateLimiter.h
|
||||
lib/src/ConfigAdapterManager.h
|
||||
lib/src/JsonConfigAdapter.h
|
||||
lib/src/YamlConfigAdapter.h
|
||||
lib/src/ConfigAdapter.h)
|
||||
|
||||
if (NOT WIN32)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
lib/src/SharedLibManager.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
lib/src/SharedLibManager.h)
|
||||
else (NOT WIN32)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
third_party/mman-win32/mman.c)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
third_party/mman-win32/mman.h)
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (BUILD_POSTGRESQL)
|
||||
# find postgres
|
||||
find_package(pg)
|
||||
if (pg_FOUND)
|
||||
message(STATUS "libpq inc path:" ${PG_INCLUDE_DIRS})
|
||||
message(STATUS "libpq lib:" ${PG_LIBRARIES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE pg_lib)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/postgresql_impl/PostgreSQLResultImpl.cc
|
||||
orm_lib/src/postgresql_impl/PgListener.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
orm_lib/src/postgresql_impl/PostgreSQLResultImpl.h
|
||||
orm_lib/src/postgresql_impl/PgListener.h)
|
||||
if (LIBPQ_BATCH_MODE)
|
||||
try_compile(libpq_supports_batch ${CMAKE_BINARY_DIR}/cmaketest
|
||||
${PROJECT_SOURCE_DIR}/cmake/tests/test_libpq_batch_mode.cc
|
||||
LINK_LIBRARIES ${PostgreSQL_LIBRARIES}
|
||||
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PostgreSQL_INCLUDE_DIR}")
|
||||
endif (LIBPQ_BATCH_MODE)
|
||||
if (libpq_supports_batch)
|
||||
message(STATUS "The libpq supports batch mode")
|
||||
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" ON)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/postgresql_impl/PgBatchConnection.cc)
|
||||
else (libpq_supports_batch)
|
||||
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" OFF)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/postgresql_impl/PgConnection.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
orm_lib/src/postgresql_impl/PgConnection.h)
|
||||
endif (libpq_supports_batch)
|
||||
endif (pg_FOUND)
|
||||
endif (BUILD_POSTGRESQL)
|
||||
|
||||
if (BUILD_MYSQL)
|
||||
# Find mysql, only mariadb client library is supported
|
||||
find_package(MySQL QUIET)
|
||||
find_package(unofficial-libmariadb QUIET)
|
||||
if (MySQL_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE MySQL_lib)
|
||||
set(DROGON_FOUND_MYSQL TRUE)
|
||||
set(MYSQL_LIB_NAME MySQL_lib)
|
||||
elseif (unofficial-libmariadb_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE unofficial::libmariadb)
|
||||
set(DROGON_FOUND_MYSQL TRUE)
|
||||
set(MYSQL_LIB_NAME unofficial::libmariadb)
|
||||
endif ()
|
||||
|
||||
if (DROGON_FOUND_MYSQL)
|
||||
message(STATUS "Ok! We find mariadb!")
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(${MYSQL_LIB_NAME} mysql_optionsv "" HAS_MYSQL_OPTIONSV)
|
||||
if (HAS_MYSQL_OPTIONSV)
|
||||
message(STATUS "Mariadb support mysql_optionsv")
|
||||
add_definitions(-DHAS_MYSQL_OPTIONSV)
|
||||
endif(HAS_MYSQL_OPTIONSV)
|
||||
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/mysql_impl/MysqlConnection.cc
|
||||
orm_lib/src/mysql_impl/MysqlResultImpl.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
orm_lib/src/mysql_impl/MysqlConnection.h
|
||||
orm_lib/src/mysql_impl/MysqlResultImpl.h)
|
||||
else (DROGON_FOUND_MYSQL)
|
||||
message(STATUS "MySql was not found.")
|
||||
endif (DROGON_FOUND_MYSQL)
|
||||
endif (BUILD_MYSQL)
|
||||
|
||||
if (BUILD_SQLITE)
|
||||
# Find sqlite3.
|
||||
find_package(SQLite3 QUIET)
|
||||
find_package(unofficial-sqlite3 QUIET)
|
||||
if (SQLite3_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite3_lib)
|
||||
set(DROGON_FOUND_SQLite3 TRUE)
|
||||
elseif (unofficial-sqlite3_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE unofficial::sqlite3::sqlite3)
|
||||
set(DROGON_FOUND_SQLite3 TRUE)
|
||||
endif ()
|
||||
|
||||
if (DROGON_FOUND_SQLite3)
|
||||
message(STATUS "Ok! We find sqlite3!")
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/sqlite3_impl/Sqlite3Connection.cc
|
||||
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
orm_lib/src/sqlite3_impl/Sqlite3Connection.h
|
||||
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.h)
|
||||
else (DROGON_FOUND_SQLite3)
|
||||
message(STATUS "sqlite3 was not found.")
|
||||
endif (DROGON_FOUND_SQLite3)
|
||||
endif (BUILD_SQLITE)
|
||||
|
||||
if (BUILD_REDIS)
|
||||
find_package(Hiredis)
|
||||
if (Hiredis_FOUND)
|
||||
add_definitions(-DUSE_REDIS)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Hiredis_lib)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
nosql_lib/redis/src/RedisClientImpl.cc
|
||||
nosql_lib/redis/src/RedisClientLockFree.cc
|
||||
nosql_lib/redis/src/RedisClientManager.cc
|
||||
nosql_lib/redis/src/RedisConnection.cc
|
||||
nosql_lib/redis/src/RedisResult.cc
|
||||
nosql_lib/redis/src/RedisTransactionImpl.cc
|
||||
nosql_lib/redis/src/SubscribeContext.cc
|
||||
nosql_lib/redis/src/RedisSubscriberImpl.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
nosql_lib/redis/src/RedisClientImpl.h
|
||||
nosql_lib/redis/src/RedisClientLockFree.h
|
||||
nosql_lib/redis/src/RedisConnection.h
|
||||
nosql_lib/redis/src/RedisTransactionImpl.h
|
||||
nosql_lib/redis/src/SubscribeContext.h
|
||||
nosql_lib/redis/src/RedisSubscriberImpl.h)
|
||||
|
||||
endif (Hiredis_FOUND)
|
||||
endif (BUILD_REDIS)
|
||||
|
||||
if (NOT Hiredis_FOUND)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
lib/src/RedisClientSkipped.cc
|
||||
lib/src/RedisResultSkipped.cc
|
||||
lib/src/RedisClientManagerSkipped.cc)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
lib/src/RedisClientManager.h)
|
||||
endif (NOT Hiredis_FOUND)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(nosql_lib/redis/tests)
|
||||
endif (BUILD_TESTING)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ZLIB::ZLIB)
|
||||
|
||||
execute_process(COMMAND "git" rev-parse HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE GIT_SHA1
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/version.h.in"
|
||||
"${PROJECT_SOURCE_DIR}/lib/inc/drogon/version.h" @ONLY)
|
||||
|
||||
if (DROGON_CXX_STANDARD EQUAL 20)
|
||||
option(USE_COROUTINE "Enable C++20 coroutine support" ON)
|
||||
else (DROGON_CXX_STANDARD EQUAL 20)
|
||||
option(USE_COROUTINE "Enable C++20 coroutine support" OFF)
|
||||
endif (DROGON_CXX_STANDARD EQUAL 20)
|
||||
|
||||
if (BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif (BUILD_EXAMPLES)
|
||||
|
||||
if (BUILD_CTL)
|
||||
add_subdirectory(drogon_ctl)
|
||||
endif (BUILD_CTL)
|
||||
|
||||
if (COZ_PROFILING)
|
||||
find_package(coz-profiler REQUIRED)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE -DCOZ_PROFILING=1)
|
||||
# If linked will not need to be ran with `coz run --- [executable]` to run the
|
||||
# profiler, but drogon_ctl currently won't build because it doesn't find debug
|
||||
# information while trying to generate it's own sources
|
||||
# target_link_libraries(${PROJECT_NAME} PUBLIC coz::coz)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${COZ_INCLUDE_DIRS})
|
||||
endif (COZ_PROFILING)
|
||||
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/ArrayParser.cc
|
||||
orm_lib/src/Criteria.cc
|
||||
orm_lib/src/DbClient.cc
|
||||
orm_lib/src/DbClientImpl.cc
|
||||
orm_lib/src/DbClientLockFree.cc
|
||||
orm_lib/src/DbConnection.cc
|
||||
orm_lib/src/DbListener.cc
|
||||
orm_lib/src/Exception.cc
|
||||
orm_lib/src/Field.cc
|
||||
orm_lib/src/Result.cc
|
||||
orm_lib/src/Row.cc
|
||||
orm_lib/src/SqlBinder.cc
|
||||
orm_lib/src/TransactionImpl.cc
|
||||
orm_lib/src/RestfulController.cc)
|
||||
set(DROGON_HEADERS
|
||||
lib/inc/drogon/Attribute.h
|
||||
lib/inc/drogon/CacheMap.h
|
||||
lib/inc/drogon/Cookie.h
|
||||
lib/inc/drogon/DrClassMap.h
|
||||
lib/inc/drogon/DrObject.h
|
||||
lib/inc/drogon/DrTemplate.h
|
||||
lib/inc/drogon/DrTemplateBase.h
|
||||
lib/inc/drogon/HttpAppFramework.h
|
||||
lib/inc/drogon/HttpBinder.h
|
||||
lib/inc/drogon/HttpClient.h
|
||||
lib/inc/drogon/HttpController.h
|
||||
lib/inc/drogon/HttpFilter.h
|
||||
lib/inc/drogon/HttpRequest.h
|
||||
lib/inc/drogon/HttpResponse.h
|
||||
lib/inc/drogon/HttpSimpleController.h
|
||||
lib/inc/drogon/HttpTypes.h
|
||||
lib/inc/drogon/HttpViewData.h
|
||||
lib/inc/drogon/IntranetIpFilter.h
|
||||
lib/inc/drogon/IOThreadStorage.h
|
||||
lib/inc/drogon/LocalHostFilter.h
|
||||
lib/inc/drogon/MultiPart.h
|
||||
lib/inc/drogon/NotFound.h
|
||||
lib/inc/drogon/Session.h
|
||||
lib/inc/drogon/UploadFile.h
|
||||
lib/inc/drogon/WebSocketClient.h
|
||||
lib/inc/drogon/WebSocketConnection.h
|
||||
lib/inc/drogon/WebSocketController.h
|
||||
lib/inc/drogon/drogon.h
|
||||
lib/inc/drogon/version.h
|
||||
lib/inc/drogon/drogon_callbacks.h
|
||||
lib/inc/drogon/PubSubService.h
|
||||
lib/inc/drogon/drogon_test.h
|
||||
lib/inc/drogon/RateLimiter.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
|
||||
set(private_headers
|
||||
${private_headers}
|
||||
lib/src/DbClientManager.h
|
||||
orm_lib/src/DbClientImpl.h
|
||||
orm_lib/src/DbConnection.h
|
||||
orm_lib/src/ResultImpl.h
|
||||
orm_lib/src/TransactionImpl.h)
|
||||
if (pg_FOUND OR DROGON_FOUND_MYSQL OR DROGON_FOUND_SQLite3)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/DbClientManager.cc)
|
||||
else (pg_FOUND OR DROGON_FOUND_MYSQL OR DROGON_FOUND_SQLite3)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
lib/src/DbClientManagerSkipped.cc)
|
||||
endif (pg_FOUND OR DROGON_FOUND_MYSQL OR DROGON_FOUND_SQLite3)
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES CXX_STANDARD ${DROGON_CXX_STANDARD})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME Drogon)
|
||||
|
||||
if (pg_FOUND OR DROGON_FOUND_MYSQL OR DROGON_FOUND_SQLite3)
|
||||
if (pg_FOUND)
|
||||
option(USE_POSTGRESQL "Enable PostgreSQL" ON)
|
||||
else (pg_FOUND)
|
||||
option(USE_POSTGRESQL "Disable PostgreSQL" OFF)
|
||||
endif (pg_FOUND)
|
||||
|
||||
if (DROGON_FOUND_MYSQL)
|
||||
option(USE_MYSQL "Enable Mysql" ON)
|
||||
else (DROGON_FOUND_MYSQL)
|
||||
option(USE_MYSQL "Disable Mysql" OFF)
|
||||
endif (DROGON_FOUND_MYSQL)
|
||||
|
||||
if (DROGON_FOUND_SQLite3)
|
||||
option(USE_SQLITE3 "Enable Sqlite3" ON)
|
||||
else (DROGON_FOUND_SQLite3)
|
||||
option(USE_SQLITE3 "Disable Sqlite3" OFF)
|
||||
endif (DROGON_FOUND_SQLite3)
|
||||
endif (pg_FOUND OR DROGON_FOUND_MYSQL OR DROGON_FOUND_SQLite3)
|
||||
|
||||
get_filename_component(COMPILER_COMMAND ${CMAKE_CXX_COMPILER} NAME)
|
||||
set(COMPILER_ID ${CMAKE_CXX_COMPILER_ID})
|
||||
|
||||
if (CMAKE_BUILD_TYPE)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
|
||||
if (_type STREQUAL release)
|
||||
set(COMPILATION_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -std=c++")
|
||||
elseif (_type STREQUAL debug)
|
||||
set(COMPILATION_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} -std=c++")
|
||||
else ()
|
||||
set(COMPILATION_FLAGS "-std=c++")
|
||||
endif ()
|
||||
else (CMAKE_BUILD_TYPE)
|
||||
set(COMPILATION_FLAGS "-std=c++")
|
||||
endif (CMAKE_BUILD_TYPE)
|
||||
|
||||
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW
|
||||
"${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
|
||||
list(REMOVE_DUPLICATES INCLUDE_DIRS_FOR_DYNAMIC_VIEW)
|
||||
set(INS_STRING "")
|
||||
foreach (loop_var ${INCLUDE_DIRS_FOR_DYNAMIC_VIEW})
|
||||
set(INS_STRING "${INS_STRING} -I${loop_var}")
|
||||
endforeach (loop_var)
|
||||
|
||||
set(INCLUDING_DIRS ${INS_STRING})
|
||||
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/templates/config.h.in
|
||||
${PROJECT_BINARY_DIR}/drogon/config.h @ONLY)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
message(STATUS "Building tests")
|
||||
enable_testing()
|
||||
add_subdirectory(lib/tests)
|
||||
if (pg_FOUND)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/postgresql_impl/test)
|
||||
endif (pg_FOUND)
|
||||
if (DROGON_FOUND_MYSQL)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/mysql_impl/test)
|
||||
endif (DROGON_FOUND_MYSQL)
|
||||
if (DROGON_FOUND_SQLite3)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/sqlite3_impl/test)
|
||||
endif (DROGON_FOUND_SQLite3)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/tests)
|
||||
endif (BUILD_TESTING)
|
||||
|
||||
# Installation
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT DrogonTargets
|
||||
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
|
||||
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib
|
||||
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib)
|
||||
|
||||
install(FILES ${DROGON_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon)
|
||||
|
||||
set(ORM_HEADERS
|
||||
orm_lib/inc/drogon/orm/ArrayParser.h
|
||||
orm_lib/inc/drogon/orm/BaseBuilder.h
|
||||
orm_lib/inc/drogon/orm/Criteria.h
|
||||
orm_lib/inc/drogon/orm/DbClient.h
|
||||
orm_lib/inc/drogon/orm/DbListener.h
|
||||
orm_lib/inc/drogon/orm/DbTypes.h
|
||||
orm_lib/inc/drogon/orm/Exception.h
|
||||
orm_lib/inc/drogon/orm/Field.h
|
||||
orm_lib/inc/drogon/orm/FunctionTraits.h
|
||||
orm_lib/inc/drogon/orm/Mapper.h
|
||||
orm_lib/inc/drogon/orm/CoroMapper.h
|
||||
orm_lib/inc/drogon/orm/Result.h
|
||||
orm_lib/inc/drogon/orm/ResultIterator.h
|
||||
orm_lib/inc/drogon/orm/Row.h
|
||||
orm_lib/inc/drogon/orm/RowIterator.h
|
||||
orm_lib/inc/drogon/orm/SqlBinder.h
|
||||
orm_lib/inc/drogon/orm/RestfulController.h)
|
||||
install(FILES ${ORM_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/orm)
|
||||
|
||||
set(NOSQL_HEADERS
|
||||
nosql_lib/redis/inc/drogon/nosql/RedisClient.h
|
||||
nosql_lib/redis/inc/drogon/nosql/RedisResult.h
|
||||
nosql_lib/redis/inc/drogon/nosql/RedisSubscriber.h
|
||||
nosql_lib/redis/inc/drogon/nosql/RedisException.h)
|
||||
install(FILES ${NOSQL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/nosql)
|
||||
|
||||
set(DROGON_UTIL_HEADERS
|
||||
lib/inc/drogon/utils/coroutine.h
|
||||
lib/inc/drogon/utils/FunctionTraits.h
|
||||
lib/inc/drogon/utils/HttpConstraint.h
|
||||
lib/inc/drogon/utils/OStringStream.h
|
||||
lib/inc/drogon/utils/Utilities.h
|
||||
lib/inc/drogon/utils/monitoring.h)
|
||||
install(FILES ${DROGON_UTIL_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
|
||||
|
||||
set(DROGON_MONITORING_HEADERS
|
||||
lib/inc/drogon/utils/monitoring/Counter.h
|
||||
lib/inc/drogon/utils/monitoring/Metric.h
|
||||
lib/inc/drogon/utils/monitoring/Registry.h
|
||||
lib/inc/drogon/utils/monitoring/Collector.h
|
||||
lib/inc/drogon/utils/monitoring/Sample.h
|
||||
lib/inc/drogon/utils/monitoring/Gauge.h
|
||||
lib/inc/drogon/utils/monitoring/Histogram.h)
|
||||
|
||||
install(FILES ${DROGON_MONITORING_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils/monitoring)
|
||||
|
||||
set(DROGON_PLUGIN_HEADERS
|
||||
lib/inc/drogon/plugins/Plugin.h
|
||||
lib/inc/drogon/plugins/Redirector.h
|
||||
lib/inc/drogon/plugins/SecureSSLRedirector.h
|
||||
lib/inc/drogon/plugins/AccessLogger.h
|
||||
lib/inc/drogon/plugins/RealIpResolver.h
|
||||
lib/inc/drogon/plugins/Hodor.h
|
||||
lib/inc/drogon/plugins/SlashRemover.h
|
||||
lib/inc/drogon/plugins/GlobalFilters.h
|
||||
lib/inc/drogon/plugins/PromExporter.h)
|
||||
|
||||
install(FILES ${DROGON_PLUGIN_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
${DROGON_SOURCES}
|
||||
${private_headers}
|
||||
${DROGON_HEADERS}
|
||||
${ORM_HEADERS}
|
||||
${DROGON_UTIL_HEADERS}
|
||||
${DROGON_PLUGIN_HEADERS}
|
||||
${NOSQL_HEADERS}
|
||||
${DROGON_MONITORING_HEADERS})
|
||||
|
||||
source_group("Public API"
|
||||
FILES
|
||||
${DROGON_HEADERS}
|
||||
${ORM_HEADERS}
|
||||
${DROGON_UTIL_HEADERS}
|
||||
${DROGON_PLUGIN_HEADERS}
|
||||
${NOSQL_HEADERS}
|
||||
${DROGON_MONITORING_HEADERS})
|
||||
source_group("Private Headers"
|
||||
FILES
|
||||
${private_headers})
|
||||
|
||||
# Export the package for use from the build-tree (this registers the build-tree
|
||||
# with a global cmake-registry) export(PACKAGE Drogon)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
# ... for the install tree
|
||||
configure_package_config_file(
|
||||
cmake/templates/DrogonConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DrogonConfig.cmake
|
||||
INSTALL_DESTINATION
|
||||
${INSTALL_DROGON_CMAKE_DIR})
|
||||
|
||||
# version
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/DrogonConfigVersion.cmake
|
||||
VERSION ${DROGON_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
# Install the DrogonConfig.cmake and DrogonConfigVersion.cmake
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DrogonConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/DrogonConfigVersion.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindUUID.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindJsoncpp.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindSQLite3.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindMySQL.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findpg.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindBrotli.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findcoz-profiler.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindHiredis.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindFilesystem.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/DrogonUtilities.cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/ParseAndAddDrogonTests.cmake"
|
||||
DESTINATION "${INSTALL_DROGON_CMAKE_DIR}"
|
||||
COMPONENT dev)
|
||||
|
||||
# Install the export set for use with the install-tree
|
||||
install(EXPORT DrogonTargets
|
||||
DESTINATION "${INSTALL_DROGON_CMAKE_DIR}"
|
||||
NAMESPACE Drogon::
|
||||
COMPONENT dev)
|
||||
|
||||
# Doxygen documentation
|
||||
find_package(Doxygen OPTIONAL_COMPONENTS dot dia)
|
||||
if(DOXYGEN_FOUND)
|
||||
set(DOXYGEN_PROJECT_BRIEF "C++14/17-based HTTP application framework")
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY docs/${PROJECT_NAME})
|
||||
set(DOXYGEN_GENERATE_LATEX NO)
|
||||
set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
|
||||
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md)
|
||||
set(DOXYGEN_STRIP_FROM_INC_PATH ${PROJECT_SOURCE_DIR}/lib/inc
|
||||
${PROJECT_SOURCE_DIR}/orm_lib/inc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/exports)
|
||||
set(DOXYGEN_EXAMPLE_PATTERNS *)
|
||||
if(WIN32)
|
||||
set(DOXYGEN_PREDEFINED _WIN32)
|
||||
endif(WIN32)
|
||||
doxygen_add_docs(doc_${PROJECT_NAME}
|
||||
README.md
|
||||
README.zh-CN.md
|
||||
README.zh-TW.md
|
||||
ChangeLog.md
|
||||
CONTRIBUTING.md
|
||||
${DROGON_HEADERS}
|
||||
${DROGON_UTIL_HEADERS}
|
||||
${DROGON_PLUGIN_HEADERS}
|
||||
${ORM_HEADERS}
|
||||
COMMENT "Generate documentation")
|
||||
if(NOT TARGET doc)
|
||||
add_custom_target(doc)
|
||||
endif()
|
||||
add_dependencies(doc doc_${PROJECT_NAME})
|
||||
if (BUILD_DOC)
|
||||
add_dependencies(${PROJECT_NAME} doc_${PROJECT_NAME})
|
||||
# Don't install twice, so limit to Debug (assume developer)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/${PROJECT_NAME}
|
||||
TYPE DOC
|
||||
CONFIGURATIONS Debug)
|
||||
endif(BUILD_DOC)
|
||||
endif(DOXYGEN_FOUND)
|
||||
|
||||
include(cmake/Packages.cmake)
|
78
vendors/drogon/CONTRIBUTING.md
vendored
Normal file
78
vendors/drogon/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
# Contributing
|
||||
|
||||
**Drogon** is an open source project at its heart and every contribution is
|
||||
welcome. By participating in this project you agree to stick to common sense and
|
||||
contribute in an overall positive way.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Fork, then clone the repository: `git clone
|
||||
git@github.com:your-username/drogon.git`
|
||||
1. Follow the [official installation steps on
|
||||
Github](https://drogonframework.github.io/drogon-docs/#/ENG-02-Installation). It’s best to
|
||||
make sure to have the `drogon_ctl` executable in your shell’s `PATH`
|
||||
environment variable in case you use a terminal.
|
||||
|
||||
Now you can create branches, start adding features & bugfixes to the code, and
|
||||
[create pull requests](https://github.com/an-tao/drogon/compare).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Feel free to [create a pull request](https://github.com/an-tao/drogon/compare)
|
||||
if you think you can contribute to the project. You will be listed as a
|
||||
[contributor](https://github.com/an-tao/drogon/graphs/contributors), agree to
|
||||
this document, and the
|
||||
[LICENSE](https://github.com/an-tao/drogon/blob/master/LICENSE).
|
||||
|
||||
There are also some recommendations you can follow. These aren’t requirements,
|
||||
but they will make the development more straightforward:
|
||||
|
||||
1. If you are unsure about a specific change, have questions, or want to get
|
||||
feedback about a feature you want to introduce, [open a new
|
||||
issue](https://github.com/an-tao/drogon/issues) (please make sure that there
|
||||
is no previous issue about a similar topic).
|
||||
1. You should branch off the current state of the `master` branch, and also
|
||||
merge it into your local branch before creating a pull request if there were
|
||||
other changes introduced in the meantime.
|
||||
1. You can use the following branch names to make your intent clearer:
|
||||
* `bugfix/123-fix-template-parser` when you want to fix a bug in the
|
||||
template parser.
|
||||
* `feature/123-add-l10n-and-i18n` if you want to add localization (l10n) and
|
||||
internationalization (i18n) as a new feature to the project.
|
||||
* If there’s no open issue and no need to open one you can skip the number,
|
||||
and just use the descriptive part: `bugfix/fix-typo-in-docs`.
|
||||
1. Write a brief, but good, and descriptive commit message / pull request title in English,
|
||||
e. g. “Added Internationalization and Localization”.
|
||||
|
||||
If you follow these recommendations your pull request will have more success:
|
||||
|
||||
1. Keep the style consistent to the project, when in doubt refer to the [Google
|
||||
C++ Style Guide](https://google.github.io/styleguide/cppguide.html#C++_Version).
|
||||
1. Please write all comments in English. Comments for new public API introduced by
|
||||
your pull request must be added and written in [Doxygen](http://www.doxygen.nl/) format.
|
||||
1. Format the code with `clang-format` (>= 8.0.0). The configuration is already
|
||||
provided in the `.clang-format` file, just run the `./format.sh` script
|
||||
before submitting your pull request.
|
||||
1. Install [Google Test](https://github.com/google/googletest), and write a test
|
||||
case.
|
||||
1. In case it is a bugfix, it’s best to write a test that breaks in the old
|
||||
version, but works in the new one. This way regressions can be tracked
|
||||
over time.
|
||||
1. If you add a feature, it is best to write the test as if it would be an
|
||||
example how to use the newly introduced feature and to test all major,
|
||||
newly introduced code.
|
||||
|
||||
## Project Maintainers & Collaborators
|
||||
|
||||
In addition to the guidelines mentioned above, collaborators with write access
|
||||
to the repository should also follow these guidelines:
|
||||
|
||||
1. If there are new tests as part of the pull request, you should make sure that
|
||||
they succeed.
|
||||
1. When merging **Pull Requests** you should use the option *Squash & Merge* and
|
||||
chose a descriptive commit message for the bugfix / feature (if not already
|
||||
done by the individual contributor).
|
||||
|
||||
This way the history in the `master` branch will be free of small
|
||||
corrections and easier to follow for people who aren’t engaged in the
|
||||
project on a day-to-day basis.
|
1620
vendors/drogon/ChangeLog.md
vendored
Normal file
1620
vendors/drogon/ChangeLog.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
vendors/drogon/LICENSE
vendored
Normal file
21
vendors/drogon/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2023 An Tao
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
222
vendors/drogon/README.md
vendored
Executable file
222
vendors/drogon/README.md
vendored
Executable file
@ -0,0 +1,222 @@
|
||||

|
||||
|
||||
[](https://github.com/drogonframework/drogon/actions)
|
||||
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[](https://discord.gg/3DvHY6Ewuj)
|
||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md)
|
||||
### Overview
|
||||
**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:
|
||||
|
||||
* Use a non-blocking I/O network lib based on epoll (kqueue under macOS/FreeBSD) to provide high-concurrency, high-performance network IO, please visit the [TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite) for more details;
|
||||
* Provide a completely asynchronous programming mode;
|
||||
* Support Http1.0/1.1 (server side and client side);
|
||||
* Based on template, a simple reflection mechanism is implemented to completely decouple the main program framework, controllers and views.
|
||||
* Support cookies and built-in sessions;
|
||||
* Support back-end rendering, the controller generates the data to the view to generate the Html page. Views are described by CSP template files, C++ codes are embedded into Html pages through CSP tags. And the drogon command-line tool automatically generates the C++ code files for compilation;
|
||||
* Support view page dynamic loading (dynamic compilation and loading at runtime);
|
||||
* Provide a convenient and flexible routing solution from the path to the controller handler;
|
||||
* Support filter chains to facilitate the execution of unified logic (such as login verification, Http Method constraint verification, etc.) before handling HTTP requests;
|
||||
* Support https (based on OpenSSL);
|
||||
* Support WebSocket (server side and client side);
|
||||
* Support JSON format request and response, very friendly to the Restful API application development;
|
||||
* Support file download and upload;
|
||||
* Support gzip, brotli compression transmission;
|
||||
* Support pipelining;
|
||||
* Provide a lightweight command line tool, drogon_ctl, to simplify the creation of various classes in Drogon and the generation of view code;
|
||||
* Support non-blocking I/O based asynchronously reading and writing database (PostgreSQL and MySQL(MariaDB) database);
|
||||
* Support asynchronously reading and writing sqlite3 database based on thread pool;
|
||||
* Support Redis with asynchronous reading and writing;
|
||||
* Support ARM Architecture;
|
||||
* Provide a convenient lightweight ORM implementation that supports for regular object-to-database bidirectional mapping;
|
||||
* Support plugins which can be installed by the configuration file at load time;
|
||||
* Support AOP with built-in joinpoints.
|
||||
* Support C++ coroutines
|
||||
|
||||
## A very simple example
|
||||
|
||||
Unlike most C++ frameworks, the main program of the drogon application can be kept clean and simple. Drogon uses a few tricks to decouple controllers from the main program. The routing settings of controllers can be done through macros or configuration file.
|
||||
|
||||
Below is the main program of a typical drogon application:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().setLogPath("./")
|
||||
.setLogLevel(trantor::Logger::kWarn)
|
||||
.addListener("0.0.0.0", 80)
|
||||
.setThreadNum(16)
|
||||
.enableRunAsDaemon()
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
It can be further simplified by using configuration file as follows:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().loadConfigFile("./config.json").run();
|
||||
}
|
||||
```
|
||||
|
||||
Drogon provides some interfaces for adding controller logic directly in the main() function, for example, user can register a handler like this in Drogon:
|
||||
|
||||
```c++
|
||||
app().registerHandler("/test?username={name}",
|
||||
[](const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback,
|
||||
const std::string &name)
|
||||
{
|
||||
Json::Value json;
|
||||
json["result"]="ok";
|
||||
json["message"]=std::string("hello,")+name;
|
||||
auto resp=HttpResponse::newHttpJsonResponse(json);
|
||||
callback(resp);
|
||||
},
|
||||
{Get,"LoginFilter"});
|
||||
```
|
||||
|
||||
While such interfaces look intuitive, they are not suitable for complex business logic scenarios. Assuming there are tens or even hundreds of handlers that need to be registered in the framework, isn't it a better practice to implement them separately in their respective classes? So unless your logic is very simple, we don't recommend using above interfaces. Instead, we can create an HttpSimpleController as follows:
|
||||
|
||||
```c++
|
||||
/// The TestCtrl.h file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
PATH_ADD("/test",Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The TestCtrl.cc file
|
||||
#include "TestCtrl.h"
|
||||
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
//write your application logic here
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("<p>Hello, world!</p>");
|
||||
resp->setExpiredTime(0);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
**Most of the above programs can be automatically generated by the command line tool `drogon_ctl` provided by drogon** (The command is `drogon_ctl create controller TestCtrl`). All the user needs to do is add their own business logic. In the example, the controller returns a `Hello, world!` string when the client accesses the `http://ip/test` URL.
|
||||
|
||||
For JSON format response, we create the controller as follows:
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
//list path definitions here;
|
||||
PATH_ADD("/json", Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The source file
|
||||
#include "JsonCtrl.h"
|
||||
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["message"] = "Hello, World!";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
Let's go a step further and create a demo RESTful API with the HttpController class, as shown below (Omit the source file):
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
using namespace drogon;
|
||||
namespace api
|
||||
{
|
||||
namespace v1
|
||||
{
|
||||
class User : public drogon::HttpController<User>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
|
||||
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
|
||||
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
|
||||
METHOD_LIST_END
|
||||
//your declaration of processing function maybe like this:
|
||||
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
|
||||
public:
|
||||
User()
|
||||
{
|
||||
LOG_DEBUG << "User constructor!";
|
||||
}
|
||||
};
|
||||
} // namespace v1
|
||||
} // namespace api
|
||||
```
|
||||
|
||||
As you can see, users can use the `HttpController` to map paths and parameters at the same time. This is a very convenient way to create a RESTful API application.
|
||||
|
||||
In addition, you can also find that all handler interfaces are in asynchronous mode, where the response is returned by a callback object. This design is for performance reasons because in asynchronous mode the drogon application can handle a large number of concurrent requests with a small number of threads.
|
||||
|
||||
After compiling all of the above source files, we get a very simple web application. This is a good start. **For more information, please visit the [wiki](https://github.com/an-tao/drogon/wiki/ENG-01-Overview)**
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
Drogon supports cross-compilation, you should define the `CMAKE_SYSTEM_NAME` in toolchain file, for example:
|
||||
|
||||
```cmake
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
```
|
||||
|
||||
You can disable building options for examples and drogon_ctl by settings `BUILD_EXAMPLES` and `BUILD_CTL` to `OFF` in the toolchain file.
|
||||
|
||||
## Building options
|
||||
|
||||
Drogon provides some building options, you can enable or disable them by setting the corresponding variables to `ON` or `OFF` in the cmake command line, cmake file etc...
|
||||
|
||||
| Option name | Description | Default value |
|
||||
| :--- | :--- | :--- |
|
||||
| BUILD_CTL | Build drogon_ctl | ON |
|
||||
| BUILD_EXAMPLES | Build examples | ON |
|
||||
| BUILD_ORM | Build orm | ON |
|
||||
| COZ_PROFILING | Use coz for profiling | OFF |
|
||||
| BUILD_SHARED_LIBS | Build drogon as a shared lib | OFF |
|
||||
| BUILD_DOC | Build Doxygen documentation | OFF |
|
||||
| BUILD_BROTLI | Build Brotli | ON |
|
||||
| BUILD_YAML_CONFIG | Build yaml config | ON |
|
||||
| USE_SUBMODULE | Use trantor as a submodule | ON |
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
This project exists thanks to all the people who contribute code.
|
||||
|
||||
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
|
||||
|
||||
Every contribution is welcome. Please refer to the [contribution guidelines](CONTRIBUTING.md) for more information.
|
199
vendors/drogon/README.zh-CN.md
vendored
Executable file
199
vendors/drogon/README.zh-CN.md
vendored
Executable file
@ -0,0 +1,199 @@
|
||||

|
||||
|
||||
[](https://github.com/drogonframework/drogon/actions)
|
||||
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[](https://discord.gg/3DvHY6Ewuj)
|
||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
[English](./README.md) | 简体中文 | [繁體中文](./README.zh-TW.md)
|
||||
|
||||
**Drogon**是一个基于C++17/20的Http应用框架,使用Drogon可以方便的使用C++构建各种类型的Web应用服务端程序。
|
||||
本版本库是github上[Drogon工程](https://github.com/an-tao/drogon)的镜像库。**Drogon**是作者非常喜欢的美剧《权力的游戏》中的一条龙的名字(汉译作卓耿),和龙有关但并不是dragon的误写,为了不至于引起不必要的误会这里说明一下。
|
||||
|
||||
Drogon是一个跨平台框架,它支持Linux,也支持macOS、FreeBSD,OpenBSD,HaikuOS,和Windows。它的主要特点如下:
|
||||
|
||||
* 网络层使用基于epoll(macOS/FreeBSD下是kqueue)的非阻塞IO框架,提供高并发、高性能的网络IO。详细请见[TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite);
|
||||
* 全异步编程模式;
|
||||
* 支持Http1.0/1.1(server端和client端);
|
||||
* 基于template实现了简单的反射机制,使主程序框架、控制器(controller)和视图(view)完全解耦;
|
||||
* 支持cookies和内建的session;
|
||||
* 支持后端渲染,把控制器生成的数据交给视图生成Html页面,视图由CSP模板文件描述,通过CSP标签把C++代码嵌入到Html页面,由drogon的命令行工具在编译阶段自动生成C++代码并编译;
|
||||
* 支持运行期的视图页面动态加载(动态编译和加载so文件);
|
||||
* 非常方便灵活的路径(path)到控制器处理函数(handler)的映射方案;
|
||||
* 支持过滤器(filter)链,方便在控制器之前执行统一的逻辑(如登录验证、Http Method约束验证等);
|
||||
* 支持https(基于OpenSSL实现);
|
||||
* 支持websocket(server端和client端);
|
||||
* 支持Json格式请求和应答, 对Restful API应用开发非常友好;
|
||||
* 支持文件下载和上传,支持sendfile系统调用;
|
||||
* 支持gzip/brotli压缩传输;
|
||||
* 支持pipelining;
|
||||
* 提供一个轻量的命令行工具drogon_ctl,帮助简化各种类的创建和视图代码的生成过程;
|
||||
* 基于非阻塞IO实现的异步数据库读写,目前支持PostgreSQL和MySQL(MariaDB)数据库;
|
||||
* 基于线程池实现sqlite3数据库的异步读写,提供与上文数据库相同的接口;
|
||||
* 支持Redis异步读写;
|
||||
* 支持ARM架构;
|
||||
* 方便的轻量级ORM实现,支持常规的对象到数据库的双向映射操作;
|
||||
* 支持插件,可通过配置文件在加载期动态拆装;
|
||||
* 支持内建插入点的AOP
|
||||
* 支持C++协程
|
||||
|
||||
## 一个非常简单的例子
|
||||
|
||||
不像大多数C++框架那样,drogon的主程序可以保持非常简单。 Drogon使用了一些小技巧使主程序和控制器解耦合. 控制器的路由设置可以在控制器类中定义或者配置文件中完成.
|
||||
|
||||
下面是一个典型的主程序的样子:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().setLogPath("./")
|
||||
.setLogLevel(trantor::Logger::kWarn)
|
||||
.addListener("0.0.0.0", 80)
|
||||
.setThreadNum(16)
|
||||
.enableRunAsDaemon()
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
如果使用配置文件,可以进一步简化成如下的样子:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().loadConfigFile("./config.json").run();
|
||||
}
|
||||
```
|
||||
|
||||
当然,Drogon也提供了一些接口,使用户可以在main()函数中直接添加控制器逻辑,比如,用户可以注册一个lambda处理器到drogon框架中,如下所示:
|
||||
|
||||
```c++
|
||||
app().registerHandler("/test?username={name}",
|
||||
[](const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback,
|
||||
const std::string &name)
|
||||
{
|
||||
Json::Value json;
|
||||
json["result"]="ok";
|
||||
json["message"]=std::string("hello,")+name;
|
||||
auto resp=HttpResponse::newHttpJsonResponse(json);
|
||||
callback(resp);
|
||||
},
|
||||
{Get,"LoginFilter"});
|
||||
```
|
||||
|
||||
|
||||
这看起来是很方便,但是这并不适用于复杂的应用,试想假如有数十个或者数百个处理函数要注册进框架,main()函数将膨胀到不可读的程度。显然,让每个包含处理函数的类在自己的定义中完成注册是更好的选择。所以,除非你的应用逻辑非常简单,我们不推荐使用上述接口,更好的实践是,我们可以创建一个HttpSimpleController对象,如下:
|
||||
|
||||
|
||||
```c++
|
||||
/// The TestCtrl.h file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
PATH_ADD("/test",Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The TestCtrl.cc file
|
||||
#include "TestCtrl.h"
|
||||
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
//write your application logic here
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("<p>Hello, world!</p>");
|
||||
resp->setExpiredTime(0);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
**上面程序的大部分代码都可以由`drogon_ctl`命令创建**(这个命令是`drogon_ctl create controller TestCtr`)。用户所需做的就是添加自己的业务逻辑。在这个例子中,当客户端访问URL`http://ip/test`时,控制器简单的返回了一个`Hello, world!`页面。
|
||||
|
||||
对于JSON格式的响应,我们可以像下面这样创建控制器:
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
//list path definitions here;
|
||||
PATH_ADD("/json", Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The source file
|
||||
#include "JsonCtrl.h"
|
||||
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["message"] = "Hello, World!";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
让我们更进一步,通过HttpController类创建一个RESTful API的例子,如下所示(忽略了实现文件):
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
using namespace drogon;
|
||||
namespace api
|
||||
{
|
||||
namespace v1
|
||||
{
|
||||
class User : public drogon::HttpController<User>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
|
||||
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
|
||||
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
|
||||
METHOD_LIST_END
|
||||
//your declaration of processing function maybe like this:
|
||||
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
|
||||
public:
|
||||
User()
|
||||
{
|
||||
LOG_DEBUG << "User constructor!";
|
||||
}
|
||||
};
|
||||
} // namespace v1
|
||||
} // namespace api
|
||||
```
|
||||
|
||||
如你所见,通过`HttpController`类,用户可以同时映射路径和路径参数,这对RESTful API应用来说非常方便。
|
||||
|
||||
另外,你可以发现前面所有的处理函数接口都是异步的,处理器的响应是通过回调对象返回的。这种设计是出于对高性能的考虑,因为在异步模式下,可以使用少量的线程(比如和处理器核心数相等的线程)处理大量的并发请求。
|
||||
|
||||
编译上述的所有源文件后,我们得到了一个非常简单的web应用程序,这是一个不错的开始。**请访问[wiki](https://github.com/an-tao/drogon/wiki/CHN-01-概述)**
|
||||
|
||||
## 贡献方式
|
||||
|
||||
欢迎您的贡献。 请阅读[贡献指南](CONTRIBUTING.md)以获取更多的信息。
|
||||
|
||||
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
|
||||
|
||||
## QQ交流群:1137909452
|
||||
|
||||
欢迎交流探讨。
|
199
vendors/drogon/README.zh-TW.md
vendored
Normal file
199
vendors/drogon/README.zh-TW.md
vendored
Normal file
@ -0,0 +1,199 @@
|
||||

|
||||
|
||||
[](https://github.com/drogonframework/drogon/actions)
|
||||
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[](https://discord.gg/3DvHY6Ewuj)
|
||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
[English](./README.md) | [简体中文](./README.zh-CN.md) | 繁體中文
|
||||
|
||||
**Drogon**是一個基於C++17/20的Http應用框架,使用Drogon可以方便的使用C++構建各種類型的Web App伺服器程式。
|
||||
本版本庫是github上[Drogon](https://github.com/an-tao/drogon)的鏡像庫。 **Drogon**是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(漢譯作卓耿),和龍有關但並不是dragon的誤寫,為了不至於引起不必要的誤會這裡說明一下。
|
||||
|
||||
Drogon是一個跨平台框架,它支援Linux,也支援macOS、FreeBSD/OpenBSD、HaikuOS和Windows。它的主要特點如下:
|
||||
|
||||
* 網路層使用基於epoll(macOS/FreeBSD下是kqueue)的非阻塞IO框架,提供高並發、高性能的網路IO。詳細請見[TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite);
|
||||
* 全異步程式設計;
|
||||
* 支援Http1.0/1.1(server端和client端);
|
||||
* 基於模板(template)實現了簡單的反射機制,使主程式框架、控制器(controller)和視圖(view)完全去耦;
|
||||
* 支援cookies和內建的session;
|
||||
* 支援後端渲染,把控制器生成的數據交給視圖生成Html頁面,視圖由CSP模板文件描述,通過CSP標籤把C++程式碼嵌入到Html頁面,由drogon的指令列工具在編譯階段自動生成C++程式碼並編譯;
|
||||
* 支援運行期的視圖頁面動態加載(動態編譯和載入so文件);
|
||||
* 非常方便靈活的路徑(path)到控制器處理函數(handler)的映射方案;
|
||||
* 支援過濾器(filter)鏈,方便在控制器之前執行統一的邏輯(如登錄驗證、Http Method約束驗證等);
|
||||
* 支援https(基於OpenSSL);
|
||||
* 支援websocket(server端和client端);
|
||||
* 支援Json格式的請求和回應, 方便開發Restful API;
|
||||
* 支援文件下載和上傳,支援sendfile系統呼叫;
|
||||
* 支援gzip/brotli壓縮傳輸;
|
||||
* 支援pipelining;
|
||||
* 提供一個輕量的指令列工具drogon_ctl,幫助簡化各種類的創造和視圖程式碼的生成過程;
|
||||
* 非同步的讀寫資料庫,目前支援PostgreSQL和MySQL(MariaDB)資料庫;
|
||||
* 支援異步讀寫Redis;
|
||||
* 基於執行序池實現sqlite3資料庫的異步讀寫,提供與上文資料庫相同的接口;
|
||||
* 支援ARM架構;
|
||||
* 方便的輕量級ORM實現,一般物件到資料庫的雙向映射;
|
||||
* 支援外掛,可通過設定文件在載入時動態載入;
|
||||
* 支援內建插入點的AOP
|
||||
* 支援C++ coroutine
|
||||
|
||||
## 一個非常簡單的例子
|
||||
|
||||
不像大多數C++框架那樣,drogon的主程式可以非常簡單。 Drogon使用了一些小技巧使主程式和控制器去耦. 控制器的路由設定可以在控制器類別中定義或者設定文件中完成.
|
||||
|
||||
下面是一個典型的主程式的樣子:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().setLogPath("./")
|
||||
.setLogLevel(trantor::Logger::kWarn)
|
||||
.addListener("0.0.0.0", 80)
|
||||
.setThreadNum(16)
|
||||
.enableRunAsDaemon()
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
如果使用設定文件,可以進一步簡化成這樣:
|
||||
|
||||
```c++
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app().loadConfigFile("./config.json").run();
|
||||
}
|
||||
```
|
||||
|
||||
當然,Drogon也提供了一些函數,使使用者可以在main()函數中直接添加控制器邏輯,比如,使用者可以註冊一個lambda處理器到drogon框架中,如下所示:
|
||||
|
||||
```c++
|
||||
app().registerHandler("/test?username={name}",
|
||||
[](const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback,
|
||||
const std::string &name)
|
||||
{
|
||||
Json::Value json;
|
||||
json["result"]="ok";
|
||||
json["message"]=std::string("hello,")+name;
|
||||
auto resp=HttpResponse::newHttpJsonResponse(json);
|
||||
callback(resp);
|
||||
},
|
||||
{Get,"LoginFilter"});
|
||||
```
|
||||
|
||||
|
||||
這看起來是很方便,但是這並不適用於復雜的場景,試想假如有數十個或者數百個處理函數要註冊進框架,main()函數將膨脹到不可讀的程度。顯然,讓每個包含處理函數的類在自己的定義中完成註冊是更好的選擇。所以,除非你的應用邏輯非常簡單,我們不推薦使用上述接口,更好的實踐是,我們可以創造一個HttpSimpleController類別,如下:
|
||||
|
||||
|
||||
```c++
|
||||
/// The TestCtrl.h file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
PATH_ADD("/test",Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The TestCtrl.cc file
|
||||
#include "TestCtrl.h"
|
||||
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
|
||||
std::function<void (const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
//write your application logic here
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("<p>Hello, world!</p>");
|
||||
resp->setExpiredTime(0);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
**上面程式的大部分程式碼都可以由`drogon_ctl`指令創造**(這個指令是`drogon_ctl create controller TestCtr`)。使用者所需做的就是添加自己的業務邏輯。在這個例子中,當客戶端訪問URL`http://ip/test`時,控制器簡單的回傳了一個`Hello, world!`頁面。
|
||||
|
||||
對於JSON格式的回應,我們可以像下面這樣創造控制器:
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
||||
{
|
||||
public:
|
||||
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
//list path definitions here;
|
||||
PATH_ADD("/json", Get);
|
||||
PATH_LIST_END
|
||||
};
|
||||
|
||||
/// The source file
|
||||
#include "JsonCtrl.h"
|
||||
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["message"] = "Hello, World!";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
callback(resp);
|
||||
}
|
||||
```
|
||||
|
||||
讓我們更進一步,通過HttpController類別創造一個RESTful API的例子,如下所示(忽略了實做文件):
|
||||
|
||||
```c++
|
||||
/// The header file
|
||||
#pragma once
|
||||
#include <drogon/HttpController.h>
|
||||
using namespace drogon;
|
||||
namespace api
|
||||
{
|
||||
namespace v1
|
||||
{
|
||||
class User : public drogon::HttpController<User>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
//use METHOD_ADD to add your custom processing function here;
|
||||
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
|
||||
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
|
||||
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
|
||||
METHOD_LIST_END
|
||||
//your declaration of processing function maybe like this:
|
||||
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
|
||||
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
|
||||
public:
|
||||
User()
|
||||
{
|
||||
LOG_DEBUG << "User constructor!";
|
||||
}
|
||||
};
|
||||
} // namespace v1
|
||||
} // namespace api
|
||||
```
|
||||
|
||||
如你所見,通過`HttpController`類別,使用者可以同時映射路徑和路徑參數,這對RESTful API應用來說非常方便。
|
||||
|
||||
另外,你可以發現前面所有的處理函數接口都是異步的,處理器的回應是通過回調對象回傳的。這種設計是出於對高性能的考慮,因為在異步模式下,可以使用少量的執行序(比如和處理器核心數相等的執行序)處理大量的並發請求。
|
||||
|
||||
編譯上述的所有源文件後,我們得到了一個非常簡單的web應用程式,這是一個不錯的開始。 **請瀏覽[wiki](https://github.com/an-tao/drogon/wiki/CHN-01-概述)**
|
||||
|
||||
## 貢獻方式
|
||||
|
||||
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以獲取更多的信息。
|
||||
|
||||
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
|
||||
|
||||
## QQ交流群:1137909452
|
||||
|
||||
歡迎交流探討。
|
101
vendors/drogon/build.sh
vendored
Executable file
101
vendors/drogon/build.sh
vendored
Executable file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#build drogon
|
||||
function build_drogon() {
|
||||
|
||||
#Update the submodule and initialize
|
||||
git submodule update --init
|
||||
|
||||
#Remove the config.h generated by the old version of drogon.
|
||||
rm -f lib/inc/drogon/config.h
|
||||
|
||||
#Save current directory
|
||||
current_dir="${PWD}"
|
||||
|
||||
#The folder in which we will build drogon
|
||||
build_dir='./build'
|
||||
if [ -d $build_dir ]; then
|
||||
echo "Deleted folder: ${build_dir}"
|
||||
rm -rf $build_dir
|
||||
fi
|
||||
|
||||
#Create building folder
|
||||
echo "Created building folder: ${build_dir}"
|
||||
mkdir $build_dir
|
||||
|
||||
echo "Entering folder: ${build_dir}"
|
||||
cd $build_dir
|
||||
|
||||
echo "Start building drogon ..."
|
||||
if [ $1 -eq 1 ]; then
|
||||
cmake .. -DBUILD_TESTING=YES $cmake_gen
|
||||
elif [ $1 -eq 2 ]; then
|
||||
cmake .. -DBUILD_TESTING=YES -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=1 $cmake_gen
|
||||
else
|
||||
cmake .. -DCMAKE_BUILD_TYPE=release $cmake_gen
|
||||
fi
|
||||
|
||||
#If errors then exit
|
||||
if [ "$?" != "0" ]; then
|
||||
exit -1
|
||||
fi
|
||||
|
||||
$make_program $make_flags
|
||||
|
||||
#If errors then exit
|
||||
if [ "$?" != "0" ]; then
|
||||
exit -1
|
||||
fi
|
||||
|
||||
echo "Installing ..."
|
||||
$make_program install
|
||||
|
||||
#Go back to the current directory
|
||||
cd $current_dir
|
||||
#Ok!
|
||||
}
|
||||
|
||||
make_program=make
|
||||
make_flags=''
|
||||
cmake_gen=''
|
||||
parallel=1
|
||||
|
||||
case $(uname) in
|
||||
FreeBSD)
|
||||
nproc=$(sysctl -n hw.ncpu)
|
||||
;;
|
||||
Darwin)
|
||||
nproc=$(sysctl -n hw.ncpu) # sysctl -n hw.ncpu is the equivalent to nproc on macOS.
|
||||
;;
|
||||
*)
|
||||
nproc=$(nproc)
|
||||
;;
|
||||
esac
|
||||
|
||||
# simulate ninja's parallelism
|
||||
case nproc in
|
||||
1)
|
||||
parallel=$(( nproc + 1 ))
|
||||
;;
|
||||
2)
|
||||
parallel=$(( nproc + 1 ))
|
||||
;;
|
||||
*)
|
||||
parallel=$(( nproc + 2 ))
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -f /bin/ninja ]; then
|
||||
make_program=ninja
|
||||
cmake_gen='-GNinja'
|
||||
else
|
||||
make_flags="$make_flags -j$parallel"
|
||||
fi
|
||||
|
||||
if [ "X$1" = "X-t" ]; then
|
||||
build_drogon 1
|
||||
elif [ "X$1" = "X-tshared" ]; then
|
||||
build_drogon 2
|
||||
else
|
||||
build_drogon 0
|
||||
fi
|
72
vendors/drogon/cmake/DrogonUtilities.cmake
vendored
Normal file
72
vendors/drogon/cmake/DrogonUtilities.cmake
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
# ##############################################################################
|
||||
# function drogon_create_views(target source_path output_path
|
||||
# [TRUE to use_path_as_namespace] [prefixed namespace])
|
||||
# ##############################################################################
|
||||
function(drogon_create_views arg)
|
||||
if(ARGC LESS 3)
|
||||
message(STATUS "arguments error when calling drogon_create_views")
|
||||
return()
|
||||
endif()
|
||||
file(MAKE_DIRECTORY ${ARGV2})
|
||||
file(GLOB_RECURSE SCP_LIST ${ARGV1}/*.csp)
|
||||
foreach(cspFile ${SCP_LIST})
|
||||
file(RELATIVE_PATH
|
||||
inFile
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${cspFile})
|
||||
if(ARGC GREATER 3 AND ARGV3)
|
||||
string(REPLACE "/"
|
||||
"_"
|
||||
f1
|
||||
${inFile})
|
||||
string(REPLACE "\\"
|
||||
"_"
|
||||
f2
|
||||
${f1})
|
||||
string(REPLACE ".csp"
|
||||
""
|
||||
outputFile
|
||||
${f2})
|
||||
set(p2ns "")
|
||||
if("${ARGV3}" STREQUAL "TRUE")
|
||||
set(p2ns "--path-to-namespace")
|
||||
endif()
|
||||
if ( (ARGC EQUAL 5) AND ( NOT "${ARGV4}" STREQUAL "") )
|
||||
string(REPLACE "::" "_" nSpace ${ARGV4})
|
||||
set(outputFile "${nSpace}_${outputFile}")
|
||||
set(ns -n ${ARGV4})
|
||||
else()
|
||||
set(ns "")
|
||||
endif()
|
||||
add_custom_command(OUTPUT ${ARGV2}/${outputFile}.h ${ARGV2}/${outputFile}.cc
|
||||
COMMAND drogon_ctl
|
||||
ARGS
|
||||
create
|
||||
view
|
||||
${inFile}
|
||||
${p2ns}
|
||||
-o
|
||||
${ARGV2}
|
||||
${ns}
|
||||
DEPENDS ${cspFile}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
VERBATIM)
|
||||
set(VIEWSRC ${VIEWSRC} ${ARGV2}/${outputFile}.cc)
|
||||
else()
|
||||
get_filename_component(classname ${cspFile} NAME_WE)
|
||||
add_custom_command(OUTPUT ${ARGV2}/${classname}.h ${ARGV2}/${classname}.cc
|
||||
COMMAND drogon_ctl
|
||||
ARGS
|
||||
create
|
||||
view
|
||||
${inFile}
|
||||
-o
|
||||
${ARGV2}
|
||||
DEPENDS ${cspFile}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
VERBATIM)
|
||||
set(VIEWSRC ${VIEWSRC} ${ARGV2}/${classname}.cc)
|
||||
endif()
|
||||
endforeach()
|
||||
target_sources(${ARGV0} PRIVATE ${VIEWSRC})
|
||||
endfunction(drogon_create_views)
|
37
vendors/drogon/cmake/Packages.cmake
vendored
Normal file
37
vendors/drogon/cmake/Packages.cmake
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_PACKAGE_CONTACT "https://github.com/drogonframework/drogon")
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_PACKAGE_VERSION "${DROGON_VERSION}")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows")
|
||||
|
||||
# DEB
|
||||
# Figure out dependencies automatically.
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
# Should be set automatically, but it is not.
|
||||
execute_process(COMMAND dpkg --print-architecture
|
||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
# The default does not produce valid Debian package names.
|
||||
set(CPACK_DEBIAN_FILE_NAME
|
||||
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
|
||||
# RPM
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
|
||||
# Figure out dependencies automatically.
|
||||
set(CPACK_RPM_PACKAGE_AUTOREQ ON)
|
||||
|
||||
# Should be set automatically, but it is not.
|
||||
execute_process(COMMAND uname -m
|
||||
OUTPUT_VARIABLE CPACK_RPM_PACKAGE_ARCHITECTURE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
include(CPack)
|
79
vendors/drogon/cmake/ParseAndAddDrogonTests.cmake
vendored
Normal file
79
vendors/drogon/cmake/ParseAndAddDrogonTests.cmake
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
#==================================================================================================#
|
||||
# Adapted and re-written from Catch2 to work with Drogon Test #
|
||||
# #
|
||||
# Usage #
|
||||
# 1. make sure this module is in the path or add this otherwise: #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") #
|
||||
# 2. make sure that you've enabled testing option for the project by the call: #
|
||||
# enable_testing() #
|
||||
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
||||
# project(testing_target) #
|
||||
# enable_testing() #
|
||||
# #
|
||||
# file(GLOB SOURCE_FILES "*.cpp") #
|
||||
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
||||
# #
|
||||
# include(ParseAndAddDrogonTests) #
|
||||
# ParseAndAddDrogonTests(${PROJECT_NAME}) #
|
||||
#==================================================================================================#
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# This removes the contents between
|
||||
# - block comments (i.e. /* ... */)
|
||||
# - full line comments (i.e. // ... )
|
||||
# contents have been read into '${CppCode}'.
|
||||
# !keep partial line comments
|
||||
function(RemoveComments CppCode)
|
||||
string(ASCII 2 CMakeBeginBlockComment)
|
||||
string(ASCII 3 CMakeEndBlockComment)
|
||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
||||
|
||||
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Worker function
|
||||
function(ParseFile SourceFile TestTarget)
|
||||
set(FullSourcePath ${CMAKE_CURRENT_SOURCE_DIR}/${SourceFile})
|
||||
if(NOT EXISTS ${FullSourcePath})
|
||||
return()
|
||||
endif()
|
||||
file(STRINGS ${FullSourcePath} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
RemoveComments(Contents)
|
||||
|
||||
# Find definition of test names
|
||||
string(REGEX MATCHALL "[ \t]*DROGON_TEST[ \t]*\\\([a-zA-Z0-9_]+\\\)" Tests "${Contents}")
|
||||
|
||||
foreach(TestLine ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestLine "${TestLine}")
|
||||
|
||||
# Get the name of the test
|
||||
string(REGEX REPLACE "[ \t]*DROGON_TEST[ \t]*" "" TestLine "${TestLine}")
|
||||
string(REGEX MATCHALL "[a-zA-Z0-9_]+" TestName "${TestLine}")
|
||||
|
||||
# Validate that a test name and tags have been provided
|
||||
list(LENGTH TestName TestNameLength)
|
||||
if(NOT TestNameLength EQUAL 1)
|
||||
message(FATAL_ERROR "${TestName} in ${SourceFile} is not a valid test name."
|
||||
" Either a bug in the Drogon Test CMake parser or a bug in the test itself")
|
||||
endif()
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "${TestName}" COMMAND ${TestTarget} -r ${TestName} ${AdditionalCatchParameters})
|
||||
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddDrogonTests TestTarget)
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
endfunction()
|
62
vendors/drogon/cmake/templates/DrogonConfig.cmake.in
vendored
Normal file
62
vendors/drogon/cmake/templates/DrogonConfig.cmake.in
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
# - Config file for the Drogon package
|
||||
# It defines the following variables
|
||||
# DROGON_INCLUDE_DIRS - include directories for Drogon
|
||||
# DROGON_LIBRARIES - libraries to link against
|
||||
# DROGON_EXECUTABLE - the drogon_ctl executable
|
||||
# Drogon_FOUND
|
||||
# This module defines the following IMPORTED target:
|
||||
# Drogon::Drogon
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
find_dependency(Jsoncpp REQUIRED)
|
||||
find_dependency(Trantor REQUIRED)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
|
||||
find_dependency(UUID REQUIRED)
|
||||
endif(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
if(@pg_FOUND@)
|
||||
find_dependency(pg)
|
||||
endif()
|
||||
if(@SQLite3_FOUND@)
|
||||
find_dependency(SQLite3)
|
||||
endif()
|
||||
if(@MySQL_FOUND@)
|
||||
find_dependency(MySQL)
|
||||
endif()
|
||||
if(@Brotli_FOUND@)
|
||||
find_dependency(Brotli)
|
||||
endif()
|
||||
if(@COZ-PROFILER_FOUND@)
|
||||
find_dependency(coz-profiler)
|
||||
endif()
|
||||
if(@Hiredis_FOUND@)
|
||||
find_dependency(Hiredis)
|
||||
endif()
|
||||
if(@yaml-cpp_FOUND@)
|
||||
find_dependency(yaml-cpp)
|
||||
endif()
|
||||
if(@BUILD_SHARED_LIBS@)
|
||||
find_dependency(Threads)
|
||||
endif()
|
||||
if(@HAS_STD_FILESYSTEM_PATH@)
|
||||
find_dependency(Filesystem)
|
||||
find_package(Filesystem COMPONENTS Final REQUIRED)
|
||||
endif()
|
||||
|
||||
|
||||
# Our library dependencies (contains definitions for IMPORTED targets)
|
||||
|
||||
get_filename_component(DROGON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
if(NOT TARGET Drogon::Drogon)
|
||||
include("${DROGON_CMAKE_DIR}/DrogonTargets.cmake")
|
||||
include("${DROGON_CMAKE_DIR}/DrogonUtilities.cmake")
|
||||
include("${DROGON_CMAKE_DIR}/ParseAndAddDrogonTests.cmake")
|
||||
endif()
|
||||
|
||||
get_target_property(DROGON_INCLUDE_DIRS Drogon::Drogon INTERFACE_INCLUDE_DIRECTORIES)
|
||||
set(DROGON_LIBRARIES Drogon::Drogon)
|
||||
set(DROGON_EXECUTABLE drogon_ctl)
|
15
vendors/drogon/cmake/templates/config.h.in
vendored
Normal file
15
vendors/drogon/cmake/templates/config.h.in
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#cmakedefine01 USE_POSTGRESQL
|
||||
#cmakedefine01 LIBPQ_SUPPORTS_BATCH_MODE
|
||||
#cmakedefine01 USE_MYSQL
|
||||
#cmakedefine01 USE_SQLITE3
|
||||
#cmakedefine01 HAS_STD_FILESYSTEM_PATH
|
||||
#cmakedefine OpenSSL_FOUND
|
||||
#cmakedefine Boost_FOUND
|
||||
|
||||
#cmakedefine COMPILATION_FLAGS "@COMPILATION_FLAGS@@DROGON_CXX_STANDARD@"
|
||||
#cmakedefine COMPILER_COMMAND "@COMPILER_COMMAND@"
|
||||
#cmakedefine COMPILER_ID "@COMPILER_ID@"
|
||||
|
||||
#cmakedefine INCLUDING_DIRS "@INCLUDING_DIRS@"
|
5
vendors/drogon/cmake/templates/version.h.in
vendored
Normal file
5
vendors/drogon/cmake/templates/version.h.in
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#define MAJOR @DROGON_MAJOR_VERSION@
|
||||
#define MINOR @DROGON_MINOR_VERSION@
|
||||
#define PATCH @DROGON_PATCH_VERSION@
|
||||
#define DROGON_VERSION "@DROGON_VERSION_STRING@"
|
||||
#define DROGON_VERSION_SHA1 "@GIT_SHA1@"
|
7
vendors/drogon/cmake/tests/check_has_std_filesystem_path.cc
vendored
Executable file
7
vendors/drogon/cmake/tests/check_has_std_filesystem_path.cc
vendored
Executable file
@ -0,0 +1,7 @@
|
||||
#include <filesystem>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::filesystem::path aPath("../");
|
||||
return 0;
|
||||
}
|
7
vendors/drogon/cmake/tests/normal_uuid_lib_test.cc
vendored
Normal file
7
vendors/drogon/cmake/tests/normal_uuid_lib_test.cc
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
#include <uuid.h>
|
||||
int main()
|
||||
{
|
||||
uuid_t uu;
|
||||
uuid_generate(uu);
|
||||
return 0;
|
||||
}
|
8
vendors/drogon/cmake/tests/ossp_uuid_lib_test.cc
vendored
Normal file
8
vendors/drogon/cmake/tests/ossp_uuid_lib_test.cc
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
#include <uuid.h>
|
||||
int main()
|
||||
{
|
||||
uuid_t *uuid;
|
||||
uuid_create(&uuid);
|
||||
uuid_make(uuid, UUID_MAKE_V1);
|
||||
return 0;
|
||||
}
|
9
vendors/drogon/cmake/tests/test_libpq_batch_mode.cc
vendored
Normal file
9
vendors/drogon/cmake/tests/test_libpq_batch_mode.cc
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
#include <libpq-fe.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
PQenterPipelineMode(NULL);
|
||||
PQexitPipelineMode(NULL);
|
||||
PQpipelineSync(NULL);
|
||||
PQpipelineStatus(NULL);
|
||||
}
|
50
vendors/drogon/cmake_modules/FindBrotli.cmake
vendored
Normal file
50
vendors/drogon/cmake_modules/FindBrotli.cmake
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# ***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which you should
|
||||
# have received as part of this distribution. The terms are also available at
|
||||
# https://curl.haxx.se/docs/copyright.html.
|
||||
#
|
||||
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
# copies of the Software, and permit persons to whom the Software is furnished
|
||||
# to do so, under the terms of the COPYING file.
|
||||
#
|
||||
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
# KIND, either express or implied.
|
||||
#
|
||||
# ##############################################################################
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
|
||||
|
||||
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon brotlicommon-static)
|
||||
find_library(BROTLIDEC_LIBRARY NAMES brotlidec brotlidec-static)
|
||||
find_library(BROTLIENC_LIBRARY NAMES brotlienc brotlienc-static)
|
||||
|
||||
find_package_handle_standard_args(Brotli
|
||||
REQUIRED_VARS
|
||||
BROTLIDEC_LIBRARY
|
||||
BROTLIENC_LIBRARY
|
||||
BROTLICOMMON_LIBRARY
|
||||
BROTLI_INCLUDE_DIR
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find BROTLI")
|
||||
|
||||
set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
|
||||
set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY}
|
||||
${BROTLIENC_LIBRARY} ${BROTLICOMMON_LIBRARY})
|
||||
|
||||
if(Brotli_FOUND)
|
||||
add_library(Brotli_lib INTERFACE IMPORTED)
|
||||
set_target_properties(Brotli_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${BROTLI_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${BROTLI_LIBRARIES}")
|
||||
endif(Brotli_FOUND)
|
261
vendors/drogon/cmake_modules/FindFilesystem.cmake
vendored
Normal file
261
vendors/drogon/cmake_modules/FindFilesystem.cmake
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindFilesystem
|
||||
##############
|
||||
|
||||
This module supports the C++17 standard library's filesystem utilities. Use the
|
||||
:imp-target:`std::filesystem` imported target to
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
The ``COMPONENTS`` argument to this module supports the following values:
|
||||
|
||||
.. find-component:: Experimental
|
||||
:name: fs.Experimental
|
||||
|
||||
Allows the module to find the "experimental" Filesystem TS version of the
|
||||
Filesystem library. This is the library that should be used with the
|
||||
``std::experimental::filesystem`` namespace.
|
||||
|
||||
.. find-component:: Final
|
||||
:name: fs.Final
|
||||
|
||||
Finds the final C++17 standard version of the filesystem library.
|
||||
|
||||
If no components are provided, behaves as if the
|
||||
:find-component:`fs.Final` component was specified.
|
||||
|
||||
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
|
||||
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
|
||||
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
|
||||
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
|
||||
|
||||
|
||||
Imported Targets
|
||||
****************
|
||||
|
||||
.. imp-target:: std::filesystem
|
||||
|
||||
The ``std::filesystem`` imported target is defined when any requested
|
||||
version of the C++ filesystem library has been found, whether it is
|
||||
*Experimental* or *Final*.
|
||||
|
||||
If no version of the filesystem library is available, this target will not
|
||||
be defined.
|
||||
|
||||
.. note::
|
||||
This target has ``cxx_std_17`` as an ``INTERFACE``
|
||||
:ref:`compile language standard feature <req-lang-standards>`. Linking
|
||||
to this target will automatically enable C++17 if no later standard
|
||||
version is already required on the linking target.
|
||||
|
||||
|
||||
.. _fs.variables:
|
||||
|
||||
Variables
|
||||
*********
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
|
||||
|
||||
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
|
||||
filesystem library was found, otherwise ``FALSE``.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_HAVE_FS
|
||||
|
||||
Set to ``TRUE`` when a filesystem header was found.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_HEADER
|
||||
|
||||
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
|
||||
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
|
||||
found.
|
||||
|
||||
.. variable:: CXX_FILESYSTEM_NAMESPACE
|
||||
|
||||
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
|
||||
depending on whether :find-component:`fs.Final` or
|
||||
:find-component:`fs.Experimental` was found.
|
||||
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
Using `find_package(Filesystem)` with no component arguments:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Filesystem REQUIRED)
|
||||
|
||||
add_executable(my-program main.cpp)
|
||||
target_link_libraries(my-program PRIVATE std::filesystem)
|
||||
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
|
||||
if(TARGET std::filesystem)
|
||||
# This module has already been processed. Don't do it again.
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Ignore filesystem check if version too low
|
||||
if(CMAKE_VERSION VERSION_LESS 3.10)
|
||||
set(CXX_FILESYSTEM_HAVE_FS FALSE CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
||||
set(Filesystem_FOUND FALSE CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
|
||||
# If we're not cross-compiling, try to run test executables.
|
||||
# Otherwise, assume that compile + link is a sufficient check.
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
include(CheckCXXSourceCompiles)
|
||||
macro(_cmcm_check_cxx_source code var)
|
||||
check_cxx_source_compiles("${code}" ${var})
|
||||
endmacro()
|
||||
else()
|
||||
include(CheckCXXSourceRuns)
|
||||
macro(_cmcm_check_cxx_source code var)
|
||||
check_cxx_source_runs("${code}" ${var})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
|
||||
|
||||
# All of our tests required C++17 or later
|
||||
set(BACKUP_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Normalize and check the component list we were given
|
||||
set(want_components ${Filesystem_FIND_COMPONENTS})
|
||||
if(Filesystem_FIND_COMPONENTS STREQUAL "")
|
||||
set(want_components Final)
|
||||
endif()
|
||||
|
||||
# Warn on any unrecognized components
|
||||
set(extra_components ${want_components})
|
||||
list(REMOVE_ITEM extra_components Final Experimental)
|
||||
foreach(component IN LISTS extra_components)
|
||||
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
|
||||
endforeach()
|
||||
|
||||
# Detect which of Experimental and Final we should look for
|
||||
set(find_experimental TRUE)
|
||||
set(find_final TRUE)
|
||||
if(NOT "Final" IN_LIST want_components)
|
||||
set(find_final FALSE)
|
||||
endif()
|
||||
if(NOT "Experimental" IN_LIST want_components)
|
||||
set(find_experimental FALSE)
|
||||
endif()
|
||||
|
||||
if(find_final)
|
||||
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
# We found the non-experimental header. Don't bother looking for the
|
||||
# experimental one.
|
||||
set(find_experimental FALSE)
|
||||
endif()
|
||||
else()
|
||||
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
|
||||
endif()
|
||||
|
||||
if(find_experimental)
|
||||
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
else()
|
||||
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
|
||||
endif()
|
||||
|
||||
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
set(_have_fs TRUE)
|
||||
set(_fs_header filesystem)
|
||||
set(_fs_namespace std::filesystem)
|
||||
set(_is_experimental FALSE)
|
||||
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||
set(_have_fs TRUE)
|
||||
set(_fs_header experimental/filesystem)
|
||||
set(_fs_namespace std::experimental::filesystem)
|
||||
set(_is_experimental TRUE)
|
||||
else()
|
||||
set(_have_fs FALSE)
|
||||
endif()
|
||||
|
||||
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
||||
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
|
||||
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
|
||||
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
|
||||
|
||||
set(_found FALSE)
|
||||
|
||||
if(CXX_FILESYSTEM_HAVE_FS)
|
||||
# We have some filesystem library available. Do link checks
|
||||
string(CONFIGURE [[
|
||||
#include <cstdio>
|
||||
#include <@CXX_FILESYSTEM_HEADER@>
|
||||
|
||||
int main() {
|
||||
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
|
||||
printf("%s", cwd.generic_string().c_str());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
]] code @ONLY)
|
||||
|
||||
# HACK: Needed to compile correctly on Yocto Linux
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GCC" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
|
||||
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(CMAKE_REQUIRED_FLAGS ${prev_req_flags} -std=c++17)
|
||||
endif ()
|
||||
# Check a simple filesystem program without any linker flags
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
|
||||
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
|
||||
|
||||
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Add the libstdc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
# Try the libc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(can_link)
|
||||
add_library(std::filesystem INTERFACE IMPORTED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||
set(_found TRUE)
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
# Nothing to add...
|
||||
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
|
||||
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
|
||||
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD "${BACKUP_CXX_STANDARD}")
|
41
vendors/drogon/cmake_modules/FindHiredis.cmake
vendored
Normal file
41
vendors/drogon/cmake_modules/FindHiredis.cmake
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# Try to find hiredis
|
||||
# Once done, this will define
|
||||
#
|
||||
# HIREDIS_FOUND - system has hiredis
|
||||
# HIREDIS_INCLUDE_DIRS - hiredis include directories
|
||||
# HIREDIS_LIBRARIES - libraries need to use hiredis
|
||||
|
||||
if (HIREDIS_INCLUDE_DIRS AND HIREDIS_LIBRARIES)
|
||||
set(HIREDIS_FIND_QUIETLY TRUE)
|
||||
set(Hiredis_FOUND TRUE)
|
||||
else ()
|
||||
find_path(
|
||||
HIREDIS_INCLUDE_DIR
|
||||
NAMES hiredis/hiredis.h
|
||||
HINTS ${HIREDIS_ROOT_DIR}
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
find_library(
|
||||
HIREDIS_LIBRARY
|
||||
NAMES hiredis
|
||||
HINTS ${HIREDIS_ROOT_DIR}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
set(HIREDIS_INCLUDE_DIRS ${HIREDIS_INCLUDE_DIR})
|
||||
set(HIREDIS_LIBRARIES ${HIREDIS_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
Hiredis DEFAULT_MSG HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
|
||||
endif ()
|
||||
|
||||
if(Hiredis_FOUND)
|
||||
add_library(Hiredis_lib INTERFACE IMPORTED)
|
||||
set_target_properties(Hiredis_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${HIREDIS_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${HIREDIS_LIBRARIES}")
|
||||
endif(Hiredis_FOUND)
|
71
vendors/drogon/cmake_modules/FindJsoncpp.cmake
vendored
Executable file
71
vendors/drogon/cmake_modules/FindJsoncpp.cmake
vendored
Executable file
@ -0,0 +1,71 @@
|
||||
# Find jsoncpp
|
||||
#
|
||||
# Find the jsoncpp includes and library
|
||||
#
|
||||
# if you nee to add a custom library search path, do it via via
|
||||
# CMAKE_PREFIX_PATH
|
||||
#
|
||||
# This module defines JSONCPP_INCLUDE_DIRS, where to find header, etc.
|
||||
# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. JSONCPP_FOUND, If
|
||||
# false, do not try to use jsoncpp.
|
||||
# Jsoncpp_lib - The imported target library.
|
||||
|
||||
# only look in default directories
|
||||
find_path(JSONCPP_INCLUDE_DIRS
|
||||
NAMES json/json.h
|
||||
DOC "jsoncpp include dir"
|
||||
PATH_SUFFIXES jsoncpp)
|
||||
|
||||
find_library(JSONCPP_LIBRARIES NAMES jsoncpp DOC "jsoncpp library")
|
||||
|
||||
# debug library on windows same naming convention as in qt (appending debug
|
||||
# library with d) boost is using the same "hack" as us with "optimized" and
|
||||
# "debug" if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# find_library(JSONCPP_LIBRARIES_DEBUG NAMES jsoncppd DOC "jsoncpp debug
|
||||
# library") if("${JSONCPP_LIBRARIES_DEBUG}" STREQUAL "JSONCPP_LIBRARIES_DEBUG-
|
||||
# NOTFOUND") set(JSONCPP_LIBRARIES_DEBUG ${JSONCPP_LIBRARIES}) endif()
|
||||
|
||||
# set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug
|
||||
# ${JSONCPP_LIBRARIES_DEBUG})
|
||||
|
||||
# endif()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE if all
|
||||
# listed variables are TRUE, hide their existence from configuration view
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Jsoncpp
|
||||
DEFAULT_MSG
|
||||
JSONCPP_INCLUDE_DIRS
|
||||
JSONCPP_LIBRARIES)
|
||||
mark_as_advanced(JSONCPP_INCLUDE_DIRS JSONCPP_LIBRARIES)
|
||||
|
||||
if(Jsoncpp_FOUND)
|
||||
if(NOT EXISTS ${JSONCPP_INCLUDE_DIRS}/json/version.h)
|
||||
message(FATAL_ERROR "Error: jsoncpp lib is too old.....stop")
|
||||
endif()
|
||||
if(NOT WIN32)
|
||||
execute_process(
|
||||
COMMAND cat ${JSONCPP_INCLUDE_DIRS}/json/version.h
|
||||
COMMAND grep JSONCPP_VERSION_STRING
|
||||
COMMAND sed -e "s/.*define/define/"
|
||||
COMMAND awk "{ printf \$3 }"
|
||||
COMMAND sed -e "s/\"//g"
|
||||
OUTPUT_VARIABLE jsoncpp_ver)
|
||||
message(STATUS "jsoncpp version:" ${jsoncpp_ver})
|
||||
if(jsoncpp_ver LESS 1.7)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"jsoncpp lib is too old, please get new version from https://github.com/open-source-parsers/jsoncpp"
|
||||
)
|
||||
endif(jsoncpp_ver LESS 1.7)
|
||||
endif()
|
||||
if (NOT TARGET Jsoncpp_lib)
|
||||
add_library(Jsoncpp_lib INTERFACE IMPORTED)
|
||||
endif()
|
||||
set_target_properties(Jsoncpp_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${JSONCPP_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${JSONCPP_LIBRARIES}")
|
||||
|
||||
endif(Jsoncpp_FOUND)
|
122
vendors/drogon/cmake_modules/FindMySQL.cmake
vendored
Normal file
122
vendors/drogon/cmake_modules/FindMySQL.cmake
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
# --------------------------------------------------------
|
||||
# Copyright (C) 1995-2007 MySQL AB
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of version 2 of the GNU General Public License as published by the
|
||||
# Free Software Foundation.
|
||||
#
|
||||
# There are special exceptions to the terms and conditions of the GPL as it is
|
||||
# applied to this software. View the full text of the exception in file
|
||||
# LICENSE.exceptions in the top-level directory of this software distribution.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||
# Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
# The MySQL Connector/ODBC is licensed under the terms of the GPL, like most
|
||||
# MySQL Connectors. There are special exceptions to the terms and conditions of
|
||||
# the GPL as it is applied to this software, see the FLOSS License Exception
|
||||
# available on mysql.com.
|
||||
# MySQL_lib - The imported target library.
|
||||
|
||||
# ##############################################################################
|
||||
|
||||
# -------------- FIND MYSQL_INCLUDE_DIRS ------------------
|
||||
find_path(MYSQL_INCLUDE_DIRS
|
||||
NAMES mysql.h
|
||||
PATH_SUFFIXES mysql
|
||||
PATHS /usr/include/mysql
|
||||
/usr/local/include/mysql
|
||||
/usr/include/mariadb
|
||||
/usr/local/include/mariadb
|
||||
/opt/mysql/mysql/include
|
||||
/opt/mysql/mysql/include/mysql
|
||||
/opt/mysql/include
|
||||
/opt/local/include/mysql5
|
||||
/usr/local/mysql/include
|
||||
/usr/local/mysql/include/mysql
|
||||
/usr/local/mariadb/include
|
||||
/usr/local/mariadb/include/mariadb
|
||||
/opt/rh/rh-mariadb105/root/usr/include
|
||||
/opt/rh/rh-mariadb105/root/usr/include/mysql
|
||||
$ENV{ProgramFiles}/MySQL/*/include
|
||||
$ENV{SystemDrive}/MySQL/*/include)
|
||||
|
||||
if(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql.h")
|
||||
|
||||
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql/mysql.h")
|
||||
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIRS}/mysql)
|
||||
endif()
|
||||
|
||||
# ----------------- FIND MYSQL_LIBRARIES_DIR -------------------
|
||||
if(WIN32)
|
||||
# Set lib path suffixes dist = for mysql binary distributions build = for
|
||||
# custom built tree
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set(libsuffixDist debug)
|
||||
set(libsuffixBuild Debug)
|
||||
else(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set(libsuffixDist opt)
|
||||
set(libsuffixBuild Release)
|
||||
add_definitions(-DDBUG_OFF)
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
|
||||
find_library(MYSQL_LIBRARIES
|
||||
NAMES mariadbclient
|
||||
PATHS $ENV{MYSQL_DIR}/lib/${libsuffixDist}
|
||||
$ENV{MYSQL_DIR}/libmysql
|
||||
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
|
||||
$ENV{MYSQL_DIR}/client/${libsuffixBuild}
|
||||
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
|
||||
$ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist}
|
||||
$ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
|
||||
else(WIN32)
|
||||
find_library(MYSQL_LIBRARIES
|
||||
NAMES mysqlclient_r mariadbclient
|
||||
PATHS /usr/lib/mysql
|
||||
/usr/lib/mariadb
|
||||
/usr/local/lib/mysql
|
||||
/usr/local/lib/mariadb
|
||||
/usr/local/mysql/lib
|
||||
/usr/local/mysql/lib/mysql
|
||||
/opt/local/mysql5/lib
|
||||
/opt/local/lib/mysql5/mysql
|
||||
/opt/mysql/mysql/lib/mysql
|
||||
/opt/mysql/lib/mysql
|
||||
/opt/rh/rh-mariadb105/root/usr/lib64)
|
||||
endif(WIN32)
|
||||
|
||||
if(MYSQL_INCLUDE_DIRS AND MYSQL_LIBRARIES)
|
||||
message(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIRS}")
|
||||
message(STATUS "MySQL client libraries: ${MYSQL_LIBRARIES}")
|
||||
elseif(MySQL_FIND_REQUIRED)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIRS} library dir: ${MYSQL_LIBRARIES_DIR}"
|
||||
)
|
||||
endif(MYSQL_INCLUDE_DIRS AND MYSQL_LIBRARIES)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MySQL
|
||||
DEFAULT_MSG
|
||||
MYSQL_LIBRARIES
|
||||
MYSQL_INCLUDE_DIRS)
|
||||
# Copy the results to the output variables.
|
||||
if(MySQL_FOUND)
|
||||
add_library(MySQL_lib INTERFACE IMPORTED)
|
||||
set_target_properties(MySQL_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${MYSQL_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${MYSQL_LIBRARIES}")
|
||||
else(MySQL_FOUND)
|
||||
set(MYSQL_LIBRARIES)
|
||||
set(MYSQL_INCLUDE_DIRS)
|
||||
endif(MySQL_FOUND)
|
||||
|
||||
mark_as_advanced(MYSQL_INCLUDE_DIRS MYSQL_LIBRARIES)
|
43
vendors/drogon/cmake_modules/FindSQLite3.cmake
vendored
Normal file
43
vendors/drogon/cmake_modules/FindSQLite3.cmake
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# Copyright (C) 2007-2009 LuaDist. Created by Peter Kapec <kapecp@gmail.com>
|
||||
# Redistribution and use of this file is allowed according to the terms of the
|
||||
# MIT license. For details see the COPYRIGHT file distributed with LuaDist.
|
||||
# Note: Searching headers and libraries is very simple and is NOT as powerful as
|
||||
# scripts distributed with CMake, because LuaDist defines directories to search
|
||||
# for. Everyone is encouraged to contact the author with improvements. Maybe
|
||||
# this file becomes part of CMake distribution sometimes.
|
||||
|
||||
# * Find sqlite3 Find the native SQLITE3 headers and libraries.
|
||||
#
|
||||
# SQLITE3_INCLUDE_DIRS - where to find sqlite3.h, etc.
|
||||
# SQLITE3_LIBRARIES - List of libraries when using sqlite.
|
||||
# SQLite3_FOUND - True if sqlite3 found.
|
||||
# SQLite3_lib - The imported target library.
|
||||
|
||||
# Look for the header file.
|
||||
find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
|
||||
|
||||
# Look for the library.
|
||||
find_library(SQLITE3_LIBRARIES NAMES sqlite3)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set SQLite3_FOUND to TRUE if all
|
||||
# listed variables are TRUE.
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SQLite3
|
||||
DEFAULT_MSG
|
||||
SQLITE3_LIBRARIES
|
||||
SQLITE3_INCLUDE_DIRS)
|
||||
|
||||
# Copy the results to the output variables.
|
||||
if(SQLite3_FOUND)
|
||||
add_library(SQLite3_lib INTERFACE IMPORTED)
|
||||
set_target_properties(SQLite3_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${SQLITE3_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${SQLITE3_LIBRARIES}")
|
||||
else(SQLite3_FOUND)
|
||||
set(SQLITE3_LIBRARIES)
|
||||
set(SQLITE3_INCLUDE_DIRS)
|
||||
endif(SQLite3_FOUND)
|
||||
|
||||
mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES)
|
118
vendors/drogon/cmake_modules/FindUUID.cmake
vendored
Executable file
118
vendors/drogon/cmake_modules/FindUUID.cmake
vendored
Executable file
@ -0,0 +1,118 @@
|
||||
# * Try to find UUID Once done this will define
|
||||
#
|
||||
# UUID_FOUND - system has UUID
|
||||
# UUID_INCLUDE_DIRS - the UUID include directory
|
||||
# UUID_LIBRARIES - Link these to use UUID UUID_DEFINITIONS - Compiler switches
|
||||
# required for using UUID
|
||||
#
|
||||
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New BSD
|
||||
# license. For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
if(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(UUID_FOUND TRUE)
|
||||
else()
|
||||
find_path(
|
||||
UUID_INCLUDE_DIR
|
||||
NAMES uuid.h
|
||||
PATH_SUFFIXES uuid
|
||||
HINTS ${UUID_DIR}/include
|
||||
$ENV{UUID_DIR}/include
|
||||
$ENV{UUID_DIR}
|
||||
${DELTA3D_EXT_DIR}/inc
|
||||
$ENV{DELTA_ROOT}/ext/inc
|
||||
$ENV{DELTA_ROOT}
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/usr/include/gdal
|
||||
/sw/include # Fink
|
||||
/opt/local/include # DarwinPorts
|
||||
/opt/csw/include # Blastwave
|
||||
/opt/include
|
||||
[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
|
||||
/usr/freeware/include)
|
||||
|
||||
find_library(UUID_LIBRARY
|
||||
NAMES uuid ossp-uuid
|
||||
HINTS ${UUID_DIR}/lib
|
||||
$ENV{UUID_DIR}/lib
|
||||
$ENV{UUID_DIR}
|
||||
${DELTA3D_EXT_DIR}/lib
|
||||
$ENV{DELTA_ROOT}/ext/lib
|
||||
$ENV{DELTA_ROOT}
|
||||
$ENV{OSG_ROOT}/lib
|
||||
PATHS ~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/sw/lib
|
||||
/opt/local/lib
|
||||
/opt/csw/lib
|
||||
/opt/lib
|
||||
/usr/freeware/lib64)
|
||||
|
||||
find_library(UUID_LIBRARY_DEBUG
|
||||
NAMES uuidd
|
||||
HINTS ${UUID_DIR}/lib
|
||||
$ENV{UUID_DIR}/lib
|
||||
$ENV{UUID_DIR}
|
||||
${DELTA3D_EXT_DIR}/lib
|
||||
$ENV{DELTA_ROOT}/ext/lib
|
||||
$ENV{DELTA_ROOT}
|
||||
$ENV{OSG_ROOT}/lib
|
||||
PATHS ~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/sw/lib
|
||||
/opt/local/lib
|
||||
/opt/csw/lib
|
||||
/opt/lib
|
||||
/usr/freeware/lib64)
|
||||
|
||||
if(NOT UUID_LIBRARY AND (BSD OR APPLE))
|
||||
set(UUID_LIBRARY "")
|
||||
endif()
|
||||
|
||||
set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR})
|
||||
set(UUID_LIBRARIES ${UUID_LIBRARY})
|
||||
|
||||
if(UUID_INCLUDE_DIRS)
|
||||
if((BSD OR APPLE) OR UUID_LIBRARIES)
|
||||
set(UUID_FOUND TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(UUID_FOUND)
|
||||
if(NOT UUID_FIND_QUIETLY)
|
||||
message(STATUS "Found UUID: ${UUID_LIBRARIES}")
|
||||
endif()
|
||||
else()
|
||||
if(UUID_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find UUID")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced
|
||||
# view
|
||||
mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
|
||||
|
||||
endif()
|
||||
|
||||
if(UUID_FOUND)
|
||||
add_library(UUID_lib INTERFACE IMPORTED)
|
||||
set_target_properties(UUID_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${UUID_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${UUID_LIBRARIES}")
|
||||
else()
|
||||
set(UUID_LIBRARIES)
|
||||
set(UUID_INCLUDE_DIRS)
|
||||
endif()
|
23
vendors/drogon/cmake_modules/Findcoz-profiler.cmake
vendored
Normal file
23
vendors/drogon/cmake_modules/Findcoz-profiler.cmake
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
find_path(COZ_INCLUDE_DIRS NAMES coz.h)
|
||||
|
||||
find_library(COZ_LIBRARIES NAMES coz PATH_SUFFIXES coz-profiler)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(coz-profiler
|
||||
DEFAULT_MSG
|
||||
COZ_LIBRARIES
|
||||
COZ_INCLUDE_DIRS)
|
||||
|
||||
if(COZ-PROFILER_FOUND)
|
||||
add_library(coz::coz INTERFACE IMPORTED)
|
||||
set_target_properties(coz::coz
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
${COZ_INCLUDE_DIRS}
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
${COZ_LIBRARIES})
|
||||
else(COZ-PROFILER_FOUND)
|
||||
set(COZ_LIBRARIES)
|
||||
set(COZ_INCLUDE_DIRS)
|
||||
endif(COZ-PROFILER_FOUND)
|
||||
|
||||
mark_as_advanced(COZ_INCLUDE_DIRS COZ_LIBRARIES)
|
27
vendors/drogon/cmake_modules/Findpg.cmake
vendored
Normal file
27
vendors/drogon/cmake_modules/Findpg.cmake
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# Find PostgreSQL
|
||||
#
|
||||
# Find the PostgreSQL includes and library
|
||||
#
|
||||
# This module defines PG_INCLUDE_DIRS, where to find header, etc. PG_LIBRARIES,
|
||||
# the libraries needed to use PostgreSQL. pg_FOUND, If false, do not try to use
|
||||
# PostgreSQL.
|
||||
# pg_lib - The imported target library.
|
||||
|
||||
find_package(PostgreSQL)
|
||||
if(PostgreSQL_FOUND)
|
||||
set(PG_LIBRARIES ${PostgreSQL_LIBRARIES})
|
||||
set(PG_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIRS})
|
||||
message(STATUS "pg inc: " ${PostgreSQL_INCLUDE_DIRS})
|
||||
add_library(pg_lib INTERFACE IMPORTED)
|
||||
set_target_properties(pg_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${PostgreSQL_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${PostgreSQL_LIBRARIES}")
|
||||
mark_as_advanced(PG_INCLUDE_DIRS PG_LIBRARIES)
|
||||
endif(PostgreSQL_FOUND)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(pg
|
||||
DEFAULT_MSG
|
||||
PG_LIBRARIES
|
||||
PG_INCLUDE_DIRS)
|
16
vendors/drogon/conanfile.txt
vendored
Normal file
16
vendors/drogon/conanfile.txt
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
[requires]
|
||||
jsoncpp/1.9.4
|
||||
zlib/1.2.11
|
||||
gtest/1.10.0
|
||||
sqlite3/3.40.1
|
||||
#libpq/13.2
|
||||
openssl/1.1.1t
|
||||
hiredis/1.0.0
|
||||
brotli/1.0.9
|
||||
|
||||
[generators]
|
||||
CMakeToolchain
|
||||
|
||||
[options]
|
||||
|
||||
[imports]
|
354
vendors/drogon/config.example.json
vendored
Normal file
354
vendors/drogon/config.example.json
vendored
Normal file
@ -0,0 +1,354 @@
|
||||
/* This is a JSON format configuration file
|
||||
*/
|
||||
{
|
||||
/*
|
||||
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
||||
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||
"ssl": {
|
||||
"cert": "../../trantor/trantor/tests/server.crt",
|
||||
"key": "../../trantor/trantor/tests/server.key",
|
||||
"conf": [
|
||||
//["Options", "-SessionTicket"],
|
||||
//["Options", "Compression"]
|
||||
]
|
||||
},
|
||||
"listeners": [
|
||||
{
|
||||
//address: Ip address,0.0.0.0 by default
|
||||
"address": "0.0.0.0",
|
||||
//port: Port number
|
||||
"port": 80,
|
||||
//https: If true, use https for security,false by default
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
//cert,key: Cert file path and key file path, empty by default,
|
||||
//if empty, use the global setting
|
||||
"cert": "",
|
||||
"key": "",
|
||||
//use_old_tls: enable the TLS1.0/1.1, false by default
|
||||
"use_old_tls": false,
|
||||
"ssl_conf": [
|
||||
//["MinProtocol", "TLSv1.3"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"db_clients": [
|
||||
{
|
||||
//name: Name of the client,'default' by default
|
||||
//"name":"",
|
||||
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||
"rdbms": "postgresql",
|
||||
//filename: Sqlite3 db file name
|
||||
//"filename":"",
|
||||
//host: Server address,localhost by default
|
||||
"host": "127.0.0.1",
|
||||
//port: Server port, 5432 by default
|
||||
"port": 5432,
|
||||
//dbname: Database name
|
||||
"dbname": "test",
|
||||
//user: 'postgres' by default
|
||||
"user": "",
|
||||
//passwd: '' by default
|
||||
"passwd": "",
|
||||
//is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
//any synchronous interface of it.
|
||||
"is_fast": false,
|
||||
//client_encoding: The character set used by the client. it is empty string by default which
|
||||
//means use the default character set.
|
||||
//"client_encoding": "",
|
||||
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
//connections per IO thread, otherwise it is the total number of all connections.
|
||||
"number_of_connections": 1,
|
||||
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0,
|
||||
//"auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||
// the wiki for more details.
|
||||
"auto_batch": false
|
||||
}
|
||||
],
|
||||
"redis_clients": [
|
||||
{
|
||||
//name: Name of the client,'default' by default
|
||||
//"name":"",
|
||||
//host: Server IP, 127.0.0.1 by default
|
||||
"host": "127.0.0.1",
|
||||
//port: Server port, 6379 by default
|
||||
"port": 6379,
|
||||
//username: '' by default which means 'default' in redis ACL
|
||||
"username": "",
|
||||
//passwd: '' by default
|
||||
"passwd": "",
|
||||
//db index: 0 by default
|
||||
"db": 0,
|
||||
//is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
//any synchronous interface of it.
|
||||
"is_fast": false,
|
||||
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
//connections per IO thread, otherwise it is the total number of all connections.
|
||||
"number_of_connections": 1,
|
||||
//timeout: -1.0 by default, in seconds, the timeout for executing a command.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0
|
||||
}
|
||||
],*/
|
||||
"app": {
|
||||
//number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
|
||||
//is the number of CPU cores
|
||||
"number_of_threads": 1,
|
||||
//enable_session: False by default
|
||||
"enable_session": true,
|
||||
"session_timeout": 0,
|
||||
//string value of SameSite attribute of the Set-Cookie HTTP response header
|
||||
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||
"session_same_site" : "Null",
|
||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
||||
"session_cookie_key": "JSESSIONID",
|
||||
//session_max_age: The max age of the session cookie, -1 by default
|
||||
"session_max_age": -1,
|
||||
//document_root: Root path of HTTP document, default path is ./
|
||||
"document_root": "./",
|
||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
||||
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
|
||||
//to the request for "/".
|
||||
"home_page": "index.html",
|
||||
//use_implicit_page: enable implicit pages if true, true by default
|
||||
"use_implicit_page": true,
|
||||
//implicit_page: Set the file which would the server access in a directory that a user accessed.
|
||||
//For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
|
||||
"implicit_page": "index.html",
|
||||
//static_file_headers: Headers for static files
|
||||
/*"static_file_headers": [
|
||||
{
|
||||
"name": "field-name",
|
||||
"value": "field-value"
|
||||
}
|
||||
],*/
|
||||
//upload_path: The path to save the uploaded file. "uploads" by default.
|
||||
//If the path isn't prefixed with /, ./ or ../,
|
||||
//it is relative path of document_root path
|
||||
"upload_path": "uploads",
|
||||
/* file_types:
|
||||
* HTTP download file types,The file types supported by drogon
|
||||
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
|
||||
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
|
||||
* "gif", "bmp", "ico", "icns", etc. */
|
||||
"file_types": [
|
||||
"gif",
|
||||
"png",
|
||||
"jpg",
|
||||
"js",
|
||||
"css",
|
||||
"html",
|
||||
"ico",
|
||||
"swf",
|
||||
"xap",
|
||||
"apk",
|
||||
"cur",
|
||||
"xml",
|
||||
"webp",
|
||||
"svg"
|
||||
],
|
||||
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||
"mime": {
|
||||
// "text/markdown": "md",
|
||||
// "text/gemini": ["gmi", "gemini"]
|
||||
},
|
||||
//locations: An array of locations of static files for GET requests.
|
||||
"locations": [
|
||||
{
|
||||
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
|
||||
//"uri_prefix": "/.well-known/acme-challenge/",
|
||||
//default_content_type: The default content type of the static files without
|
||||
//an extension. empty string by default.
|
||||
"default_content_type": "text/plain",
|
||||
//alias: The location in file system, if it is prefixed with "/", it
|
||||
//presents an absolute path, otherwise it presents a relative path to
|
||||
//the document_root path.
|
||||
//The default value is "" which means use the document root path as the location base path.
|
||||
"alias": "",
|
||||
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
|
||||
"is_case_sensitive": false,
|
||||
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
|
||||
"allow_all": true,
|
||||
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
|
||||
"is_recursive": true,
|
||||
//filters: string array, the filters applied to the location.
|
||||
"filters": []
|
||||
}
|
||||
],
|
||||
//max_connections: maximum number of connections, 100000 by default
|
||||
"max_connections": 100000,
|
||||
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
||||
"max_connections_per_ip": 0,
|
||||
//Load_dynamic_views: False by default, when set to true, drogon
|
||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||
//by "dynamic_views_path"
|
||||
"load_dynamic_views": false,
|
||||
//dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
|
||||
//it is relative path of document_root path
|
||||
"dynamic_views_path": [
|
||||
"./views"
|
||||
],
|
||||
//dynamic_views_output_path: Default by an empty string which means the output path of source
|
||||
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
|
||||
//path of the current working directory.
|
||||
"dynamic_views_output_path": "",
|
||||
//json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
|
||||
"json_parser_stack_limit": 1000,
|
||||
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
|
||||
"enable_unicode_escaping_in_json": true,
|
||||
//float_precision_in_json: set precision of float number in json.
|
||||
"float_precision_in_json": {
|
||||
//precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
|
||||
"precision": 0,
|
||||
//precision_type: must be "significant" or "decimal", defaults to "significant" that means
|
||||
//setting max number of significant digits in string, "decimal" means setting max number of
|
||||
//digits after "." in string
|
||||
"precision_type": "significant"
|
||||
},
|
||||
//log: Set log output, drogon output logs to stdout by default
|
||||
"log": {
|
||||
//use_spdlog: Use spdlog library to log
|
||||
//"use_spdlog": false
|
||||
"use_spdlog": false,
|
||||
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||
//"log_path": "./",
|
||||
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||
//drogon.log ...
|
||||
"logfile_base_name": "",
|
||||
//log_size_limit: 100000000 bytes by default,
|
||||
//When the log file size reaches "log_size_limit", the log file is switched.
|
||||
"log_size_limit": 100000000,
|
||||
//max_files: 0 by default,
|
||||
//When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
|
||||
"max_files": 0,
|
||||
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||
//The TRACE level is only valid when built in DEBUG mode.
|
||||
"log_level": "DEBUG",
|
||||
//display_local_time: false by default, if true, the log time is displayed in local time
|
||||
"display_local_time": false
|
||||
},
|
||||
//run_as_daemon: False by default
|
||||
"run_as_daemon": false,
|
||||
//handle_sig_term: True by default
|
||||
"handle_sig_term": true,
|
||||
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
|
||||
"relaunch_on_error": false,
|
||||
//use_sendfile: True by default, if true, the program
|
||||
//uses sendfile() system-call to send static files to clients;
|
||||
"use_sendfile": true,
|
||||
//use_gzip: True by default, use gzip to compress the response body's content;
|
||||
"use_gzip": true,
|
||||
//use_brotli: False by default, use brotli to compress the response body's content;
|
||||
"use_brotli": false,
|
||||
//static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
|
||||
//0 means cache forever, the negative value means no cache
|
||||
"static_files_cache_time": 5,
|
||||
//simple_controllers_map: Used to configure mapping from path to simple controller
|
||||
//"simple_controllers_map": [
|
||||
// {
|
||||
// "path": "/path/name",
|
||||
// "controller": "controllerClassName",
|
||||
// "http_methods": [
|
||||
// "get",
|
||||
// "post"
|
||||
// ],
|
||||
// "filters": [
|
||||
// "FilterClassName"
|
||||
// ]
|
||||
// }
|
||||
//],
|
||||
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||
//of the connection without read or write
|
||||
"idle_connection_timeout": 60,
|
||||
//server_header_field: Set the 'Server' header field in each response sent by drogon,
|
||||
//empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
|
||||
"server_header_field": "",
|
||||
//enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
|
||||
//value is true.
|
||||
"enable_server_header": true,
|
||||
//enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
|
||||
//value is true.
|
||||
"enable_date_header": true,
|
||||
//keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
|
||||
//After the maximum number of requests are made, the connection is closed.
|
||||
//The default value of 0 means no limit.
|
||||
"keepalive_requests": 0,
|
||||
//pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
|
||||
//After the maximum number of requests are made, the connection is closed.
|
||||
//The default value of 0 means no limit.
|
||||
"pipelining_requests": 0,
|
||||
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
//The default value of gzip_static is true.
|
||||
"gzip_static": true,
|
||||
//br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".br" in the same path and send the compressed file to the client.
|
||||
//The default value of br_static is true.
|
||||
"br_static": true,
|
||||
//client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_body_size": "1M",
|
||||
//max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
|
||||
//If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
|
||||
//Setting it to "" means no limit.
|
||||
"client_max_memory_body_size": "64K",
|
||||
//client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_websocket_message_size": "128K",
|
||||
//reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||
"reuse_port": false,
|
||||
// enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||
// will be rejected.
|
||||
"enabled_compressed_request": false
|
||||
},
|
||||
//plugins: Define all plugins running in the application
|
||||
"plugins": [
|
||||
{
|
||||
//name: The class name of the plugin
|
||||
"name": "drogon::plugin::PromExporter",
|
||||
//dependencies: Plugins that the plugin depends on. It can be commented out
|
||||
"dependencies": [],
|
||||
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||
//It can be commented out
|
||||
"config": {
|
||||
"path": "/metrics"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drogon::plugin::AccessLogger",
|
||||
"dependencies": [],
|
||||
"config": {
|
||||
"use_spdlog": false,
|
||||
"log_path": "",
|
||||
"log_format": "",
|
||||
"log_file": "access.log",
|
||||
"log_size_limit": 0,
|
||||
"use_local_time": true,
|
||||
"log_index": 0,
|
||||
// "show_microseconds": true,
|
||||
// "custom_time_format": "",
|
||||
// "use_real_ip": false
|
||||
}
|
||||
}
|
||||
],
|
||||
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||
"custom_config": {
|
||||
"realm": "drogonRealm",
|
||||
"opaque": "drogonOpaque",
|
||||
"credentials": [
|
||||
{
|
||||
"user": "drogon",
|
||||
"password": "dr0g0n"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
296
vendors/drogon/config.example.yaml
vendored
Normal file
296
vendors/drogon/config.example.yaml
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
# This is a YAML format configuration file
|
||||
|
||||
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
||||
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||
# ssl:
|
||||
# cert: ../../trantor/trantor/tests/server.pem
|
||||
# key: ../../trantor/trantor/tests/server.pem
|
||||
# conf: [
|
||||
# # [Options, -SessionTicket],
|
||||
# # [Options, Compression]
|
||||
# ]
|
||||
# listeners:
|
||||
# # address: Ip address,0.0.0.0 by default
|
||||
# - address: 0.0.0.0
|
||||
# # port: Port number
|
||||
# port: 80
|
||||
# # https: If true, use https for security,false by default
|
||||
# https: false
|
||||
# - address: 0.0.0.0
|
||||
# port: 443
|
||||
# https: true
|
||||
# # cert,key: Cert file path and key file path, empty by default,
|
||||
# # if empty, use the global setting
|
||||
# cert: ''
|
||||
# key: ''
|
||||
# # use_old_tls: enable the TLS1.0/1.1, false by default
|
||||
# use_old_tls: false
|
||||
# ssl_conf: [
|
||||
# # [MinProtocol, TLSv1.3]
|
||||
# ]
|
||||
# db_clients:
|
||||
# # name: Name of the client,'default' by default
|
||||
# - name: ''
|
||||
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||
# rdbms: postgresql
|
||||
# # filename: Sqlite3 db file name
|
||||
# # filename: '',
|
||||
# # host: Server address,localhost by default
|
||||
# host: 127.0.0.1
|
||||
# # port: Server port, 5432 by default
|
||||
# port: 5432
|
||||
# # dbname: Database name
|
||||
# dbname: test
|
||||
# # user: 'postgres' by default
|
||||
# user: ''
|
||||
# # passwd: '' by default
|
||||
# passwd: ''
|
||||
# # is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
# # any synchronous interface of it.
|
||||
# is_fast: false
|
||||
# # client_encoding: The character set used by the client. it is empty string by default which
|
||||
# # means use the default character set.
|
||||
# # client_encoding: '',
|
||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||
# number_of_connections: 1
|
||||
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
||||
# # zero or negative value means no timeout.
|
||||
# timeout: -1
|
||||
# # "auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||
# # the wiki for more details.
|
||||
# auto_batch: false
|
||||
# redis_clients:
|
||||
# # name: Name of the client,'default' by default
|
||||
# - name: ''
|
||||
# # host: Server IP, 127.0.0.1 by default
|
||||
# host: 127.0.0.1
|
||||
# # port: Server port, 6379 by default
|
||||
# port: 6379
|
||||
# # username: '' by default which means 'default' in redis ACL
|
||||
# username: ''
|
||||
# # passwd: '' by default
|
||||
# passwd: ''
|
||||
# # db index: 0 by default
|
||||
# db: 0
|
||||
# # is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
# # any synchronous interface of it.
|
||||
# is_fast: false
|
||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||
# number_of_connections: 1
|
||||
# # timeout: -1.0 by default, in seconds, the timeout for executing a command.
|
||||
# # zero or negative value means no timeout.
|
||||
# timeout: -1
|
||||
app:
|
||||
# number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
|
||||
# is the number of CPU cores
|
||||
number_of_threads: 1
|
||||
# enable_session: False by default
|
||||
enable_session: true
|
||||
session_timeout: 0
|
||||
# string value of SameSite attribute of the Set-Cookie HTTP response header
|
||||
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||
session_same_site: 'Null'
|
||||
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
||||
session_cookie_key: 'JSESSIONID'
|
||||
# session_max_age: The max age of the session cookie, -1 by default
|
||||
session_max_age: -1
|
||||
# document_root: Root path of HTTP document, default path is ./
|
||||
document_root: ./
|
||||
# home_page: Set the HTML file of the home page, the default value is "index.html"
|
||||
# If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
|
||||
# to the request for "/".
|
||||
home_page: index.html
|
||||
# use_implicit_page: enable implicit pages if true, true by default
|
||||
use_implicit_page: true
|
||||
# implicit_page: Set the file which would the server access in a directory that a user accessed.
|
||||
# For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
|
||||
implicit_page: index.html
|
||||
# static_file_headers: Headers for static files
|
||||
# static_file_headers:
|
||||
# - name: field-name
|
||||
# value: field-value
|
||||
# upload_path: The path to save the uploaded file. "uploads" by default.
|
||||
# If the path isn't prefixed with /, ./ or ../,
|
||||
# it is relative path of document_root path
|
||||
upload_path: uploads
|
||||
# file_types:
|
||||
# HTTP download file types,The file types supported by drogon
|
||||
# by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
|
||||
# "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
|
||||
# "gif", "bmp", "ico", "icns", etc.
|
||||
file_types:
|
||||
- gif
|
||||
- png
|
||||
- jpg
|
||||
- js
|
||||
- css
|
||||
- html
|
||||
- ico
|
||||
- swf
|
||||
- xap
|
||||
- apk
|
||||
- cur
|
||||
- xml
|
||||
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||
mime: {
|
||||
# text/markdown: md,
|
||||
# text/gemini: [gmi, gemini]
|
||||
}
|
||||
# locations: An array of locations of static files for GET requests.
|
||||
locations:
|
||||
# uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
|
||||
- uri_prefix: '' # /.well-known/acme-challenge/
|
||||
# default_content_type: The default content type of the static files without
|
||||
# an extension. empty string by default.
|
||||
default_content_type: text/plain
|
||||
# alias: The location in file system, if it is prefixed with "/", it
|
||||
# presents an absolute path, otherwise it presents a relative path to
|
||||
# the document_root path.
|
||||
# The default value is "" which means use the document root path as the location base path.
|
||||
alias: ''
|
||||
# is_case_sensitive: indicates whether the URI prefix is case sensitive.
|
||||
is_case_sensitive: false
|
||||
# allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
|
||||
allow_all: true
|
||||
# is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
|
||||
is_recursive: true
|
||||
# filters: string array, the filters applied to the location.
|
||||
filters: []
|
||||
# max_connections: maximum number of connections, 100000 by default
|
||||
max_connections: 100000
|
||||
# max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
||||
max_connections_per_ip: 0
|
||||
# Load_dynamic_views: False by default, when set to true, drogon
|
||||
# compiles and loads dynamically "CSP View Files" in directories defined
|
||||
# by "dynamic_views_path"
|
||||
load_dynamic_views: false
|
||||
# dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
|
||||
# it is relative path of document_root path
|
||||
dynamic_views_path:
|
||||
- ./views
|
||||
# dynamic_views_output_path: Default by an empty string which means the output path of source
|
||||
# files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
|
||||
# path of the current working directory.
|
||||
dynamic_views_output_path: ''
|
||||
# json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
|
||||
json_parser_stack_limit: 1000
|
||||
# enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
|
||||
enable_unicode_escaping_in_json: true
|
||||
# float_precision_in_json: set precision of float number in json.
|
||||
float_precision_in_json:
|
||||
# precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
|
||||
precision: 0
|
||||
# precision_type: must be "significant" or "decimal", defaults to "significant" that means
|
||||
# setting max number of significant digits in string, "decimal" means setting max number of
|
||||
# digits after "." in string
|
||||
precision_type: significant
|
||||
# log: Set log output, drogon output logs to stdout by default
|
||||
log:
|
||||
# use_spdlog: Use spdlog library to log
|
||||
use_spdlog: false,
|
||||
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||
# log_path: ./
|
||||
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||
# drogon.log ...
|
||||
logfile_base_name: ''
|
||||
# log_size_limit: 100000000 bytes by default,
|
||||
# When the log file size reaches "log_size_limit", the log file is switched.
|
||||
log_size_limit: 100000000
|
||||
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||
# The TRACE level is only valid when built in DEBUG mode.
|
||||
log_level: DEBUG
|
||||
# display_local_time: false by default, if true, the log time is displayed in local time
|
||||
display_local_time: false
|
||||
# run_as_daemon: False by default
|
||||
run_as_daemon: false
|
||||
# handle_sig_term: True by default
|
||||
handle_sig_term: true
|
||||
# relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
|
||||
relaunch_on_error: false
|
||||
# use_sendfile: True by default, if true, the program
|
||||
# uses sendfile() system-call to send static files to clients;
|
||||
use_sendfile: true
|
||||
# use_gzip: True by default, use gzip to compress the response body's content;
|
||||
use_gzip: true
|
||||
# use_brotli: False by default, use brotli to compress the response body's content;
|
||||
use_brotli: false
|
||||
# static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
|
||||
# 0 means cache forever, the negative value means no cache
|
||||
static_files_cache_time: 5
|
||||
# simple_controllers_map: Used to configure mapping from path to simple controller
|
||||
simple_controllers_map:
|
||||
- path: /path/name
|
||||
controller: controllerClassName
|
||||
http_methods:
|
||||
- get
|
||||
- post
|
||||
filters:
|
||||
- FilterClassName
|
||||
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||
# of the connection without read or write
|
||||
idle_connection_timeout: 60
|
||||
# server_header_field: Set the 'Server' header field in each response sent by drogon,
|
||||
# empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
|
||||
server_header_field: ''
|
||||
# enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
|
||||
# value is true.
|
||||
enable_server_header: true
|
||||
# enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
|
||||
# value is true.
|
||||
enable_date_header: true
|
||||
# keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
|
||||
# After the maximum number of requests are made, the connection is closed.
|
||||
# The default value of 0 means no limit.
|
||||
keepalive_requests: 0
|
||||
# pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
|
||||
# After the maximum number of requests are made, the connection is closed.
|
||||
# The default value of 0 means no limit.
|
||||
pipelining_requests: 0
|
||||
# gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
# file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
# The default value of gzip_static is true.
|
||||
gzip_static: true
|
||||
# br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
# file with the extension ".br" in the same path and send the compressed file to the client.
|
||||
# The default value of br_static is true.
|
||||
br_static: true
|
||||
# client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
|
||||
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
client_max_body_size: 1M
|
||||
# max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
|
||||
# If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
|
||||
# Setting it to "" means no limit.
|
||||
client_max_memory_body_size: 64K
|
||||
# client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
|
||||
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
client_max_websocket_message_size: 128K
|
||||
# reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||
reuse_port: false
|
||||
# enabled_compresed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||
# will be rejected.
|
||||
enabled_compresed_request: false
|
||||
# plugins: Define all plugins running in the application
|
||||
plugins:
|
||||
# name: The class name of the plugin
|
||||
- name: '' # drogon::plugin::SecureSSLRedirector
|
||||
# dependencies: Plugins that the plugin depends on. It can be commented out
|
||||
dependencies: []
|
||||
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||
# It can be commented out
|
||||
config:
|
||||
ssl_redirect_exempt:
|
||||
- .*\.jpg
|
||||
secure_ssl_host: 'localhost:8849'
|
||||
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||
custom_config:
|
||||
realm: drogonRealm
|
||||
opaque: drogonOpaque
|
||||
credentials:
|
||||
- user: drogon
|
||||
password: dr0g0n
|
||||
|
42
vendors/drogon/docker/alpine/Dockerfile
vendored
Normal file
42
vendors/drogon/docker/alpine/Dockerfile
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
FROM alpine:3.14
|
||||
|
||||
ARG USER=drogon
|
||||
ARG UID=1000
|
||||
ARG GID=1000
|
||||
ARG USER_HOME=/drogon
|
||||
|
||||
ENV TZ=UTC
|
||||
|
||||
RUN apk update && apk --no-cache --upgrade add tzdata \
|
||||
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
|
||||
&& echo $TZ > /etc/timezone
|
||||
|
||||
RUN apk --no-cache --upgrade add \
|
||||
sudo curl wget cmake make pkgconfig git gcc g++ \
|
||||
openssl libressl-dev jsoncpp-dev util-linux-dev zlib-dev c-ares-dev \
|
||||
postgresql-dev mariadb-dev sqlite-dev hiredis-dev
|
||||
|
||||
RUN addgroup -S -g $GID $USER \
|
||||
&& adduser -D -u $UID -G $USER -h $USER_HOME $USER \
|
||||
&& mkdir -p /etc/sudoers.d \
|
||||
&& echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER \
|
||||
&& chmod 0440 /etc/sudoers.d/$USER
|
||||
|
||||
USER $USER
|
||||
WORKDIR $USER_HOME
|
||||
|
||||
ENV LANG=en_US.UTF-8 \
|
||||
LANGUAGE=en_US:en \
|
||||
LC_ALL=en_US.UTF-8 \
|
||||
CC=gcc \
|
||||
CXX=g++ \
|
||||
AR=gcc-ar \
|
||||
RANLIB=gcc-ranlib \
|
||||
DROGON_INSTALLED_ROOT=$USER_HOME/install
|
||||
|
||||
RUN wget -O $USER_HOME/version.json https://api.github.com/repos/an-tao/drogon/git/refs/heads/master \
|
||||
&& git clone https://github.com/an-tao/drogon $DROGON_INSTALLED_ROOT
|
||||
|
||||
RUN cd $DROGON_INSTALLED_ROOT \
|
||||
&& sed -i 's/bash/sh/' ./build.sh \
|
||||
&& ./build.sh
|
32
vendors/drogon/docker/alpine/README.md
vendored
Normal file
32
vendors/drogon/docker/alpine/README.md
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
## Build Docker Image
|
||||
|
||||
```shell
|
||||
$ cd drogon/docker/alpine # from this repository
|
||||
$ docker build --no-cache --build-arg UID=`id -u` --build-arg GID=`id -g` -t drogon-alpine . # include last dot(.)
|
||||
```
|
||||
|
||||
## Create a Drogon Project
|
||||
|
||||
```shell
|
||||
$ cd ~/drogon_app # example
|
||||
$ docker run --rm -v="$PWD:/drogon/app" -w="/drogon/app" drogon-alpine drogon_ctl create project hello_world
|
||||
```
|
||||
|
||||
## Build the Project
|
||||
|
||||
```shell
|
||||
$ cd hello_world
|
||||
$ docker run --rm --volume="$PWD:/drogon/app" -w="/drogon/app/build" drogon-alpine sh -c "cmake .. && make"
|
||||
```
|
||||
|
||||
## Start Server
|
||||
|
||||
```shell
|
||||
$ docker run --name drogon_test --rm -u 0 -v="$PWD/build:/drogon/app" -w="/drogon/app" -p 8080:80 -d drogon-alpine ./hello_world # expose port 80 to 8080
|
||||
```
|
||||
|
||||
## Stop Server
|
||||
|
||||
```shell
|
||||
$ docker kill drogon_test
|
||||
```
|
21
vendors/drogon/docker/arch/Dockerfile
vendored
Normal file
21
vendors/drogon/docker/arch/Dockerfile
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
FROM archlinux:base-20210307.0.16708
|
||||
|
||||
RUN pacman -Syu --noconfirm && pacman -S wget sudo cmake make git gcc jsoncpp postgresql mariadb-clients hiredis --noconfirm
|
||||
|
||||
ENV LANG=en_US.UTF-8 \
|
||||
LANGUAGE=en_US:en \
|
||||
LC_ALL=en_US.UTF-8 \
|
||||
CC=gcc \
|
||||
CXX=g++ \
|
||||
AR=gcc-ar \
|
||||
RANLIB=gcc-ranlib \
|
||||
IROOT=/install
|
||||
|
||||
ENV DROGON_ROOT="$IROOT/drogon"
|
||||
|
||||
ADD https://api.github.com/repos/an-tao/drogon/git/refs/heads/master $IROOT/version.json
|
||||
RUN git clone https://github.com/an-tao/drogon $DROGON_ROOT
|
||||
|
||||
WORKDIR $DROGON_ROOT
|
||||
|
||||
RUN ./build.sh
|
30
vendors/drogon/docker/ubuntu/Dockerfile
vendored
Normal file
30
vendors/drogon/docker/ubuntu/Dockerfile
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV TZ=UTC
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN apt-get update -yqq \
|
||||
&& apt-get install -yqq --no-install-recommends software-properties-common \
|
||||
sudo curl wget cmake make pkg-config locales git gcc-11 g++-11 \
|
||||
openssl libssl-dev libjsoncpp-dev uuid-dev zlib1g-dev libc-ares-dev\
|
||||
postgresql-server-dev-all libmariadb-dev libsqlite3-dev libhiredis-dev\
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& locale-gen en_US.UTF-8
|
||||
|
||||
ENV LANG=en_US.UTF-8 \
|
||||
LANGUAGE=en_US:en \
|
||||
LC_ALL=en_US.UTF-8 \
|
||||
CC=gcc-11 \
|
||||
CXX=g++-11 \
|
||||
AR=gcc-ar-11 \
|
||||
RANLIB=gcc-ranlib-11 \
|
||||
IROOT=/install
|
||||
|
||||
ENV DROGON_ROOT="$IROOT/drogon"
|
||||
|
||||
ADD https://api.github.com/repos/drogonframework/drogon/git/refs/heads/master $IROOT/version.json
|
||||
RUN git clone https://github.com/drogonframework/drogon $DROGON_ROOT
|
||||
|
||||
WORKDIR $DROGON_ROOT
|
||||
|
||||
RUN ./build.sh
|
BIN
vendors/drogon/drogon.jpg
vendored
Normal file
BIN
vendors/drogon/drogon.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
88
vendors/drogon/drogon_ctl/CMakeLists.txt
vendored
Executable file
88
vendors/drogon/drogon_ctl/CMakeLists.txt
vendored
Executable file
@ -0,0 +1,88 @@
|
||||
set(ctl_sources
|
||||
cmd.cc
|
||||
create.cc
|
||||
create_controller.cc
|
||||
create_filter.cc
|
||||
create_model.cc
|
||||
create_plugin.cc
|
||||
create_project.cc
|
||||
create_view.cc
|
||||
help.cc
|
||||
main.cc
|
||||
press.cc
|
||||
version.cc)
|
||||
add_executable(_drogon_ctl
|
||||
main.cc
|
||||
cmd.cc
|
||||
create.cc
|
||||
create_view.cc)
|
||||
target_link_libraries(_drogon_ctl ${PROJECT_NAME})
|
||||
if (WIN32 AND BUILD_SHARED_LIBS)
|
||||
set(DROGON_FILE $<TARGET_FILE:drogon>)
|
||||
if (USE_SUBMODULE)
|
||||
set(TRANTOR_FILE $<TARGET_FILE:trantor>)
|
||||
else()
|
||||
set(TRANTOR_FILE $<TARGET_FILE:Trantor::Trantor>)
|
||||
endif()
|
||||
add_custom_command(TARGET _drogon_ctl POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCTL_FILE=${DROGON_FILE}
|
||||
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
|
||||
-P
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
|
||||
add_custom_command(TARGET _drogon_ctl POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCTL_FILE=${TRANTOR_FILE}
|
||||
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
|
||||
-P
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
|
||||
endif()
|
||||
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/templates/*.csp)
|
||||
foreach(cspFile ${SCP_LIST})
|
||||
message(STATUS "cspFile:" ${cspFile})
|
||||
get_filename_component(classname ${cspFile} NAME_WE)
|
||||
message(STATUS "view classname:" ${classname})
|
||||
add_custom_command(OUTPUT ${classname}.h ${classname}.cc
|
||||
COMMAND $<TARGET_FILE:_drogon_ctl>
|
||||
ARGS
|
||||
create
|
||||
view
|
||||
${cspFile}
|
||||
DEPENDS ${cspFile}
|
||||
VERBATIM)
|
||||
set(TEMPL_SRC ${TEMPL_SRC} ${classname}.cc)
|
||||
endforeach()
|
||||
add_executable(drogon_ctl ${ctl_sources} ${TEMPL_SRC})
|
||||
target_link_libraries(drogon_ctl PRIVATE ${PROJECT_NAME})
|
||||
target_include_directories(drogon_ctl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_dependencies(drogon_ctl _drogon_ctl)
|
||||
if(WIN32)
|
||||
target_link_libraries(drogon_ctl PRIVATE ws2_32 Rpcrt4 iphlpapi)
|
||||
endif(WIN32)
|
||||
if(APPLE)
|
||||
target_link_libraries(drogon_ctl PRIVATE resolv)
|
||||
endif()
|
||||
message(STATUS "bin:" ${INSTALL_BIN_DIR})
|
||||
install(TARGETS drogon_ctl RUNTIME DESTINATION ${INSTALL_BIN_DIR})
|
||||
if(WIN32)
|
||||
set(CTL_FILE $<TARGET_FILE:drogon_ctl>)
|
||||
add_custom_command(TARGET drogon_ctl POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCTL_FILE=${CTL_FILE}
|
||||
-DINSTALL_BIN_DIR=${INSTALL_BIN_DIR}
|
||||
-DRENAME_EXE=ON
|
||||
-P
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
|
||||
else(WIN32)
|
||||
install(CODE "execute_process( \
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||
./drogon_ctl \
|
||||
./dg_ctl \
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dg_ctl"
|
||||
DESTINATION ${INSTALL_BIN_DIR})
|
||||
endif(WIN32)
|
||||
set(ctl_targets _drogon_ctl drogon_ctl)
|
||||
set_property(TARGET ${ctl_targets} PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD})
|
||||
set_property(TARGET ${ctl_targets} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
set_property(TARGET ${ctl_targets} PROPERTY CXX_EXTENSIONS OFF)
|
44
vendors/drogon/drogon_ctl/CommandHandler.h
vendored
Normal file
44
vendors/drogon/drogon_ctl/CommandHandler.h
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
*
|
||||
* CommandHandler.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CommandHandler : public virtual drogon::DrObjectBase
|
||||
{
|
||||
public:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) = 0;
|
||||
|
||||
virtual bool isTopCommand()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual std::string script()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string detail()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual ~CommandHandler()
|
||||
{
|
||||
}
|
||||
};
|
8
vendors/drogon/drogon_ctl/CopyDlls.cmake
vendored
Normal file
8
vendors/drogon/drogon_ctl/CopyDlls.cmake
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
make_directory("${INSTALL_BIN_DIR}")
|
||||
get_filename_component(CTL_PATH ${CTL_FILE} DIRECTORY)
|
||||
file(GLOB DLL_FILES ${CTL_PATH}/*.dll)
|
||||
file(COPY ${DLL_FILES} DESTINATION ${INSTALL_BIN_DIR})
|
||||
file(COPY ${CTL_FILE} DESTINATION ${INSTALL_BIN_DIR})
|
||||
if (RENAME_EXE)
|
||||
file(RENAME ${INSTALL_BIN_DIR}/drogon_ctl.exe ${INSTALL_BIN_DIR}/dg_ctl.exe)
|
||||
endif()
|
56
vendors/drogon/drogon_ctl/cmd.cc
vendored
Normal file
56
vendors/drogon/drogon_ctl/cmd.cc
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
*
|
||||
* cmd.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cmd.h"
|
||||
#include "CommandHandler.h"
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <memory>
|
||||
using namespace drogon;
|
||||
|
||||
void exeCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
if (parameters.empty())
|
||||
{
|
||||
std::cout << "incomplete command!use help command to get usage!"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
std::string command = parameters[0];
|
||||
|
||||
std::string handlerName = std::string("drogon_ctl::").append(command);
|
||||
|
||||
parameters.erase(parameters.begin());
|
||||
|
||||
// new command handler to do cmd
|
||||
auto obj = std::shared_ptr<DrObjectBase>(
|
||||
drogon::DrClassMap::newObject(handlerName));
|
||||
if (obj)
|
||||
{
|
||||
auto ctl = std::dynamic_pointer_cast<CommandHandler>(obj);
|
||||
if (ctl)
|
||||
{
|
||||
ctl->handleCommand(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "command not found!use help command to get usage!"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "command error!use help command to get usage!"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
21
vendors/drogon/drogon_ctl/cmd.h
vendored
Executable file
21
vendors/drogon/drogon_ctl/cmd.h
vendored
Executable file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
*
|
||||
* cmd.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
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#define ARGS_ERROR_STR "args error!use help command to get usage!"
|
||||
void exeCommand(std::vector<std::string> ¶meters);
|
56
vendors/drogon/drogon_ctl/create.cc
vendored
Normal file
56
vendors/drogon/drogon_ctl/create.cc
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
*
|
||||
* @file create.cc
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create.h"
|
||||
#include "cmd.h"
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
using namespace drogon_ctl;
|
||||
|
||||
std::string create::detail()
|
||||
{
|
||||
return "Use create command to create some source files of drogon webapp\n\n"
|
||||
"Usage:drogon_ctl create <view|controller|filter|project|model> "
|
||||
"[-options] <object name>\n\n"
|
||||
"drogon_ctl create view <csp file name> [-o <output path>] [-n "
|
||||
"<namespace>] [--path-to-namespace] //create HttpView source files "
|
||||
"from csp files, namespace is prefixed of path-to-namespace\n\n"
|
||||
"drogon_ctl create controller [-s] <[namespace::]class_name> //"
|
||||
"create HttpSimpleController source files\n\n"
|
||||
"drogon_ctl create controller -h <[namespace::]class_name> //"
|
||||
"create HttpController source files\n\n"
|
||||
"drogon_ctl create controller -w <[namespace::]class_name> //"
|
||||
"create WebSocketController source files\n\n"
|
||||
"drogon_ctl create controller -r <[namespace::]class_name> "
|
||||
"[--resource=...]//"
|
||||
"create restful controller source files\n\n"
|
||||
"drogon_ctl create filter <[namespace::]class_name> //"
|
||||
"create a filter named class_name\n\n"
|
||||
"drogon_ctl create plugin <[namespace::]class_name> //"
|
||||
"create a plugin named class_name\n\n"
|
||||
"drogon_ctl create project <project_name> //"
|
||||
"create a project named project_name\n\n"
|
||||
"drogon_ctl create model <model_path> [--table=<table_name>] [-f]//"
|
||||
"create model classes in model_path\n";
|
||||
}
|
||||
|
||||
void create::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
// std::cout<<"create!"<<std::endl;
|
||||
auto createObjName = parameters[0];
|
||||
createObjName = std::string("create_") + createObjName;
|
||||
parameters[0] = createObjName;
|
||||
exeCommand(parameters);
|
||||
}
|
41
vendors/drogon/drogon_ctl/create.h
vendored
Normal file
41
vendors/drogon/drogon_ctl/create.h
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
*
|
||||
* create.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create : public DrObject<create>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶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
|
471
vendors/drogon/drogon_ctl/create_controller.cc
vendored
Normal file
471
vendors/drogon/drogon_ctl/create_controller.cc
vendored
Normal file
@ -0,0 +1,471 @@
|
||||
/**
|
||||
*
|
||||
* create_controller.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create_controller.h"
|
||||
#include "cmd.h"
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
void create_controller::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
// std::cout<<"create!"<<std::endl;
|
||||
ControllerType type = Simple;
|
||||
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter)
|
||||
{
|
||||
if ((*iter)[0] == '-')
|
||||
{
|
||||
if (*iter == "-s" || (*iter == "--simple"))
|
||||
{
|
||||
parameters.erase(iter);
|
||||
break;
|
||||
}
|
||||
else if (*iter == "-a" || *iter == "-h" || *iter == "--http")
|
||||
{
|
||||
type = Http;
|
||||
parameters.erase(iter);
|
||||
break;
|
||||
}
|
||||
else if (*iter == "-w" || *iter == "--websocket")
|
||||
{
|
||||
type = WebSocket;
|
||||
parameters.erase(iter);
|
||||
break;
|
||||
}
|
||||
else if (*iter == "-r" || *iter == "--restful")
|
||||
{
|
||||
type = Restful;
|
||||
parameters.erase(iter);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << ARGS_ERROR_STR << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type != Restful)
|
||||
createController(parameters, type);
|
||||
else
|
||||
{
|
||||
std::string resource;
|
||||
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter)
|
||||
{
|
||||
if ((*iter).find("--resource=") == 0)
|
||||
{
|
||||
resource = (*iter).substr(strlen("--resource="));
|
||||
parameters.erase(iter);
|
||||
break;
|
||||
}
|
||||
if ((*iter)[0] == '-')
|
||||
{
|
||||
std::cerr << "Error parameter for '" << (*iter) << "'"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (parameters.size() > 1)
|
||||
{
|
||||
std::cerr << "Too many parameters" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
auto className = parameters[0];
|
||||
createARestfulController(className, resource);
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::newSimpleControllerHeaderFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className)
|
||||
{
|
||||
file << "#pragma once\n";
|
||||
file << "\n";
|
||||
file << "#include <drogon/HttpSimpleController.h>\n";
|
||||
file << "\n";
|
||||
file << "using namespace drogon;\n";
|
||||
file << "\n";
|
||||
std::string class_name = className;
|
||||
std::string namepace_path = "/";
|
||||
auto pos = class_name.find("::");
|
||||
size_t namespaceCount = 0;
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
++namespaceCount;
|
||||
auto namespaceName = class_name.substr(0, pos);
|
||||
class_name = class_name.substr(pos + 2);
|
||||
file << "namespace " << namespaceName << "\n";
|
||||
namepace_path.append(namespaceName).append("/");
|
||||
file << "{\n";
|
||||
pos = class_name.find("::");
|
||||
}
|
||||
file << "class " << class_name << " : public drogon::HttpSimpleController<"
|
||||
<< class_name << ">\n";
|
||||
file << "{\n";
|
||||
file << " public:\n";
|
||||
file << " void asyncHandleHttpRequest(const HttpRequestPtr& "
|
||||
"req, std::function<void (const HttpResponsePtr &)> &&callback) "
|
||||
"override;\n";
|
||||
|
||||
file << " PATH_LIST_BEGIN\n";
|
||||
file << " // list path definitions here;\n";
|
||||
file << " "
|
||||
"// PATH_ADD(\"/"
|
||||
"path\", \"filter1\", \"filter2\", HttpMethod1, HttpMethod2...);\n";
|
||||
file << " PATH_LIST_END\n";
|
||||
file << "};\n";
|
||||
while (namespaceCount > 0)
|
||||
{
|
||||
--namespaceCount;
|
||||
file << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::newSimpleControllerSourceFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename)
|
||||
{
|
||||
file << "#include \"" << filename << ".h\"\n";
|
||||
file << "\n";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\n";
|
||||
file << "\n";
|
||||
class_name = className.substr(pos + 2);
|
||||
}
|
||||
file << "void " << class_name
|
||||
<< "::asyncHandleHttpRequest(const HttpRequestPtr& req, "
|
||||
"std::function<void (const HttpResponsePtr &)> &&callback)\n";
|
||||
file << "{\n";
|
||||
file << " // write your application logic here\n";
|
||||
file << "}\n";
|
||||
}
|
||||
|
||||
void create_controller::newWebsockControllerHeaderFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className)
|
||||
{
|
||||
file << "#pragma once\n";
|
||||
file << "\n";
|
||||
file << "#include <drogon/WebSocketController.h>\n";
|
||||
file << "\n";
|
||||
file << "using namespace drogon;\n";
|
||||
file << "\n";
|
||||
std::string class_name = className;
|
||||
std::string namepace_path = "/";
|
||||
auto pos = class_name.find("::");
|
||||
size_t namespaceCount = 0;
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
++namespaceCount;
|
||||
auto namespaceName = class_name.substr(0, pos);
|
||||
class_name = class_name.substr(pos + 2);
|
||||
file << "namespace " << namespaceName << "\n";
|
||||
namepace_path.append(namespaceName).append("/");
|
||||
file << "{\n";
|
||||
pos = class_name.find("::");
|
||||
}
|
||||
file << "class " << class_name << " : public drogon::WebSocketController<"
|
||||
<< class_name << ">\n";
|
||||
file << "{\n";
|
||||
file << " public:\n";
|
||||
file << " void handleNewMessage(const WebSocketConnectionPtr&,\n";
|
||||
file << " std::string &&,\n";
|
||||
file << " const WebSocketMessageType &) "
|
||||
"override;\n";
|
||||
file << " void handleNewConnection(const HttpRequestPtr &,\n";
|
||||
file << " const "
|
||||
"WebSocketConnectionPtr&) override;\n";
|
||||
file << " void handleConnectionClosed(const "
|
||||
"WebSocketConnectionPtr&) override;\n";
|
||||
file << " WS_PATH_LIST_BEGIN\n";
|
||||
file << " // list path definitions here;\n";
|
||||
file << " // WS_PATH_ADD(\"/path\", \"filter1\", \"filter2\", ...);\n";
|
||||
file << " WS_PATH_LIST_END\n";
|
||||
file << "};\n";
|
||||
while (namespaceCount > 0)
|
||||
{
|
||||
--namespaceCount;
|
||||
file << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::newWebsockControllerSourceFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename)
|
||||
{
|
||||
file << "#include \"" << filename << ".h\"\n";
|
||||
file << "\n";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\n";
|
||||
file << "\n";
|
||||
class_name = className.substr(pos + 2);
|
||||
}
|
||||
file << "void " << class_name
|
||||
<< "::handleNewMessage(const WebSocketConnectionPtr& wsConnPtr, "
|
||||
"std::string &&message, const WebSocketMessageType &type)\n";
|
||||
file << "{\n";
|
||||
file << " // write your application logic here\n";
|
||||
file << "}\n";
|
||||
file << "\n";
|
||||
file << "void " << class_name
|
||||
<< "::handleNewConnection(const HttpRequestPtr &req, const "
|
||||
"WebSocketConnectionPtr& wsConnPtr)\n";
|
||||
file << "{\n";
|
||||
file << " // write your application logic here\n";
|
||||
file << "}\n";
|
||||
file << "\n";
|
||||
file << "void " << class_name
|
||||
<< "::handleConnectionClosed(const WebSocketConnectionPtr& "
|
||||
"wsConnPtr)\n";
|
||||
file << "{\n";
|
||||
file << " // write your application logic here\n";
|
||||
file << "}\n";
|
||||
}
|
||||
|
||||
void create_controller::newHttpControllerHeaderFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className)
|
||||
{
|
||||
file << "#pragma once\n";
|
||||
file << "\n";
|
||||
file << "#include <drogon/HttpController.h>\n";
|
||||
file << "\n";
|
||||
file << "using namespace drogon;\n";
|
||||
file << "\n";
|
||||
std::string class_name = className;
|
||||
std::string namepace_path = "/";
|
||||
auto pos = class_name.find("::");
|
||||
size_t namespaceCount = 0;
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
++namespaceCount;
|
||||
auto namespaceName = class_name.substr(0, pos);
|
||||
class_name = class_name.substr(pos + 2);
|
||||
file << "namespace " << namespaceName << "\n";
|
||||
namepace_path.append(namespaceName).append("/");
|
||||
file << "{\n";
|
||||
pos = class_name.find("::");
|
||||
}
|
||||
file << "class " << class_name << " : public drogon::HttpController<"
|
||||
<< class_name << ">\n";
|
||||
file << "{\n";
|
||||
file << " public:\n";
|
||||
file << " METHOD_LIST_BEGIN\n";
|
||||
file << " // use METHOD_ADD to add your custom processing function "
|
||||
"here;\n";
|
||||
file << " // METHOD_ADD(" << class_name
|
||||
<< "::get, \"/{2}/{1}\", Get);"
|
||||
" // path is "
|
||||
<< namepace_path << class_name << "/{arg2}/{arg1}\n";
|
||||
file << " // METHOD_ADD(" << class_name
|
||||
<< "::your_method_name, \"/{1}/{2}/list\", Get);"
|
||||
" // path is "
|
||||
<< namepace_path << class_name << "/{arg1}/{arg2}/list\n";
|
||||
file << " // ADD_METHOD_TO(" << class_name
|
||||
<< "::your_method_name, \"/absolute/path/{1}/{2}/list\", Get);"
|
||||
" // path is /absolute/path/{arg1}/{arg2}/list\n";
|
||||
file << "\n";
|
||||
file << " METHOD_LIST_END\n";
|
||||
file << " // your declaration of processing function maybe like this:\n";
|
||||
file << " // void get(const HttpRequestPtr& req, "
|
||||
"std::function<void (const HttpResponsePtr &)> &&callback, int "
|
||||
"p1, std::string p2);\n";
|
||||
file << " // void your_method_name(const HttpRequestPtr& req, "
|
||||
"std::function<void (const HttpResponsePtr &)> &&callback, double "
|
||||
"p1, int p2) const;\n";
|
||||
file << "};\n";
|
||||
while (namespaceCount > 0)
|
||||
{
|
||||
--namespaceCount;
|
||||
file << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::newHttpControllerSourceFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename)
|
||||
{
|
||||
file << "#include \"" << filename << ".h\"\n";
|
||||
file << "\n";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\n";
|
||||
file << "\n";
|
||||
class_name = className.substr(pos + 2);
|
||||
}
|
||||
|
||||
file << "// Add definition of your processing function here\n";
|
||||
}
|
||||
|
||||
void create_controller::createController(std::vector<std::string> &httpClasses,
|
||||
ControllerType type)
|
||||
{
|
||||
for (auto iter = httpClasses.begin(); iter != httpClasses.end(); ++iter)
|
||||
{
|
||||
if ((*iter)[0] == '-')
|
||||
{
|
||||
std::cout << ARGS_ERROR_STR << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto const &className : httpClasses)
|
||||
{
|
||||
createController(className, type);
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::createController(const std::string &className,
|
||||
ControllerType type)
|
||||
{
|
||||
std::regex regex("::");
|
||||
std::string ctlName =
|
||||
std::regex_replace(className, regex, std::string("_"));
|
||||
|
||||
std::string headFileName = ctlName + ".h";
|
||||
std::string sourceFilename = ctlName + ".cc";
|
||||
{
|
||||
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
||||
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
|
||||
|
||||
if (iHeadFile || iSourceFile)
|
||||
{
|
||||
std::cout << "The file you want to create already exists, "
|
||||
"overwrite it(y/n)?"
|
||||
<< std::endl;
|
||||
auto in = getchar();
|
||||
(void)getchar(); // get the return key
|
||||
if (in != 'Y' && in != 'y')
|
||||
{
|
||||
std::cout << "Abort!" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
||||
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
||||
if (!oHeadFile || !oSourceFile)
|
||||
{
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
if (type == Http)
|
||||
{
|
||||
std::cout << "Create a http controller: " << className << std::endl;
|
||||
newHttpControllerHeaderFile(oHeadFile, className);
|
||||
newHttpControllerSourceFile(oSourceFile, className, ctlName);
|
||||
}
|
||||
else if (type == Simple)
|
||||
{
|
||||
std::cout << "Create a http simple controller: " << className
|
||||
<< std::endl;
|
||||
newSimpleControllerHeaderFile(oHeadFile, className);
|
||||
newSimpleControllerSourceFile(oSourceFile, className, ctlName);
|
||||
}
|
||||
else if (type == WebSocket)
|
||||
{
|
||||
std::cout << "Create a websocket controller: " << className
|
||||
<< std::endl;
|
||||
newWebsockControllerHeaderFile(oHeadFile, className);
|
||||
newWebsockControllerSourceFile(oSourceFile, className, ctlName);
|
||||
}
|
||||
}
|
||||
|
||||
void create_controller::createARestfulController(const std::string &className,
|
||||
const std::string &resource)
|
||||
{
|
||||
std::regex regex("::");
|
||||
std::string ctlName =
|
||||
std::regex_replace(className, regex, std::string("_"));
|
||||
|
||||
std::string headFileName = ctlName + ".h";
|
||||
std::string sourceFilename = ctlName + ".cc";
|
||||
{
|
||||
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
||||
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
|
||||
|
||||
if (iHeadFile || iSourceFile)
|
||||
{
|
||||
std::cout << "The file you want to create already exists, "
|
||||
"overwrite it(y/n)?"
|
||||
<< std::endl;
|
||||
auto in = getchar();
|
||||
(void)getchar(); // get the return key
|
||||
if (in != 'Y' && in != 'y')
|
||||
{
|
||||
std::cout << "Abort!" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
||||
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
||||
if (!oHeadFile || !oSourceFile)
|
||||
{
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
auto v = utils::splitString(className, "::");
|
||||
drogon::DrTemplateData data;
|
||||
data.insert("className", v[v.size() - 1]);
|
||||
v.pop_back();
|
||||
data.insert("namespaceVector", v);
|
||||
data.insert("resource", resource);
|
||||
data.insert("fileName", ctlName);
|
||||
if (resource.empty())
|
||||
{
|
||||
data.insert("ctlCommand",
|
||||
std::string("drogon_ctl create controller -r ") +
|
||||
className);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert("ctlCommand",
|
||||
std::string("drogon_ctl create controller -r ") +
|
||||
className + " --resource=" + resource);
|
||||
}
|
||||
try
|
||||
{
|
||||
auto templ = DrTemplateBase::newTemplate("restful_controller_h.csp");
|
||||
oHeadFile << templ->genText(data);
|
||||
templ = DrTemplateBase::newTemplate("restful_controller_cc.csp");
|
||||
oSourceFile << templ->genText(data);
|
||||
}
|
||||
catch (const std::exception &err)
|
||||
{
|
||||
std::cerr << err.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "Create a http restful API controller: " << className
|
||||
<< std::endl;
|
||||
std::cout << "File name: " << ctlName << ".h and " << ctlName << ".cc"
|
||||
<< std::endl;
|
||||
}
|
68
vendors/drogon/drogon_ctl/create_controller.h
vendored
Normal file
68
vendors/drogon/drogon_ctl/create_controller.h
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
* create_controller.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_controller : public DrObject<create_controller>,
|
||||
public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create controller files";
|
||||
}
|
||||
|
||||
protected:
|
||||
enum ControllerType
|
||||
{
|
||||
Simple = 0,
|
||||
Http,
|
||||
WebSocket,
|
||||
Restful
|
||||
};
|
||||
|
||||
void createController(std::vector<std::string> &httpClasses,
|
||||
ControllerType type);
|
||||
void createController(const std::string &className, ControllerType type);
|
||||
void createARestfulController(const std::string &className,
|
||||
const std::string &resource);
|
||||
|
||||
void newSimpleControllerHeaderFile(std::ofstream &file,
|
||||
const std::string &className);
|
||||
void newSimpleControllerSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename);
|
||||
|
||||
void newWebsockControllerHeaderFile(std::ofstream &file,
|
||||
const std::string &className);
|
||||
void newWebsockControllerSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename);
|
||||
|
||||
void newHttpControllerHeaderFile(std::ofstream &file,
|
||||
const std::string &className);
|
||||
void newHttpControllerSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &filename);
|
||||
};
|
||||
} // namespace drogon_ctl
|
118
vendors/drogon/drogon_ctl/create_filter.cc
vendored
Normal file
118
vendors/drogon/drogon_ctl/create_filter.cc
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/**
|
||||
*
|
||||
* create_filter.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create_filter.h"
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
static void createFilterHeaderFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &fileName)
|
||||
{
|
||||
auto templ = drogon::DrTemplateBase::newTemplate("filter_h");
|
||||
HttpViewData data;
|
||||
if (className.find("::") != std::string::npos)
|
||||
{
|
||||
auto namespaceVector = utils::splitString(className, "::");
|
||||
data.insert("className", namespaceVector.back());
|
||||
namespaceVector.pop_back();
|
||||
data.insert("namespaceVector", namespaceVector);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert("className", className);
|
||||
}
|
||||
data.insert("filename", fileName);
|
||||
file << templ->genText(data);
|
||||
}
|
||||
|
||||
static void createFilterSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &fileName)
|
||||
{
|
||||
auto templ = drogon::DrTemplateBase::newTemplate("filter_cc");
|
||||
HttpViewData data;
|
||||
if (className.find("::") != std::string::npos)
|
||||
{
|
||||
auto pos = className.rfind("::");
|
||||
data.insert("namespaceString", className.substr(0, pos));
|
||||
data.insert("className", className.substr(pos + 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert("className", className);
|
||||
}
|
||||
data.insert("filename", fileName);
|
||||
file << templ->genText(data);
|
||||
}
|
||||
|
||||
void create_filter::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
if (parameters.size() < 1)
|
||||
{
|
||||
std::cout << "Invalid parameters!" << std::endl;
|
||||
}
|
||||
for (auto className : parameters)
|
||||
{
|
||||
std::regex regex("::");
|
||||
std::string fileName =
|
||||
std::regex_replace(className, regex, std::string("_"));
|
||||
|
||||
std::string headFileName = fileName + ".h";
|
||||
std::string sourceFilename = fileName + ".cc";
|
||||
{
|
||||
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
||||
std::ifstream iSourceFile(sourceFilename.c_str(),
|
||||
std::ifstream::in);
|
||||
|
||||
if (iHeadFile || iSourceFile)
|
||||
{
|
||||
std::cout << "The file you want to create already exists, "
|
||||
"overwrite it(y/n)?"
|
||||
<< std::endl;
|
||||
auto in = getchar();
|
||||
(void)getchar(); // get the return key
|
||||
if (in != 'Y' && in != 'y')
|
||||
{
|
||||
std::cout << "Abort!" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
||||
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
||||
if (!oHeadFile || !oSourceFile)
|
||||
{
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "create a http filter:" << className << std::endl;
|
||||
createFilterHeaderFile(oHeadFile, className, fileName);
|
||||
createFilterSourceFile(oSourceFile, className, fileName);
|
||||
}
|
||||
}
|
36
vendors/drogon/drogon_ctl/create_filter.h
vendored
Normal file
36
vendors/drogon/drogon_ctl/create_filter.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
*
|
||||
* create_filter.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_filter : public DrObject<create_filter>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create filter class files";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
};
|
||||
} // namespace drogon_ctl
|
1380
vendors/drogon/drogon_ctl/create_model.cc
vendored
Normal file
1380
vendors/drogon/drogon_ctl/create_model.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
430
vendors/drogon/drogon_ctl/create_model.h
vendored
Normal file
430
vendors/drogon/drogon_ctl/create_model.h
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
/**
|
||||
*
|
||||
* create_model.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
|
||||
|
||||
#include <drogon/config.h>
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <json/json.h>
|
||||
#include <drogon/orm/DbClient.h>
|
||||
using namespace drogon::orm;
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
struct ColumnInfo
|
||||
{
|
||||
std::string colName_;
|
||||
std::string colValName_;
|
||||
std::string colTypeName_;
|
||||
std::string colType_;
|
||||
std::string colDatabaseType_;
|
||||
std::string dbType_;
|
||||
ssize_t colLength_{0};
|
||||
size_t index_{0};
|
||||
bool isAutoVal_{false};
|
||||
bool isPrimaryKey_{false};
|
||||
bool notNull_{false};
|
||||
bool hasDefaultVal_{false};
|
||||
};
|
||||
|
||||
inline std::string nameTransform(const std::string &origName, bool isType)
|
||||
{
|
||||
auto str = origName;
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
|
||||
return tolower(c);
|
||||
});
|
||||
std::string::size_type startPos = 0;
|
||||
std::string::size_type pos;
|
||||
std::string ret;
|
||||
do
|
||||
{
|
||||
pos = str.find("_", startPos);
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
pos = str.find(".", startPos);
|
||||
}
|
||||
if (pos != std::string::npos)
|
||||
ret += str.substr(startPos, pos - startPos);
|
||||
else
|
||||
{
|
||||
ret += str.substr(startPos);
|
||||
break;
|
||||
}
|
||||
while (str[pos] == '_' || str[pos] == '.')
|
||||
++pos;
|
||||
if (str[pos] >= 'a' && str[pos] <= 'z')
|
||||
str[pos] += ('A' - 'a');
|
||||
startPos = pos;
|
||||
} while (1);
|
||||
if (isType && ret[0] >= 'a' && ret[0] <= 'z')
|
||||
ret[0] += ('A' - 'a');
|
||||
return ret;
|
||||
}
|
||||
|
||||
class PivotTable
|
||||
{
|
||||
public:
|
||||
PivotTable() = default;
|
||||
|
||||
PivotTable(const Json::Value &json)
|
||||
: tableName_(json.get("table_name", "").asString())
|
||||
{
|
||||
if (tableName_.empty())
|
||||
{
|
||||
throw std::runtime_error("table_name can't be empty");
|
||||
}
|
||||
originalKey_ = json.get("original_key", "").asString();
|
||||
if (originalKey_.empty())
|
||||
{
|
||||
throw std::runtime_error("original_key can't be empty");
|
||||
}
|
||||
targetKey_ = json.get("target_key", "").asString();
|
||||
if (targetKey_.empty())
|
||||
{
|
||||
throw std::runtime_error("target_key can't be empty");
|
||||
}
|
||||
}
|
||||
|
||||
PivotTable reverse() const
|
||||
{
|
||||
PivotTable pivot;
|
||||
pivot.tableName_ = tableName_;
|
||||
pivot.originalKey_ = targetKey_;
|
||||
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_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string tableName_;
|
||||
std::string originalKey_;
|
||||
std::string targetKey_;
|
||||
};
|
||||
|
||||
class ConvertMethod
|
||||
{
|
||||
public:
|
||||
ConvertMethod(const Json::Value &convert)
|
||||
{
|
||||
tableName_ = convert.get("table", "*").asString();
|
||||
colName_ = convert.get("column", "*").asString();
|
||||
|
||||
auto method = convert["method"];
|
||||
if (method.isNull())
|
||||
{
|
||||
throw std::runtime_error("method - object is missing.");
|
||||
} // endif
|
||||
if (!method.isObject())
|
||||
{
|
||||
throw std::runtime_error("method is not an object.");
|
||||
} // endif
|
||||
methodBeforeDbWrite_ = method.get("before_db_write", "").asString();
|
||||
methodAfterDbRead_ = method.get("after_db_read", "").asString();
|
||||
|
||||
auto includeFiles = convert["includes"];
|
||||
if (includeFiles.isNull())
|
||||
{
|
||||
return;
|
||||
} // endif
|
||||
if (!includeFiles.isArray())
|
||||
{
|
||||
throw std::runtime_error("includes must be an array");
|
||||
} // endif
|
||||
for (auto &i : includeFiles)
|
||||
{
|
||||
includeFiles_.push_back(i.asString());
|
||||
} // for
|
||||
}
|
||||
|
||||
ConvertMethod() = default;
|
||||
|
||||
bool shouldConvert(const std::string &tableName,
|
||||
const std::string &colName) const;
|
||||
|
||||
const std::string &tableName() const
|
||||
{
|
||||
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<std::string> &includeFiles() const
|
||||
{
|
||||
return includeFiles_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string tableName_{"*"};
|
||||
std::string colName_{"*"};
|
||||
std::string methodBeforeDbWrite_;
|
||||
std::string methodAfterDbRead_;
|
||||
std::vector<std::string> includeFiles_;
|
||||
};
|
||||
|
||||
class Relationship
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
HasOne,
|
||||
HasMany,
|
||||
ManyToMany
|
||||
};
|
||||
|
||||
Relationship(const Json::Value &relationship)
|
||||
{
|
||||
auto type = relationship.get("type", "has one").asString();
|
||||
if (type == "has one")
|
||||
{
|
||||
type_ = Relationship::Type::HasOne;
|
||||
}
|
||||
else if (type == "has many")
|
||||
{
|
||||
type_ = Relationship::Type::HasMany;
|
||||
}
|
||||
else if (type == "many to many")
|
||||
{
|
||||
type_ = Relationship::Type::ManyToMany;
|
||||
}
|
||||
else
|
||||
{
|
||||
char message[128];
|
||||
snprintf(message,
|
||||
sizeof(message),
|
||||
"Invalid relationship type: %s",
|
||||
type.data());
|
||||
throw std::runtime_error(message);
|
||||
}
|
||||
originalTableName_ =
|
||||
relationship.get("original_table_name", "").asString();
|
||||
if (originalTableName_.empty())
|
||||
{
|
||||
throw std::runtime_error("original_table_name can't be empty");
|
||||
}
|
||||
originalKey_ = relationship.get("original_key", "").asString();
|
||||
if (originalKey_.empty())
|
||||
{
|
||||
throw std::runtime_error("original_key can't be empty");
|
||||
}
|
||||
originalTableAlias_ =
|
||||
relationship.get("original_table_alias", "").asString();
|
||||
targetTableName_ = relationship.get("target_table_name", "").asString();
|
||||
if (targetTableName_.empty())
|
||||
{
|
||||
throw std::runtime_error("target_table_name can't be empty");
|
||||
}
|
||||
targetKey_ = relationship.get("target_key", "").asString();
|
||||
if (targetKey_.empty())
|
||||
{
|
||||
throw std::runtime_error("target_key can't be empty");
|
||||
}
|
||||
targetTableAlias_ =
|
||||
relationship.get("target_table_alias", "").asString();
|
||||
enableReverse_ = relationship.get("enable_reverse", false).asBool();
|
||||
if (type_ == Type::ManyToMany)
|
||||
{
|
||||
auto &pivot = relationship["pivot_table"];
|
||||
if (pivot.isNull())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"ManyToMany relationship needs a pivot table");
|
||||
}
|
||||
pivotTable_ = PivotTable(pivot);
|
||||
}
|
||||
}
|
||||
|
||||
Relationship() = default;
|
||||
|
||||
Relationship reverse() const
|
||||
{
|
||||
Relationship r;
|
||||
if (type_ == Type::HasMany)
|
||||
{
|
||||
r.type_ = Type::HasOne;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.type_ = type_;
|
||||
}
|
||||
r.originalTableName_ = targetTableName_;
|
||||
r.originalTableAlias_ = targetTableAlias_;
|
||||
r.originalKey_ = targetKey_;
|
||||
r.targetTableName_ = originalTableName_;
|
||||
r.targetTableAlias_ = originalTableAlias_;
|
||||
r.targetKey_ = originalKey_;
|
||||
r.enableReverse_ = enableReverse_;
|
||||
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_;
|
||||
}
|
||||
|
||||
private:
|
||||
Type type_{Type::HasOne};
|
||||
std::string originalTableName_;
|
||||
std::string originalTableAlias_;
|
||||
std::string targetTableName_;
|
||||
std::string targetTableAlias_;
|
||||
std::string originalKey_;
|
||||
std::string targetKey_;
|
||||
bool enableReverse_{false};
|
||||
PivotTable pivotTable_;
|
||||
};
|
||||
|
||||
class create_model : public DrObject<create_model>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create Model classes files";
|
||||
}
|
||||
|
||||
protected:
|
||||
void createModel(const std::string &path,
|
||||
const std::string &singleModelName);
|
||||
void createModel(const std::string &path,
|
||||
const Json::Value &config,
|
||||
const std::string &singleModelName);
|
||||
#if USE_POSTGRESQL
|
||||
void createModelClassFromPG(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const std::string &tableName,
|
||||
const std::string &schema,
|
||||
const Json::Value &restfulApiConfig,
|
||||
const std::vector<Relationship> &relationships,
|
||||
const std::vector<ConvertMethod> &convertMethods);
|
||||
|
||||
void createModelFromPG(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const std::string &schema,
|
||||
const Json::Value &restfulApiConfig,
|
||||
std::map<std::string, std::vector<Relationship>> &relationships,
|
||||
std::map<std::string, std::vector<ConvertMethod>> &convertMethods);
|
||||
#endif
|
||||
#if USE_MYSQL
|
||||
void createModelClassFromMysql(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const std::string &tableName,
|
||||
const Json::Value &restfulApiConfig,
|
||||
const std::vector<Relationship> &relationships,
|
||||
const std::vector<ConvertMethod> &convertMethods);
|
||||
void createModelFromMysql(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const Json::Value &restfulApiConfig,
|
||||
std::map<std::string, std::vector<Relationship>> &relationships,
|
||||
std::map<std::string, std::vector<ConvertMethod>> &convertMethods);
|
||||
#endif
|
||||
#if USE_SQLITE3
|
||||
void createModelClassFromSqlite3(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const std::string &tableName,
|
||||
const Json::Value &restfulApiConfig,
|
||||
const std::vector<Relationship> &relationships,
|
||||
const std::vector<ConvertMethod> &convertMethod);
|
||||
void createModelFromSqlite3(
|
||||
const std::string &path,
|
||||
const DbClientPtr &client,
|
||||
const Json::Value &restfulApiConfig,
|
||||
std::map<std::string, std::vector<Relationship>> &relationships,
|
||||
std::map<std::string, std::vector<ConvertMethod>> &convertMethod);
|
||||
#endif
|
||||
void createRestfulAPIController(const DrTemplateData &tableInfo,
|
||||
const Json::Value &restfulApiConfig);
|
||||
std::string dbname_;
|
||||
bool forceOverwrite_{false};
|
||||
};
|
||||
} // namespace drogon_ctl
|
118
vendors/drogon/drogon_ctl/create_plugin.cc
vendored
Normal file
118
vendors/drogon/drogon_ctl/create_plugin.cc
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/**
|
||||
*
|
||||
* create_plugin.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create_plugin.h"
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
static void createPluginHeaderFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &fileName)
|
||||
{
|
||||
auto templ = drogon::DrTemplateBase::newTemplate("plugin_h");
|
||||
HttpViewData data;
|
||||
if (className.find("::") != std::string::npos)
|
||||
{
|
||||
auto namespaceVector = utils::splitString(className, "::");
|
||||
data.insert("className", namespaceVector.back());
|
||||
namespaceVector.pop_back();
|
||||
data.insert("namespaceVector", namespaceVector);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert("className", className);
|
||||
}
|
||||
data.insert("filename", fileName);
|
||||
file << templ->genText(data);
|
||||
}
|
||||
|
||||
static void createPluginSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &fileName)
|
||||
{
|
||||
auto templ = drogon::DrTemplateBase::newTemplate("plugin_cc");
|
||||
HttpViewData data;
|
||||
if (className.find("::") != std::string::npos)
|
||||
{
|
||||
auto pos = className.rfind("::");
|
||||
data.insert("namespaceString", className.substr(0, pos));
|
||||
data.insert("className", className.substr(pos + 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
data.insert("className", className);
|
||||
}
|
||||
data.insert("filename", fileName);
|
||||
file << templ->genText(data);
|
||||
}
|
||||
|
||||
void create_plugin::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
if (parameters.size() < 1)
|
||||
{
|
||||
std::cout << "Invalid parameters!" << std::endl;
|
||||
}
|
||||
for (auto className : parameters)
|
||||
{
|
||||
std::regex regex("::");
|
||||
std::string fileName =
|
||||
std::regex_replace(className, regex, std::string("_"));
|
||||
|
||||
std::string headFileName = fileName + ".h";
|
||||
std::string sourceFilename = fileName + ".cc";
|
||||
{
|
||||
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
|
||||
std::ifstream iSourceFile(sourceFilename.c_str(),
|
||||
std::ifstream::in);
|
||||
|
||||
if (iHeadFile || iSourceFile)
|
||||
{
|
||||
std::cout << "The file you want to create already exists, "
|
||||
"overwrite it(y/n)?"
|
||||
<< std::endl;
|
||||
auto in = getchar();
|
||||
(void)getchar(); // get the return key
|
||||
if (in != 'Y' && in != 'y')
|
||||
{
|
||||
std::cout << "Abort!" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
||||
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
|
||||
if (!oHeadFile || !oSourceFile)
|
||||
{
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "create a plugin:" << className << std::endl;
|
||||
createPluginHeaderFile(oHeadFile, className, fileName);
|
||||
createPluginSourceFile(oSourceFile, className, fileName);
|
||||
}
|
||||
}
|
36
vendors/drogon/drogon_ctl/create_plugin.h
vendored
Normal file
36
vendors/drogon/drogon_ctl/create_plugin.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
*
|
||||
* create_plugin.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_plugin : public DrObject<create_plugin>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create plugin class files";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
};
|
||||
} // namespace drogon_ctl
|
143
vendors/drogon/drogon_ctl/create_project.cc
vendored
Normal file
143
vendors/drogon/drogon_ctl/create_project.cc
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
/**
|
||||
*
|
||||
* create_project.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create_project.h"
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
void create_project::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
if (parameters.size() < 1)
|
||||
{
|
||||
std::cout << "please input project name" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
auto pName = parameters[0];
|
||||
createProject(pName);
|
||||
}
|
||||
|
||||
static void newCmakeFile(std::ofstream &cmakeFile,
|
||||
const std::string &projectName)
|
||||
{
|
||||
HttpViewData data;
|
||||
data.insert("ProjectName", projectName);
|
||||
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");
|
||||
gitFile << templ->genText();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
HttpViewData data;
|
||||
data.insert("ProjectName", projectName);
|
||||
auto templ = DrTemplateBase::newTemplate("test_cmake");
|
||||
testCmakeFile << templ->genText(data);
|
||||
}
|
||||
|
||||
void create_project::createProject(const std::string &projectName)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (_access(projectName.data(), 0) == 0)
|
||||
#else
|
||||
if (access(projectName.data(), 0) == 0)
|
||||
#endif
|
||||
{
|
||||
std::cerr
|
||||
<< "The directory already exists, please use another project name!"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
std::cout << "create a project named " << projectName << std::endl;
|
||||
|
||||
drogon::utils::createPath(projectName);
|
||||
// 1.create CMakeLists.txt
|
||||
#ifdef _WIN32
|
||||
auto r = _chdir(projectName.data());
|
||||
#else
|
||||
auto r = chdir(projectName.data());
|
||||
#endif
|
||||
(void)(r);
|
||||
std::ofstream cmakeFile("CMakeLists.txt", std::ofstream::out);
|
||||
newCmakeFile(cmakeFile, projectName);
|
||||
std::ofstream mainFile("main.cc", std::ofstream::out);
|
||||
newMainFile(mainFile);
|
||||
drogon::utils::createPath("views");
|
||||
drogon::utils::createPath("controllers");
|
||||
drogon::utils::createPath("filters");
|
||||
drogon::utils::createPath("plugins");
|
||||
drogon::utils::createPath("build");
|
||||
drogon::utils::createPath("models");
|
||||
drogon::utils::createPath("test");
|
||||
|
||||
std::ofstream gitFile(".gitignore", std::ofstream::out);
|
||||
newGitIgFile(gitFile);
|
||||
std::ofstream configJsonFile("config.json", std::ofstream::out);
|
||||
newConfigJsonFile(configJsonFile);
|
||||
std::ofstream configYamlFile("config.yaml", std::ofstream::out);
|
||||
newConfigYamlFile(configYamlFile);
|
||||
std::ofstream modelConfigFile("models/model.json", std::ofstream::out);
|
||||
newModelConfigFile(modelConfigFile);
|
||||
std::ofstream testMainFile("test/test_main.cc", std::ofstream::out);
|
||||
newTestMainFile(testMainFile);
|
||||
std::ofstream testCmakeFile("test/CMakeLists.txt", std::ofstream::out);
|
||||
newTestCmakeFile(testCmakeFile, projectName);
|
||||
}
|
36
vendors/drogon/drogon_ctl/create_project.h
vendored
Normal file
36
vendors/drogon/drogon_ctl/create_project.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
*
|
||||
* create_project.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_project : public DrObject<create_project>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create a project";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
void createProject(const std::string &projectName);
|
||||
};
|
||||
} // namespace drogon_ctl
|
553
vendors/drogon/drogon_ctl/create_view.cc
vendored
Normal file
553
vendors/drogon/drogon_ctl/create_view.cc
vendored
Normal file
@ -0,0 +1,553 @@
|
||||
/**
|
||||
*
|
||||
* @file create_view.cc
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "create_view.h"
|
||||
#include "cmd.h"
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
||||
static const std::string cxx_include = "<%inc";
|
||||
static const std::string cxx_end = "%>";
|
||||
static const std::string cxx_lang = "<%c++";
|
||||
static const std::string cxx_view_data = "@@";
|
||||
static const std::string cxx_output = "$$";
|
||||
static const std::string cxx_val_start = "[[";
|
||||
static const std::string cxx_val_end = "]]";
|
||||
static const std::string sub_view_start = "<%view";
|
||||
static const std::string sub_view_end = "%>";
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
static std::string &replace_all(std::string &str,
|
||||
const std::string &old_value,
|
||||
const std::string &new_value)
|
||||
{
|
||||
std::string::size_type pos(0);
|
||||
while (true)
|
||||
{
|
||||
// std::cout<<str<<endl;
|
||||
// std::cout<<"pos="<<pos<<endl;
|
||||
if ((pos = str.find(old_value, pos)) != std::string::npos)
|
||||
{
|
||||
str = str.replace(pos, old_value.length(), new_value);
|
||||
pos += new_value.length() - old_value.length();
|
||||
++pos;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void parseCxxLine(std::ofstream &oSrcFile,
|
||||
const std::string &line,
|
||||
const std::string &streamName,
|
||||
const std::string &viewDataName)
|
||||
{
|
||||
if (line.length() > 0)
|
||||
{
|
||||
std::string tmp = line;
|
||||
replace_all(tmp, cxx_output, streamName);
|
||||
replace_all(tmp, cxx_view_data, viewDataName);
|
||||
oSrcFile << tmp << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void outputVal(std::ofstream &oSrcFile,
|
||||
const std::string &streamName,
|
||||
const std::string &viewDataName,
|
||||
const std::string &keyName)
|
||||
{
|
||||
oSrcFile << "{\n";
|
||||
oSrcFile << " auto & val=" << viewDataName << "[\"" << keyName
|
||||
<< "\"];\n";
|
||||
oSrcFile << " if(val.type()==typeid(const char *)){\n";
|
||||
oSrcFile << " " << streamName
|
||||
<< "<<*(std::any_cast<const char *>(&val));\n";
|
||||
oSrcFile << " }else "
|
||||
"if(val.type()==typeid(std::string)||val.type()==typeid(const "
|
||||
"std::string)){\n";
|
||||
oSrcFile << " " << streamName
|
||||
<< "<<*(std::any_cast<const std::string>(&val));\n";
|
||||
oSrcFile << " }\n";
|
||||
oSrcFile << "}\n";
|
||||
}
|
||||
|
||||
static void outputSubView(std::ofstream &oSrcFile,
|
||||
const std::string &streamName,
|
||||
const std::string &viewDataName,
|
||||
const std::string &keyName)
|
||||
{
|
||||
oSrcFile << "{\n";
|
||||
oSrcFile << " auto templ=DrTemplateBase::newTemplate(\"" << keyName
|
||||
<< "\");\n";
|
||||
oSrcFile << " if(templ){\n";
|
||||
oSrcFile << " " << streamName << "<< templ->genText(" << viewDataName
|
||||
<< ");\n";
|
||||
oSrcFile << " }\n";
|
||||
oSrcFile << "}\n";
|
||||
}
|
||||
|
||||
static void parseLine(std::ofstream &oSrcFile,
|
||||
std::string &line,
|
||||
const std::string &streamName,
|
||||
const std::string &viewDataName,
|
||||
int &cxx_flag,
|
||||
int returnFlag = 1)
|
||||
{
|
||||
std::string::size_type pos(0);
|
||||
// std::cout<<line<<"("<<line.length()<<")\n";
|
||||
if (line.length() > 0 && line[line.length() - 1] == '\r')
|
||||
{
|
||||
line.resize(line.length() - 1);
|
||||
}
|
||||
if (line.length() == 0)
|
||||
{
|
||||
// std::cout<<"blank line!"<<std::endl;
|
||||
// std::cout<<streamName<<"<<\"\\n\";\n";
|
||||
if (returnFlag && !cxx_flag)
|
||||
oSrcFile << streamName << "<<\"\\n\";\n";
|
||||
return;
|
||||
}
|
||||
if (cxx_flag == 0)
|
||||
{
|
||||
// find cxx lang begin
|
||||
if ((pos = line.find(cxx_lang)) != std::string::npos)
|
||||
{
|
||||
std::string oldLine = line.substr(0, pos);
|
||||
if (oldLine.length() > 0)
|
||||
parseLine(
|
||||
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
|
||||
std::string newLine = line.substr(pos + cxx_lang.length());
|
||||
cxx_flag = 1;
|
||||
if (newLine.length() > 0)
|
||||
parseLine(oSrcFile,
|
||||
newLine,
|
||||
streamName,
|
||||
viewDataName,
|
||||
cxx_flag,
|
||||
returnFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pos = line.find(cxx_val_start)) != std::string::npos)
|
||||
{
|
||||
std::string oldLine = line.substr(0, pos);
|
||||
parseLine(
|
||||
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
|
||||
std::string newLine = line.substr(pos + cxx_val_start.length());
|
||||
if ((pos = newLine.find(cxx_val_end)) != std::string::npos)
|
||||
{
|
||||
std::string keyName = newLine.substr(0, pos);
|
||||
auto iter = keyName.begin();
|
||||
while (iter != keyName.end() && *iter == ' ')
|
||||
++iter;
|
||||
auto iterEnd = iter;
|
||||
while (iterEnd != keyName.end() && *iterEnd != ' ')
|
||||
++iterEnd;
|
||||
keyName = std::string(iter, iterEnd);
|
||||
outputVal(oSrcFile, streamName, viewDataName, keyName);
|
||||
std::string tailLine =
|
||||
newLine.substr(pos + cxx_val_end.length());
|
||||
parseLine(oSrcFile,
|
||||
tailLine,
|
||||
streamName,
|
||||
viewDataName,
|
||||
cxx_flag,
|
||||
returnFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "format err!" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if ((pos = line.find(sub_view_start)) != std::string::npos)
|
||||
{
|
||||
std::string oldLine = line.substr(0, pos);
|
||||
parseLine(
|
||||
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
|
||||
std::string newLine =
|
||||
line.substr(pos + sub_view_start.length());
|
||||
if ((pos = newLine.find(sub_view_end)) != std::string::npos)
|
||||
{
|
||||
std::string keyName = newLine.substr(0, pos);
|
||||
auto iter = keyName.begin();
|
||||
while (iter != keyName.end() && *iter == ' ')
|
||||
++iter;
|
||||
auto iterEnd = iter;
|
||||
while (iterEnd != keyName.end() && *iterEnd != ' ')
|
||||
++iterEnd;
|
||||
keyName = std::string(iter, iterEnd);
|
||||
outputSubView(oSrcFile, streamName, viewDataName, keyName);
|
||||
std::string tailLine =
|
||||
newLine.substr(pos + sub_view_end.length());
|
||||
parseLine(oSrcFile,
|
||||
tailLine,
|
||||
streamName,
|
||||
viewDataName,
|
||||
cxx_flag,
|
||||
returnFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "format err!" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.length() > 0)
|
||||
{
|
||||
replace_all(line, "\\", "\\\\");
|
||||
replace_all(line, "\"", "\\\"");
|
||||
oSrcFile << "\t" << streamName << " << \"" << line;
|
||||
}
|
||||
if (returnFlag)
|
||||
oSrcFile << "\\n\";\n";
|
||||
else
|
||||
oSrcFile << "\";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pos = line.find(cxx_end)) != std::string::npos)
|
||||
{
|
||||
std::string newLine = line.substr(0, pos);
|
||||
parseCxxLine(oSrcFile, newLine, streamName, viewDataName);
|
||||
std::string oldLine = line.substr(pos + cxx_end.length());
|
||||
cxx_flag = 0;
|
||||
if (oldLine.length() > 0)
|
||||
parseLine(oSrcFile,
|
||||
oldLine,
|
||||
streamName,
|
||||
viewDataName,
|
||||
cxx_flag,
|
||||
returnFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
parseCxxLine(oSrcFile, line, streamName, viewDataName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_view::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
for (auto iter = parameters.begin(); iter != parameters.end();)
|
||||
{
|
||||
auto &file = *iter;
|
||||
if (file == "-o" || file == "--output")
|
||||
{
|
||||
iter = parameters.erase(iter);
|
||||
if (iter != parameters.end())
|
||||
{
|
||||
outputPath_ = *iter;
|
||||
iter = parameters.erase(iter);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (file == "-n" || file == "--namespace")
|
||||
{
|
||||
iter = parameters.erase(iter);
|
||||
if (iter != parameters.end())
|
||||
{
|
||||
namespaces_ = utils::splitString(*iter, "::");
|
||||
iter = parameters.erase(iter);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (file == "--path-to-namespace")
|
||||
{
|
||||
iter = parameters.erase(iter);
|
||||
pathToNamespaceFlag_ = true;
|
||||
continue;
|
||||
}
|
||||
else if (file[0] == '-')
|
||||
{
|
||||
std::cout << ARGS_ERROR_STR << std::endl;
|
||||
return;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
createViewFiles(parameters);
|
||||
}
|
||||
|
||||
void create_view::createViewFiles(std::vector<std::string> &cspFileNames)
|
||||
{
|
||||
for (auto const &file : cspFileNames)
|
||||
{
|
||||
std::cout << "create view:" << file << std::endl;
|
||||
if (createViewFile(file) != 0)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int create_view::createViewFile(const std::string &script_filename)
|
||||
{
|
||||
std::cout << "create HttpView Class file by " << script_filename
|
||||
<< std::endl;
|
||||
if (pathToNamespaceFlag_)
|
||||
{
|
||||
std::string::size_type pos1 = 0, pos2 = 0;
|
||||
if (script_filename.length() >= 2 && script_filename[0] == '.' &&
|
||||
(script_filename[1] == '/' || script_filename[1] == '\\'))
|
||||
{
|
||||
pos1 = pos2 = 2;
|
||||
}
|
||||
else if (script_filename.length() >= 1 &&
|
||||
(script_filename[0] == '/' || script_filename[0] == '\\'))
|
||||
{
|
||||
pos1 = pos2 = 1;
|
||||
}
|
||||
while (pos2 < script_filename.length() - 1)
|
||||
{
|
||||
if (script_filename[pos2] == '/' || script_filename[pos2] == '\\')
|
||||
{
|
||||
if (pos2 > pos1)
|
||||
{
|
||||
namespaces_.push_back(
|
||||
script_filename.substr(pos1, pos2 - pos1));
|
||||
}
|
||||
pos1 = ++pos2;
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos2;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string npPrefix;
|
||||
for (auto &np : namespaces_)
|
||||
{
|
||||
npPrefix += np;
|
||||
npPrefix += "_";
|
||||
}
|
||||
std::ifstream infile(script_filename.c_str(), std::ifstream::in);
|
||||
if (infile)
|
||||
{
|
||||
std::string::size_type pos = script_filename.rfind('.');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string className = script_filename.substr(0, pos);
|
||||
if ((pos = className.rfind('/')) != std::string::npos)
|
||||
{
|
||||
className = className.substr(pos + 1);
|
||||
}
|
||||
std::cout << "className=" << className << std::endl;
|
||||
std::string headFileName =
|
||||
outputPath_ + "/" + npPrefix + className + ".h";
|
||||
std::string sourceFilename =
|
||||
outputPath_ + "/" + npPrefix + className + ".cc";
|
||||
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
|
||||
std::ofstream oSourceFile(sourceFilename.c_str(),
|
||||
std::ofstream::out);
|
||||
if (!oHeadFile || !oSourceFile)
|
||||
{
|
||||
std::cerr << "Can't open " << headFileName << " or "
|
||||
<< sourceFilename << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
newViewHeaderFile(oHeadFile, className);
|
||||
newViewSourceFile(oSourceFile, className, npPrefix, infile);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "can't open file " << script_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void create_view::newViewHeaderFile(std::ofstream &file,
|
||||
const std::string &className)
|
||||
{
|
||||
file << "//this file is generated by program automatically,don't modify "
|
||||
"it!\n";
|
||||
file << "#include <drogon/DrTemplate.h>\n";
|
||||
for (auto &np : namespaces_)
|
||||
{
|
||||
file << "namespace " << np << "\n";
|
||||
file << "{\n";
|
||||
}
|
||||
file << "class " << className << ":public drogon::DrTemplate<" << className
|
||||
<< ">\n";
|
||||
file << "{\npublic:\n\t" << className << "(){};\n\tvirtual ~" << className
|
||||
<< "(){};\n\t"
|
||||
"virtual std::string genText(const drogon::DrTemplateData &) "
|
||||
"override;\n};\n";
|
||||
for (std::size_t i = 0; i < namespaces_.size(); ++i)
|
||||
{
|
||||
file << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void create_view::newViewSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &namespacePrefix,
|
||||
std::ifstream &infile)
|
||||
{
|
||||
file << "//this file is generated by program(drogon_ctl) "
|
||||
"automatically,don't modify it!\n";
|
||||
file << "#include \"" << namespacePrefix << className << ".h\"\n";
|
||||
file << "#include <drogon/utils/OStringStream.h>\n";
|
||||
file << "#include <string>\n";
|
||||
file << "#include <map>\n";
|
||||
file << "#include <vector>\n";
|
||||
file << "#include <set>\n";
|
||||
file << "#include <iostream>\n";
|
||||
file << "#include <unordered_map>\n";
|
||||
file << "#include <unordered_set>\n";
|
||||
file << "#include <algorithm>\n";
|
||||
file << "#include <list>\n";
|
||||
file << "#include <deque>\n";
|
||||
file << "#include <queue>\n";
|
||||
|
||||
// Find layout tag
|
||||
std::string layoutName;
|
||||
std::regex layoutReg("<%layout[ \\t]+(((?!%\\}).)*[^ \\t])[ \\t]*%>");
|
||||
for (std::string buffer; std::getline(infile, buffer);)
|
||||
{
|
||||
std::smatch results;
|
||||
if (std::regex_search(buffer, results, layoutReg))
|
||||
{
|
||||
if (results.size() > 1)
|
||||
{
|
||||
layoutName = results[1].str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
infile.clear();
|
||||
infile.seekg(0, std::ifstream::beg);
|
||||
bool import_flag{false};
|
||||
for (std::string buffer; std::getline(infile, buffer);)
|
||||
{
|
||||
std::string::size_type pos(0);
|
||||
|
||||
if (!import_flag)
|
||||
{
|
||||
std::string lowerBuffer = buffer;
|
||||
std::transform(lowerBuffer.begin(),
|
||||
lowerBuffer.end(),
|
||||
lowerBuffer.begin(),
|
||||
[](unsigned char c) { return tolower(c); });
|
||||
if ((pos = lowerBuffer.find(cxx_include)) != std::string::npos)
|
||||
{
|
||||
// std::cout<<"haha find it!"<<endl;
|
||||
std::string newLine = buffer.substr(pos + cxx_include.length());
|
||||
import_flag = true;
|
||||
if ((pos = newLine.find(cxx_end)) != std::string::npos)
|
||||
{
|
||||
newLine = newLine.substr(0, pos);
|
||||
file << newLine << "\n";
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
file << newLine << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout<<buffer<<endl;
|
||||
if ((pos = buffer.find(cxx_end)) != std::string::npos)
|
||||
{
|
||||
std::string newLine = buffer.substr(0, pos);
|
||||
file << newLine << "\n";
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout<<"to source file"<<buffer<<endl;
|
||||
file << buffer << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// std::cout<<"import_flag="<<import_flag<<std::endl;
|
||||
if (!import_flag)
|
||||
{
|
||||
infile.clear();
|
||||
infile.seekg(0, std::ifstream::beg);
|
||||
}
|
||||
|
||||
if (!namespaces_.empty())
|
||||
{
|
||||
file << "using namespace ";
|
||||
for (std::size_t i = 0; i < namespaces_.size(); ++i)
|
||||
{
|
||||
if (i != namespaces_.size() - 1)
|
||||
{
|
||||
file << namespaces_[i] << "::";
|
||||
}
|
||||
else
|
||||
{
|
||||
file << namespaces_[i] << ";";
|
||||
}
|
||||
}
|
||||
file << "\n";
|
||||
}
|
||||
file << "using namespace drogon;\n";
|
||||
std::string viewDataName = className + "_view_data";
|
||||
// virtual std::string genText(const DrTemplateData &)
|
||||
file << "std::string " << className << "::genText(const DrTemplateData& "
|
||||
<< viewDataName << ")\n{\n";
|
||||
// std::string bodyName=className+"_bodystr";
|
||||
std::string streamName = className + "_tmp_stream";
|
||||
|
||||
// oSrcFile <<"\tstd::string "<<bodyName<<";\n";
|
||||
file << "\tdrogon::OStringStream " << streamName << ";\n";
|
||||
file << "\tstd::string layoutName{\"" << layoutName << "\"};\n";
|
||||
int cxx_flag = 0;
|
||||
for (std::string buffer; std::getline(infile, buffer);)
|
||||
{
|
||||
if (buffer.length() > 0)
|
||||
{
|
||||
std::smatch results;
|
||||
if (std::regex_search(buffer, results, layoutReg))
|
||||
{
|
||||
if (results.size() > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
std::regex re("\\{%[ \\t]*(((?!%\\}).)*[^ \\t])[ \\t]*%\\}");
|
||||
buffer = std::regex_replace(buffer, re, "<%c++$$$$<<$1;%>");
|
||||
}
|
||||
parseLine(file, buffer, streamName, viewDataName, cxx_flag);
|
||||
}
|
||||
file << "if(layoutName.empty())\n{\n";
|
||||
file << "std::string ret{std::move(" << streamName << ".str())};\n";
|
||||
file << "return ret;\n}else\n{\n";
|
||||
file << "auto templ = DrTemplateBase::newTemplate(layoutName);\n";
|
||||
file << "if(!templ) return \"\";\n";
|
||||
file << "HttpViewData data = " << viewDataName << ";\n";
|
||||
file << "auto str = std::move(" << streamName << ".str());\n";
|
||||
file << "if(!str.empty() && str[str.length()-1] == '\\n') "
|
||||
"str.resize(str.length()-1);\n";
|
||||
file << "data[\"\"] = std::move(str);\n";
|
||||
file << "return templ->genText(data);\n";
|
||||
file << "}\n}\n";
|
||||
}
|
45
vendors/drogon/drogon_ctl/create_view.h
vendored
Normal file
45
vendors/drogon/drogon_ctl/create_view.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
*
|
||||
* @file create_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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class create_view : public DrObject<create_view>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "create view class files";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
std::vector<std::string> namespaces_;
|
||||
bool pathToNamespaceFlag_{false};
|
||||
void createViewFiles(std::vector<std::string> &cspFileNames);
|
||||
int createViewFile(const std::string &script_filename);
|
||||
void newViewHeaderFile(std::ofstream &file, const std::string &className);
|
||||
void newViewSourceFile(std::ofstream &file,
|
||||
const std::string &className,
|
||||
const std::string &namespacePrefix,
|
||||
std::ifstream &infile);
|
||||
};
|
||||
} // namespace drogon_ctl
|
70
vendors/drogon/drogon_ctl/help.cc
vendored
Normal file
70
vendors/drogon/drogon_ctl/help.cc
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* help.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "help.h"
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
using namespace drogon_ctl;
|
||||
|
||||
void help::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
if (parameters.size() == 0)
|
||||
{
|
||||
std::cout << "usage: drogon_ctl [-v | --version] [-h | --help] "
|
||||
"<command> [<args>]"
|
||||
<< std::endl;
|
||||
std::cout << "commands list:" << std::endl;
|
||||
for (auto &className : drogon::DrClassMap::getAllClassName())
|
||||
{
|
||||
auto classPtr = std::shared_ptr<DrObjectBase>(
|
||||
drogon::DrClassMap::newObject(className));
|
||||
if (classPtr)
|
||||
{
|
||||
auto cmdHdlPtr =
|
||||
std::dynamic_pointer_cast<CommandHandler>(classPtr);
|
||||
if (cmdHdlPtr)
|
||||
{
|
||||
if (!cmdHdlPtr->isTopCommand())
|
||||
continue;
|
||||
auto pos = className.rfind("::");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
className = className.substr(pos + 2);
|
||||
}
|
||||
while (className.length() < 24)
|
||||
className.append(" ");
|
||||
std::cout << className << cmdHdlPtr->script() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto cmd = std::string("drogon_ctl::") + parameters[0];
|
||||
|
||||
auto classPtr =
|
||||
std::shared_ptr<DrObjectBase>(drogon::DrClassMap::newObject(cmd));
|
||||
if (classPtr)
|
||||
{
|
||||
auto cmdHdlPtr =
|
||||
std::dynamic_pointer_cast<CommandHandler>(classPtr);
|
||||
if (cmdHdlPtr)
|
||||
{
|
||||
if (cmdHdlPtr->isTopCommand())
|
||||
std::cout << cmdHdlPtr->detail() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
vendors/drogon/drogon_ctl/help.h
vendored
Normal file
38
vendors/drogon/drogon_ctl/help.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
*
|
||||
* help.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class help : public DrObject<help>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "display this message";
|
||||
}
|
||||
|
||||
bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace drogon_ctl
|
49
vendors/drogon/drogon_ctl/main.cc
vendored
Executable file
49
vendors/drogon/drogon_ctl/main.cc
vendored
Executable file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
*
|
||||
* @file main.cc
|
||||
* @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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cmd.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
if (argc < 2)
|
||||
{
|
||||
args = {"help"};
|
||||
exeCommand(args);
|
||||
return 0;
|
||||
}
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
args.push_back(argv[i]);
|
||||
}
|
||||
if (args.size() > 0)
|
||||
{
|
||||
auto &arg = args[0];
|
||||
if (arg == "-h" || arg == "--help")
|
||||
{
|
||||
arg = "help";
|
||||
}
|
||||
else if (arg == "-v" || arg == "--version")
|
||||
{
|
||||
arg = "version";
|
||||
}
|
||||
}
|
||||
|
||||
exeCommand(args);
|
||||
|
||||
return 0;
|
||||
}
|
327
vendors/drogon/drogon_ctl/press.cc
vendored
Normal file
327
vendors/drogon/drogon_ctl/press.cc
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
/**
|
||||
*
|
||||
* press.cc
|
||||
* An Tao
|
||||
*
|
||||
* Copyright 2018, An Tao. All rights reserved.
|
||||
* https://github.com/an-tao/drogon
|
||||
* Use of this source code is governed by the MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* Drogon
|
||||
*
|
||||
*/
|
||||
|
||||
#include "press.h"
|
||||
#include "cmd.h"
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace drogon_ctl;
|
||||
|
||||
std::string press::detail()
|
||||
{
|
||||
return "Use press command to do stress testing\n"
|
||||
"Usage:drogon_ctl press <options> <url>\n"
|
||||
" -n num number of requests(default : 1)\n"
|
||||
" -t num number of threads(default : 1)\n"
|
||||
" -c num concurrent connections(default : 1)\n"
|
||||
" -k disable SSL certificate validation(default: enable)\n"
|
||||
" -q no progress indication(default: show)\n\n"
|
||||
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
|
||||
"http://localhost:8080/index.html\n";
|
||||
}
|
||||
|
||||
void outputErrorAndExit(const std::string_view &err)
|
||||
{
|
||||
std::cout << err << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void press::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
for (auto iter = parameters.begin(); iter != parameters.end(); iter++)
|
||||
{
|
||||
auto ¶m = *iter;
|
||||
if (param.find("-n") == 0)
|
||||
{
|
||||
if (param == "-n")
|
||||
{
|
||||
++iter;
|
||||
if (iter == parameters.end())
|
||||
{
|
||||
outputErrorAndExit("No number of requests!");
|
||||
}
|
||||
auto &num = *iter;
|
||||
try
|
||||
{
|
||||
numOfRequests_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of requests!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto num = param.substr(2);
|
||||
try
|
||||
{
|
||||
numOfRequests_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of requests!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (param.find("-t") == 0)
|
||||
{
|
||||
if (param == "-t")
|
||||
{
|
||||
++iter;
|
||||
if (iter == parameters.end())
|
||||
{
|
||||
outputErrorAndExit("No number of threads!");
|
||||
}
|
||||
auto &num = *iter;
|
||||
try
|
||||
{
|
||||
numOfThreads_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of threads!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto num = param.substr(2);
|
||||
try
|
||||
{
|
||||
numOfThreads_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of threads!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (param.find("-c") == 0)
|
||||
{
|
||||
if (param == "-c")
|
||||
{
|
||||
++iter;
|
||||
if (iter == parameters.end())
|
||||
{
|
||||
outputErrorAndExit("No number of connections!");
|
||||
}
|
||||
auto &num = *iter;
|
||||
try
|
||||
{
|
||||
numOfConnections_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of connections!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto num = param.substr(2);
|
||||
try
|
||||
{
|
||||
numOfConnections_ = std::stoll(num);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
outputErrorAndExit("Invalid number of connections!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (param == "-k")
|
||||
{
|
||||
certValidation_ = false;
|
||||
continue;
|
||||
}
|
||||
else if (param == "-q")
|
||||
{
|
||||
processIndication_ = false;
|
||||
}
|
||||
else if (param[0] != '-')
|
||||
{
|
||||
url_ = param;
|
||||
}
|
||||
}
|
||||
// std::cout << "n=" << numOfRequests_ << std::endl;
|
||||
// std::cout << "t=" << numOfThreads_ << std::endl;
|
||||
// std::cout << "c=" << numOfConnections_ << std::endl;
|
||||
// std::cout << "q=" << processIndication_ << std::endl;
|
||||
// std::cout << "url=" << url_ << std::endl;
|
||||
if (url_.empty() || url_.compare(0, 4, "http") != 0 ||
|
||||
(url_.compare(4, 3, "://") != 0 && url_.compare(4, 4, "s://") != 0))
|
||||
{
|
||||
outputErrorAndExit("Invalid URL");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pos = url_.find("://");
|
||||
auto posOfPath = url_.find('/', pos + 3);
|
||||
if (posOfPath == std::string::npos)
|
||||
{
|
||||
host_ = url_;
|
||||
path_ = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
host_ = url_.substr(0, posOfPath);
|
||||
path_ = url_.substr(posOfPath);
|
||||
}
|
||||
}
|
||||
// std::cout << "host=" << host_ << std::endl;
|
||||
// std::cout << "path=" << path_ << std::endl;
|
||||
doTesting();
|
||||
}
|
||||
|
||||
void press::doTesting()
|
||||
{
|
||||
createRequestAndClients();
|
||||
if (clients_.empty())
|
||||
{
|
||||
outputErrorAndExit("No connection!");
|
||||
}
|
||||
statistics_.startDate_ = trantor::Date::now();
|
||||
for (auto &client : clients_)
|
||||
{
|
||||
sendRequest(client);
|
||||
}
|
||||
loopPool_->wait();
|
||||
}
|
||||
|
||||
void press::createRequestAndClients()
|
||||
{
|
||||
loopPool_ = std::make_unique<trantor::EventLoopThreadPool>(numOfThreads_);
|
||||
loopPool_->start();
|
||||
for (size_t i = 0; i < numOfConnections_; ++i)
|
||||
{
|
||||
auto client = HttpClient::newHttpClient(host_,
|
||||
loopPool_->getNextLoop(),
|
||||
false,
|
||||
certValidation_);
|
||||
client->enableCookies();
|
||||
clients_.push_back(client);
|
||||
}
|
||||
}
|
||||
|
||||
void press::sendRequest(const HttpClientPtr &client)
|
||||
{
|
||||
auto numOfRequest = statistics_.numOfRequestsSent_++;
|
||||
if (numOfRequest >= numOfRequests_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto request = HttpRequest::newHttpRequest();
|
||||
request->setPath(path_);
|
||||
request->setMethod(Get);
|
||||
// std::cout << "send!" << std::endl;
|
||||
client->sendRequest(
|
||||
request,
|
||||
[this, client, request](ReqResult r, const HttpResponsePtr &resp) {
|
||||
size_t goodNum, badNum;
|
||||
if (r == ReqResult::Ok)
|
||||
{
|
||||
// std::cout << "OK" << std::endl;
|
||||
goodNum = ++statistics_.numOfGoodResponse_;
|
||||
badNum = statistics_.numOfBadResponse_;
|
||||
statistics_.bytesRecieved_ += resp->body().length();
|
||||
auto delay = trantor::Date::now().microSecondsSinceEpoch() -
|
||||
request->creationDate().microSecondsSinceEpoch();
|
||||
statistics_.totalDelay_ += delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
goodNum = statistics_.numOfGoodResponse_;
|
||||
badNum = ++statistics_.numOfBadResponse_;
|
||||
if (badNum > numOfRequests_ / 10)
|
||||
{
|
||||
outputErrorAndExit("Too many errors");
|
||||
}
|
||||
}
|
||||
if (goodNum + badNum >= numOfRequests_)
|
||||
{
|
||||
outputResults();
|
||||
}
|
||||
if (r == ReqResult::Ok)
|
||||
sendRequest(client);
|
||||
else
|
||||
{
|
||||
client->getLoop()->runAfter(1, [this, client]() {
|
||||
sendRequest(client);
|
||||
});
|
||||
}
|
||||
|
||||
if (processIndication_)
|
||||
{
|
||||
auto rec = goodNum + badNum;
|
||||
if (rec % 100000 == 0)
|
||||
{
|
||||
std::cout << rec << " responses are received" << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void press::outputResults()
|
||||
{
|
||||
size_t totalSent = 0;
|
||||
size_t totalRecv = 0;
|
||||
for (auto &client : clients_)
|
||||
{
|
||||
totalSent += client->bytesSent();
|
||||
totalRecv += client->bytesReceived();
|
||||
}
|
||||
auto now = trantor::Date::now();
|
||||
auto microSecs = now.microSecondsSinceEpoch() -
|
||||
statistics_.startDate_.microSecondsSinceEpoch();
|
||||
double seconds = (double)microSecs / 1000000.0;
|
||||
auto rps = static_cast<size_t>(statistics_.numOfGoodResponse_ / seconds);
|
||||
std::cout << std::endl;
|
||||
std::cout << "TOTALS: " << numOfConnections_ << " connect, "
|
||||
<< numOfRequests_ << " requests, "
|
||||
<< statistics_.numOfGoodResponse_ << " success, "
|
||||
<< statistics_.numOfBadResponse_ << " fail" << std::endl;
|
||||
|
||||
std::cout << "TRAFFIC: "
|
||||
<< statistics_.bytesRecieved_ / statistics_.numOfGoodResponse_
|
||||
<< " avg bytes, "
|
||||
<< (totalRecv - statistics_.bytesRecieved_) /
|
||||
statistics_.numOfGoodResponse_
|
||||
<< " avg overhead, " << statistics_.bytesRecieved_ << " bytes, "
|
||||
<< totalRecv - statistics_.bytesRecieved_ << " overhead"
|
||||
<< std::endl;
|
||||
|
||||
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(3)
|
||||
<< "TIMING: " << seconds << " seconds, " << rps << " rps, "
|
||||
<< (double)(statistics_.totalDelay_) /
|
||||
statistics_.numOfGoodResponse_ / 1000
|
||||
<< " ms avg req time" << std::endl;
|
||||
|
||||
std::cout << "SPEED: download " << totalRecv / seconds / 1000
|
||||
<< " kBps, upload " << totalSent / seconds / 1000 << " kBps"
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
exit(0);
|
||||
}
|
78
vendors/drogon/drogon_ctl/press.h
vendored
Normal file
78
vendors/drogon/drogon_ctl/press.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
*
|
||||
* press.h
|
||||
* An Tao
|
||||
*
|
||||
* Copyright 2018, An Tao. All rights reserved.
|
||||
* https://github.com/an-tao/drogon
|
||||
* Use of this source code is governed by the MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* Drogon
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CommandHandler.h"
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <drogon/HttpClient.h>
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <trantor/net/EventLoopThreadPool.h>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
struct Statistics
|
||||
{
|
||||
std::atomic_size_t numOfRequestsSent_{0};
|
||||
std::atomic_size_t bytesRecieved_{0};
|
||||
std::atomic_size_t numOfGoodResponse_{0};
|
||||
std::atomic_size_t numOfBadResponse_{0};
|
||||
std::atomic_size_t totalDelay_{0};
|
||||
trantor::Date startDate_;
|
||||
trantor::Date endDate_;
|
||||
};
|
||||
|
||||
class press : public DrObject<press>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶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:
|
||||
size_t numOfThreads_{1};
|
||||
size_t numOfRequests_{1};
|
||||
size_t numOfConnections_{1};
|
||||
bool certValidation_{true};
|
||||
bool processIndication_{true};
|
||||
std::string url_;
|
||||
std::string host_;
|
||||
std::string path_;
|
||||
void doTesting();
|
||||
void createRequestAndClients();
|
||||
void sendRequest(const HttpClientPtr &client);
|
||||
void outputResults();
|
||||
std::unique_ptr<trantor::EventLoopThreadPool> loopPool_;
|
||||
std::vector<HttpClientPtr> clients_;
|
||||
Statistics statistics_;
|
||||
};
|
||||
} // namespace drogon_ctl
|
75
vendors/drogon/drogon_ctl/templates/cmake.csp
vendored
Normal file
75
vendors/drogon/drogon_ctl/templates/cmake.csp
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project([[ProjectName]] CXX)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
|
||||
check_include_file_cxx(any HAS_ANY)
|
||||
check_include_file_cxx(string_view HAS_STRING_VIEW)
|
||||
check_include_file_cxx(coroutine HAS_COROUTINE)
|
||||
if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "")
|
||||
# Do nothing
|
||||
elseif (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
elseif (HAS_ANY AND HAS_STRING_VIEW)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
else ()
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif ()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cc)
|
||||
|
||||
# ##############################################################################
|
||||
# If you include the drogon source code locally in your project, use this method
|
||||
# to add drogon
|
||||
# add_subdirectory(drogon)
|
||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
||||
#
|
||||
# and comment out the following lines
|
||||
find_package(Drogon CONFIG REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
||||
|
||||
# ##############################################################################
|
||||
|
||||
if (CMAKE_CXX_STANDARD LESS 17)
|
||||
message(FATAL_ERROR "c++17 or higher is required")
|
||||
elseif (CMAKE_CXX_STANDARD LESS 20)
|
||||
message(STATUS "use c++17")
|
||||
else ()
|
||||
message(STATUS "use c++20")
|
||||
endif ()
|
||||
|
||||
aux_source_directory(controllers CTL_SRC)
|
||||
aux_source_directory(filters FILTER_SRC)
|
||||
aux_source_directory(plugins PLUGIN_SRC)
|
||||
aux_source_directory(models MODEL_SRC)
|
||||
|
||||
drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
# use the following line to create views with namespaces.
|
||||
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
||||
# ${CMAKE_CURRENT_BINARY_DIR} TRUE)
|
||||
# use the following line to create views with namespace CHANGE_ME prefixed
|
||||
# and path namespaces.
|
||||
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
||||
# ${CMAKE_CURRENT_BINARY_DIR} TRUE CHANGE_ME)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/models)
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${SRC_DIR}
|
||||
${CTL_SRC}
|
||||
${FILTER_SRC}
|
||||
${PLUGIN_SRC}
|
||||
${MODEL_SRC})
|
||||
# ##############################################################################
|
||||
# uncomment the following line for dynamically loading views
|
||||
# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON)
|
||||
|
||||
# ##############################################################################
|
||||
|
||||
add_subdirectory(test)
|
345
vendors/drogon/drogon_ctl/templates/config_json.csp
vendored
Normal file
345
vendors/drogon/drogon_ctl/templates/config_json.csp
vendored
Normal file
@ -0,0 +1,345 @@
|
||||
/* This is a JSON format configuration file
|
||||
*/
|
||||
{
|
||||
/*
|
||||
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
||||
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||
"ssl": {
|
||||
"cert": "../../trantor/trantor/tests/server.crt",
|
||||
"key": "../../trantor/trantor/tests/server.key",
|
||||
"conf": [
|
||||
//["Options", "-SessionTicket"],
|
||||
//["Options", "Compression"]
|
||||
]
|
||||
},
|
||||
"listeners": [
|
||||
{
|
||||
//address: Ip address,0.0.0.0 by default
|
||||
"address": "0.0.0.0",
|
||||
//port: Port number
|
||||
"port": 80,
|
||||
//https: If true, use https for security,false by default
|
||||
"https": false
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"port": 443,
|
||||
"https": true,
|
||||
//cert,key: Cert file path and key file path, empty by default,
|
||||
//if empty, use the global setting
|
||||
"cert": "",
|
||||
"key": "",
|
||||
//use_old_tls: enable the TLS1.0/1.1, false by default
|
||||
"use_old_tls": false,
|
||||
"ssl_conf": [
|
||||
//["MinProtocol", "TLSv1.3"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"db_clients": [
|
||||
{
|
||||
//name: Name of the client,'default' by default
|
||||
//"name":"",
|
||||
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||
"rdbms": "postgresql",
|
||||
//filename: Sqlite3 db file name
|
||||
//"filename":"",
|
||||
//host: Server address,localhost by default
|
||||
"host": "127.0.0.1",
|
||||
//port: Server port, 5432 by default
|
||||
"port": 5432,
|
||||
//dbname: Database name
|
||||
"dbname": "test",
|
||||
//user: 'postgres' by default
|
||||
"user": "",
|
||||
//passwd: '' by default
|
||||
"passwd": "",
|
||||
//is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
//any synchronous interface of it.
|
||||
"is_fast": false,
|
||||
//client_encoding: The character set used by the client. it is empty string by default which
|
||||
//means use the default character set.
|
||||
//"client_encoding": "",
|
||||
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
//connections per IO thread, otherwise it is the total number of all connections.
|
||||
"number_of_connections": 1,
|
||||
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0,
|
||||
//"auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||
// the wiki for more details.
|
||||
"auto_batch": false
|
||||
}
|
||||
],
|
||||
"redis_clients": [
|
||||
{
|
||||
//name: Name of the client,'default' by default
|
||||
//"name":"",
|
||||
//host: Server IP, 127.0.0.1 by default
|
||||
"host": "127.0.0.1",
|
||||
//port: Server port, 6379 by default
|
||||
"port": 6379,
|
||||
//username: '' by default which means 'default' in redis ACL
|
||||
"username": "",
|
||||
//passwd: '' by default
|
||||
"passwd": "",
|
||||
//db index: 0 by default
|
||||
"db": 0,
|
||||
//is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
//any synchronous interface of it.
|
||||
"is_fast": false,
|
||||
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
//connections per IO thread, otherwise it is the total number of all connections.
|
||||
"number_of_connections": 1,
|
||||
//timeout: -1.0 by default, in seconds, the timeout for executing a command.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0
|
||||
}
|
||||
],*/
|
||||
"app": {
|
||||
//number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
|
||||
//is the number of CPU cores
|
||||
"number_of_threads": 1,
|
||||
//enable_session: False by default
|
||||
"enable_session": false,
|
||||
"session_timeout": 0,
|
||||
//string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||
"session_same_site" : "Null",
|
||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
||||
"session_cookie_key": "JSESSIONID",
|
||||
//session_max_age: The max age of the session cookie, -1 by default
|
||||
"session_max_age": -1,
|
||||
//document_root: Root path of HTTP document, defaut path is ./
|
||||
"document_root": "./",
|
||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
||||
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
|
||||
//to the request for "/".
|
||||
"home_page": "index.html",
|
||||
//use_implicit_page: enable implicit pages if true, true by default
|
||||
"use_implicit_page": true,
|
||||
//implicit_page: Set the file which would the server access in a directory that a user accessed.
|
||||
//For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
|
||||
"implicit_page": "index.html",
|
||||
//static_file_headers: Headers for static files
|
||||
/*"static_file_headers": [
|
||||
{
|
||||
"name": "field-name",
|
||||
"value": "field-value"
|
||||
}
|
||||
],*/
|
||||
//upload_path: The path to save the uploaded file. "uploads" by default.
|
||||
//If the path isn't prefixed with /, ./ or ../,
|
||||
//it is relative path of document_root path
|
||||
"upload_path": "uploads",
|
||||
/* file_types:
|
||||
* HTTP download file types,The file types supported by drogon
|
||||
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
|
||||
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
|
||||
* "gif", "bmp", "ico", "icns", etc. */
|
||||
"file_types": [
|
||||
"gif",
|
||||
"png",
|
||||
"jpg",
|
||||
"js",
|
||||
"css",
|
||||
"html",
|
||||
"ico",
|
||||
"swf",
|
||||
"xap",
|
||||
"apk",
|
||||
"cur",
|
||||
"xml",
|
||||
"webp",
|
||||
"svg"
|
||||
],
|
||||
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||
"mime": {
|
||||
// "text/markdown": "md",
|
||||
// "text/gemini": ["gmi", "gemini"]
|
||||
},
|
||||
//locations: An array of locations of static files for GET requests.
|
||||
"locations": [
|
||||
{
|
||||
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
|
||||
//"uri_prefix": "/.well-known/acme-challenge/",
|
||||
//default_content_type: The default content type of the static files without
|
||||
//an extension. empty string by default.
|
||||
"default_content_type": "text/plain",
|
||||
//alias: The location in file system, if it is prefixed with "/", it
|
||||
//presents an absolute path, otherwise it presents a relative path to
|
||||
//the document_root path.
|
||||
//The default value is "" which means use the document root path as the location base path.
|
||||
"alias": "",
|
||||
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
|
||||
"is_case_sensitive": false,
|
||||
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
|
||||
"allow_all": true,
|
||||
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
|
||||
"is_recursive": true,
|
||||
//filters: string array, the filters applied to the location.
|
||||
"filters": []
|
||||
}
|
||||
],
|
||||
//max_connections: maximum number of connections, 100000 by default
|
||||
"max_connections": 100000,
|
||||
//max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||
"max_connections_per_ip": 0,
|
||||
//Load_dynamic_views: False by default, when set to true, drogon
|
||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||
//by "dynamic_views_path"
|
||||
"load_dynamic_views": false,
|
||||
//dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
|
||||
//it is relative path of document_root path
|
||||
"dynamic_views_path": [
|
||||
"./views"
|
||||
],
|
||||
//dynamic_views_output_path: Default by an empty string which means the output path of source
|
||||
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
|
||||
//path of the current working directory.
|
||||
"dynamic_views_output_path": "",
|
||||
//json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
|
||||
"json_parser_stack_limit": 1000,
|
||||
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
|
||||
"enable_unicode_escaping_in_json": true,
|
||||
//float_precision_in_json: set precision of float number in json.
|
||||
"float_precision_in_json": {
|
||||
//precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
|
||||
"precision": 0,
|
||||
//precision_type: must be "significant" or "decimal", defaults to "significant" that means
|
||||
//setting max number of significant digits in string, "decimal" means setting max number of
|
||||
//digits after "." in string
|
||||
"precision_type": "significant"
|
||||
},
|
||||
//log: Set log output, drogon output logs to stdout by default
|
||||
"log": {
|
||||
//use_spdlog: Use spdlog library to log
|
||||
//"use_spdlog": false
|
||||
"use_spdlog": false,
|
||||
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||
//"log_path": "./",
|
||||
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||
//drogon.log ...
|
||||
"logfile_base_name": "",
|
||||
//log_size_limit: 100000000 bytes by default,
|
||||
//When the log file size reaches "log_size_limit", the log file is switched.
|
||||
"log_size_limit": 100000000,
|
||||
//max_files: 0 by default,
|
||||
//When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
|
||||
"max_files": 0,
|
||||
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||
//The TRACE level is only valid when built in DEBUG mode.
|
||||
"log_level": "DEBUG",
|
||||
//display_local_time: false by default, if true, the log time is displayed in local time
|
||||
"display_local_time": false
|
||||
},
|
||||
//run_as_daemon: False by default
|
||||
"run_as_daemon": false,
|
||||
//handle_sig_term: True by default
|
||||
"handle_sig_term": true,
|
||||
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
|
||||
"relaunch_on_error": false,
|
||||
//use_sendfile: True by default, if true, the program
|
||||
//uses sendfile() system-call to send static files to clients;
|
||||
"use_sendfile": true,
|
||||
//use_gzip: True by default, use gzip to compress the response body's content;
|
||||
"use_gzip": true,
|
||||
//use_brotli: False by default, use brotli to compress the response body's content;
|
||||
"use_brotli": false,
|
||||
//static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
|
||||
//0 means cache forever, the negative value means no cache
|
||||
"static_files_cache_time": 5,
|
||||
//simple_controllers_map: Used to configure mapping from path to simple controller
|
||||
//"simple_controllers_map": [
|
||||
// {
|
||||
// "path": "/path/name",
|
||||
// "controller": "controllerClassName",
|
||||
// "http_methods": [
|
||||
// "get",
|
||||
// "post"
|
||||
// ],
|
||||
// "filters": [
|
||||
// "FilterClassName"
|
||||
// ]
|
||||
// }
|
||||
//],
|
||||
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||
//of the connection without read or write
|
||||
"idle_connection_timeout": 60,
|
||||
//server_header_field: Set the 'Server' header field in each response sent by drogon,
|
||||
//empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
|
||||
"server_header_field": "",
|
||||
//enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
|
||||
//value is true.
|
||||
"enable_server_header": true,
|
||||
//enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
|
||||
//value is true.
|
||||
"enable_date_header": true,
|
||||
//keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
|
||||
//After the maximum number of requests are made, the connection is closed.
|
||||
//The default value of 0 means no limit.
|
||||
"keepalive_requests": 0,
|
||||
//pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
|
||||
//After the maximum number of requests are made, the connection is closed.
|
||||
//The default value of 0 means no limit.
|
||||
"pipelining_requests": 0,
|
||||
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
//The default value of gzip_static is true.
|
||||
"gzip_static": true,
|
||||
//br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
//file with the extension ".br" in the same path and send the compressed file to the client.
|
||||
//The default value of br_static is true.
|
||||
"br_static": true,
|
||||
//client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_body_size": "1M",
|
||||
//max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
|
||||
//If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
|
||||
//Setting it to "" means no limit.
|
||||
"client_max_memory_body_size": "64K",
|
||||
//client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
|
||||
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
"client_max_websocket_message_size": "128K",
|
||||
//reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||
"reuse_port": false,
|
||||
// enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||
// will be rejected.
|
||||
"enabled_compressed_request": false
|
||||
},
|
||||
//plugins: Define all plugins running in the application
|
||||
"plugins": [
|
||||
{
|
||||
//name: The class name of the plugin
|
||||
"name": "drogon::plugin::PromExporter",
|
||||
//dependencies: Plugins that the plugin depends on. It can be commented out
|
||||
"dependencies": [],
|
||||
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||
//It can be commented out
|
||||
"config": {
|
||||
"path": "/metrics"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drogon::plugin::AccessLogger",
|
||||
"dependencies": [],
|
||||
"config": {
|
||||
"use_spdlog": false,
|
||||
"log_path": "",
|
||||
"log_format": "",
|
||||
"log_file": "access.log",
|
||||
"log_size_limit": 0,
|
||||
"use_local_time": true,
|
||||
"log_index": 0,
|
||||
// "show_microseconds": true,
|
||||
// "custom_time_format": "",
|
||||
// "use_real_ip": false
|
||||
}
|
||||
}
|
||||
],
|
||||
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||
"custom_config": {}
|
||||
}
|
296
vendors/drogon/drogon_ctl/templates/config_yaml.csp
vendored
Normal file
296
vendors/drogon/drogon_ctl/templates/config_yaml.csp
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
# This is a YAML format configuration file
|
||||
|
||||
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
||||
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||
# ssl:
|
||||
# cert: ../../trantor/trantor/tests/server.pem
|
||||
# key: ../../trantor/trantor/tests/server.pem
|
||||
# conf: [
|
||||
# # [Options, -SessionTicket],
|
||||
# # [Options, Compression]
|
||||
# ]
|
||||
# listeners:
|
||||
# # address: Ip address,0.0.0.0 by default
|
||||
# - address: 0.0.0.0
|
||||
# # port: Port number
|
||||
# port: 80
|
||||
# # https: If true, use https for security,false by default
|
||||
# https: false
|
||||
# - address: 0.0.0.0
|
||||
# port: 443
|
||||
# https: true
|
||||
# # cert,key: Cert file path and key file path, empty by default,
|
||||
# # if empty, use the global setting
|
||||
# cert: ''
|
||||
# key: ''
|
||||
# # use_old_tls: enable the TLS1.0/1.1, false by default
|
||||
# use_old_tls: false
|
||||
# ssl_conf: [
|
||||
# # [MinProtocol, TLSv1.3]
|
||||
# ]
|
||||
# db_clients:
|
||||
# # name: Name of the client,'default' by default
|
||||
# - name: ''
|
||||
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||
# rdbms: postgresql
|
||||
# # filename: Sqlite3 db file name
|
||||
# # filename: '',
|
||||
# # host: Server address,localhost by default
|
||||
# host: 127.0.0.1
|
||||
# # port: Server port, 5432 by default
|
||||
# port: 5432
|
||||
# # dbname: Database name
|
||||
# dbname: test
|
||||
# # user: 'postgres' by default
|
||||
# user: ''
|
||||
# # passwd: '' by default
|
||||
# passwd: ''
|
||||
# # is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
# # any synchronous interface of it.
|
||||
# is_fast: false
|
||||
# # client_encoding: The character set used by the client. it is empty string by default which
|
||||
# # means use the default character set.
|
||||
# # client_encoding: '',
|
||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||
# number_of_connections: 1
|
||||
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
||||
# # zero or negative value means no timeout.
|
||||
# timeout: -1
|
||||
# # "auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||
# # the wiki for more details.
|
||||
# auto_batch: false
|
||||
# redis_clients:
|
||||
# # name: Name of the client,'default' by default
|
||||
# - name: ''
|
||||
# # host: Server IP, 127.0.0.1 by default
|
||||
# host: 127.0.0.1
|
||||
# # port: Server port, 6379 by default
|
||||
# port: 6379
|
||||
# # username: '' by default which means 'default' in redis ACL
|
||||
# username: ''
|
||||
# # passwd: '' by default
|
||||
# passwd: ''
|
||||
# # db index: 0 by default
|
||||
# db: 0
|
||||
# # is_fast: false by default, if it is true, the client is faster but user can't call
|
||||
# # any synchronous interface of it.
|
||||
# is_fast: false
|
||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
||||
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||
# number_of_connections: 1
|
||||
# # timeout: -1.0 by default, in seconds, the timeout for executing a command.
|
||||
# # zero or negative value means no timeout.
|
||||
# timeout: -1
|
||||
app:
|
||||
# number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
|
||||
# is the number of CPU cores
|
||||
number_of_threads: 1
|
||||
# enable_session: False by default
|
||||
enable_session: true
|
||||
session_timeout: 0
|
||||
# string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||
session_same_site: 'Null'
|
||||
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
||||
session_cookie_key: 'JSESSIONID'
|
||||
# session_max_age: The max age of the session cookie, -1 by default
|
||||
session_max_age: -1
|
||||
# document_root: Root path of HTTP document, defaut path is ./
|
||||
document_root: ./
|
||||
# home_page: Set the HTML file of the home page, the default value is "index.html"
|
||||
# If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
|
||||
# to the request for "/".
|
||||
home_page: index.html
|
||||
# use_implicit_page: enable implicit pages if true, true by default
|
||||
use_implicit_page: true
|
||||
# implicit_page: Set the file which would the server access in a directory that a user accessed.
|
||||
# For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
|
||||
implicit_page: index.html
|
||||
# static_file_headers: Headers for static files
|
||||
# static_file_headers:
|
||||
# - name: field-name
|
||||
# value: field-value
|
||||
# upload_path: The path to save the uploaded file. "uploads" by default.
|
||||
# If the path isn't prefixed with /, ./ or ../,
|
||||
# it is relative path of document_root path
|
||||
upload_path: uploads
|
||||
# file_types:
|
||||
# HTTP download file types,The file types supported by drogon
|
||||
# by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
|
||||
# "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
|
||||
# "gif", "bmp", "ico", "icns", etc.
|
||||
file_types:
|
||||
- gif
|
||||
- png
|
||||
- jpg
|
||||
- js
|
||||
- css
|
||||
- html
|
||||
- ico
|
||||
- swf
|
||||
- xap
|
||||
- apk
|
||||
- cur
|
||||
- xml
|
||||
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||
mime: {
|
||||
# text/markdown: md,
|
||||
# text/gemini: [gmi, gemini]
|
||||
}
|
||||
# locations: An array of locations of static files for GET requests.
|
||||
locations:
|
||||
# uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
|
||||
- uri_prefix: '' # /.well-known/acme-challenge/
|
||||
# default_content_type: The default content type of the static files without
|
||||
# an extension. empty string by default.
|
||||
default_content_type: text/plain
|
||||
# alias: The location in file system, if it is prefixed with "/", it
|
||||
# presents an absolute path, otherwise it presents a relative path to
|
||||
# the document_root path.
|
||||
# The default value is "" which means use the document root path as the location base path.
|
||||
alias: ''
|
||||
# is_case_sensitive: indicates whether the URI prefix is case sensitive.
|
||||
is_case_sensitive: false
|
||||
# allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
|
||||
allow_all: true
|
||||
# is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
|
||||
is_recursive: true
|
||||
# filters: string array, the filters applied to the location.
|
||||
filters: []
|
||||
# max_connections: maximum number of connections, 100000 by default
|
||||
max_connections: 100000
|
||||
# max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||
max_connections_per_ip: 0
|
||||
# Load_dynamic_views: False by default, when set to true, drogon
|
||||
# compiles and loads dynamically "CSP View Files" in directories defined
|
||||
# by "dynamic_views_path"
|
||||
load_dynamic_views: false
|
||||
# dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
|
||||
# it is relative path of document_root path
|
||||
dynamic_views_path:
|
||||
- ./views
|
||||
# dynamic_views_output_path: Default by an empty string which means the output path of source
|
||||
# files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
|
||||
# path of the current working directory.
|
||||
dynamic_views_output_path: ''
|
||||
# json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
|
||||
json_parser_stack_limit: 1000
|
||||
# enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
|
||||
enable_unicode_escaping_in_json: true
|
||||
# float_precision_in_json: set precision of float number in json.
|
||||
float_precision_in_json:
|
||||
# precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
|
||||
precision: 0
|
||||
# precision_type: must be "significant" or "decimal", defaults to "significant" that means
|
||||
# setting max number of significant digits in string, "decimal" means setting max number of
|
||||
# digits after "." in string
|
||||
precision_type: significant
|
||||
# log: Set log output, drogon output logs to stdout by default
|
||||
log:
|
||||
# use_spdlog: Use spdlog library to log
|
||||
use_spdlog: false,
|
||||
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||
# log_path: ./
|
||||
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||
# drogon.log ...
|
||||
logfile_base_name: ''
|
||||
# log_size_limit: 100000000 bytes by default,
|
||||
# When the log file size reaches "log_size_limit", the log file is switched.
|
||||
log_size_limit: 100000000
|
||||
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||
# The TRACE level is only valid when built in DEBUG mode.
|
||||
log_level: DEBUG
|
||||
# display_local_time: false by default, if true, the log time is displayed in local time
|
||||
display_local_time: false
|
||||
# run_as_daemon: False by default
|
||||
run_as_daemon: false
|
||||
# handle_sig_term: True by default
|
||||
handle_sig_term: true
|
||||
# relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
|
||||
relaunch_on_error: false
|
||||
# use_sendfile: True by default, if true, the program
|
||||
# uses sendfile() system-call to send static files to clients;
|
||||
use_sendfile: true
|
||||
# use_gzip: True by default, use gzip to compress the response body's content;
|
||||
use_gzip: true
|
||||
# use_brotli: False by default, use brotli to compress the response body's content;
|
||||
use_brotli: false
|
||||
# static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
|
||||
# 0 means cache forever, the negative value means no cache
|
||||
static_files_cache_time: 5
|
||||
# simple_controllers_map: Used to configure mapping from path to simple controller
|
||||
simple_controllers_map:
|
||||
- path: /path/name
|
||||
controller: controllerClassName
|
||||
http_methods:
|
||||
- get
|
||||
- post
|
||||
filters:
|
||||
- FilterClassName
|
||||
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||
# of the connection without read or write
|
||||
idle_connection_timeout: 60
|
||||
# server_header_field: Set the 'Server' header field in each response sent by drogon,
|
||||
# empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
|
||||
server_header_field: ''
|
||||
# enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
|
||||
# value is true.
|
||||
enable_server_header: true
|
||||
# enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
|
||||
# value is true.
|
||||
enable_date_header: true
|
||||
# keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
|
||||
# After the maximum number of requests are made, the connection is closed.
|
||||
# The default value of 0 means no limit.
|
||||
keepalive_requests: 0
|
||||
# pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
|
||||
# After the maximum number of requests are made, the connection is closed.
|
||||
# The default value of 0 means no limit.
|
||||
pipelining_requests: 0
|
||||
# gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
# file with the extension ".gz" in the same path and send the compressed file to the client.
|
||||
# The default value of gzip_static is true.
|
||||
gzip_static: true
|
||||
# br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
|
||||
# file with the extension ".br" in the same path and send the compressed file to the client.
|
||||
# The default value of br_static is true.
|
||||
br_static: true
|
||||
# client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
|
||||
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
client_max_body_size: 1M
|
||||
# max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
|
||||
# If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
|
||||
# Setting it to "" means no limit.
|
||||
client_max_memory_body_size: 64K
|
||||
# client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
|
||||
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
|
||||
client_max_websocket_message_size: 128K
|
||||
# reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||
reuse_port: false
|
||||
# enabled_compresed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||
# will be rejected.
|
||||
enabled_compresed_request: false
|
||||
# plugins: Define all plugins running in the application
|
||||
plugins:
|
||||
# name: The class name of the plugin
|
||||
- name: '' # drogon::plugin::SecureSSLRedirector
|
||||
# dependencies: Plugins that the plugin depends on. It can be commented out
|
||||
dependencies: []
|
||||
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||
# It can be commented out
|
||||
config:
|
||||
ssl_redirect_exempt:
|
||||
- .*\.jpg
|
||||
secure_ssl_host: 'localhost:8849'
|
||||
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||
custom_config:
|
||||
realm: drogonRealm
|
||||
opaque: drogonOpaque
|
||||
credentials:
|
||||
- user: drogon
|
||||
password: dr0g0n
|
||||
|
11
vendors/drogon/drogon_ctl/templates/demoMain.csp
vendored
Normal file
11
vendors/drogon/drogon_ctl/templates/demoMain.csp
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include <drogon/drogon.h>
|
||||
int main() {
|
||||
//Set HTTP listener address and port
|
||||
drogon::app().addListener("0.0.0.0", 5555);
|
||||
//Load config file
|
||||
//drogon::app().loadConfigFile("../config.json");
|
||||
//drogon::app().loadConfigFile("../config.yaml");
|
||||
//Run HTTP framework,the method will block in the internal event loop
|
||||
drogon::app().run();
|
||||
return 0;
|
||||
}
|
30
vendors/drogon/drogon_ctl/templates/filter_cc.csp
vendored
Normal file
30
vendors/drogon/drogon_ctl/templates/filter_cc.csp
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
*
|
||||
* [[filename]].cc
|
||||
*
|
||||
*/
|
||||
|
||||
#include "[[filename]].h"
|
||||
|
||||
using namespace drogon;
|
||||
<%c++auto namespaceStr=@@.get<std::string>("namespaceString");
|
||||
if(!namespaceStr.empty())
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
%>
|
||||
|
||||
void [[className]]::doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb)
|
||||
{
|
||||
//Edit your logic here
|
||||
if (1)
|
||||
{
|
||||
//Passed
|
||||
fccb();
|
||||
return;
|
||||
}
|
||||
//Check failed
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
res->setStatusCode(k500InternalServerError);
|
||||
fcb(res);
|
||||
}
|
32
vendors/drogon/drogon_ctl/templates/filter_h.csp
vendored
Normal file
32
vendors/drogon/drogon_ctl/templates/filter_h.csp
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
*
|
||||
* [[filename]].h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpFilter.h>
|
||||
using namespace drogon;
|
||||
<%c++
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
if(namespaceVector.empty())
|
||||
$$<<"\n";
|
||||
for(auto &namespaceName:namespaceVector){%>
|
||||
namespace {%namespaceName%}
|
||||
|
||||
{
|
||||
<%c++}
|
||||
$$<<"\n";%>
|
||||
class [[className]] : public HttpFilter<[[className]]>
|
||||
{
|
||||
public:
|
||||
[[className]]() {}
|
||||
void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) override;
|
||||
};
|
||||
|
||||
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
|
||||
}
|
||||
<%c++}%>
|
561
vendors/drogon/drogon_ctl/templates/gitignore.csp
vendored
Normal file
561
vendors/drogon/drogon_ctl/templates/gitignore.csp
vendored
Normal file
@ -0,0 +1,561 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,visualstudio,visualstudiocode,cmake,c,c++
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,visualstudio,visualstudiocode,cmake,c,c++
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
### C++ ###
|
||||
# Prerequisites
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
|
||||
# Precompiled Headers
|
||||
|
||||
# Linker files
|
||||
|
||||
# Debugger Files
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
|
||||
# Executables
|
||||
|
||||
### CMake ###
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
CMakeUserPresets.json
|
||||
|
||||
### CMake Patch ###
|
||||
# External projects
|
||||
*-prefix/
|
||||
|
||||
### Intellij+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij+all Patch ###
|
||||
# Ignores the whole .idea folder and all .iml files
|
||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||
|
||||
.idea/
|
||||
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
modules.xml
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
*.code-workspace
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.meta
|
||||
*.iobj
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*[.json, .xml, .info]
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
### VisualStudio Patch ###
|
||||
# Additional files built by Visual Studio
|
||||
*.tlog
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/intellij+all,visualstudio,visualstudiocode,cmake,c,c++
|
1768
vendors/drogon/drogon_ctl/templates/model_cc.csp
vendored
Normal file
1768
vendors/drogon/drogon_ctl/templates/model_cc.csp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
569
vendors/drogon/drogon_ctl/templates/model_h.csp
vendored
Normal file
569
vendors/drogon/drogon_ctl/templates/model_h.csp
vendored
Normal file
@ -0,0 +1,569 @@
|
||||
<%inc#include "create_model.h"
|
||||
using namespace drogon_ctl;
|
||||
%>
|
||||
/**
|
||||
*
|
||||
* [[className]].h
|
||||
* DO NOT EDIT. This file is generated by drogon_ctl
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <drogon/orm/Result.h>
|
||||
#include <drogon/orm/Row.h>
|
||||
#include <drogon/orm/Field.h>
|
||||
#include <drogon/orm/SqlBinder.h>
|
||||
#include <drogon/orm/Mapper.h>
|
||||
#include <drogon/orm/BaseBuilder.h>
|
||||
#ifdef __cpp_impl_coroutine
|
||||
#include <drogon/orm/CoroMapper.h>
|
||||
#endif
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <json/json.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace orm
|
||||
{
|
||||
class DbClient;
|
||||
using DbClientPtr = std::shared_ptr<DbClient>;
|
||||
}
|
||||
}
|
||||
namespace drogon_model
|
||||
{
|
||||
namespace [[dbName]]
|
||||
{
|
||||
<%c++
|
||||
auto &schema=@@.get<std::string>("schema");
|
||||
if(!schema.empty())
|
||||
{
|
||||
$$<<"namespace "<<schema<<"\n";
|
||||
$$<<"{\n";
|
||||
}
|
||||
std::vector<std::string> relationshipClassNames;
|
||||
auto &relationships=@@.get<std::vector<Relationship>>("relationships");
|
||||
for(auto &relationship : relationships)
|
||||
{
|
||||
auto &name = relationship.targetTableName();
|
||||
auto relationshipClassName = nameTransform(name, true);
|
||||
relationshipClassNames.push_back(relationshipClassName);
|
||||
if(relationship.type() == Relationship::Type::ManyToMany)
|
||||
{
|
||||
auto &pivotTableName = relationship.pivotTable().tableName();
|
||||
auto pivotTableClassName = nameTransform(pivotTableName, true);
|
||||
relationshipClassNames.push_back(pivotTableClassName);
|
||||
}
|
||||
}
|
||||
std::sort(relationshipClassNames.begin(), relationshipClassNames.end());
|
||||
relationshipClassNames.erase(std::unique(relationshipClassNames.begin(), relationshipClassNames.end()), relationshipClassNames.end());
|
||||
for(std::string &relationshipClassName : relationshipClassNames)
|
||||
{
|
||||
%>
|
||||
class {%relationshipClassName%};
|
||||
<%c++
|
||||
}
|
||||
%>
|
||||
|
||||
class [[className]]
|
||||
{
|
||||
public:
|
||||
struct Cols
|
||||
{
|
||||
<%c++
|
||||
auto cols=@@.get<std::vector<ColumnInfo>>("columns");
|
||||
for(size_t i=0;i<cols.size();i++)
|
||||
{
|
||||
$$<<" static const std::string _"<<cols[i].colName_<<";\n";
|
||||
}
|
||||
%>
|
||||
};
|
||||
|
||||
const static int primaryKeyNumber;
|
||||
const static std::string tableName;
|
||||
const static bool hasPrimaryKey;
|
||||
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
|
||||
const static std::string primaryKeyName;
|
||||
<%c++if(!@@.get<std::string>("primaryKeyType").empty()){%>
|
||||
using PrimaryKeyType = [[primaryKeyType]];
|
||||
const PrimaryKeyType &getPrimaryKey() const;
|
||||
<%c++}else{%>
|
||||
using PrimaryKeyType = void;
|
||||
int getPrimaryKey() const { assert(false); return 0; }
|
||||
<%c++}%>
|
||||
<%c++}else{
|
||||
auto pkTypes=@@.get<std::vector<std::string>>("primaryKeyType");
|
||||
std::string typelist;
|
||||
for(size_t i=0;i<pkTypes.size();i++)
|
||||
{
|
||||
typelist += pkTypes[i];
|
||||
if(i<(pkTypes.size()-1))
|
||||
typelist += ",";
|
||||
}
|
||||
%>
|
||||
const static std::vector<std::string> primaryKeyName;
|
||||
using PrimaryKeyType = std::tuple<{%typelist%}>;//<%c++
|
||||
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
|
||||
for(size_t i=0;i<pkName.size();i++)
|
||||
{
|
||||
$$<<pkName[i];
|
||||
if(i<(pkName.size()-1))
|
||||
$$<<",";
|
||||
}
|
||||
%>
|
||||
|
||||
PrimaryKeyType getPrimaryKey() const;
|
||||
<%c++}%>
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
* @param r One row of records in the SQL query result.
|
||||
* @param indexOffset Set the offset to -1 to access all columns by column names,
|
||||
* otherwise access all columns by offsets.
|
||||
* @note If the SQL is not a style of 'select * from table_name ...' (select all
|
||||
* columns by an asterisk), please set the offset to -1.
|
||||
*/
|
||||
explicit [[className]](const drogon::orm::Row &r, const ssize_t indexOffset = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
* @param pJson The json object to construct a new instance.
|
||||
*/
|
||||
explicit [[className]](const Json::Value &pJson) noexcept(false);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
* @param pJson The json object to construct a new instance.
|
||||
* @param pMasqueradingVector The aliases of table columns.
|
||||
*/
|
||||
[[className]](const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false);
|
||||
|
||||
[[className]]() = default;
|
||||
|
||||
void updateByJson(const Json::Value &pJson) noexcept(false);
|
||||
void updateByMasqueradedJson(const Json::Value &pJson,
|
||||
const std::vector<std::string> &pMasqueradingVector) noexcept(false);
|
||||
static bool validateJsonForCreation(const Json::Value &pJson, std::string &err);
|
||||
static bool validateMasqueradedJsonForCreation(const Json::Value &,
|
||||
const std::vector<std::string> &pMasqueradingVector,
|
||||
std::string &err);
|
||||
static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err);
|
||||
static bool validateMasqueradedJsonForUpdate(const Json::Value &,
|
||||
const std::vector<std::string> &pMasqueradingVector,
|
||||
std::string &err);
|
||||
static bool validJsonOfField(size_t index,
|
||||
const std::string &fieldName,
|
||||
const Json::Value &pJson,
|
||||
std::string &err,
|
||||
bool isForCreation);
|
||||
|
||||
<%c++
|
||||
for(const auto &col:cols)
|
||||
{
|
||||
$$<<" /** For column "<<col.colName_<<" */\n";
|
||||
if(!col.colType_.empty())
|
||||
{
|
||||
$$<<" ///Get the value of the column "<<col.colName_<<", returns the default value if the column is null\n";
|
||||
$$<<" const "<<col.colType_<<" &getValueOf"<<col.colTypeName_<<"() const noexcept;\n";
|
||||
if(col.colType_=="std::vector<char>")
|
||||
{
|
||||
$$<<" ///Return the column value by std::string with binary data\n";
|
||||
$$<<" std::string getValueOf"<<col.colTypeName_<<"AsString() const noexcept;\n";
|
||||
}
|
||||
$$<<" ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null\n";
|
||||
$$<<" const std::shared_ptr<"<<col.colType_<<"> &get"<<col.colTypeName_<<"() const noexcept;\n";
|
||||
|
||||
$$<<" ///Set the value of the column "<<col.colName_<<"\n";
|
||||
$$<<" void set"<<col.colTypeName_<<"(const "<<col.colType_<<" &p"<<col.colTypeName_<<") noexcept;\n";
|
||||
if(col.colType_=="std::string")
|
||||
$$<<" void set"<<col.colTypeName_<<"("<<col.colType_<<" &&p"<<col.colTypeName_<<") noexcept;\n";
|
||||
if(col.colType_=="std::vector<char>")
|
||||
{
|
||||
$$<<" void set"<<col.colTypeName_<<"(const std::string &p"<<col.colTypeName_<<") noexcept;\n";
|
||||
}
|
||||
if(!col.notNull_)
|
||||
{
|
||||
$$<<" void set"<<col.colTypeName_<<"ToNull() noexcept;\n";
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
$$<<" //FIXME!!"<<" getValueOf"<<col.colTypeName_<<"() const noexcept;\n";
|
||||
$$<<"\n";
|
||||
}
|
||||
%>
|
||||
|
||||
static size_t getColumnNumber() noexcept { return {% cols.size() %}; }
|
||||
static const std::string &getColumnName(size_t index) noexcept(false);
|
||||
|
||||
Json::Value toJson() const;
|
||||
Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const;
|
||||
/// Relationship interfaces
|
||||
<%c++
|
||||
for(auto &relationship : relationships)
|
||||
{
|
||||
if(relationship.targetKey().empty() || relationship.originalKey().empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto &name=relationship.targetTableName();
|
||||
auto relationshipClassName=nameTransform(name, true);
|
||||
auto relationshipValName=nameTransform(name, false);
|
||||
auto alias=relationship.targetTableAlias();
|
||||
auto aliasValName=nameTransform(alias, false);
|
||||
if(relationship.type() == Relationship::Type::HasOne)
|
||||
{
|
||||
if(!alias.empty())
|
||||
{
|
||||
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||
{
|
||||
alias[0] += ('A' - 'a');
|
||||
}
|
||||
std::string alind(alias.length(), ' ');
|
||||
%>
|
||||
{%relationshipClassName%} get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
{%relationshipClassName%} get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
else if(relationship.type() == Relationship::Type::HasMany)
|
||||
{
|
||||
if(!alias.empty())
|
||||
{
|
||||
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||
{
|
||||
alias[0] += ('A' - 'a');
|
||||
}
|
||||
std::string alind(alias.length(), ' ');
|
||||
%>
|
||||
std::vector<{%relationshipClassName%}> get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
std::vector<{%relationshipClassName%}> get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
else if(relationship.type() == Relationship::Type::ManyToMany)
|
||||
{
|
||||
auto &pivotTableName=relationship.pivotTable().tableName();
|
||||
auto pivotTableClassName=nameTransform(pivotTableName, true);
|
||||
if(!alias.empty())
|
||||
{
|
||||
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||
{
|
||||
alias[0] += ('A' - 'a');
|
||||
}
|
||||
std::string alind(alias.length(), ' ');
|
||||
%>
|
||||
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
|
||||
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
}
|
||||
%>
|
||||
private:
|
||||
friend drogon::orm::Mapper<[[className]]>;
|
||||
friend drogon::orm::BaseBuilder<[[className]], true, true>;
|
||||
friend drogon::orm::BaseBuilder<[[className]], true, false>;
|
||||
friend drogon::orm::BaseBuilder<[[className]], false, true>;
|
||||
friend drogon::orm::BaseBuilder<[[className]], false, false>;
|
||||
#ifdef __cpp_impl_coroutine
|
||||
friend drogon::orm::CoroMapper<[[className]]>;
|
||||
#endif
|
||||
static const std::vector<std::string> &insertColumns() noexcept;
|
||||
void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
|
||||
const std::vector<std::string> updateColumns() const;
|
||||
void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
|
||||
///For mysql or sqlite3
|
||||
void updateId(const uint64_t id);
|
||||
<%c++
|
||||
for(auto col:cols)
|
||||
{
|
||||
if(!col.colType_.empty())
|
||||
$$<<" std::shared_ptr<"<<col.colType_<<"> "<<col.colValName_<<"_;\n";
|
||||
}
|
||||
%>
|
||||
struct MetaData
|
||||
{
|
||||
const std::string colName_;
|
||||
const std::string colType_;
|
||||
const std::string colDatabaseType_;
|
||||
const ssize_t colLength_;
|
||||
const bool isAutoVal_;
|
||||
const bool isPrimaryKey_;
|
||||
const bool notNull_;
|
||||
};
|
||||
static const std::vector<MetaData> metaData_;
|
||||
bool dirtyFlag_[{%cols.size()%}]={ false };
|
||||
public:
|
||||
static const std::string &sqlForFindingByPrimaryKey()
|
||||
{
|
||||
<%c++
|
||||
auto rdbms=@@.get<std::string>("rdbms");
|
||||
if(@@.get<int>("hasPrimaryKey")<=1){
|
||||
if(!@@.get<std::string>("primaryKeyType").empty()){%>
|
||||
static const std::string sql="select * from " + tableName + " where [[primaryKeyName]] = {%(rdbms=="postgresql"?"$1":"?")%}";
|
||||
<%c++}else{%>
|
||||
static const std::string sql="";
|
||||
<%c++}%>
|
||||
<%c++}else{
|
||||
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
|
||||
%>
|
||||
static const std::string sql="select * from " + tableName + " where <%c++
|
||||
for(size_t i=0;i<pkName.size();i++)
|
||||
{
|
||||
if(rdbms=="postgresql")
|
||||
{
|
||||
$$<<pkName[i]<<" = $"<<i+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$$<<pkName[i]<<" = ?";
|
||||
}
|
||||
if(i<(pkName.size()-1))
|
||||
$$<<" and ";
|
||||
}
|
||||
$$<<"\";\n";
|
||||
}
|
||||
%>
|
||||
return sql;
|
||||
}
|
||||
|
||||
static const std::string &sqlForDeletingByPrimaryKey()
|
||||
{
|
||||
<%c++
|
||||
if(@@.get<int>("hasPrimaryKey")<=1){
|
||||
if(!@@.get<std::string>("primaryKeyType").empty()){%>
|
||||
static const std::string sql="delete from " + tableName + " where [[primaryKeyName]] = {%(rdbms=="postgresql"?"$1":"?")%}";
|
||||
<%c++}else{%>
|
||||
static const std::string sql="";
|
||||
<%c++}%>
|
||||
<%c++}else{
|
||||
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
|
||||
%>
|
||||
static const std::string sql="delete from " + tableName + " where <%c++
|
||||
for(size_t i=0;i<pkName.size();i++)
|
||||
{
|
||||
if(rdbms=="postgresql")
|
||||
{
|
||||
$$<<pkName[i]<<" = $"<<i+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$$<<pkName[i]<<" = ?";
|
||||
}
|
||||
if(i<(pkName.size()-1))
|
||||
$$<<" and ";
|
||||
}
|
||||
$$<<"\";\n";
|
||||
}
|
||||
%>
|
||||
return sql;
|
||||
}
|
||||
std::string sqlForInserting(bool &needSelection) const
|
||||
{
|
||||
std::string sql="insert into " + tableName + " (";
|
||||
size_t parametersCount = 0;
|
||||
needSelection = false;
|
||||
<%c++
|
||||
bool selFlag=false;
|
||||
for(size_t i=0;i<cols.size();i++)
|
||||
{
|
||||
if(cols[i].isAutoVal_)
|
||||
{
|
||||
if(@@.get<std::string>("rdbms")=="sqlite3")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(@@.get<int>("hasPrimaryKey")>0)
|
||||
{
|
||||
selFlag = true;
|
||||
}
|
||||
$$<<" sql += \""<<cols[i].colName_<<",\";\n";
|
||||
$$<<" ++parametersCount;\n";
|
||||
continue;
|
||||
}
|
||||
if(cols[i].colType_.empty())
|
||||
continue;
|
||||
if(cols[i].hasDefaultVal_)
|
||||
{
|
||||
if(@@.get<std::string>("rdbms")!="sqlite3")
|
||||
{
|
||||
$$<<" sql += \""<<cols[i].colName_<<",\";\n";
|
||||
$$<<" ++parametersCount;\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
%>
|
||||
if(dirtyFlag_[{%i%}])
|
||||
{
|
||||
sql += "{%cols[i].colName_%},";
|
||||
++parametersCount;
|
||||
}
|
||||
<%c++
|
||||
}
|
||||
if(@@.get<int>("hasPrimaryKey")>0||@@.get<std::string>("rdbms")=="postgresql")
|
||||
{
|
||||
%>
|
||||
if(!dirtyFlag_[{%i%}])
|
||||
{
|
||||
needSelection=true;
|
||||
}
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
%>
|
||||
if(dirtyFlag_[{%i%}])
|
||||
{
|
||||
sql += "{%cols[i].colName_%},";
|
||||
++parametersCount;
|
||||
}
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
if(selFlag)
|
||||
{
|
||||
$$<<" needSelection=true;\n";
|
||||
}
|
||||
%>
|
||||
if(parametersCount > 0)
|
||||
{
|
||||
sql[sql.length()-1]=')';
|
||||
sql += " values (";
|
||||
}
|
||||
else
|
||||
sql += ") values (";
|
||||
|
||||
<%c++
|
||||
if(@@.get<std::string>("rdbms")=="postgresql")
|
||||
{
|
||||
%>
|
||||
int placeholder=1;
|
||||
char placeholderStr[64];
|
||||
size_t n=0;
|
||||
<%c++
|
||||
}
|
||||
for(size_t i=0;i<cols.size();i++)
|
||||
{
|
||||
if(cols[i].isAutoVal_)
|
||||
{
|
||||
if(@@.get<std::string>("rdbms")!="sqlite3")
|
||||
{
|
||||
%>
|
||||
sql +="default,";
|
||||
<%c++
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(cols[i].colType_.empty())
|
||||
continue;
|
||||
%>
|
||||
if(dirtyFlag_[{%i%}])
|
||||
{
|
||||
<%c++
|
||||
if(@@.get<std::string>("rdbms")=="postgresql")
|
||||
{
|
||||
%>
|
||||
n = snprintf(placeholderStr,sizeof(placeholderStr),"$%d,",placeholder++);
|
||||
sql.append(placeholderStr, n);
|
||||
<%c++
|
||||
}else
|
||||
{
|
||||
%>
|
||||
sql.append("?,");
|
||||
|
||||
<%c++
|
||||
}
|
||||
%>
|
||||
}
|
||||
<%c++
|
||||
if(cols[i].hasDefaultVal_&&@@.get<std::string>("rdbms")!="sqlite3")
|
||||
{
|
||||
%>
|
||||
else
|
||||
{
|
||||
sql +="default,";
|
||||
}
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
%>
|
||||
if(parametersCount > 0)
|
||||
{
|
||||
sql.resize(sql.length() - 1);
|
||||
}
|
||||
<%c++
|
||||
if(rdbms=="postgresql")
|
||||
{
|
||||
%>
|
||||
if(needSelection)
|
||||
{
|
||||
sql.append(") returning *");
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.append(1, ')');
|
||||
}
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
$$<<" sql.append(1, ')');\n";
|
||||
}
|
||||
%>
|
||||
LOG_TRACE << sql;
|
||||
return sql;
|
||||
}
|
||||
};
|
||||
<%c++
|
||||
if(!schema.empty())
|
||||
{
|
||||
$$<<"} // namespace "<<schema<<"\n";
|
||||
}
|
||||
%>
|
||||
} // namespace [[dbName]]
|
||||
} // namespace drogon_model
|
104
vendors/drogon/drogon_ctl/templates/model_json.csp
vendored
Normal file
104
vendors/drogon/drogon_ctl/templates/model_json.csp
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
{
|
||||
//rdbms: server type, postgresql,mysql or sqlite3
|
||||
"rdbms": "postgresql",
|
||||
//filename: sqlite3 db file name
|
||||
//"filename":"",
|
||||
//host: server address,localhost by default;
|
||||
"host": "127.0.0.1",
|
||||
//port: server port, 5432 by default;
|
||||
"port": 5432,
|
||||
//dbname: Database name;
|
||||
"dbname": "",
|
||||
//schema: valid for postgreSQL, "public" by default;
|
||||
"schema": "public",
|
||||
//user: User name
|
||||
"user": "",
|
||||
//password or passwd: Password
|
||||
"password": "",
|
||||
//client_encoding: The character set used by drogon_ctl. it is empty string by default which
|
||||
//means use the default character set.
|
||||
//"client_encoding": "",
|
||||
//table: An array of tables to be modelized. if the array is empty, all revealed tables are modelized.
|
||||
"tables": [],
|
||||
//convert: the value can be changed by a function call before it is stored into database or
|
||||
//after it is read from database
|
||||
"convert": {
|
||||
"enabled": false,
|
||||
"items":[{
|
||||
"table": "user",
|
||||
"column": "password",
|
||||
"method": {
|
||||
//after_db_read: name of the method which is called after reading from database, signature: void([const] std::shared_ptr [&])
|
||||
"after_db_read": "decrypt_password",
|
||||
//before_db_write: name of the method which is called before writing to database, signature: void([const] std::shared_ptr [&])
|
||||
"before_db_write": "encrypt_password"
|
||||
},
|
||||
"includes": [
|
||||
"\"file_local_search_path.h\"","<file_in_global_search_path.h>"
|
||||
]
|
||||
}]
|
||||
},
|
||||
"relationships": {
|
||||
"enabled": false,
|
||||
"items": [{
|
||||
"type": "has one",
|
||||
"original_table_name": "products",
|
||||
"original_table_alias": "product",
|
||||
"original_key": "id",
|
||||
"target_table_name": "skus",
|
||||
"target_table_alias": "SKU",
|
||||
"target_key": "product_id",
|
||||
"enable_reverse": true
|
||||
},
|
||||
{
|
||||
"type": "has many",
|
||||
"original_table_name": "products",
|
||||
"original_table_alias": "product",
|
||||
"original_key": "id",
|
||||
"target_table_name": "reviews",
|
||||
"target_table_alias": "",
|
||||
"target_key": "product_id",
|
||||
"enable_reverse": true
|
||||
},
|
||||
{
|
||||
"type": "many to many",
|
||||
"original_table_name": "products",
|
||||
"original_table_alias": "",
|
||||
"original_key": "id",
|
||||
"pivot_table": {
|
||||
"table_name": "carts_products",
|
||||
"original_key": "product_id",
|
||||
"target_key": "cart_id"
|
||||
},
|
||||
"target_table_name": "carts",
|
||||
"target_table_alias": "",
|
||||
"target_key": "id",
|
||||
"enable_reverse": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"restful_api_controllers": {
|
||||
"enabled": false,
|
||||
// resource_uri: The URI to access the resource, the default value
|
||||
// is '/*' in which the asterisk represents the table name.
|
||||
// If this option is set to a empty string, the URI is composed of the namespaces and the class name.
|
||||
"resource_uri": "/*",
|
||||
// class_name: "Restful*Ctrl" by default, the asterisk represents the table name.
|
||||
// This option can contain namespaces.
|
||||
"class_name": "Restful*Ctrl",
|
||||
// filters: an array of filter names.
|
||||
"filters": [],
|
||||
// db_client: the database client used by the controller. this option must be consistent with
|
||||
// the configuration of the application.
|
||||
"db_client": {
|
||||
//name: Name of the client,'default' by default
|
||||
"name": "default",
|
||||
//is_fast:
|
||||
"is_fast": false
|
||||
},
|
||||
// directory: The directory where the controller source files are stored.
|
||||
"directory": "controllers",
|
||||
// generate_base_only: false by default. Set to true to avoid overwriting custom subclasses.
|
||||
"generate_base_only": false
|
||||
}
|
||||
}
|
23
vendors/drogon/drogon_ctl/templates/plugin_cc.csp
vendored
Normal file
23
vendors/drogon/drogon_ctl/templates/plugin_cc.csp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
*
|
||||
* [[filename]].cc
|
||||
*
|
||||
*/
|
||||
|
||||
#include "[[filename]].h"
|
||||
|
||||
using namespace drogon;
|
||||
<%c++auto namespaceStr=@@.get<std::string>("namespaceString");
|
||||
if(!namespaceStr.empty())
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
%>
|
||||
|
||||
void [[className]]::initAndStart(const Json::Value &config)
|
||||
{
|
||||
/// Initialize and start the plugin
|
||||
}
|
||||
|
||||
void [[className]]::shutdown()
|
||||
{
|
||||
/// Shutdown the plugin
|
||||
}
|
35
vendors/drogon/drogon_ctl/templates/plugin_h.csp
vendored
Normal file
35
vendors/drogon/drogon_ctl/templates/plugin_h.csp
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
*
|
||||
* [[filename]].h
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/plugins/Plugin.h>
|
||||
<%c++
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
if(namespaceVector.empty())
|
||||
$$<<"\n";
|
||||
for(auto &namespaceName:namespaceVector){%>
|
||||
namespace {%namespaceName%}
|
||||
|
||||
{
|
||||
<%c++}
|
||||
$$<<"\n";%>
|
||||
class [[className]] : public drogon::Plugin<[[className]]>
|
||||
{
|
||||
public:
|
||||
[[className]]() {}
|
||||
/// 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;
|
||||
|
||||
/// This method must be called by drogon to shutdown the plugin.
|
||||
/// It must be implemented by the user.
|
||||
void shutdown() override;
|
||||
};
|
||||
|
||||
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
|
||||
}
|
||||
<%c++}%>
|
494
vendors/drogon/drogon_ctl/templates/restful_controller_base_cc.csp
vendored
Normal file
494
vendors/drogon/drogon_ctl/templates/restful_controller_base_cc.csp
vendored
Normal file
@ -0,0 +1,494 @@
|
||||
<%inc#include "create_model.h"
|
||||
using namespace drogon_ctl;
|
||||
%>
|
||||
|
||||
/**
|
||||
*
|
||||
* [[fileName]]Base.cc
|
||||
* DO NOT EDIT. This file is generated by drogon_ctl automatically.
|
||||
* Users should implement business logic in the derived class.
|
||||
*/
|
||||
|
||||
#include "[[fileName]]Base.h"
|
||||
#include <string>
|
||||
|
||||
<%c++
|
||||
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
|
||||
auto modelName = tableInfo.get<std::string>("className");
|
||||
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
std::string namespaceStr;
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
namespaceStr.append(name);
|
||||
namespaceStr.append("::");
|
||||
}
|
||||
if(!namespaceStr.empty())
|
||||
{
|
||||
namespaceStr.resize(namespaceStr.length()-2);
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
}
|
||||
std::string indentStr(@@.get<std::string>("className").length(), ' ');
|
||||
%>
|
||||
<%c++
|
||||
if(hasPrimaryKey)
|
||||
{%>
|
||||
void [[className]]Base::getOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
|
||||
auto dbClientPtr = getDbClient();
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
|
||||
std::move(callback));
|
||||
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
|
||||
mapper.findByPrimaryKey(
|
||||
id,
|
||||
[req, callbackPtr, this]({%modelName%} r) {
|
||||
(*callbackPtr)(HttpResponse::newHttpJsonResponse(makeJson(req, r)));
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e) {
|
||||
const drogon::orm::UnexpectedRows *s=dynamic_cast<const drogon::orm::UnexpectedRows *>(&e.base());
|
||||
if(s)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k404NotFound);
|
||||
(*callbackPtr)(resp);
|
||||
return;
|
||||
}
|
||||
LOG_ERROR<<e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void [[className]]Base::updateOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
auto jsonPtr=req->jsonObject();
|
||||
if(!jsonPtr)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"]="No json object is found in the request";
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
{%modelName%} object;
|
||||
std::string err;
|
||||
if(!doCustomValidations(*jsonPtr, err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if(isMasquerading())
|
||||
{
|
||||
if(!{%modelName%}::validateMasqueradedJsonForUpdate(*jsonPtr, masqueradingVector(), err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
object.updateByMasqueradedJson(*jsonPtr, masqueradingVector());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!{%modelName%}::validateJsonForUpdate(*jsonPtr, err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
object.updateByJson(*jsonPtr);
|
||||
}
|
||||
}
|
||||
catch(const Json::Exception &e)
|
||||
{
|
||||
LOG_ERROR << e.what();
|
||||
Json::Value ret;
|
||||
ret["error"]="Field type error";
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
if(object.getPrimaryKey() != id)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"]="Bad primary key";
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dbClientPtr = getDbClient();
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
|
||||
std::move(callback));
|
||||
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
|
||||
|
||||
mapper.update(
|
||||
object,
|
||||
[callbackPtr](const size_t count)
|
||||
{
|
||||
if(count == 1)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k202Accepted);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
else if(count == 0)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"]="No resources are updated";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k404NotFound);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL << "More than one resource is updated: " << count;
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e) {
|
||||
LOG_ERROR << e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void [[className]]Base::deleteOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
|
||||
auto dbClientPtr = getDbClient();
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
|
||||
std::move(callback));
|
||||
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
|
||||
mapper.deleteByPrimaryKey(
|
||||
id,
|
||||
[callbackPtr](const size_t count) {
|
||||
if(count == 1)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k204NoContent);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
else if(count == 0)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = "No resources deleted";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k404NotFound);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL << "Delete more than one records: " << count;
|
||||
Json::Value ret;
|
||||
ret["error"] = "Database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
}
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e) {
|
||||
LOG_ERROR << e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
<%c++}%>
|
||||
|
||||
void [[className]]Base::get(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
auto dbClientPtr = getDbClient();
|
||||
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
|
||||
auto ¶meters = req->parameters();
|
||||
auto iter = parameters.find("sort");
|
||||
if(iter != parameters.end())
|
||||
{
|
||||
auto sortFields = drogon::utils::splitString(iter->second, ",");
|
||||
for(auto &field : sortFields)
|
||||
{
|
||||
if(field.empty())
|
||||
continue;
|
||||
if(field[0] == '+')
|
||||
{
|
||||
field = field.substr(1);
|
||||
mapper.orderBy(field, SortOrder::ASC);
|
||||
}
|
||||
else if(field[0] == '-')
|
||||
{
|
||||
field = field.substr(1);
|
||||
mapper.orderBy(field, SortOrder::DESC);
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.orderBy(field, SortOrder::ASC);
|
||||
}
|
||||
}
|
||||
}
|
||||
iter = parameters.find("offset");
|
||||
if(iter != parameters.end())
|
||||
{
|
||||
try{
|
||||
auto offset = std::stoll(iter->second);
|
||||
mapper.offset(offset);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
iter = parameters.find("limit");
|
||||
if(iter != parameters.end())
|
||||
{
|
||||
try{
|
||||
auto limit = std::stoll(iter->second);
|
||||
mapper.limit(limit);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
|
||||
std::move(callback));
|
||||
auto jsonPtr = req->jsonObject();
|
||||
if(jsonPtr && jsonPtr->isMember("filter"))
|
||||
{
|
||||
try{
|
||||
auto criteria = makeCriteria((*jsonPtr)["filter"]);
|
||||
mapper.findBy(criteria,
|
||||
[req, callbackPtr, this](const std::vector<{%modelName%}> &v) {
|
||||
Json::Value ret;
|
||||
ret.resize(0);
|
||||
for (auto &obj : v)
|
||||
{
|
||||
ret.append(makeJson(req, obj));
|
||||
}
|
||||
(*callbackPtr)(HttpResponse::newHttpJsonResponse(ret));
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e) {
|
||||
LOG_ERROR << e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
LOG_ERROR << e.what();
|
||||
Json::Value ret;
|
||||
ret["error"] = e.what();
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
(*callbackPtr)(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.findAll([req, callbackPtr, this](const std::vector<{%modelName%}> &v) {
|
||||
Json::Value ret;
|
||||
ret.resize(0);
|
||||
for (auto &obj : v)
|
||||
{
|
||||
ret.append(makeJson(req, obj));
|
||||
}
|
||||
(*callbackPtr)(HttpResponse::newHttpJsonResponse(ret));
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e) {
|
||||
LOG_ERROR << e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void [[className]]Base::create(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
auto jsonPtr=req->jsonObject();
|
||||
if(!jsonPtr)
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"]="No json object is found in the request";
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
std::string err;
|
||||
if(!doCustomValidations(*jsonPtr, err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
if(isMasquerading())
|
||||
{
|
||||
if(!{%modelName%}::validateMasqueradedJsonForCreation(*jsonPtr, masqueradingVector(), err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!{%modelName%}::validateJsonForCreation(*jsonPtr, err))
|
||||
{
|
||||
Json::Value ret;
|
||||
ret["error"] = err;
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
{%modelName%} object =
|
||||
(isMasquerading()?
|
||||
{%modelName%}(*jsonPtr, masqueradingVector()) :
|
||||
{%modelName%}(*jsonPtr));
|
||||
auto dbClientPtr = getDbClient();
|
||||
auto callbackPtr =
|
||||
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
|
||||
std::move(callback));
|
||||
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
|
||||
mapper.insert(
|
||||
object,
|
||||
[req, callbackPtr, this]({%modelName%} newObject){
|
||||
(*callbackPtr)(HttpResponse::newHttpJsonResponse(
|
||||
makeJson(req, newObject)));
|
||||
},
|
||||
[callbackPtr](const DrogonDbException &e){
|
||||
LOG_ERROR << e.base().what();
|
||||
Json::Value ret;
|
||||
ret["error"] = "database error";
|
||||
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k500InternalServerError);
|
||||
(*callbackPtr)(resp);
|
||||
});
|
||||
}
|
||||
catch(const Json::Exception &e)
|
||||
{
|
||||
LOG_ERROR << e.what();
|
||||
Json::Value ret;
|
||||
ret["error"]="Field type error";
|
||||
auto resp= HttpResponse::newHttpJsonResponse(ret);
|
||||
resp->setStatusCode(k400BadRequest);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void [[className]]Base::update(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
[[className]]Base::[[className]]Base()
|
||||
: RestfulController({
|
||||
<%c++
|
||||
tableInfo = @@.get<DrTemplateData>("tableInfo");
|
||||
const auto &cols=tableInfo.get<std::vector<ColumnInfo>>("columns");
|
||||
for(size_t i=0; i<cols.size(); ++i)
|
||||
{
|
||||
auto &col = cols[i];
|
||||
if(i < (cols.size()-1))
|
||||
{
|
||||
%>
|
||||
"{%col.colName_%}",
|
||||
<%c++
|
||||
}else{
|
||||
%>
|
||||
"{%col.colName_%}"
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
%>
|
||||
})
|
||||
{
|
||||
/**
|
||||
* The items in the vector are aliases of column names in the table.
|
||||
* if one item is set to an empty string, the related column is not sent
|
||||
* to clients.
|
||||
*/
|
||||
enableMasquerading({
|
||||
<%c++
|
||||
for(size_t i=0; i<cols.size(); ++i)
|
||||
{
|
||||
auto &col = cols[i];
|
||||
if(i < (cols.size()-1))
|
||||
{
|
||||
%>
|
||||
"{%col.colName_%}", // the alias for the {%col.colName_%} column.
|
||||
<%c++
|
||||
}else{
|
||||
%>
|
||||
"{%col.colName_%}" // the alias for the {%col.colName_%} column.
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
%>
|
||||
});
|
||||
}
|
87
vendors/drogon/drogon_ctl/templates/restful_controller_base_h.csp
vendored
Normal file
87
vendors/drogon/drogon_ctl/templates/restful_controller_base_h.csp
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
<%inc#include "create_model.h"
|
||||
using namespace drogon_ctl;
|
||||
%>
|
||||
/**
|
||||
*
|
||||
* [[fileName]]Base.h
|
||||
* DO NOT EDIT. This file is generated by drogon_ctl automatically.
|
||||
* Users should implement business logic in the derived class.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpController.h>
|
||||
#include <drogon/orm/RestfulController.h>
|
||||
|
||||
<%c++
|
||||
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
|
||||
auto modelName = tableInfo.get<std::string>("className");
|
||||
$$<<"#include \""<<modelName<<".h\"\n";
|
||||
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
|
||||
$$<<"using namespace drogon;\n";
|
||||
$$<<"using namespace drogon::orm;\n";
|
||||
|
||||
$$<<"using namespace drogon_model::"<<tableInfo.get<std::string>("dbName");
|
||||
auto &schema=tableInfo.get<std::string>("schema");
|
||||
if(!schema.empty())
|
||||
{
|
||||
$$<<"::"<<schema<<";\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$$<<";\n";
|
||||
}
|
||||
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
%>
|
||||
namespace {%name%}
|
||||
{
|
||||
<%c++}%>
|
||||
/**
|
||||
* @brief this class is created by the drogon_ctl command.
|
||||
* this class is a restful API controller for reading and writing the [[tableName]] table.
|
||||
*/
|
||||
|
||||
class [[className]]Base : public RestfulController
|
||||
{
|
||||
public:
|
||||
<%c++if(hasPrimaryKey)
|
||||
{
|
||||
%>
|
||||
void getOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
void updateOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
void deleteOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
<%c++}
|
||||
%>
|
||||
void get(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void create(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
|
||||
// void update(const HttpRequestPtr &req,
|
||||
// std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
orm::DbClientPtr getDbClient()
|
||||
{
|
||||
return drogon::app().get{%(@@.get<bool>("isFastDbClient")?"Fast":"")%}DbClient(dbClientName_);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Ensure that subclasses inherited from this class are instantiated.
|
||||
[[className]]Base();
|
||||
const std::string dbClientName_{"[[dbClientName]]"};
|
||||
};
|
||||
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
|
||||
{
|
||||
$$<<"}\n";
|
||||
}
|
||||
%>
|
58
vendors/drogon/drogon_ctl/templates/restful_controller_cc.csp
vendored
Normal file
58
vendors/drogon/drogon_ctl/templates/restful_controller_cc.csp
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
*
|
||||
* [[fileName]].cc
|
||||
* This file is generated by drogon_ctl
|
||||
*
|
||||
*/
|
||||
|
||||
#include "[[fileName]].h"
|
||||
#include <string>
|
||||
|
||||
<%c++
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
std::string namespaceStr;
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
namespaceStr.append(name);
|
||||
namespaceStr.append("::");
|
||||
}
|
||||
if(!namespaceStr.empty())
|
||||
{
|
||||
namespaceStr.resize(namespaceStr.length()-2);
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
}
|
||||
std::string indentStr(@@.get<std::string>("className").length(), ' ');
|
||||
%>
|
||||
|
||||
void [[className]]::getOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} std::string &&id)
|
||||
{
|
||||
}
|
||||
|
||||
void [[className]]::get(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
}
|
||||
void [[className]]::create(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
}
|
||||
void [[className]]::updateOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} std::string &&id)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
void [[className]]::update(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
void [[className]]::deleteOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} std::string &&id)
|
||||
{
|
||||
}
|
70
vendors/drogon/drogon_ctl/templates/restful_controller_custom_cc.csp
vendored
Normal file
70
vendors/drogon/drogon_ctl/templates/restful_controller_custom_cc.csp
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* [[fileName]].cc
|
||||
* This file is generated by drogon_ctl
|
||||
*
|
||||
*/
|
||||
|
||||
#include "[[fileName]].h"
|
||||
#include <string>
|
||||
|
||||
<%c++
|
||||
|
||||
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
|
||||
auto modelName = tableInfo.get<std::string>("className");
|
||||
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
|
||||
|
||||
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
std::string namespaceStr;
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
namespaceStr.append(name);
|
||||
namespaceStr.append("::");
|
||||
}
|
||||
if(!namespaceStr.empty())
|
||||
{
|
||||
namespaceStr.resize(namespaceStr.length()-2);
|
||||
$$<<"using namespace "<<namespaceStr<<";\n";
|
||||
}
|
||||
std::string indentStr(@@.get<std::string>("className").length(), ' ');
|
||||
%>
|
||||
|
||||
<%c++
|
||||
if(hasPrimaryKey)
|
||||
{%>
|
||||
void [[className]]::getOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
[[className]]Base::getOne(req, std::move(callback), std::move(id));
|
||||
}
|
||||
|
||||
|
||||
void [[className]]::updateOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
[[className]]Base::updateOne(req, std::move(callback), std::move(id));
|
||||
}
|
||||
|
||||
|
||||
void [[className]]::deleteOne(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
|
||||
{
|
||||
[[className]]Base::deleteOne(req, std::move(callback), std::move(id));
|
||||
}
|
||||
<%c++}%>
|
||||
|
||||
void [[className]]::get(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
[[className]]Base::get(req, std::move(callback));
|
||||
}
|
||||
|
||||
void [[className]]::create(const HttpRequestPtr &req,
|
||||
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
[[className]]Base::create(req, std::move(callback));
|
||||
}
|
104
vendors/drogon/drogon_ctl/templates/restful_controller_custom_h.csp
vendored
Normal file
104
vendors/drogon/drogon_ctl/templates/restful_controller_custom_h.csp
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
<%inc#include "create_model.h"
|
||||
using namespace drogon_ctl;
|
||||
%>
|
||||
/**
|
||||
*
|
||||
* [[fileName]].h
|
||||
* This file is generated by drogon_ctl
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpController.h>
|
||||
#include "[[className]]Base.h"
|
||||
|
||||
<%c++
|
||||
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
|
||||
auto modelName = tableInfo.get<std::string>("className");
|
||||
$$<<"#include \""<<modelName<<".h\"\n";
|
||||
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
|
||||
$$<<"using namespace drogon;\n";
|
||||
|
||||
$$<<"using namespace drogon_model::"<<tableInfo.get<std::string>("dbName");
|
||||
auto &schema=tableInfo.get<std::string>("schema");
|
||||
if(!schema.empty())
|
||||
{
|
||||
$$<<"::"<<schema<<";\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$$<<";\n";
|
||||
}
|
||||
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
%>
|
||||
namespace {%name%}
|
||||
{
|
||||
<%c++}%>
|
||||
/**
|
||||
* @brief this class is created by the drogon_ctl command.
|
||||
* this class is a restful API controller for reading and writing the [[tableName]] table.
|
||||
*/
|
||||
|
||||
class [[className]]: public drogon::HttpController<[[className]]>, public [[className]]Base
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
<%c++
|
||||
auto resource=@@.get<std::string>("resource");
|
||||
if(resource.empty())
|
||||
{
|
||||
if(hasPrimaryKey)
|
||||
{
|
||||
%>
|
||||
METHOD_ADD([[className]]::getOne,"/{1}",Get,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::updateOne,"/{1}",Put,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::deleteOne,"/{1}",Delete,Options[[filters]]);
|
||||
<%c++}%>
|
||||
METHOD_ADD([[className]]::get,"",Get,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::create,"",Post,Options[[filters]]);
|
||||
//METHOD_ADD([[className]]::update,"",Put,Options[[filters]]);
|
||||
<%c++
|
||||
}else
|
||||
{
|
||||
if(hasPrimaryKey)
|
||||
{
|
||||
%>
|
||||
ADD_METHOD_TO([[className]]::getOne,"{%resource%}/{1}",Get,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::updateOne,"{%resource%}/{1}",Put,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::deleteOne,"{%resource%}/{1}",Delete,Options[[filters]]);
|
||||
<%c++}%>
|
||||
ADD_METHOD_TO([[className]]::get,"{%resource%}",Get,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::create,"{%resource%}",Post,Options[[filters]]);
|
||||
//ADD_METHOD_TO([[className]]::update,"{%resource%}",Put,Options[[filters]]);
|
||||
<%c++}%>
|
||||
METHOD_LIST_END
|
||||
|
||||
<%c++if(hasPrimaryKey)
|
||||
{
|
||||
%>
|
||||
void getOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
void updateOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
void deleteOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
{%modelName%}::PrimaryKeyType &&id);
|
||||
<%c++}
|
||||
%>
|
||||
void get(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void create(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
};
|
||||
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
|
||||
{
|
||||
$$<<"}\n";
|
||||
}
|
||||
%>
|
80
vendors/drogon/drogon_ctl/templates/restful_controller_h.csp
vendored
Normal file
80
vendors/drogon/drogon_ctl/templates/restful_controller_h.csp
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
<%inc#include "create_model.h"
|
||||
using namespace drogon_ctl;
|
||||
%>
|
||||
/**
|
||||
*
|
||||
* [[fileName]].h
|
||||
* This file is generated by drogon_ctl
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/HttpController.h>
|
||||
<%c++
|
||||
$$<<"using namespace drogon;\n";
|
||||
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
|
||||
for(auto &name:namespaceVector)
|
||||
{
|
||||
%>
|
||||
namespace {%name%}
|
||||
{
|
||||
<%c++
|
||||
}
|
||||
%>
|
||||
/**
|
||||
* @brief this class is created by the drogon_ctl command ([[ctlCommand]]).
|
||||
* this class is a restful API controller.
|
||||
*/
|
||||
class [[className]]: public drogon::HttpController<[[className]]>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
// use METHOD_ADD to add your custom processing function here;
|
||||
<%c++
|
||||
auto resource=@@.get<std::string>("resource");
|
||||
if(resource.empty())
|
||||
{
|
||||
%>
|
||||
METHOD_ADD([[className]]::getOne,"/{1}",Get,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::get,"",Get,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::create,"",Post,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::updateOne,"/{1}",Put,Options[[filters]]);
|
||||
//METHOD_ADD([[className]]::update,"",Put,Options[[filters]]);
|
||||
METHOD_ADD([[className]]::deleteOne,"/{1}",Delete,Options[[filters]]);
|
||||
<%c++
|
||||
}else
|
||||
{
|
||||
%>
|
||||
ADD_METHOD_TO([[className]]::getOne,"{%resource%}/{1}",Get,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::updateOne,"{%resource%}/{1}",Put,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::deleteOne,"{%resource%}/{1}",Delete,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::get,"{%resource%}",Get,Options[[filters]]);
|
||||
ADD_METHOD_TO([[className]]::create,"{%resource%}",Post,Options[[filters]]);
|
||||
//ADD_METHOD_TO([[className]]::update,"{%resource%}",Put,Options[[filters]]);
|
||||
<%c++}%>
|
||||
METHOD_LIST_END
|
||||
|
||||
void getOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
std::string &&id);
|
||||
void updateOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
std::string &&id);
|
||||
void deleteOne(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
std::string &&id);
|
||||
void get(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
void create(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
// void update(const HttpRequestPtr &req,
|
||||
// std::function<void(const HttpResponsePtr &)> &&callback);
|
||||
|
||||
};
|
||||
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
|
||||
{
|
||||
$$<<"}\n";
|
||||
}
|
||||
%>
|
14
vendors/drogon/drogon_ctl/templates/test_cmake.csp
vendored
Normal file
14
vendors/drogon/drogon_ctl/templates/test_cmake.csp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project([[ProjectName]]_test CXX)
|
||||
|
||||
add_executable(${PROJECT_NAME} test_main.cc)
|
||||
|
||||
# ##############################################################################
|
||||
# If you include the drogon source code locally in your project, use this method
|
||||
# to add drogon
|
||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
||||
#
|
||||
# and comment out the following lines
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
||||
|
||||
ParseAndAddDrogonTests(${PROJECT_NAME})
|
32
vendors/drogon/drogon_ctl/templates/test_main.csp
vendored
Normal file
32
vendors/drogon/drogon_ctl/templates/test_main.csp
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
#define DROGON_TEST_MAIN
|
||||
#include <drogon/drogon_test.h>
|
||||
#include <drogon/drogon.h>
|
||||
|
||||
DROGON_TEST(BasicTest)
|
||||
{
|
||||
// Add your tests here
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace drogon;
|
||||
|
||||
std::promise<void> p1;
|
||||
std::future<void> f1 = p1.get_future();
|
||||
|
||||
// Start the main loop on another thread
|
||||
std::thread thr([&]() {
|
||||
// Queues the promise to be fulfilled after starting the loop
|
||||
app().getLoop()->queueInLoop([&p1]() { p1.set_value(); });
|
||||
app().run();
|
||||
});
|
||||
|
||||
// The future is only satisfied after the event loop started
|
||||
f1.get();
|
||||
int status = test::run(argc, argv);
|
||||
|
||||
// Ask the event loop to shutdown and wait
|
||||
app().getLoop()->queueInLoop([]() { app().quit(); });
|
||||
thr.join();
|
||||
return status;
|
||||
}
|
68
vendors/drogon/drogon_ctl/version.cc
vendored
Normal file
68
vendors/drogon/drogon_ctl/version.cc
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
* version.cc
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "version.h"
|
||||
#include <drogon/config.h>
|
||||
#include <drogon/version.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <trantor/net/Resolver.h>
|
||||
#include <trantor/utils/Utilities.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
static const char banner[] =
|
||||
R"( _
|
||||
__| |_ __ ___ __ _ ___ _ __
|
||||
/ _` | '__/ _ \ / _` |/ _ \| '_ \
|
||||
| (_| | | | (_) | (_| | (_) | | | |
|
||||
\__,_|_| \___/ \__, |\___/|_| |_|
|
||||
|___/
|
||||
)";
|
||||
|
||||
void version::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
const auto tlsBackend = trantor::utils::tlsBackend();
|
||||
const bool tlsSupported = drogon::utils::supportsTls();
|
||||
std::cout << banner << std::endl;
|
||||
std::cout << "A utility for drogon" << std::endl;
|
||||
std::cout << "Version: " << DROGON_VERSION << std::endl;
|
||||
std::cout << "Git commit: " << DROGON_VERSION_SHA1 << std::endl;
|
||||
std::cout << "Compilation: \n Compiler: " << COMPILER_COMMAND
|
||||
<< "\n Compiler ID: " << COMPILER_ID
|
||||
<< "\n Compilation flags: " << COMPILATION_FLAGS
|
||||
<< INCLUDING_DIRS << std::endl;
|
||||
std::cout << "Libraries: \n postgresql: "
|
||||
<< (USE_POSTGRESQL ? "yes" : "no") << " (pipeline mode: "
|
||||
<< (LIBPQ_SUPPORTS_BATCH_MODE ? "yes)\n" : "no)\n")
|
||||
<< " mariadb: " << (USE_MYSQL ? "yes\n" : "no\n")
|
||||
<< " sqlite3: " << (USE_SQLITE3 ? "yes\n" : "no\n");
|
||||
std::cout << " ssl/tls backend: " << tlsBackend << "\n";
|
||||
#ifdef USE_BROTLI
|
||||
std::cout << " brotli: yes\n";
|
||||
#else
|
||||
std::cout << " brotli: no\n";
|
||||
#endif
|
||||
#ifdef USE_REDIS
|
||||
std::cout << " hiredis: yes\n";
|
||||
#else
|
||||
std::cout << " hiredis: no\n";
|
||||
#endif
|
||||
std::cout << " c-ares: "
|
||||
<< (trantor::Resolver::isCAresUsed() ? "yes\n" : "no\n");
|
||||
#ifdef HAS_YAML_CPP
|
||||
std::cout << " yaml-cpp: yes\n";
|
||||
#else
|
||||
std::cout << " yaml-cpp: no\n";
|
||||
#endif
|
||||
}
|
42
vendors/drogon/drogon_ctl/version.h
vendored
Normal file
42
vendors/drogon/drogon_ctl/version.h
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
*
|
||||
* version.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include "CommandHandler.h"
|
||||
using namespace drogon;
|
||||
|
||||
namespace drogon_ctl
|
||||
{
|
||||
class version : public DrObject<version>, public CommandHandler
|
||||
{
|
||||
public:
|
||||
void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
|
||||
std::string script() override
|
||||
{
|
||||
return "display version of this tool";
|
||||
}
|
||||
|
||||
bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
version()
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace drogon_ctl
|
14
vendors/drogon/format.sh
vendored
Executable file
14
vendors/drogon/format.sh
vendored
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# You can customize the clang-format path by setting the CLANG_FORMAT environment variable
|
||||
CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
|
||||
|
||||
# Check if clang-format version is 14 to avoid inconsistent formatting
|
||||
$CLANG_FORMAT --version
|
||||
if [[ ! $($CLANG_FORMAT --version) =~ "version 14" ]]; then
|
||||
echo "Error: clang-format version must be 14"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find lib orm_lib nosql_lib examples drogon_ctl -name *.h -o -name *.cc -exec dos2unix {} \;
|
||||
find lib orm_lib nosql_lib examples drogon_ctl -name *.h -o -name *.cc|xargs $CLANG_FORMAT -i -style=file
|
130
vendors/drogon/lib/inc/drogon/Attribute.h
vendored
Normal file
130
vendors/drogon/lib/inc/drogon/Attribute.h
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
*
|
||||
* Attribute.h
|
||||
* armstrong@sweelia.com
|
||||
*
|
||||
* 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
|
||||
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <any>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief This class represents the attributes stored in the HTTP request.
|
||||
* One can add/get any type of data to/from an Attributes object.
|
||||
*/
|
||||
class Attributes
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Get the data identified by the key parameter.
|
||||
* @note if the data is not found, a default value is returned.
|
||||
* For example:
|
||||
* @code
|
||||
auto &userName = attributesPtr->get<std::string>("user name");
|
||||
@endcode
|
||||
*/
|
||||
template <typename T>
|
||||
const T &get(const std::string &key) const
|
||||
{
|
||||
const static T nullVal = T();
|
||||
auto it = attributesMap_.find(key);
|
||||
if (it != attributesMap_.end())
|
||||
{
|
||||
if (typeid(T) == it->second.type())
|
||||
{
|
||||
return *(std::any_cast<T>(&(it->second)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Bad type";
|
||||
}
|
||||
}
|
||||
return nullVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the 'any' object identified by the given key
|
||||
*/
|
||||
std::any &operator[](const std::string &key)
|
||||
{
|
||||
return attributesMap_[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a key-value pair
|
||||
* @note here the any object can be created implicitly. for example
|
||||
* @code
|
||||
attributesPtr->insert("user name", userNameString);
|
||||
@endcode
|
||||
*/
|
||||
void insert(const std::string &key, const std::any &obj)
|
||||
{
|
||||
attributesMap_[key] = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a key-value pair
|
||||
* @note here the any object can be created implicitly. for example
|
||||
* @code
|
||||
attributesPtr->insert("user name", userNameString);
|
||||
@endcode
|
||||
*/
|
||||
void insert(const std::string &key, std::any &&obj)
|
||||
{
|
||||
attributesMap_[key] = std::move(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erase the data identified by the given key.
|
||||
*/
|
||||
void erase(const std::string &key)
|
||||
{
|
||||
attributesMap_.erase(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return true if the data identified by the key exists.
|
||||
*/
|
||||
bool find(const std::string &key)
|
||||
{
|
||||
if (attributesMap_.find(key) == attributesMap_.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all attributes.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
attributesMap_.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor, usually called by the framework
|
||||
*/
|
||||
Attributes() = default;
|
||||
|
||||
private:
|
||||
using AttributesMap = std::map<std::string, std::any>;
|
||||
AttributesMap attributesMap_;
|
||||
};
|
||||
|
||||
using AttributesPtr = std::shared_ptr<Attributes>;
|
||||
|
||||
} // namespace drogon
|
562
vendors/drogon/lib/inc/drogon/CacheMap.h
vendored
Normal file
562
vendors/drogon/lib/inc/drogon/CacheMap.h
vendored
Normal file
@ -0,0 +1,562 @@
|
||||
/**
|
||||
*
|
||||
* @file CacheMap.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
|
||||
|
||||
#include <trantor/net/EventLoop.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <assert.h>
|
||||
|
||||
#define WHEELS_NUM 4
|
||||
#define BUCKET_NUM_PER_WHEEL 200
|
||||
#define TICK_INTERVAL 1.0
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief A utility class for CacheMap
|
||||
*/
|
||||
class CallbackEntry
|
||||
{
|
||||
public:
|
||||
CallbackEntry(std::function<void()> cb) : cb_(std::move(cb))
|
||||
{
|
||||
}
|
||||
|
||||
~CallbackEntry()
|
||||
{
|
||||
cb_();
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> cb_;
|
||||
};
|
||||
|
||||
using CallbackEntryPtr = std::shared_ptr<CallbackEntry>;
|
||||
using WeakCallbackEntryPtr = std::weak_ptr<CallbackEntry>;
|
||||
|
||||
using CallbackBucket = std::unordered_set<CallbackEntryPtr>;
|
||||
using CallbackBucketQueue = std::deque<CallbackBucket>;
|
||||
|
||||
/**
|
||||
* @brief Cache Map
|
||||
*
|
||||
* @tparam T1 The keyword type.
|
||||
* @tparam T2 The value type.
|
||||
* @note
|
||||
* Four wheels with 200 buckets per wheel means the cache map can work with a
|
||||
* timeout up to 200^4 seconds (about 50 years).
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
class CacheMap
|
||||
{
|
||||
public:
|
||||
/// constructor
|
||||
/**
|
||||
* @param loop
|
||||
* eventloop pointer
|
||||
* @param tickInterval
|
||||
* second
|
||||
* @param wheelsNum
|
||||
* number of wheels
|
||||
* @param bucketsNumPerWheel
|
||||
* buckets number per wheel
|
||||
* @param fnOnInsert
|
||||
* function to execute on insertion
|
||||
* @param fnOnErase
|
||||
* function to execute on erase
|
||||
* @details The max delay of the CacheMap is about
|
||||
* tickInterval*(bucketsNumPerWheel^wheelsNum) seconds.
|
||||
*/
|
||||
CacheMap(trantor::EventLoop *loop,
|
||||
float tickInterval = TICK_INTERVAL,
|
||||
size_t wheelsNum = WHEELS_NUM,
|
||||
size_t bucketsNumPerWheel = BUCKET_NUM_PER_WHEEL,
|
||||
std::function<void(const T1 &)> fnOnInsert = nullptr,
|
||||
std::function<void(const T1 &)> fnOnErase = nullptr)
|
||||
: loop_(loop),
|
||||
tickInterval_(tickInterval),
|
||||
wheelsNumber_(wheelsNum),
|
||||
bucketsNumPerWheel_(bucketsNumPerWheel),
|
||||
ctrlBlockPtr_(std::make_shared<ControlBlock>()),
|
||||
fnOnInsert_(fnOnInsert),
|
||||
fnOnErase_(fnOnErase)
|
||||
{
|
||||
wheels_.resize(wheelsNumber_);
|
||||
for (size_t i = 0; i < wheelsNumber_; ++i)
|
||||
{
|
||||
wheels_[i].resize(bucketsNumPerWheel_);
|
||||
}
|
||||
if (tickInterval_ > 0 && wheelsNumber_ > 0 && bucketsNumPerWheel_ > 0)
|
||||
{
|
||||
timerId_ = loop_->runEvery(
|
||||
tickInterval_, [this, ctrlBlockPtr = ctrlBlockPtr_]() {
|
||||
std::lock_guard<std::mutex> lock(ctrlBlockPtr->mtx);
|
||||
if (ctrlBlockPtr->destructed)
|
||||
return;
|
||||
|
||||
size_t t = ++ticksCounter_;
|
||||
size_t pow = 1;
|
||||
for (size_t i = 0; i < wheelsNumber_; ++i)
|
||||
{
|
||||
if ((t % pow) == 0)
|
||||
{
|
||||
CallbackBucket tmp;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
// use tmp val to make this critical area as
|
||||
// short as possible.
|
||||
wheels_[i].front().swap(tmp);
|
||||
wheels_[i].pop_front();
|
||||
wheels_[i].push_back(CallbackBucket());
|
||||
}
|
||||
}
|
||||
pow = pow * bucketsNumPerWheel_;
|
||||
}
|
||||
});
|
||||
loop_->runOnQuit([ctrlBlockPtr = ctrlBlockPtr_] {
|
||||
std::lock_guard<std::mutex> lock(ctrlBlockPtr->mtx);
|
||||
ctrlBlockPtr->loopEnded = true;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
noWheels_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
~CacheMap()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ctrlBlockPtr_->mtx);
|
||||
ctrlBlockPtr_->destructed = true;
|
||||
map_.clear();
|
||||
if (!ctrlBlockPtr_->loopEnded)
|
||||
{
|
||||
loop_->invalidateTimer(timerId_);
|
||||
}
|
||||
for (auto iter = wheels_.rbegin(); iter != wheels_.rend(); ++iter)
|
||||
{
|
||||
iter->clear();
|
||||
}
|
||||
LOG_TRACE << "CacheMap destruct!";
|
||||
}
|
||||
|
||||
struct MapValue
|
||||
{
|
||||
MapValue(const T2 &value,
|
||||
size_t timeout,
|
||||
std::function<void()> &&callback)
|
||||
: value_(value),
|
||||
timeout_(timeout),
|
||||
timeoutCallback_(std::move(callback))
|
||||
{
|
||||
}
|
||||
|
||||
MapValue(T2 &&value, size_t timeout, std::function<void()> &&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};
|
||||
std::function<void()> timeoutCallback_;
|
||||
WeakCallbackEntryPtr weakEntryPtr_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Insert a key-value pair into the cache.
|
||||
*
|
||||
* @param key The key
|
||||
* @param value The value
|
||||
* @param timeout The timeout in seconds, if timeout > 0, the value will be
|
||||
* erased within the 'timeout' seconds after the last access. If the timeout
|
||||
* is zero, the value exists until being removed explicitly.
|
||||
* @param timeoutCallback is called when the timeout expires.
|
||||
*/
|
||||
void insert(const T1 &key,
|
||||
T2 &&value,
|
||||
size_t timeout = 0,
|
||||
std::function<void()> timeoutCallback = std::function<void()>())
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
MapValue v{std::move(value), timeout, std::move(timeoutCallback)};
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
map_.insert(std::make_pair(key, std::move(v)));
|
||||
eraseAfter(timeout, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapValue v{std::move(value)};
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
map_.insert(std::make_pair(key, std::move(v)));
|
||||
}
|
||||
if (fnOnInsert_)
|
||||
fnOnInsert_(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a key-value pair into the cache.
|
||||
*
|
||||
* @param key The key
|
||||
* @param value The value
|
||||
* @param timeout The timeout in seconds, if timeout > 0, the value will be
|
||||
* erased within the 'timeout' seconds after the last access. If the timeout
|
||||
* is zero, the value exists until being removed explicitly.
|
||||
* @param timeoutCallback is called when the timeout expires.
|
||||
*/
|
||||
void insert(const T1 &key,
|
||||
const T2 &value,
|
||||
size_t timeout = 0,
|
||||
std::function<void()> timeoutCallback = std::function<void()>())
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
MapValue v{value, timeout, std::move(timeoutCallback)};
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
map_.insert(std::make_pair(key, std::move(v)));
|
||||
eraseAfter(timeout, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapValue v{value};
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
map_.insert(std::make_pair(key, std::move(v)));
|
||||
}
|
||||
if (fnOnInsert_)
|
||||
fnOnInsert_(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the value of the keyword.
|
||||
*
|
||||
* @param key
|
||||
* @return T2
|
||||
* @note This function returns a copy of the data in the cache. If the data
|
||||
* is not found, a default T2 type value is returned and nothing is inserted
|
||||
* into the cache.
|
||||
*/
|
||||
T2 operator[](const T1 &key)
|
||||
{
|
||||
size_t timeout = 0;
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
auto iter = map_.find(key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
timeout = iter->second.timeout_;
|
||||
if (timeout > 0)
|
||||
eraseAfter(timeout, key);
|
||||
return iter->second.value_;
|
||||
}
|
||||
return T2();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Modify or visit the data identified by the key parameter.
|
||||
*
|
||||
* @tparam Callable the type of the handler.
|
||||
* @param key
|
||||
* @param handler A callable that can modify or visit the data. The
|
||||
* signature of the handler should be equivalent to 'void(T2&)' or
|
||||
* 'void(const T2&)'
|
||||
* @param timeout In seconds.
|
||||
*
|
||||
* @note This function is multiple-thread safe. if the data identified by
|
||||
* the key doesn't exist, a new one is created and passed to the handler and
|
||||
* stored in the cache with the timeout parameter. The changing of the data
|
||||
* is protected by the mutex of the cache.
|
||||
*
|
||||
*/
|
||||
template <typename Callable>
|
||||
void modify(const T1 &key, Callable &&handler, size_t timeout = 0)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
auto iter = map_.find(key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
timeout = iter->second.timeout_;
|
||||
handler(iter->second.value_);
|
||||
if (timeout > 0)
|
||||
eraseAfter(timeout, key);
|
||||
return;
|
||||
}
|
||||
|
||||
MapValue v{T2(), timeout};
|
||||
handler(v.value_);
|
||||
map_.insert(std::make_pair(key, std::move(v)));
|
||||
if (timeout > 0)
|
||||
{
|
||||
eraseAfter(timeout, key);
|
||||
}
|
||||
}
|
||||
if (fnOnInsert_)
|
||||
fnOnInsert_(key);
|
||||
}
|
||||
|
||||
/// Check if the value of the keyword exists
|
||||
bool find(const T1 &key)
|
||||
{
|
||||
size_t timeout = 0;
|
||||
bool flag = false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
auto iter = map_.find(key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
timeout = iter->second.timeout_;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (timeout > 0)
|
||||
eraseAfter(timeout, key);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// Atomically find and get the value of a keyword
|
||||
/**
|
||||
* Return true when the value is found, and the value
|
||||
* is assigned to the value argument.
|
||||
*/
|
||||
bool findAndFetch(const T1 &key, T2 &value)
|
||||
{
|
||||
size_t timeout = 0;
|
||||
bool flag = false;
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
auto iter = map_.find(key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
timeout = iter->second.timeout_;
|
||||
flag = true;
|
||||
value = iter->second.value_;
|
||||
}
|
||||
|
||||
if (timeout > 0)
|
||||
eraseAfter(timeout, key);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// Erase the value of the keyword.
|
||||
/**
|
||||
* @param key the keyword.
|
||||
* @note This function does not cause the timeout callback to be executed.
|
||||
*/
|
||||
void erase(const T1 &key)
|
||||
{
|
||||
// in this case,we don't evoke the timeout callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
map_.erase(key);
|
||||
}
|
||||
if (fnOnErase_)
|
||||
fnOnErase_(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the event loop object
|
||||
*
|
||||
* @return trantor::EventLoop*
|
||||
*/
|
||||
trantor::EventLoop *getLoop()
|
||||
{
|
||||
return loop_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief run the task function after a period of time.
|
||||
*
|
||||
* @param delay in seconds
|
||||
* @param task
|
||||
* @note This timer is a low-precision timer whose accuracy depends on the
|
||||
* tickInterval parameter of the cache. The advantage of the timer is its
|
||||
* low cost.
|
||||
*/
|
||||
void runAfter(size_t delay, std::function<void()> &&task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
insertEntry(delay, std::make_shared<CallbackEntry>(std::move(task)));
|
||||
}
|
||||
|
||||
void runAfter(size_t delay, const std::function<void()> &task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
insertEntry(delay, std::make_shared<CallbackEntry>(task));
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief ControlBlock in a internal structure that deals with synchronizing
|
||||
* CacheMap destructing, event loop destructing and updating the CacheMap.
|
||||
* It is possible that the EventLoop destructed before the CacheMap (ex:
|
||||
* both CacheMap and the EventLoop being globals, the order of destruction
|
||||
* is not defined), thus we shouldn't invalidate the time. Or CacheMap
|
||||
* destructed before the event loop but the timer is still active. Thus we
|
||||
* should avoid updating the CacheMap.
|
||||
*/
|
||||
struct ControlBlock
|
||||
{
|
||||
ControlBlock() : destructed(false), loopEnded(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool destructed;
|
||||
bool loopEnded;
|
||||
std::mutex mtx;
|
||||
};
|
||||
|
||||
std::unordered_map<T1, MapValue> map_;
|
||||
|
||||
std::vector<CallbackBucketQueue> wheels_;
|
||||
|
||||
std::atomic<size_t> ticksCounter_{0};
|
||||
|
||||
std::mutex mtx_;
|
||||
std::mutex bucketMutex_;
|
||||
trantor::TimerId timerId_;
|
||||
trantor::EventLoop *loop_;
|
||||
|
||||
float tickInterval_;
|
||||
size_t wheelsNumber_;
|
||||
size_t bucketsNumPerWheel_;
|
||||
std::shared_ptr<ControlBlock> ctrlBlockPtr_;
|
||||
std::function<void(const T1 &)> fnOnInsert_;
|
||||
std::function<void(const T1 &)> fnOnErase_;
|
||||
|
||||
bool noWheels_{false};
|
||||
|
||||
void insertEntry(size_t delay, CallbackEntryPtr entryPtr)
|
||||
{
|
||||
// protected by bucketMutex;
|
||||
if (delay <= 0)
|
||||
return;
|
||||
delay = static_cast<size_t>(delay / tickInterval_ + 1);
|
||||
size_t t = ticksCounter_;
|
||||
for (size_t i = 0; i < wheelsNumber_; ++i)
|
||||
{
|
||||
if (delay <= bucketsNumPerWheel_)
|
||||
{
|
||||
wheels_[i][delay - 1].insert(entryPtr);
|
||||
break;
|
||||
}
|
||||
if (i < (wheelsNumber_ - 1))
|
||||
{
|
||||
entryPtr = std::make_shared<CallbackEntry>(
|
||||
[this, delay, i, t, entryPtr]() {
|
||||
if (delay > 0)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
wheels_[i][(delay + (t % bucketsNumPerWheel_) - 1) %
|
||||
bucketsNumPerWheel_]
|
||||
.insert(entryPtr);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// delay is too long to put entry at valid position in wheels;
|
||||
wheels_[i][bucketsNumPerWheel_ - 1].insert(entryPtr);
|
||||
}
|
||||
delay =
|
||||
(delay + (t % bucketsNumPerWheel_) - 1) / bucketsNumPerWheel_;
|
||||
t = t / bucketsNumPerWheel_;
|
||||
}
|
||||
}
|
||||
|
||||
void eraseAfter(size_t delay, const T1 &key)
|
||||
{
|
||||
if (noWheels_)
|
||||
return;
|
||||
assert(map_.find(key) != map_.end());
|
||||
|
||||
CallbackEntryPtr entryPtr;
|
||||
|
||||
if (map_.find(key) != map_.end())
|
||||
{
|
||||
entryPtr = map_[key].weakEntryPtr_.lock();
|
||||
}
|
||||
|
||||
if (entryPtr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
insertEntry(delay, entryPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::function<void()> cb = [this, key]() {
|
||||
bool erased{false};
|
||||
std::function<void()> timeoutCallback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
auto iter = map_.find(key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
auto &value = iter->second;
|
||||
auto entryPtr = value.weakEntryPtr_.lock();
|
||||
// entryPtr is used to avoid race conditions
|
||||
if (value.timeout_ > 0 && !entryPtr)
|
||||
{
|
||||
erased = true;
|
||||
timeoutCallback = std::move(value.timeoutCallback_);
|
||||
map_.erase(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (erased && fnOnErase_)
|
||||
fnOnErase_(key);
|
||||
if (erased && timeoutCallback)
|
||||
timeoutCallback();
|
||||
};
|
||||
entryPtr = std::make_shared<CallbackEntry>(std::move(cb));
|
||||
map_[key].weakEntryPtr_ = entryPtr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(bucketMutex_);
|
||||
insertEntry(delay, entryPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace drogon
|
418
vendors/drogon/lib/inc/drogon/Cookie.h
vendored
Normal file
418
vendors/drogon/lib/inc/drogon/Cookie.h
vendored
Normal file
@ -0,0 +1,418 @@
|
||||
/**
|
||||
*
|
||||
* @file Cookie.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief this class represents a cookie entity.
|
||||
*/
|
||||
class DROGON_EXPORT Cookie
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
/**
|
||||
* @param key key of the cookie
|
||||
* @param value value of the cookie
|
||||
*/
|
||||
Cookie(const std::string &key, const std::string &value)
|
||||
: key_(key), value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
Cookie(std::string &&key, std::string &&value)
|
||||
: key_(std::move(key)), value_(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
Cookie() = default;
|
||||
enum class SameSite
|
||||
{
|
||||
kNull,
|
||||
kLax,
|
||||
kStrict,
|
||||
kNone
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Set the Expires Date
|
||||
*
|
||||
* @param date The expiration date
|
||||
*/
|
||||
void setExpiresDate(const trantor::Date &date)
|
||||
{
|
||||
expiresDate_ = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set if the cookie is HTTP only.
|
||||
*/
|
||||
void setHttpOnly(bool only)
|
||||
{
|
||||
httpOnly_ = only;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set if the cookie is secure.
|
||||
*/
|
||||
void setSecure(bool secure)
|
||||
{
|
||||
secure_ = secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the domain of the cookie.
|
||||
*/
|
||||
void setDomain(const std::string &domain)
|
||||
{
|
||||
domain_ = domain;
|
||||
}
|
||||
|
||||
void setDomain(std::string &&domain)
|
||||
{
|
||||
domain_ = std::move(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the path of the cookie.
|
||||
*/
|
||||
void setPath(const std::string &path)
|
||||
{
|
||||
path_ = path;
|
||||
}
|
||||
|
||||
void setPath(std::string &&path)
|
||||
{
|
||||
path_ = std::move(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the key of the cookie.
|
||||
*/
|
||||
void setKey(const std::string &key)
|
||||
{
|
||||
key_ = key;
|
||||
}
|
||||
|
||||
void setKey(std::string &&key)
|
||||
{
|
||||
key_ = std::move(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the value of the cookie.
|
||||
*/
|
||||
void setValue(const std::string &value)
|
||||
{
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
void setValue(std::string &&value)
|
||||
{
|
||||
value_ = std::move(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the max-age of the cookie.
|
||||
*/
|
||||
void setMaxAge(int value)
|
||||
{
|
||||
maxAge_ = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the same site of the cookie.
|
||||
*/
|
||||
void setSameSite(SameSite sameSite)
|
||||
{
|
||||
sameSite_ = sameSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the string value of the cookie
|
||||
*/
|
||||
std::string cookieString() const;
|
||||
|
||||
/**
|
||||
* @brief Get the string value of the cookie
|
||||
*/
|
||||
std::string getCookieString() const
|
||||
{
|
||||
return cookieString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the expiration date of the cookie
|
||||
*/
|
||||
const trantor::Date &expiresDate() const
|
||||
{
|
||||
return expiresDate_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the expiration date of the cookie
|
||||
*/
|
||||
const trantor::Date &getExpiresDate() const
|
||||
{
|
||||
return expiresDate_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the domain of the cookie
|
||||
*/
|
||||
const std::string &domain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the domain of the cookie
|
||||
*/
|
||||
const std::string &getDomain() const
|
||||
{
|
||||
return domain_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the path of the cookie
|
||||
*/
|
||||
const std::string &path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the path of the cookie
|
||||
*/
|
||||
const std::string &getPath() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the keyword of the cookie
|
||||
*/
|
||||
const std::string &key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the keyword of the cookie
|
||||
*/
|
||||
const std::string &getKey() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of the cookie
|
||||
*/
|
||||
const std::string &value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of the cookie
|
||||
*/
|
||||
const std::string &getValue() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the cookie is empty
|
||||
*
|
||||
* @return true means the cookie is not empty
|
||||
* @return false means the cookie is empty
|
||||
*/
|
||||
operator bool() const
|
||||
{
|
||||
return (!key_.empty()) && (!value_.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the cookie is HTTP only
|
||||
*
|
||||
* @return true means the cookie is HTTP only
|
||||
* @return false means the cookie is not HTTP only
|
||||
*/
|
||||
bool isHttpOnly() const
|
||||
{
|
||||
return httpOnly_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the cookie is secure.
|
||||
*
|
||||
* @return true means the cookie is secure.
|
||||
* @return false means the cookie is not secure.
|
||||
*/
|
||||
bool isSecure() const
|
||||
{
|
||||
return secure_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the max-age of the cookie
|
||||
*/
|
||||
std::optional<int> maxAge() const
|
||||
{
|
||||
return maxAge_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the max-age of the cookie
|
||||
*/
|
||||
std::optional<int> getMaxAge() const
|
||||
{
|
||||
return maxAge_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the same site of the cookie
|
||||
*/
|
||||
SameSite sameSite() const
|
||||
{
|
||||
return sameSite_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the same site of the cookie
|
||||
*/
|
||||
SameSite getSameSite() const
|
||||
{
|
||||
return sameSite_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare two strings ignoring the their cases
|
||||
*
|
||||
* @param str1 string to check its value
|
||||
* @param str2 string to check against, written in lower case
|
||||
*
|
||||
* @note the function is optimized to check for cookie's samesite value
|
||||
* where we check if the value equals to a specific value we already know in
|
||||
* str2. so the function doesn't apply tolower to the second argument
|
||||
* str2 as it's always in lower case.
|
||||
*
|
||||
* @return true if both strings are equal ignoring case
|
||||
*/
|
||||
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 false;
|
||||
for (size_t idx{0}; idx < str1Len; ++idx)
|
||||
{
|
||||
auto lowerChar{tolower(str1[idx])};
|
||||
|
||||
if (lowerChar != str2[idx])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a string value to its associated enum class SameSite
|
||||
* value
|
||||
*/
|
||||
static SameSite convertString2SameSite(const std::string_view &sameSite)
|
||||
{
|
||||
if (stricmp(sameSite, "lax"))
|
||||
{
|
||||
return Cookie::SameSite::kLax;
|
||||
}
|
||||
else if (stricmp(sameSite, "strict"))
|
||||
{
|
||||
return Cookie::SameSite::kStrict;
|
||||
}
|
||||
else if (stricmp(sameSite, "none"))
|
||||
{
|
||||
return Cookie::SameSite::kNone;
|
||||
}
|
||||
else if (!stricmp(sameSite, "null"))
|
||||
{
|
||||
LOG_WARN
|
||||
<< "'" << sameSite
|
||||
<< "' is not a valid SameSite policy. 'Null', 'Lax', 'Strict' "
|
||||
"or "
|
||||
"'None' are proper values. Return value is SameSite::kNull.";
|
||||
}
|
||||
return Cookie::SameSite::kNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts an enum class SameSite value to its associated string
|
||||
* value
|
||||
*/
|
||||
static const std::string_view &convertSameSite2String(SameSite sameSite)
|
||||
{
|
||||
switch (sameSite)
|
||||
{
|
||||
case SameSite::kLax:
|
||||
{
|
||||
static std::string_view sv{"Lax"};
|
||||
return sv;
|
||||
}
|
||||
case SameSite::kStrict:
|
||||
{
|
||||
static std::string_view sv{"Strict"};
|
||||
return sv;
|
||||
}
|
||||
case SameSite::kNone:
|
||||
{
|
||||
static std::string_view sv{"None"};
|
||||
return sv;
|
||||
}
|
||||
case SameSite::kNull:
|
||||
{
|
||||
static std::string_view sv{"Null"};
|
||||
return sv;
|
||||
}
|
||||
}
|
||||
{
|
||||
static std::string_view sv{"UNDEFINED"};
|
||||
return sv;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
trantor::Date expiresDate_{(std::numeric_limits<int64_t>::max)()};
|
||||
bool httpOnly_{true};
|
||||
bool secure_{false};
|
||||
std::string domain_;
|
||||
std::string path_;
|
||||
std::string key_;
|
||||
std::string value_;
|
||||
std::optional<int> maxAge_;
|
||||
SameSite sameSite_{SameSite::kNull};
|
||||
};
|
||||
|
||||
} // namespace drogon
|
144
vendors/drogon/lib/inc/drogon/DrClassMap.h
vendored
Normal file
144
vendors/drogon/lib/inc/drogon/DrClassMap.h
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
*
|
||||
* @file DrClassMap.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <cstdlib>
|
||||
#ifndef _MSC_VER
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class DrObjectBase;
|
||||
using DrAllocFunc = std::function<DrObjectBase *()>;
|
||||
using DrSharedAllocFunc = std::function<std::shared_ptr<DrObjectBase>()>;
|
||||
|
||||
/**
|
||||
* @brief A map class which can create DrObjects from names.
|
||||
*/
|
||||
class DROGON_EXPORT DrClassMap
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Register a class into the map
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @param func The function which can create a new instance of the class.
|
||||
*/
|
||||
static void registerClass(const std::string &className,
|
||||
const DrAllocFunc &func,
|
||||
const DrSharedAllocFunc &sharedFunc = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of the class named by className
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @return DrObjectBase* The pointer to the newly created instance.
|
||||
*/
|
||||
static DrObjectBase *newObject(const std::string &className);
|
||||
|
||||
/**
|
||||
* @brief Get the shared_ptr instance of the class named by className
|
||||
*/
|
||||
static std::shared_ptr<DrObjectBase> newSharedObject(
|
||||
const std::string &className);
|
||||
|
||||
/**
|
||||
* @brief Get the singleton object of the class named by className
|
||||
*
|
||||
* @param className The name of the class
|
||||
* @return const std::shared_ptr<DrObjectBase>& The smart pointer to the
|
||||
* instance.
|
||||
*/
|
||||
static const std::shared_ptr<DrObjectBase> &getSingleInstance(
|
||||
const std::string &className);
|
||||
|
||||
/**
|
||||
* @brief Get the singleton T type object
|
||||
*
|
||||
* @tparam T The type of the class
|
||||
* @return std::shared_ptr<T> The smart pointer to the instance.
|
||||
* @note The T must be a subclass of the DrObjectBase class.
|
||||
*/
|
||||
template <typename T>
|
||||
static std::shared_ptr<T> getSingleInstance()
|
||||
{
|
||||
static_assert(std::is_base_of<DrObjectBase, T>::value,
|
||||
"T must be a sub-class of DrObjectBase");
|
||||
static auto const singleton =
|
||||
std::dynamic_pointer_cast<T>(getSingleInstance(T::classTypeName()));
|
||||
assert(singleton);
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a singleton object into the map.
|
||||
*
|
||||
* @param ins The smart pointer to the instance.
|
||||
*/
|
||||
static void setSingleInstance(const std::shared_ptr<DrObjectBase> &ins);
|
||||
|
||||
/**
|
||||
* @brief Get all names of classes registered in the map.
|
||||
*
|
||||
* @return std::vector<std::string> the vector of class names.
|
||||
*/
|
||||
static std::vector<std::string> getAllClassName();
|
||||
|
||||
/**
|
||||
* @brief demangle the type name which is returned by typeid(T).name().
|
||||
*
|
||||
* @param mangled_name The type name which is returned by typeid(T).name().
|
||||
* @return std::string The human readable type name.
|
||||
*/
|
||||
static std::string demangle(const char *mangled_name)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
std::size_t len = 0;
|
||||
int status = 0;
|
||||
std::unique_ptr<char, decltype(&std::free)> ptr(
|
||||
__cxxabiv1::__cxa_demangle(mangled_name, nullptr, &len, &status),
|
||||
&std::free);
|
||||
if (status == 0)
|
||||
{
|
||||
return std::string(ptr.get());
|
||||
}
|
||||
LOG_ERROR << "Demangle error!";
|
||||
return "";
|
||||
#else
|
||||
auto pos = strstr(mangled_name, " ");
|
||||
if (pos == nullptr)
|
||||
return std::string{mangled_name};
|
||||
else
|
||||
return std::string{pos + 1};
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::unordered_map<std::string,
|
||||
std::pair<DrAllocFunc, DrSharedAllocFunc>>
|
||||
&getMap();
|
||||
};
|
||||
} // namespace drogon
|
151
vendors/drogon/lib/inc/drogon/DrObject.h
vendored
Normal file
151
vendors/drogon/lib/inc/drogon/DrObject.h
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
*
|
||||
* @file DrObject.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4250)
|
||||
#endif
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief The base class for all drogon reflection classes.
|
||||
*
|
||||
*/
|
||||
class DROGON_EXPORT DrObjectBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Get the class name
|
||||
*
|
||||
* @return const std::string& the class name
|
||||
*/
|
||||
virtual const std::string &className() const
|
||||
{
|
||||
static const std::string name{"DrObjectBase"};
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return true if the class name is 'class_name'
|
||||
*/
|
||||
virtual bool isClass(const std::string &class_name) const
|
||||
{
|
||||
return (className() == class_name);
|
||||
}
|
||||
|
||||
virtual ~DrObjectBase()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct isAutoCreationClass
|
||||
{
|
||||
template <class C>
|
||||
static constexpr auto check(C *)
|
||||
-> std::enable_if_t<std::is_same_v<decltype(C::isAutoCreation), bool>,
|
||||
bool>
|
||||
{
|
||||
return C::isAutoCreation;
|
||||
}
|
||||
|
||||
template <typename>
|
||||
static constexpr bool check(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool value = check<T>(nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* a class template to
|
||||
* implement the reflection function of creating the class object by class name
|
||||
*/
|
||||
template <typename T>
|
||||
class DrObject : public virtual DrObjectBase
|
||||
{
|
||||
public:
|
||||
const std::string &className() const override
|
||||
{
|
||||
return alloc_.className();
|
||||
}
|
||||
|
||||
static const std::string &classTypeName()
|
||||
{
|
||||
return alloc_.className();
|
||||
}
|
||||
|
||||
bool isClass(const std::string &class_name) const override
|
||||
{
|
||||
return (className() == class_name);
|
||||
}
|
||||
|
||||
protected:
|
||||
// protect constructor to make this class only inheritable
|
||||
DrObject() = default;
|
||||
~DrObject() override = default;
|
||||
|
||||
private:
|
||||
class DrAllocator
|
||||
{
|
||||
public:
|
||||
DrAllocator()
|
||||
{
|
||||
registerClass<T>();
|
||||
}
|
||||
|
||||
const std::string &className() const
|
||||
{
|
||||
static std::string className =
|
||||
DrClassMap::demangle(typeid(T).name());
|
||||
return className;
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
void registerClass()
|
||||
{
|
||||
if constexpr (std::is_default_constructible<D>::value)
|
||||
{
|
||||
DrClassMap::registerClass(
|
||||
className(),
|
||||
[]() -> DrObjectBase * { return new T; },
|
||||
[]() -> std::shared_ptr<DrObjectBase> {
|
||||
return std::make_shared<T>();
|
||||
});
|
||||
}
|
||||
else if constexpr (isAutoCreationClass<D>::value)
|
||||
{
|
||||
static_assert(std::is_default_constructible<D>::value,
|
||||
"Class is not default constructable!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// use static val to register allocator function for class T;
|
||||
static DrAllocator alloc_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
typename DrObject<T>::DrAllocator DrObject<T>::alloc_;
|
||||
|
||||
} // namespace drogon
|
31
vendors/drogon/lib/inc/drogon/DrTemplate.h
vendored
Normal file
31
vendors/drogon/lib/inc/drogon/DrTemplate.h
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
* DrTemplate.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/DrTemplateBase.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
template <typename T>
|
||||
class DrTemplate : public DrObject<T>, public DrTemplateBase
|
||||
{
|
||||
protected:
|
||||
DrTemplate()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace drogon
|
58
vendors/drogon/lib/inc/drogon/DrTemplateBase.h
vendored
Normal file
58
vendors/drogon/lib/inc/drogon/DrTemplateBase.h
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
*
|
||||
* @file DrTemplateBase.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/HttpViewData.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
using DrTemplateData = HttpViewData;
|
||||
|
||||
/// The templating engine class
|
||||
/**
|
||||
* This class can generate a text string from the template file and template
|
||||
* data.
|
||||
* For more details on the template file, see the wiki site (the 'View' section)
|
||||
*/
|
||||
class DROGON_EXPORT DrTemplateBase : public virtual DrObjectBase
|
||||
{
|
||||
public:
|
||||
/// Create an object of the implementation class
|
||||
/**
|
||||
* @param templateName represents the name of the template file. A template
|
||||
* file is a description file with a special format. Its extension is
|
||||
* usually .csp. The user should preprocess the template file with the
|
||||
* drogon_ctl tool to create c++ source files.
|
||||
*/
|
||||
static std::shared_ptr<DrTemplateBase> newTemplate(
|
||||
const std::string &templateName);
|
||||
|
||||
/// Generate the text string
|
||||
/**
|
||||
* @param data represents data rendered in the string in a format
|
||||
* according to the template file.
|
||||
*/
|
||||
virtual std::string genText(
|
||||
const DrTemplateData &data = DrTemplateData()) = 0;
|
||||
|
||||
virtual ~DrTemplateBase(){};
|
||||
DrTemplateBase(){};
|
||||
};
|
||||
|
||||
} // namespace drogon
|
1599
vendors/drogon/lib/inc/drogon/HttpAppFramework.h
vendored
Normal file
1599
vendors/drogon/lib/inc/drogon/HttpAppFramework.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
467
vendors/drogon/lib/inc/drogon/HttpBinder.h
vendored
Normal file
467
vendors/drogon/lib/inc/drogon/HttpBinder.h
vendored
Normal file
@ -0,0 +1,467 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpBinder.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
|
||||
*
|
||||
*/
|
||||
|
||||
/// The classes in the file are internal tool classes. Do not include this
|
||||
/// file directly and use any of these classes directly.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/utils/FunctionTraits.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
// we only accept value type or const lreference type or right reference type as
|
||||
// the handle method parameters type
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits
|
||||
{
|
||||
static const bool isValid = true;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T *>
|
||||
{
|
||||
static const bool isValid = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T &>
|
||||
{
|
||||
static const bool isValid = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<T &&>
|
||||
{
|
||||
static const bool isValid = true;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<const T &&>
|
||||
{
|
||||
static const bool isValid = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BinderArgTypeTraits<const T &>
|
||||
{
|
||||
static const bool isValid = true;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T getHandlerArgumentValue(std::string &&p)
|
||||
{
|
||||
if constexpr (internal::CanConstructFromString<T>::value)
|
||||
{
|
||||
return T(std::move(p));
|
||||
}
|
||||
else if constexpr (internal::CanConvertFromStringStream<T>::value)
|
||||
{
|
||||
T value{T()};
|
||||
if (!p.empty())
|
||||
{
|
||||
std::stringstream ss(std::move(p));
|
||||
ss >> value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if constexpr (internal::CanConvertFromString<T>::value)
|
||||
{
|
||||
T value;
|
||||
value = p;
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Can't convert string to type " << typeid(T).name();
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string getHandlerArgumentValue<std::string>(std::string &&p)
|
||||
{
|
||||
return std::move(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int getHandlerArgumentValue<int>(std::string &&p)
|
||||
{
|
||||
return std::stoi(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long getHandlerArgumentValue<long>(std::string &&p)
|
||||
{
|
||||
return std::stol(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long long getHandlerArgumentValue<long long>(std::string &&p)
|
||||
{
|
||||
return std::stoll(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long getHandlerArgumentValue<unsigned long>(std::string &&p)
|
||||
{
|
||||
return std::stoul(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long long getHandlerArgumentValue<unsigned long long>(
|
||||
std::string &&p)
|
||||
{
|
||||
return std::stoull(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float getHandlerArgumentValue<float>(std::string &&p)
|
||||
{
|
||||
return std::stof(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double getHandlerArgumentValue<double>(std::string &&p)
|
||||
{
|
||||
return std::stod(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long double getHandlerArgumentValue<long double>(std::string &&p)
|
||||
{
|
||||
return std::stold(p);
|
||||
}
|
||||
|
||||
class HttpBinderBase
|
||||
{
|
||||
public:
|
||||
virtual void handleHttpRequest(
|
||||
std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
|
||||
virtual size_t paramCount() = 0;
|
||||
virtual const std::string &handlerName() const = 0;
|
||||
|
||||
virtual ~HttpBinderBase()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T &getControllerObj()
|
||||
{
|
||||
// Initialization of function-local statics is guaranteed to occur only once
|
||||
// even when
|
||||
// called from multiple threads, and may be more efficient than the
|
||||
// equivalent code using std::call_once.
|
||||
static T obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
DROGON_EXPORT void handleException(
|
||||
const std::exception &,
|
||||
const HttpRequestPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&);
|
||||
|
||||
using HttpBinderBasePtr = std::shared_ptr<HttpBinderBase>;
|
||||
|
||||
template <typename FUNCTION>
|
||||
class HttpBinder : public HttpBinderBase
|
||||
{
|
||||
public:
|
||||
using traits = FunctionTraits<FUNCTION>;
|
||||
using FunctionType = FUNCTION;
|
||||
|
||||
void handleHttpRequest(
|
||||
std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) override
|
||||
{
|
||||
if (!pathArguments.empty())
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
args.reserve(pathArguments.size());
|
||||
for (auto &arg : pathArguments)
|
||||
{
|
||||
args.emplace_back(arg);
|
||||
}
|
||||
req->setRoutingParameters(std::move(args));
|
||||
}
|
||||
run(pathArguments, req, std::move(callback));
|
||||
}
|
||||
|
||||
size_t paramCount() override
|
||||
{
|
||||
return traits::arity;
|
||||
}
|
||||
|
||||
HttpBinder(FUNCTION &&func) : func_(std::forward<FUNCTION>(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 <bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass>
|
||||
void createHandlerInstance()
|
||||
{
|
||||
if constexpr (isClassFunction)
|
||||
{
|
||||
if constexpr (isDrObjectClass)
|
||||
{
|
||||
auto objPtr = DrClassMap::getSingleInstance<
|
||||
typename traits::class_type>();
|
||||
LOG_TRACE << "create handler class object: " << objPtr.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &obj = getControllerObj<typename traits::class_type>();
|
||||
LOG_TRACE << "create handler class object: " << &obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FUNCTION func_;
|
||||
template <std::size_t Index>
|
||||
using nth_argument_type = typename traits::template argument<Index>;
|
||||
|
||||
static const size_t argument_count = traits::arity;
|
||||
std::string handlerName_;
|
||||
|
||||
template <typename... Values,
|
||||
std::size_t Boundary = argument_count,
|
||||
bool isCoroutine = traits::isCoroutine>
|
||||
void run(std::deque<std::string> &pathArguments,
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
Values &&...values)
|
||||
{
|
||||
if constexpr (sizeof...(Values) < Boundary)
|
||||
{ // Call this function recursively until parameter's count equals to
|
||||
// the count of target function parameters
|
||||
static_assert(
|
||||
BinderArgTypeTraits<
|
||||
nth_argument_type<sizeof...(Values)>>::isValid,
|
||||
"your handler argument type must be value type or const left "
|
||||
"reference type or right reference type");
|
||||
using ValueType = std::remove_cv_t<
|
||||
std::remove_reference_t<nth_argument_type<sizeof...(Values)>>>;
|
||||
if (!pathArguments.empty())
|
||||
{
|
||||
std::string v{std::move(pathArguments.front())};
|
||||
pathArguments.pop_front();
|
||||
try
|
||||
{
|
||||
if (!v.empty())
|
||||
{
|
||||
auto value =
|
||||
getHandlerArgumentValue<ValueType>(std::move(v));
|
||||
run(pathArguments,
|
||||
req,
|
||||
std::move(callback),
|
||||
std::forward<Values>(values)...,
|
||||
std::move(value));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
handleException(e, req, std::move(callback));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
auto value = req->as<ValueType>();
|
||||
run(pathArguments,
|
||||
req,
|
||||
std::move(callback),
|
||||
std::forward<Values>(values)...,
|
||||
std::move(value));
|
||||
return;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
handleException(e, req, std::move(callback));
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
run(pathArguments,
|
||||
req,
|
||||
std::move(callback),
|
||||
std::forward<Values>(values)...,
|
||||
ValueType());
|
||||
}
|
||||
else if constexpr (sizeof...(Values) == Boundary)
|
||||
{
|
||||
if constexpr (!isCoroutine)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Explicit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
callFunction(req, cb, std::move(values)...);
|
||||
}
|
||||
catch (const std::exception &except)
|
||||
{
|
||||
handleException(except, req, std::move(callback));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef __cpp_impl_coroutine
|
||||
else
|
||||
{
|
||||
[this](HttpRequestPtr req,
|
||||
std::function<void(const HttpResponsePtr &)> callback,
|
||||
Values &&...values) -> AsyncTask {
|
||||
try
|
||||
{
|
||||
if constexpr (std::is_same_v<
|
||||
AsyncTask,
|
||||
typename traits::return_type>)
|
||||
{
|
||||
// Explicit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
callFunction(req, cb, std::move(values)...);
|
||||
}
|
||||
else if constexpr (std::is_same_v<
|
||||
Task<>,
|
||||
typename traits::return_type>)
|
||||
{
|
||||
// Explicit copy because `callFunction` moves it
|
||||
auto cb = callback;
|
||||
co_await callFunction(req,
|
||||
cb,
|
||||
std::move(values)...);
|
||||
}
|
||||
else if constexpr (std::is_same_v<
|
||||
Task<HttpResponsePtr>,
|
||||
typename traits::return_type>)
|
||||
{
|
||||
auto resp =
|
||||
co_await callFunction(req,
|
||||
std::move(values)...);
|
||||
callback(std::move(resp));
|
||||
}
|
||||
}
|
||||
catch (const std::exception &except)
|
||||
{
|
||||
handleException(except, req, std::move(callback));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR
|
||||
<< "Exception not derived from std::exception";
|
||||
}
|
||||
co_return;
|
||||
}(req, std::move(callback), std::move(values)...);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Values,
|
||||
bool isClassFunction = traits::isClassFunction,
|
||||
bool isDrObjectClass = traits::isDrObjectClass,
|
||||
bool isNormal = std::is_same_v<typename traits::first_param_type,
|
||||
HttpRequestPtr>>
|
||||
typename traits::return_type callFunction(const HttpRequestPtr &req,
|
||||
Values &&...values)
|
||||
{
|
||||
if constexpr (isNormal)
|
||||
{
|
||||
if constexpr (isClassFunction)
|
||||
{
|
||||
if constexpr (!isDrObjectClass)
|
||||
{
|
||||
static auto &obj =
|
||||
getControllerObj<typename traits::class_type>();
|
||||
return (obj.*func_)(req, std::move(values)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
static auto objPtr = DrClassMap::getSingleInstance<
|
||||
typename traits::class_type>();
|
||||
return (*objPtr.*func_)(req, std::move(values)...);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func_(req, std::move(values)...);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (isClassFunction)
|
||||
{
|
||||
if constexpr (!isDrObjectClass)
|
||||
{
|
||||
static auto &obj =
|
||||
getControllerObj<typename traits::class_type>();
|
||||
return (obj.*func_)((*req), std::move(values)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
static auto objPtr = DrClassMap::getSingleInstance<
|
||||
typename traits::class_type>();
|
||||
return (*objPtr.*func_)((*req), std::move(values)...);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func_((*req), std::move(values)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace drogon
|
395
vendors/drogon/lib/inc/drogon/HttpClient.h
vendored
Normal file
395
vendors/drogon/lib/inc/drogon/HttpClient.h
vendored
Normal file
@ -0,0 +1,395 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpClient.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 the MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* Drogon
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/net/EventLoop.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include "drogon/HttpBinder.h"
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
#include <drogon/utils/coroutine.h>
|
||||
#endif
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class HttpClient;
|
||||
using HttpClientPtr = std::shared_ptr<HttpClient>;
|
||||
#ifdef __cpp_impl_coroutine
|
||||
namespace internal
|
||||
{
|
||||
struct HttpRespAwaiter : public CallbackAwaiter<HttpResponsePtr>
|
||||
{
|
||||
HttpRespAwaiter(HttpClient *client, HttpRequestPtr req, double timeout)
|
||||
: client_(client), req_(std::move(req)), timeout_(timeout)
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> handle);
|
||||
|
||||
private:
|
||||
HttpClient *client_;
|
||||
HttpRequestPtr req_;
|
||||
double timeout_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
#endif
|
||||
|
||||
/// Asynchronous http client
|
||||
/**
|
||||
* HttpClient implementation object uses the HttpAppFramework's event loop by
|
||||
* default, so you should call app().run() to make the client work.
|
||||
* Each HttpClient object establishes a persistent connection with the server.
|
||||
* If the connection is broken, the client attempts to reconnect
|
||||
* when calling the sendRequest method.
|
||||
*
|
||||
* Using the static method newHttpClient(...) to get shared_ptr of the object
|
||||
* implementing the class, the shared_ptr is retained in the framework until all
|
||||
* response callbacks are invoked without fear of accidental deconstruction.
|
||||
*
|
||||
*/
|
||||
class DROGON_EXPORT HttpClient : public trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Send a request asynchronously to the server
|
||||
*
|
||||
* @param req The request sent to the server.
|
||||
* @param callback The callback is called when the response is received from
|
||||
* the server.
|
||||
* @param timeout In seconds. If the response is not received within the
|
||||
* timeout, the callback is called with `ReqResult::Timeout` and an empty
|
||||
* response. The zero value by default disables the timeout.
|
||||
*
|
||||
* @note
|
||||
* The request object is altered(some headers are added to it) before it is
|
||||
* sent, so calling this method with a same request object in different
|
||||
* thread is dangerous.
|
||||
* Please be careful when using timeout on an non-idempotent request.
|
||||
*/
|
||||
virtual void sendRequest(const HttpRequestPtr &req,
|
||||
const HttpReqCallback &callback,
|
||||
double timeout = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Send a request asynchronously to the server
|
||||
*
|
||||
* @param req The request sent to the server.
|
||||
* @param callback The callback is called when the response is received from
|
||||
* the server.
|
||||
* @param timeout In seconds. If the response is not received within
|
||||
* the timeout, the callback is called with `ReqResult::Timeout` and an
|
||||
* empty response. The zero value by default disables the timeout.
|
||||
*
|
||||
* @note
|
||||
* The request object is altered(some headers are added to it) before it is
|
||||
* sent, so calling this method with a same request object in different
|
||||
* thread is dangerous.
|
||||
* Please be careful when using timeout on an non-idempotent request.
|
||||
*/
|
||||
virtual void sendRequest(const HttpRequestPtr &req,
|
||||
HttpReqCallback &&callback,
|
||||
double timeout = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief Send a request synchronously to the server and return the
|
||||
* response.
|
||||
*
|
||||
* @param req
|
||||
* @param timeout In seconds. If the response is not received within the
|
||||
* timeout, the `ReqResult::Timeout` and an empty response is returned. The
|
||||
* zero value by default disables the timeout.
|
||||
*
|
||||
* @return std::pair<ReqResult, HttpResponsePtr>
|
||||
* @note Never call this function in the event loop thread of the
|
||||
* client (partially in the callback function of the asynchronous
|
||||
* sendRequest method), otherwise the thread will be blocked forever.
|
||||
* Please be careful when using timeout on an non-idempotent request.
|
||||
*/
|
||||
std::pair<ReqResult, HttpResponsePtr> sendRequest(const HttpRequestPtr &req,
|
||||
double timeout = 0)
|
||||
{
|
||||
assert(!getLoop()->isInLoopThread() &&
|
||||
"Deadlock detected! Calling a sync API from the same loop as "
|
||||
"the HTTP client processes on will deadlock the event loop");
|
||||
std::promise<std::pair<ReqResult, HttpResponsePtr>> prom;
|
||||
auto f = prom.get_future();
|
||||
sendRequest(
|
||||
req,
|
||||
[&prom](ReqResult r, const HttpResponsePtr &resp) {
|
||||
prom.set_value({r, resp});
|
||||
},
|
||||
timeout);
|
||||
return f.get();
|
||||
}
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
/**
|
||||
* @brief Send a request via coroutines to the server and return an
|
||||
* awaiter what could be `co_await`-ed to retrieve the response
|
||||
* (HttpResponsePtr)
|
||||
*
|
||||
* @param req
|
||||
* @param timeout In seconds. If the response is not received within the
|
||||
* timeout, A `drogon::HttpException` with `ReqResult::Timeout` is thrown.
|
||||
* The zero value by default disables the timeout.
|
||||
*
|
||||
* @return internal::HttpRespAwaiter. Await on it to get the response
|
||||
*/
|
||||
internal::HttpRespAwaiter sendRequestCoro(HttpRequestPtr req,
|
||||
double timeout = 0)
|
||||
{
|
||||
return internal::HttpRespAwaiter(this, std::move(req), timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Set socket options(before connecting)
|
||||
/**
|
||||
* @brief Set the callback which is called before connecting to the
|
||||
* server. The callback is used to set socket options on the socket fd.
|
||||
*
|
||||
* @code
|
||||
auto client = HttpClient::newHttpClient("http://www.baidu.com");
|
||||
client->setSockOptCallback([](int fd) {});
|
||||
auto req = HttpRequest::newHttpRequest();
|
||||
client->sendRequest(req, [](ReqResult result, const HttpResponsePtr&
|
||||
response) {});
|
||||
@endcode
|
||||
*/
|
||||
virtual void setSockOptCallback(std::function<void(int)> cb) = 0;
|
||||
|
||||
/// Set the pipelining depth, which is the number of requests that are not
|
||||
/// responding.
|
||||
/**
|
||||
* If this method is not called, the default depth value is 0 which means
|
||||
* the pipelining is disabled. For details about pipelining, see
|
||||
* rfc2616-8.1.2.2
|
||||
*/
|
||||
virtual void setPipeliningDepth(size_t depth) = 0;
|
||||
|
||||
/// Enable cookies for the client
|
||||
/**
|
||||
* @param flag if the parameter is true, all requests sent by the client
|
||||
* carry the cookies set by the server side. Cookies are disabled by
|
||||
* default.
|
||||
*/
|
||||
virtual void enableCookies(bool flag = true) = 0;
|
||||
|
||||
/// Add a cookie to the client
|
||||
/**
|
||||
* @note
|
||||
* These methods are independent of the enableCookies() method. Whether the
|
||||
* enableCookies() is called with true or false, the cookies added by these
|
||||
* methods will be sent to the server.
|
||||
*/
|
||||
virtual void addCookie(const std::string &key,
|
||||
const std::string &value) = 0;
|
||||
|
||||
/// Add a cookie to the client
|
||||
/**
|
||||
* @note
|
||||
* These methods are independent of the enableCookies() method. Whether the
|
||||
* enableCookies() is called with true or false, the cookies added by these
|
||||
* methods will be sent to the server.
|
||||
*/
|
||||
virtual void addCookie(const Cookie &cookie) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the user_agent header, the default value is 'DrogonClient' if
|
||||
* this method is not used.
|
||||
*
|
||||
* @param userAgent The user_agent value, if it is empty, the user_agent
|
||||
* header is not sent to the server.
|
||||
*/
|
||||
virtual void setUserAgent(const std::string &userAgent) = 0;
|
||||
|
||||
/**
|
||||
* @brief Create a new HTTP client which use ip and port to connect to
|
||||
* server
|
||||
*
|
||||
* @param ip The ip address of the HTTP server
|
||||
* @param port The port of the HTTP server
|
||||
* @param useSSL if the parameter is set to true, the client connects to the
|
||||
* server using HTTPS.
|
||||
* @param loop If the loop parameter is set to nullptr, the client uses the
|
||||
* HttpAppFramework's event loop, otherwise it runs in the loop identified
|
||||
* by the parameter.
|
||||
* @param useOldTLS If the parameter is set to true, the TLS1.0/1.1 are
|
||||
* enabled for HTTPS.
|
||||
* @param validateCert If the parameter is set to true, the client validates
|
||||
* the server certificate when SSL handshaking.
|
||||
* @return HttpClientPtr The smart pointer to the new client object.
|
||||
* @note: The ip parameter support for both ipv4 and ipv6 address
|
||||
*/
|
||||
static HttpClientPtr newHttpClient(const std::string &ip,
|
||||
uint16_t port,
|
||||
bool useSSL = false,
|
||||
trantor::EventLoop *loop = nullptr,
|
||||
bool useOldTLS = false,
|
||||
bool validateCert = true);
|
||||
|
||||
/// Get the event loop of the client;
|
||||
virtual trantor::EventLoop *getLoop() = 0;
|
||||
|
||||
/// Get the number of bytes sent or received
|
||||
virtual size_t bytesSent() const = 0;
|
||||
virtual size_t bytesReceived() const = 0;
|
||||
|
||||
virtual std::string host() const = 0;
|
||||
|
||||
std::string getHost() const
|
||||
{
|
||||
return host();
|
||||
}
|
||||
|
||||
virtual uint16_t port() const = 0;
|
||||
|
||||
uint16_t getPort() const
|
||||
{
|
||||
return port();
|
||||
}
|
||||
|
||||
virtual bool secure() const = 0;
|
||||
|
||||
bool onDefaultPort() const
|
||||
{
|
||||
if (secure())
|
||||
return port() == 443;
|
||||
return port() == 80;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the client certificate used by the HTTP connection
|
||||
*
|
||||
* @param cert Path to the certificate
|
||||
* @param key Path to the certificate's private key
|
||||
* @note this method has no effect if the HTTP client is communicating via
|
||||
* unencrypted HTTP
|
||||
*/
|
||||
virtual void setCertPath(const std::string &cert,
|
||||
const std::string &key) = 0;
|
||||
|
||||
/**
|
||||
* @brief Supplies command style options for `SSL_CONF_cmd`
|
||||
*
|
||||
* @param sslConfCmds options for SSL_CONF_cmd
|
||||
* @note this method has no effect if the HTTP client is communicating via
|
||||
* unencrypted HTTP
|
||||
* @code
|
||||
addSSLConfigs({{"-dhparam", "/path/to/dhparam"}, {"-strict", ""}});
|
||||
* @endcode
|
||||
*/
|
||||
virtual void addSSLConfigs(
|
||||
const std::vector<std::pair<std::string, std::string>>
|
||||
&sslConfCmds) = 0;
|
||||
|
||||
/// Create a Http client using the hostString to connect to server
|
||||
/**
|
||||
*
|
||||
* @param hostString this parameter must be prefixed by 'http://' or
|
||||
* 'https://'.
|
||||
*
|
||||
* Examples for hostString:
|
||||
* @code
|
||||
https://www.baidu.com
|
||||
http://www.baidu.com
|
||||
https://127.0.0.1:8080/
|
||||
http://127.0.0.1
|
||||
http://[::1]:8080/ //IPv6 address must be enclosed in [], rfc2732
|
||||
@endcode
|
||||
*
|
||||
* @param loop If the loop parameter is set to nullptr, the client uses the
|
||||
* HttpAppFramework's event loop, otherwise it runs in the loop identified
|
||||
* by the parameter.
|
||||
*
|
||||
* @param useOldTLS If the parameter is set to true, the TLS1.0/1.1 are
|
||||
* enabled for HTTPS.
|
||||
* @note
|
||||
*
|
||||
* @param validateCert If the parameter is set to true, the client validates
|
||||
* the server certificate when SSL handshaking.
|
||||
*
|
||||
* @note Don't add path and parameters in hostString, the request path and
|
||||
* parameters should be set in HttpRequestPtr when calling the sendRequest()
|
||||
* method.
|
||||
*
|
||||
*/
|
||||
static HttpClientPtr newHttpClient(const std::string &hostString,
|
||||
trantor::EventLoop *loop = nullptr,
|
||||
bool useOldTLS = false,
|
||||
bool validateCert = true);
|
||||
|
||||
virtual ~HttpClient()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
HttpClient() = default;
|
||||
};
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
|
||||
class HttpException : public std::exception
|
||||
{
|
||||
public:
|
||||
HttpException() = delete;
|
||||
|
||||
explicit HttpException(ReqResult res)
|
||||
: resultCode_(res), message_(to_string_view(res))
|
||||
{
|
||||
}
|
||||
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return message_.data();
|
||||
}
|
||||
|
||||
ReqResult code() const
|
||||
{
|
||||
return resultCode_;
|
||||
}
|
||||
|
||||
private:
|
||||
ReqResult resultCode_;
|
||||
std::string_view message_;
|
||||
};
|
||||
|
||||
inline void internal::HttpRespAwaiter::await_suspend(
|
||||
std::coroutine_handle<> handle)
|
||||
{
|
||||
assert(client_ != nullptr);
|
||||
assert(req_ != nullptr);
|
||||
client_->sendRequest(
|
||||
req_,
|
||||
[handle, this](ReqResult result, const HttpResponsePtr &resp) {
|
||||
if (result == ReqResult::Ok)
|
||||
setValue(resp);
|
||||
else
|
||||
setException(std::make_exception_ptr(HttpException(result)));
|
||||
handle.resume();
|
||||
},
|
||||
timeout_);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace drogon
|
151
vendors/drogon/lib/inc/drogon/HttpController.h
vendored
Normal file
151
vendors/drogon/lib/inc/drogon/HttpController.h
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
*
|
||||
* HttpController.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/utils/HttpConstraint.h>
|
||||
#include <drogon/HttpAppFramework.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <vector>
|
||||
|
||||
/// For more details on the class, see the wiki site (the 'HttpController'
|
||||
/// section)
|
||||
|
||||
#define METHOD_LIST_BEGIN \
|
||||
static void initPathRouting() \
|
||||
{
|
||||
#define METHOD_ADD(method, pattern, ...) \
|
||||
registerMethod(&method, pattern, {__VA_ARGS__}, true, #method)
|
||||
#define ADD_METHOD_TO(method, path_pattern, ...) \
|
||||
registerMethod(&method, path_pattern, {__VA_ARGS__}, false, #method)
|
||||
#define ADD_METHOD_VIA_REGEX(method, regex, ...) \
|
||||
registerMethodViaRegex(&method, regex, {__VA_ARGS__}, #method)
|
||||
#define METHOD_LIST_END \
|
||||
return; \
|
||||
}
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief The base class for HTTP controllers.
|
||||
*
|
||||
*/
|
||||
class HttpControllerBase
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The reflection base class template for HTTP controllers
|
||||
*
|
||||
* @tparam T the type of the implementation class
|
||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpController : public DrObject<T>, public HttpControllerBase
|
||||
{
|
||||
public:
|
||||
static constexpr bool isAutoCreation = AutoCreation;
|
||||
|
||||
protected:
|
||||
template <typename FUNCTION>
|
||||
static void registerMethod(
|
||||
FUNCTION &&function,
|
||||
const std::string &pattern,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
bool classNameInPath = true,
|
||||
const std::string &handlerName = "")
|
||||
{
|
||||
if (classNameInPath)
|
||||
{
|
||||
std::string path = "/";
|
||||
path.append(HttpController<T, AutoCreation>::classTypeName());
|
||||
LOG_TRACE << "classname:"
|
||||
<< HttpController<T, AutoCreation>::classTypeName();
|
||||
|
||||
// transform(path.begin(), path.end(), path.begin(), [](unsigned
|
||||
// char c){ return tolower(c); });
|
||||
std::string::size_type pos;
|
||||
while ((pos = path.find("::")) != std::string::npos)
|
||||
{
|
||||
path.replace(pos, 2, "/");
|
||||
}
|
||||
if (pattern.empty() || pattern[0] == '/')
|
||||
app().registerHandler(path + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
else
|
||||
app().registerHandler(path + "/" + pattern,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = pattern;
|
||||
if (path.empty() || path[0] != '/')
|
||||
{
|
||||
path = "/" + path;
|
||||
}
|
||||
app().registerHandler(path,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FUNCTION>
|
||||
static void registerMethodViaRegex(
|
||||
FUNCTION &&function,
|
||||
const std::string ®Exp,
|
||||
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||
std::vector<internal::HttpConstraint>{},
|
||||
const std::string &handlerName = "")
|
||||
{
|
||||
app().registerHandlerViaRegex(regExp,
|
||||
std::forward<FUNCTION>(function),
|
||||
filtersAndMethods,
|
||||
handlerName);
|
||||
}
|
||||
|
||||
private:
|
||||
class methodRegistrator
|
||||
{
|
||||
public:
|
||||
methodRegistrator()
|
||||
{
|
||||
if (AutoCreation)
|
||||
T::initPathRouting();
|
||||
}
|
||||
};
|
||||
|
||||
// use static value to register controller method in framework before
|
||||
// main();
|
||||
static methodRegistrator registrator_;
|
||||
|
||||
virtual void *touch()
|
||||
{
|
||||
return ®istrator_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, bool AutoCreation>
|
||||
typename HttpController<T, AutoCreation>::methodRegistrator
|
||||
HttpController<T, AutoCreation>::registrator_;
|
||||
} // namespace drogon
|
123
vendors/drogon/lib/inc/drogon/HttpFilter.h
vendored
Normal file
123
vendors/drogon/lib/inc/drogon/HttpFilter.h
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpFilter.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
|
||||
|
||||
#include <drogon/DrObject.h>
|
||||
#include <drogon/drogon_callbacks.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
#include <drogon/utils/coroutine.h>
|
||||
#endif
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/**
|
||||
* @brief The abstract base class for filters
|
||||
* For more details on the class, see the wiki site (the 'Filter' section)
|
||||
*/
|
||||
class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase
|
||||
{
|
||||
public:
|
||||
/// This virtual function should be overridden in subclasses.
|
||||
/**
|
||||
* This method is an asynchronous interface, user should return the result
|
||||
* via 'FilterCallback' or 'FilterChainCallback'.
|
||||
* @param req is the request object processed by the filter
|
||||
* @param fcb if this is called, the response object is send to the client
|
||||
* by the callback, and doFilter methods of next filters and the handler
|
||||
* registered on the path are not called anymore.
|
||||
* @param fccb if this callback is called, the next filter's doFilter method
|
||||
* or the handler registered on the path is called.
|
||||
*/
|
||||
virtual void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) = 0;
|
||||
~HttpFilterBase() override = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The reflection base class template for filters
|
||||
*
|
||||
* @tparam T The type of the implementation class
|
||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||
* flag to false for classes that have nondefault constructors.
|
||||
*/
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpFilter : public DrObject<T>, public HttpFilterBase
|
||||
{
|
||||
public:
|
||||
static constexpr bool isAutoCreation{AutoCreation};
|
||||
~HttpFilter() override = default;
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
DROGON_EXPORT void handleException(
|
||||
const std::exception &,
|
||||
const HttpRequestPtr &,
|
||||
std::function<void(const HttpResponsePtr &)> &&);
|
||||
}
|
||||
|
||||
#ifdef __cpp_impl_coroutine
|
||||
template <typename T, bool AutoCreation = true>
|
||||
class HttpCoroFilter : public DrObject<T>, public HttpFilterBase
|
||||
{
|
||||
public:
|
||||
static constexpr bool isAutoCreation{AutoCreation};
|
||||
~HttpCoroFilter() override = default;
|
||||
|
||||
void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) final
|
||||
{
|
||||
drogon::async_run([this,
|
||||
req,
|
||||
fcb = std::move(fcb),
|
||||
fccb = std::move(fccb)]() mutable -> drogon::Task<> {
|
||||
HttpResponsePtr resp;
|
||||
try
|
||||
{
|
||||
resp = co_await doFilter(req);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
internal::handleException(ex, req, std::move(fcb));
|
||||
co_return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR << "Exception not derived from std::exception";
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
{
|
||||
fcb(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fccb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
virtual Task<HttpResponsePtr> doFilter(const HttpRequestPtr &req) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace drogon
|
532
vendors/drogon/lib/inc/drogon/HttpRequest.h
vendored
Normal file
532
vendors/drogon/lib/inc/drogon/HttpRequest.h
vendored
Normal file
@ -0,0 +1,532 @@
|
||||
/**
|
||||
*
|
||||
* @file HttpRequest.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/Session.h>
|
||||
#include <drogon/Attribute.h>
|
||||
#include <drogon/UploadFile.h>
|
||||
#include <json/json.h>
|
||||
#include <trantor/net/InetAddress.h>
|
||||
#include <trantor/net/Certificate.h>
|
||||
#include <trantor/utils/Date.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
class HttpRequest;
|
||||
using HttpRequestPtr = std::shared_ptr<HttpRequest>;
|
||||
|
||||
/**
|
||||
* @brief This template is used to convert a request object to a custom
|
||||
* type object. Users must specialize the template for a particular type.
|
||||
*/
|
||||
template <typename T>
|
||||
T fromRequest(const HttpRequest &)
|
||||
{
|
||||
LOG_ERROR << "You must specialize the fromRequest template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This template is used to create a request object from a custom
|
||||
* type object by calling the newCustomHttpRequest(). Users must specialize
|
||||
* the template for a particular type.
|
||||
*/
|
||||
template <typename T>
|
||||
HttpRequestPtr toRequest(T &&)
|
||||
{
|
||||
LOG_ERROR << "You must specialize the toRequest template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
template <>
|
||||
HttpRequestPtr toRequest<const Json::Value &>(const Json::Value &pJson);
|
||||
template <>
|
||||
HttpRequestPtr toRequest(Json::Value &&pJson);
|
||||
|
||||
template <>
|
||||
inline HttpRequestPtr toRequest<Json::Value &>(Json::Value &pJson)
|
||||
{
|
||||
return toRequest((const Json::Value &)pJson);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::shared_ptr<Json::Value> fromRequest(const HttpRequest &req);
|
||||
|
||||
/// Abstract class for webapp developer to get or set the Http request;
|
||||
class DROGON_EXPORT HttpRequest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief This template enables implicit type conversion. For using this
|
||||
* template, user must specialize the fromRequest template. For example a
|
||||
* shared_ptr<Json::Value> specialization version is available above, so
|
||||
* we can use the following code to get a json object:
|
||||
* @code
|
||||
std::shared_ptr<Json::Value> jsonPtr = *requestPtr;
|
||||
@endcode
|
||||
* With this template, user can use their favorite JSON library instead of
|
||||
* the default jsoncpp library or convert the request to an object of any
|
||||
* custom type.
|
||||
*/
|
||||
template <typename T>
|
||||
operator T() const
|
||||
{
|
||||
return fromRequest<T>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This template enables explicit type conversion, see the above
|
||||
* template.
|
||||
*/
|
||||
template <typename T>
|
||||
T as() const
|
||||
{
|
||||
return fromRequest<T>(*this);
|
||||
}
|
||||
|
||||
/// Return the method string of the request, such as GET, POST, etc.
|
||||
virtual const char *methodString() const = 0;
|
||||
|
||||
const char *getMethodString() const
|
||||
{
|
||||
return methodString();
|
||||
}
|
||||
|
||||
/// Return the enum type method of the request.
|
||||
virtual HttpMethod method() const = 0;
|
||||
|
||||
HttpMethod getMethod() const
|
||||
{
|
||||
return method();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the method is or was HttpMethod::Head
|
||||
* @details Allows to know that an incoming request is a HEAD request, since
|
||||
* drogon sets the method to HttpMethod::Get before calling the
|
||||
* controller
|
||||
* @return true if method() returns HttpMethod::Head, or HttpMethod::Get but
|
||||
* was previously HttpMethod::Head
|
||||
*/
|
||||
virtual bool isHead() const = 0;
|
||||
|
||||
/// Get the header string identified by the key parameter.
|
||||
/**
|
||||
* @note
|
||||
* If there is no the header, a empty string is returned.
|
||||
* The key is case insensitive
|
||||
*/
|
||||
virtual const std::string &getHeader(std::string key) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the header string identified by the field parameter
|
||||
*
|
||||
* @param field The field parameter is transformed to lower case before
|
||||
* storing.
|
||||
* @param value The value of the header.
|
||||
*/
|
||||
virtual void addHeader(std::string field, const std::string &value) = 0;
|
||||
virtual void addHeader(std::string field, std::string &&value) = 0;
|
||||
|
||||
/**
|
||||
* @brief Remove the header identified by the key parameter.
|
||||
*
|
||||
* @param key The key is case insensitive
|
||||
*/
|
||||
virtual void removeHeader(std::string key) = 0;
|
||||
|
||||
/// Get the cookie string identified by the field parameter
|
||||
virtual const std::string &getCookie(const std::string &field) const = 0;
|
||||
|
||||
/// Get all headers of the request
|
||||
virtual const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&headers() const = 0;
|
||||
|
||||
/// Get all headers of the request
|
||||
const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&getHeaders() const
|
||||
{
|
||||
return headers();
|
||||
}
|
||||
|
||||
/// Get all cookies of the request
|
||||
virtual const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&cookies() const = 0;
|
||||
|
||||
/// Get all cookies of the request
|
||||
const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&getCookies() const
|
||||
{
|
||||
return cookies();
|
||||
}
|
||||
|
||||
/// Get the query string of the request.
|
||||
/**
|
||||
* The query string is the substring after the '?' in the URL string.
|
||||
*/
|
||||
virtual const std::string &query() const = 0;
|
||||
|
||||
/// Get the query string of the request.
|
||||
const std::string &getQuery() const
|
||||
{
|
||||
return query();
|
||||
}
|
||||
|
||||
/// Get the content string of the request, which is the body part of the
|
||||
/// request.
|
||||
std::string_view body() const
|
||||
{
|
||||
return std::string_view(bodyData(), bodyLength());
|
||||
}
|
||||
|
||||
/// Get the content string of the request, which is the body part of the
|
||||
/// request.
|
||||
std::string_view getBody() const
|
||||
{
|
||||
return body();
|
||||
}
|
||||
|
||||
virtual const char *bodyData() const = 0;
|
||||
virtual size_t bodyLength() const = 0;
|
||||
|
||||
/// Set the content string of the request.
|
||||
virtual void setBody(const std::string &body) = 0;
|
||||
|
||||
/// Set the content string of the request.
|
||||
virtual void setBody(std::string &&body) = 0;
|
||||
|
||||
/// Get the path of the request.
|
||||
virtual const std::string &path() const = 0;
|
||||
|
||||
/// Get the original path of the request.(before url-decoding)
|
||||
virtual const std::string &getOriginalPath() const = 0;
|
||||
|
||||
/// Get the path of the request.
|
||||
const std::string &getPath() const
|
||||
{
|
||||
return path();
|
||||
}
|
||||
|
||||
/// Get the matched path pattern after routing
|
||||
std::string_view getMatchedPathPattern() const
|
||||
{
|
||||
return matchedPathPattern();
|
||||
}
|
||||
|
||||
/// Get the matched path pattern after routing
|
||||
std::string_view matchedPathPattern() const
|
||||
{
|
||||
return std::string_view(matchedPathPatternData(),
|
||||
matchedPathPatternLength());
|
||||
}
|
||||
|
||||
/// Get the matched path pattern after routing (including matched parameters
|
||||
/// in the query string)
|
||||
virtual const std::vector<std::string> &getRoutingParameters() const = 0;
|
||||
|
||||
/// This method usually is called by the framework.
|
||||
virtual void setRoutingParameters(std::vector<std::string> &¶ms) = 0;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/// Return the enum type version of the request.
|
||||
/**
|
||||
* kHttp10 means Http version is 1.0
|
||||
* kHttp11 means Http version is 1.1
|
||||
*/
|
||||
virtual Version version() const = 0;
|
||||
|
||||
/// Return the enum type version of the request.
|
||||
Version getVersion() const
|
||||
{
|
||||
return version();
|
||||
}
|
||||
|
||||
/// Get the session to which the request belongs.
|
||||
virtual const SessionPtr &session() const = 0;
|
||||
|
||||
/// Get the session to which the request belongs.
|
||||
const SessionPtr &getSession() const
|
||||
{
|
||||
return session();
|
||||
}
|
||||
|
||||
/// Get the attributes store, users can add/get any type of data to/from
|
||||
/// this store
|
||||
virtual const AttributesPtr &attributes() const = 0;
|
||||
|
||||
/// Get the attributes store, users can add/get any type of data to/from
|
||||
/// this store
|
||||
const AttributesPtr &getAttributes() const
|
||||
{
|
||||
return attributes();
|
||||
}
|
||||
|
||||
/// Get parameters of the request.
|
||||
virtual const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
¶meters() const = 0;
|
||||
|
||||
/// Get parameters of the request.
|
||||
const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&getParameters() const
|
||||
{
|
||||
return parameters();
|
||||
}
|
||||
|
||||
/// Get a parameter identified by the @param key
|
||||
virtual const std::string &getParameter(const std::string &key) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the optional parameter identified by the @p key. if the
|
||||
* parameter doesn't exist, or the original parameter can't be converted to
|
||||
* a T type object, an empty optional object is returned.
|
||||
*
|
||||
* @tparam T
|
||||
* @param key
|
||||
* @return optional<T>
|
||||
*/
|
||||
template <typename T>
|
||||
std::optional<T> getOptionalParameter(const std::string &key)
|
||||
{
|
||||
auto ¶ms = getParameters();
|
||||
auto it = params.find(key);
|
||||
if (it != params.end())
|
||||
{
|
||||
try
|
||||
{
|
||||
return std::optional<T>(
|
||||
drogon::utils::fromString<T>(it->second));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_ERROR << e.what();
|
||||
return std::optional<T>{};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::optional<T>{};
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the remote IP address and port
|
||||
virtual const trantor::InetAddress &peerAddr() const = 0;
|
||||
|
||||
const trantor::InetAddress &getPeerAddr() const
|
||||
{
|
||||
return peerAddr();
|
||||
}
|
||||
|
||||
/// Return the local IP address and port
|
||||
virtual const trantor::InetAddress &localAddr() const = 0;
|
||||
|
||||
const trantor::InetAddress &getLocalAddr() const
|
||||
{
|
||||
return localAddr();
|
||||
}
|
||||
|
||||
/// Return the creation timestamp set by the framework.
|
||||
virtual const trantor::Date &creationDate() const = 0;
|
||||
|
||||
const trantor::Date &getCreationDate() const
|
||||
{
|
||||
return creationDate();
|
||||
}
|
||||
|
||||
// Return the peer certificate (if any)
|
||||
virtual const trantor::CertificatePtr &peerCertificate() const = 0;
|
||||
|
||||
const trantor::CertificatePtr &getPeerCertificate() const
|
||||
{
|
||||
return peerCertificate();
|
||||
}
|
||||
|
||||
/// Get the Json object of the request
|
||||
/**
|
||||
* The content type of the request must be 'application/json',
|
||||
* otherwise the method returns an empty shared_ptr object.
|
||||
*/
|
||||
virtual const std::shared_ptr<Json::Value> &jsonObject() const = 0;
|
||||
|
||||
/// Get the Json object of the request
|
||||
const std::shared_ptr<Json::Value> &getJsonObject() const
|
||||
{
|
||||
return jsonObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the error message of parsing the JSON body received from peer.
|
||||
* This method usually is called after getting a empty shared_ptr object
|
||||
* by the getJsonObject() method.
|
||||
*
|
||||
* @return const std::string& The error message. An empty string is returned
|
||||
* when no error occurs.
|
||||
*/
|
||||
virtual const std::string &getJsonError() const = 0;
|
||||
|
||||
/// Get the content type
|
||||
virtual ContentType contentType() const = 0;
|
||||
|
||||
ContentType getContentType() const
|
||||
{
|
||||
return contentType();
|
||||
}
|
||||
|
||||
/// Set the Http method
|
||||
virtual void setMethod(const HttpMethod method) = 0;
|
||||
|
||||
/// Set the path of the request
|
||||
virtual void setPath(const std::string &path) = 0;
|
||||
virtual void setPath(std::string &&path) = 0;
|
||||
|
||||
/**
|
||||
* @brief The default behavior is to encode the value of setPath
|
||||
* using urlEncode. Setting the path encode to false avoid the
|
||||
* value of path will be changed by the library
|
||||
*
|
||||
* @param bool true --> the path will be url encoded
|
||||
* false --> using value of path as it is set
|
||||
*/
|
||||
virtual void setPathEncode(bool) = 0;
|
||||
|
||||
/// Set the parameter of the request
|
||||
virtual void setParameter(const std::string &key,
|
||||
const std::string &value) = 0;
|
||||
|
||||
/// Set or get the content type
|
||||
virtual void setContentTypeCode(const ContentType type) = 0;
|
||||
|
||||
/// 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 std::string_view &typeString)
|
||||
{
|
||||
setContentTypeString(typeString.data(), typeString.size());
|
||||
}
|
||||
|
||||
/// Set the request content-type string, The string
|
||||
/// must contain the header name and CRLF.
|
||||
/// For example, "content-type: text/plain\r\n"
|
||||
virtual void setCustomContentTypeString(const std::string &type) = 0;
|
||||
|
||||
/// Add a cookie
|
||||
virtual void addCookie(const std::string &key,
|
||||
const std::string &value) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the request object to the pass-through mode or not. It's not
|
||||
* by default when a new request object is created.
|
||||
* In pass-through mode, no additional headers (including user-agent,
|
||||
* connection, etc.) are added to the request. This mode is useful for some
|
||||
* applications such as a proxy.
|
||||
*
|
||||
* @param flag
|
||||
*/
|
||||
virtual void setPassThrough(bool flag) = 0;
|
||||
|
||||
/// The following methods are a series of factory methods that help users
|
||||
/// create request objects.
|
||||
|
||||
/// Create a normal request with http method Get and version Http1.1.
|
||||
static HttpRequestPtr newHttpRequest();
|
||||
|
||||
/// Create a http request with:
|
||||
/// Method: Get
|
||||
/// Version: Http1.1
|
||||
/// Content type: application/json, the @param data is serialized into the
|
||||
/// content of the request.
|
||||
static HttpRequestPtr newHttpJsonRequest(const Json::Value &data);
|
||||
|
||||
/// Create a http request with:
|
||||
/// Method: Post
|
||||
/// Version: Http1.1
|
||||
/// Content type: application/x-www-form-urlencoded
|
||||
static HttpRequestPtr newHttpFormPostRequest();
|
||||
|
||||
/// Create a http file upload request with:
|
||||
/// Method: Post
|
||||
/// Version: Http1.1
|
||||
/// Content type: multipart/form-data
|
||||
/// The @param files represents pload files which are transferred to the
|
||||
/// server via the multipart/form-data format
|
||||
static HttpRequestPtr newFileUploadRequest(
|
||||
const std::vector<UploadFile> &files);
|
||||
|
||||
/**
|
||||
* @brief Create a custom HTTP request object. For using this template,
|
||||
* users must specialize the toRequest template.
|
||||
*/
|
||||
template <typename T>
|
||||
static HttpRequestPtr newCustomHttpRequest(T &&obj)
|
||||
{
|
||||
return toRequest(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
virtual bool isOnSecureConnection() const noexcept = 0;
|
||||
virtual void setContentTypeString(const char *typeString,
|
||||
size_t typeStringLength) = 0;
|
||||
|
||||
virtual ~HttpRequest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline HttpRequestPtr toRequest<const Json::Value &>(const Json::Value &pJson)
|
||||
{
|
||||
return HttpRequest::newHttpJsonRequest(pJson);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline HttpRequestPtr toRequest(Json::Value &&pJson)
|
||||
{
|
||||
return HttpRequest::newHttpJsonRequest(std::move(pJson));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::shared_ptr<Json::Value> fromRequest(const HttpRequest &req)
|
||||
{
|
||||
return req.getJsonObject();
|
||||
}
|
||||
|
||||
} // namespace drogon
|
564
vendors/drogon/lib/inc/drogon/HttpResponse.h
vendored
Normal file
564
vendors/drogon/lib/inc/drogon/HttpResponse.h
vendored
Normal file
@ -0,0 +1,564 @@
|
||||
/**
|
||||
* @file HttpResponse.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
|
||||
|
||||
#include <drogon/exports.h>
|
||||
#include <trantor/net/Certificate.h>
|
||||
#include <drogon/DrClassMap.h>
|
||||
#include <drogon/Cookie.h>
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <drogon/HttpTypes.h>
|
||||
#include <drogon/HttpViewData.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
/// Abstract class for webapp developer to get or set the Http response;
|
||||
class HttpResponse;
|
||||
using HttpResponsePtr = std::shared_ptr<HttpResponse>;
|
||||
|
||||
/**
|
||||
* @brief This template is used to convert a response object to a custom
|
||||
* type object. Users must specialize the template for a particular type.
|
||||
*/
|
||||
template <typename T>
|
||||
T fromResponse(const HttpResponse &resp)
|
||||
{
|
||||
LOG_ERROR
|
||||
<< "You must specialize the fromResponse template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This template is used to create a response object from a custom
|
||||
* type object by calling the newCustomHttpResponse(). Users must specialize
|
||||
* the template for a particular type.
|
||||
*/
|
||||
template <typename T>
|
||||
HttpResponsePtr toResponse(T &&)
|
||||
{
|
||||
LOG_ERROR << "You must specialize the toResponse template for the type of "
|
||||
<< DrClassMap::demangle(typeid(T).name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
template <>
|
||||
HttpResponsePtr toResponse<const Json::Value &>(const Json::Value &pJson);
|
||||
template <>
|
||||
HttpResponsePtr toResponse(Json::Value &&pJson);
|
||||
|
||||
template <>
|
||||
inline HttpResponsePtr toResponse<Json::Value &>(Json::Value &pJson)
|
||||
{
|
||||
return toResponse((const Json::Value &)pJson);
|
||||
}
|
||||
|
||||
class DROGON_EXPORT HttpResponse
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief This template enables automatic type conversion. For using this
|
||||
* template, user must specialize the fromResponse template. For example a
|
||||
* shared_ptr<Json::Value> specialization version is available above, so
|
||||
* we can use the following code to get a json object:
|
||||
* @code
|
||||
* std::shared_ptr<Json::Value> jsonPtr = *responsePtr;
|
||||
* @endcode
|
||||
* With this template, user can use their favorite JSON library instead of
|
||||
* the default jsoncpp library or convert the response to an object of any
|
||||
* custom type.
|
||||
*/
|
||||
template <typename T>
|
||||
operator T() const
|
||||
{
|
||||
return fromResponse<T>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This template enables explicit type conversion, see the above
|
||||
* template.
|
||||
*/
|
||||
template <typename T>
|
||||
T as() const
|
||||
{
|
||||
return fromResponse<T>(*this);
|
||||
}
|
||||
|
||||
/// Get the status code such as 200, 404
|
||||
virtual HttpStatusCode statusCode() const = 0;
|
||||
|
||||
HttpStatusCode getStatusCode() const
|
||||
{
|
||||
return statusCode();
|
||||
}
|
||||
|
||||
/// Set the status code of the response.
|
||||
virtual void setStatusCode(HttpStatusCode code) = 0;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/// Set the http version, http1.0 or http1.1
|
||||
virtual void setVersion(const Version v) = 0;
|
||||
|
||||
/// Set if close the connection after the request is sent.
|
||||
/**
|
||||
* @param on if the parameter is false, the connection keeps alive on the
|
||||
* condition that the client request has a 'keep-alive' head, otherwise it
|
||||
* is closed immediately after sending the last byte of the response. It's
|
||||
* false by default when the response is created.
|
||||
*/
|
||||
virtual void setCloseConnection(bool on) = 0;
|
||||
|
||||
/// Get the status set by the setCloseConnection() method.
|
||||
virtual bool ifCloseConnection() const = 0;
|
||||
|
||||
/// Set the response content type, such as text/html, text/plain, image/png
|
||||
/// and so on. If the content type
|
||||
/// is a text type, the character set is utf8.
|
||||
virtual void setContentTypeCode(ContentType type) = 0;
|
||||
|
||||
/// 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 std::string_view &typeString)
|
||||
{
|
||||
setContentTypeString(typeString.data(), typeString.size());
|
||||
}
|
||||
|
||||
/// Set the response content type and 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 setContentTypeCodeAndCustomString(ContentType type,
|
||||
const std::string_view &typeString)
|
||||
{
|
||||
setContentTypeCodeAndCustomString(type,
|
||||
typeString.data(),
|
||||
typeString.length());
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void setContentTypeCodeAndCustomString(ContentType type,
|
||||
const char (&typeString)[N])
|
||||
{
|
||||
assert(N > 0);
|
||||
setContentTypeCodeAndCustomString(type, typeString, N - 1);
|
||||
}
|
||||
|
||||
/// Set the response content type and the character set.
|
||||
/// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
|
||||
/// std::string &charSet = "utf-8") = 0;
|
||||
|
||||
/// Get the response content type.
|
||||
virtual ContentType contentType() const = 0;
|
||||
|
||||
ContentType getContentType() const
|
||||
{
|
||||
return contentType();
|
||||
}
|
||||
|
||||
/// Get the header string identified by the key parameter.
|
||||
/**
|
||||
* @note
|
||||
* If there is no the header, a empty string is returned.
|
||||
* The key is case insensitive
|
||||
*/
|
||||
virtual const std::string &getHeader(std::string key) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Remove the header identified by the key parameter.
|
||||
*
|
||||
* @param key The key is case insensitive
|
||||
*/
|
||||
virtual void removeHeader(std::string key) = 0;
|
||||
|
||||
/// Get all headers of the response
|
||||
virtual const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&headers() const = 0;
|
||||
|
||||
/// Get all headers of the response
|
||||
const std::
|
||||
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||
&getHeaders() const
|
||||
{
|
||||
return headers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the header string identified by the field parameter
|
||||
*
|
||||
* @param field The field parameter is transformed to lower case before
|
||||
* storing.
|
||||
* @param value The value of the header.
|
||||
*/
|
||||
virtual void addHeader(std::string field, const std::string &value) = 0;
|
||||
virtual void addHeader(std::string field, std::string &&value) = 0;
|
||||
|
||||
/// Add a cookie
|
||||
virtual void addCookie(const std::string &key,
|
||||
const std::string &value) = 0;
|
||||
|
||||
/// Add a cookie
|
||||
virtual void addCookie(const Cookie &cookie) = 0;
|
||||
virtual void addCookie(Cookie &&cookie) = 0;
|
||||
|
||||
/// Get the cookie identified by the key parameter.
|
||||
/// If there is no the cookie, the empty cookie is returned.
|
||||
virtual const Cookie &getCookie(const std::string &key) const = 0;
|
||||
|
||||
/// Get all cookies.
|
||||
virtual const std::
|
||||
unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
|
||||
&cookies() const = 0;
|
||||
|
||||
/// Get all cookies.
|
||||
const std::
|
||||
unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
|
||||
&getCookies() const
|
||||
{
|
||||
return cookies();
|
||||
}
|
||||
|
||||
/// Remove the cookie identified by the key parameter.
|
||||
virtual void removeCookie(const std::string &key) = 0;
|
||||
|
||||
/// Set the response body(content).
|
||||
/**
|
||||
* @note The body must match the content type
|
||||
*/
|
||||
virtual void setBody(const std::string &body) = 0;
|
||||
|
||||
/// Set the response body(content).
|
||||
virtual void setBody(std::string &&body) = 0;
|
||||
|
||||
/// Set the response body(content).
|
||||
template <int N>
|
||||
void setBody(const char (&body)[N])
|
||||
{
|
||||
assert(strnlen(body, N) == N - 1);
|
||||
setBody(body, N - 1);
|
||||
}
|
||||
|
||||
/// Get the response body.
|
||||
std::string_view body() const
|
||||
{
|
||||
return std::string_view{getBodyData(), getBodyLength()};
|
||||
}
|
||||
|
||||
/// Get the response body.
|
||||
std::string_view getBody() const
|
||||
{
|
||||
return body();
|
||||
}
|
||||
|
||||
/// 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();
|
||||
}
|
||||
|
||||
/// Return the enum type version of the response.
|
||||
/**
|
||||
* kHttp10 means Http version is 1.0
|
||||
* kHttp11 means Http version is 1.1
|
||||
*/
|
||||
virtual Version version() const = 0;
|
||||
|
||||
/// Return the enum type version of the response.
|
||||
Version getVersion() const
|
||||
{
|
||||
return version();
|
||||
}
|
||||
|
||||
/// Reset the response object to its initial state
|
||||
virtual void clear() = 0;
|
||||
|
||||
/// Set the expiration time of the response cache in memory.
|
||||
/// in seconds, 0 means always cache, negative means not cache, default is
|
||||
/// -1.
|
||||
virtual void setExpiredTime(ssize_t expiredTime) = 0;
|
||||
|
||||
/// Get the expiration time of the response.
|
||||
virtual ssize_t expiredTime() const = 0;
|
||||
|
||||
ssize_t getExpiredTime() const
|
||||
{
|
||||
return expiredTime();
|
||||
}
|
||||
|
||||
/// Get the json object from the server response.
|
||||
/// If the response is not in json format, then a empty shared_ptr is
|
||||
/// returned.
|
||||
virtual const std::shared_ptr<Json::Value> &jsonObject() const = 0;
|
||||
|
||||
const std::shared_ptr<Json::Value> &getJsonObject() const
|
||||
{
|
||||
return jsonObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the error message of parsing the JSON body received from peer.
|
||||
* This method usually is called after getting a empty shared_ptr object
|
||||
* by the getJsonObject() method.
|
||||
*
|
||||
* @return const std::string& The error message. An empty string is returned
|
||||
* when no error occurs.
|
||||
*/
|
||||
virtual const std::string &getJsonError() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the response object to the pass-through mode or not. It's not
|
||||
* by default when a new response object is created.
|
||||
* In pass-through mode, no additional headers (including server, date,
|
||||
* content-type and content-length, etc.) are added to the response. This
|
||||
* mode is useful for some applications such as a proxy.
|
||||
*
|
||||
* @param flag
|
||||
*/
|
||||
virtual void setPassThrough(bool flag) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the certificate of the peer, if any.
|
||||
* @return The certificate of the peer. nullptr is none.
|
||||
*/
|
||||
virtual const trantor::CertificatePtr &peerCertificate() const = 0;
|
||||
|
||||
const trantor::CertificatePtr &getPeerCertificate() const
|
||||
{
|
||||
return peerCertificate();
|
||||
}
|
||||
|
||||
/* The following methods are a series of factory methods that help users
|
||||
* create response objects. */
|
||||
|
||||
/// Create a normal response with a status code of 200ok and a content type
|
||||
/// of text/html.
|
||||
static HttpResponsePtr newHttpResponse();
|
||||
/// Create a response with a status code and a content type
|
||||
static HttpResponsePtr newHttpResponse(HttpStatusCode code,
|
||||
ContentType type);
|
||||
/// Create a response which returns a 404 page.
|
||||
static HttpResponsePtr newNotFoundResponse(
|
||||
const HttpRequestPtr &req = HttpRequestPtr());
|
||||
/// Create a response which returns a json object. Its content-type is set
|
||||
/// to application/json.
|
||||
static HttpResponsePtr newHttpJsonResponse(const Json::Value &data);
|
||||
/// Create a response which returns a json object. Its content-type is set
|
||||
/// to application/json.
|
||||
static HttpResponsePtr newHttpJsonResponse(Json::Value &&data);
|
||||
/// Create a response that returns a page rendered by a view named
|
||||
/// viewName.
|
||||
/**
|
||||
* @param viewName The name of the view
|
||||
* @param data is the data displayed on the page.
|
||||
* @note For more details, see the wiki pages, the "View" section.
|
||||
*/
|
||||
static HttpResponsePtr newHttpViewResponse(
|
||||
const std::string &viewName,
|
||||
const HttpViewData &data = HttpViewData(),
|
||||
const HttpRequestPtr &req = HttpRequestPtr());
|
||||
|
||||
/// Create a response that returns a redirection page, redirecting to
|
||||
/// another page located in the location parameter.
|
||||
/**
|
||||
* @param location The location to redirect
|
||||
* @param status The HTTP status code, k302Found by default. Users could set
|
||||
* it to one of the 301, 302, 303, 307, ...
|
||||
*/
|
||||
static HttpResponsePtr newRedirectionResponse(
|
||||
const std::string &location,
|
||||
HttpStatusCode status = k302Found);
|
||||
|
||||
/// Create a response that returns a file to the client.
|
||||
/**
|
||||
* @param fullPath is the full path to the file.
|
||||
* @param attachmentFileName if the parameter is not empty, the browser
|
||||
* does not open the file, but saves it as an attachment.
|
||||
* @param type the content type code. If the parameter is CT_NONE, the
|
||||
* content type is set by drogon based on the file extension and typeString.
|
||||
* Set it to CT_CUSTOM when no drogon internal content type matches.
|
||||
* @param typeString the MIME string of the content type.
|
||||
*/
|
||||
static HttpResponsePtr newFileResponse(
|
||||
const std::string &fullPath,
|
||||
const std::string &attachmentFileName = "",
|
||||
ContentType type = CT_NONE,
|
||||
const std::string &typeString = "",
|
||||
const HttpRequestPtr &req = HttpRequestPtr());
|
||||
|
||||
/// Create a response that returns part of a file to the client.
|
||||
/**
|
||||
* @brief If offset and length can not be satisfied, statusCode will be set
|
||||
* to k416RequestedRangeNotSatisfiable, and nothing else will be modified.
|
||||
*
|
||||
* @param fullPath is the full path to the file.
|
||||
* @param offset is the offset to begin sending, in bytes.
|
||||
* @param length is the total length to send, in bytes. In particular,
|
||||
* length = 0 means send all content from offset till end of file.
|
||||
* @param setContentRange whether set 'Content-Range' header automatically.
|
||||
* @param attachmentFileName if the parameter is not empty, the browser
|
||||
* does not open the file, but saves it as an attachment.
|
||||
* @param type the content type code. If the parameter is CT_NONE, the
|
||||
* content type is set by drogon based on the file extension and typeString.
|
||||
* Set it to CT_CUSTOM when no drogon internal content type matches.
|
||||
* @param typeString the MIME string of the content type.
|
||||
*/
|
||||
static HttpResponsePtr newFileResponse(
|
||||
const std::string &fullPath,
|
||||
size_t offset,
|
||||
size_t length,
|
||||
bool setContentRange = true,
|
||||
const std::string &attachmentFileName = "",
|
||||
ContentType type = CT_NONE,
|
||||
const std::string &typeString = "",
|
||||
const HttpRequestPtr &req = HttpRequestPtr());
|
||||
|
||||
/// Create a response that returns a file to the client from buffer in
|
||||
/// memory/stack
|
||||
/**
|
||||
* @param pBuffer is a uint 8 bit flat buffer for object/files in memory
|
||||
* @param bufferLength is the length of the expected buffer
|
||||
* @param attachmentFileName if the parameter is not empty, the browser
|
||||
* does not open the file, but saves it as an attachment.
|
||||
* @param type the content type code. If the parameter is CT_NONE, the
|
||||
* content type is set by drogon based on the file extension and typeString.
|
||||
* Set it to CT_CUSTOM when no drogon internal content type matches.
|
||||
* @param typeString the MIME string of the content type.
|
||||
*/
|
||||
static HttpResponsePtr newFileResponse(
|
||||
const unsigned char *pBuffer,
|
||||
size_t bufferLength,
|
||||
const std::string &attachmentFileName = "",
|
||||
ContentType type = CT_NONE,
|
||||
const std::string &typeString = "");
|
||||
|
||||
/// Create a response that returns a file to the client from a callback
|
||||
/// function
|
||||
/**
|
||||
* @note if the Connection is keep-alive and the Content-Length header is
|
||||
* not set, the stream data is sent with Transfer-Encoding: chunked.
|
||||
* @param callback function to retrieve the stream data (stream ends when a
|
||||
* zero size is returned) the callback will be called with
|
||||
* nullptr when the send is finished/interrupted so that it
|
||||
* cleans up its internals.
|
||||
* @param attachmentFileName if the parameter is not empty, the browser
|
||||
* does not open the file, but saves it as an
|
||||
* attachment.
|
||||
* @param type the content type code. If the parameter is CT_NONE, the
|
||||
* content type is set by drogon based on the file extension and
|
||||
* typeString. Set it to CT_CUSTOM when no drogon internal
|
||||
* content type matches.
|
||||
* @param typeString the MIME string of the content type.
|
||||
*/
|
||||
static HttpResponsePtr newStreamResponse(
|
||||
const std::function<std::size_t(char *, std::size_t)> &callback,
|
||||
const std::string &attachmentFileName = "",
|
||||
ContentType type = CT_NONE,
|
||||
const std::string &typeString = "",
|
||||
const HttpRequestPtr &req = HttpRequestPtr());
|
||||
|
||||
/**
|
||||
* @brief Create a custom HTTP response object. For using this template,
|
||||
* users must specialize the toResponse template.
|
||||
*/
|
||||
template <typename T>
|
||||
static HttpResponsePtr newCustomHttpResponse(T &&obj)
|
||||
{
|
||||
return toResponse(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If the response is a file response (i.e. created by
|
||||
* newFileResponse) returns the path on the filesystem. Otherwise a
|
||||
* empty string.
|
||||
*/
|
||||
virtual const std::string &sendfileName() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the range of the file response as a pair ot size_t
|
||||
* (offset, length). Length of 0 means the entire file is sent. Behavior of
|
||||
* this function is undefined if the response if not a file response
|
||||
*/
|
||||
using SendfileRange = std::pair<size_t, size_t>; // { offset, length }
|
||||
virtual const SendfileRange &sendfileRange() const = 0;
|
||||
|
||||
/**
|
||||
* @brief If the response is a stream response (i.e. created by
|
||||
* newStreamResponse) returns the callback function. Otherwise a
|
||||
* null function.
|
||||
*/
|
||||
virtual const std::function<std::size_t(char *, std::size_t)>
|
||||
&streamCallback() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the content type associated with the response
|
||||
*/
|
||||
virtual std::string contentTypeString() const = 0;
|
||||
|
||||
virtual ~HttpResponse()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void setBody(const char *body, size_t len) = 0;
|
||||
virtual const char *getBodyData() const = 0;
|
||||
virtual size_t getBodyLength() const = 0;
|
||||
virtual void setContentTypeCodeAndCustomString(ContentType type,
|
||||
const char *typeString,
|
||||
size_t typeStringLength) = 0;
|
||||
virtual void setContentTypeString(const char *typeString,
|
||||
size_t typeStringLength) = 0;
|
||||
virtual void setCustomStatusCode(int code,
|
||||
const char *message,
|
||||
size_t messageLength) = 0;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline HttpResponsePtr toResponse<const Json::Value &>(const Json::Value &pJson)
|
||||
{
|
||||
return HttpResponse::newHttpJsonResponse(pJson);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline HttpResponsePtr toResponse(Json::Value &&pJson)
|
||||
{
|
||||
return HttpResponse::newHttpJsonResponse(std::move(pJson));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::shared_ptr<Json::Value> fromResponse(const HttpResponse &resp)
|
||||
{
|
||||
return resp.getJsonObject();
|
||||
}
|
||||
} // namespace drogon
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user