mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
Added drogon as a module.
This commit is contained in:
parent
e8459d5fd0
commit
e50dc2560d
36
modules/drogon/SCsub
Normal file
36
modules/drogon/SCsub
Normal file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env_mod")
|
||||
Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/lib/src/*.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/lib/src/ssl_funcs/*.cc")
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/orm_lib/src/*.cc")
|
||||
|
||||
if env.mysql_available:
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/orm_lib/src/mysql_impl/*.cc")
|
||||
#env_mod.add_source_files(env_mod.core_sources, "drogon/orm_lib/src/postgresql_impl/*.cc")
|
||||
#env_mod.add_source_files(env_mod.core_sources, "drogon/orm_lib/src/sqlite3_impl/*.cc")
|
||||
|
||||
#todo detect
|
||||
#env_mod.add_source_files(env_mod.core_sources, "drogon/nosql_lib/redis/src/*.cc")
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/net/*.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/net/inner/*.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/net/inner/poller/*.cc")
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/AsyncFileLogger.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/ConcurrentTaskQueue.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/Date.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/Logger.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/LogStream.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/MsgBuffer.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/SerialTaskQueue.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "trantor/utils/TimingWheel.cc")
|
||||
|
||||
# Build it all as a library
|
||||
lib = env_mod.add_library("drogon", env_mod.core_sources)
|
||||
env.Prepend(LIBS=[lib])
|
92
modules/drogon/detect.py
Normal file
92
modules/drogon/detect.py
Normal file
@ -0,0 +1,92 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
|
||||
def is_active():
|
||||
return True
|
||||
|
||||
|
||||
def get_name():
|
||||
return "drogon"
|
||||
|
||||
|
||||
def can_build():
|
||||
if os.name == "posix" or sys.platform == "darwin":
|
||||
err = os.system("pkg-config --version > /dev/null")
|
||||
if err:
|
||||
return False
|
||||
|
||||
err = os.system("pkg-config uuid --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if err:
|
||||
print("Package uuid not found..")
|
||||
return False
|
||||
|
||||
err = os.system("pkg-config jsoncpp --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if err:
|
||||
print("Package jsoncpp not found..")
|
||||
return False
|
||||
|
||||
err = os.system("pkg-config libcares --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if err:
|
||||
print("Package libcares not found..")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_opts():
|
||||
return []
|
||||
|
||||
def get_flags():
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def configure(env):
|
||||
err = os.system("pkg-config uuid --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if not err:
|
||||
env.ParseConfig("pkg-config uuid --cflags --libs")
|
||||
|
||||
err = os.system("pkg-config jsoncpp --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if not err:
|
||||
env.ParseConfig("pkg-config jsoncpp --cflags --libs")
|
||||
|
||||
err = os.system("pkg-config libcares --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if not err:
|
||||
env.ParseConfig("pkg-config libcares --cflags --libs")
|
||||
|
||||
#env.Append(CXX=["-std=c++17"])
|
||||
|
||||
mariadb_error = os.system("pkg-config mariadb --modversion --silence-errors > /dev/null ")
|
||||
mysql_error = os.system("pkg-config mysql --modversion --silence-errors > /dev/null ")
|
||||
|
||||
if not mariadb_error:
|
||||
env.ParseConfig("pkg-config mariadb --cflags --libs")
|
||||
# env.Append(CPPDEFINES=["USE_MYSQL"])
|
||||
env.mysql_available = True
|
||||
|
||||
if not mysql_error:
|
||||
env.ParseConfig("pkg-config mysql --cflags --libs")
|
||||
# env.Append(CPPDEFINES=["USE_MYSQL"])
|
||||
env.mysql_available = True
|
||||
|
||||
#USE_SQLITE3
|
||||
|
||||
env.Prepend(CPPPATH=["#modules/drogon/drogon/lib/inc"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/drogon/orm_lib/inc"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/drogon/nosql_lib/redis/inc"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/drogon/config"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon"])
|
||||
|
||||
env.Prepend(CPPPATH=["#modules/drogon/trantor"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/trantor/net"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/trantor/net/inner"])
|
||||
env.Prepend(CPPPATH=["#modules/drogon/trantor/utils"])
|
||||
|
150
modules/drogon/drogon/.clang-format
Normal file
150
modules/drogon/drogon/.clang-format
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
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: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Allman
|
||||
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: true
|
||||
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: Left
|
||||
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
|
||||
SortIncludes: false
|
||||
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
|
||||
...
|
||||
|
49
modules/drogon/drogon/.gitignore
vendored
Executable file
49
modules/drogon/drogon/.gitignore
vendored
Executable file
@ -0,0 +1,49 @@
|
||||
# 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
|
||||
.idea
|
||||
lib/inc/drogon/version.h
|
||||
html/
|
||||
latex/
|
||||
.vscode
|
||||
*.kdev4
|
||||
.cproject
|
||||
.project
|
||||
.settings/
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
install
|
||||
trace.json
|
||||
.cache
|
4
modules/drogon/drogon/.gitmodules
vendored
Executable file
4
modules/drogon/drogon/.gitmodules
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
[submodule "trantor"]
|
||||
path = trantor
|
||||
url = https://github.com/an-tao/trantor.git
|
||||
|
80
modules/drogon/drogon/.travis.yml
Normal file
80
modules/drogon/drogon/.travis.yml
Normal file
@ -0,0 +1,80 @@
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
- os: osx
|
||||
osx_image: xcode12.2
|
||||
|
||||
sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- xenial
|
||||
- sourceline: 'deb http://archive.ubuntu.com/ubuntu xenial main'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- gcc
|
||||
- g++
|
||||
- libjsoncpp-dev
|
||||
- uuid-dev
|
||||
- zlib1g-dev
|
||||
- postgresql-server-dev-10
|
||||
- openssl
|
||||
- libssl-dev
|
||||
- libsqlite3-dev
|
||||
- mariadb-client
|
||||
- mariadb-server
|
||||
- build-essential
|
||||
- cmake
|
||||
- boost1.67
|
||||
- libbrotli-dev
|
||||
homebrew:
|
||||
packages:
|
||||
- jsoncpp
|
||||
- ossp-uuid
|
||||
- openssl
|
||||
- cmake
|
||||
- libtool
|
||||
- lz4
|
||||
- mariadb
|
||||
- sqlite3
|
||||
update: true
|
||||
mariadb: '10.0'
|
||||
|
||||
before_install:
|
||||
- wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz
|
||||
- tar xf release-1.10.0.tar.gz
|
||||
- cd googletest-release-1.10.0
|
||||
- cmake .
|
||||
- make
|
||||
- sudo make install
|
||||
- cd -
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew tap homebrew/services;
|
||||
brew services restart postgresql;
|
||||
brew services start mariadb;
|
||||
sleep 4;
|
||||
mariadb -e "CREATE USER 'root'@'localhost' IDENTIFIED BY ''";
|
||||
mariadb -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('')";
|
||||
mariadb -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost'";
|
||||
mariadb -e "FLUSH PRIVILEGES";
|
||||
brew services restart mariadb;
|
||||
sleep 4;
|
||||
psql -c 'create user postgres superuser;' postgres;
|
||||
fi
|
||||
|
||||
services:
|
||||
- postgresql
|
||||
- mysql
|
||||
|
||||
script:
|
||||
- ./build.sh -t
|
||||
- ./test.sh -t
|
||||
- sudo rm /usr/local/lib/libtrantor.a && sudo rm /usr/local/lib/libdrogon.a
|
||||
- ./build.sh -tshared
|
||||
- ./test.sh -t
|
574
modules/drogon/drogon/CMakeLists.txt
Normal file
574
modules/drogon/drogon/CMakeLists.txt
Normal file
@ -0,0 +1,574 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(drogon)
|
||||
|
||||
message(STATUS "compiler: " ${CMAKE_CXX_COMPILER_ID})
|
||||
|
||||
# If your cross compile is failing, you should set
|
||||
# CMAKE_SYSTEM_NAME in your toolchain file
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
set(BUILD_PROGRAMS ON)
|
||||
else ()
|
||||
set(BUILD_PROGRAMS OFF)
|
||||
endif ()
|
||||
|
||||
option(BUILD_CTL "Build drogon_ctl" ${BUILD_PROGRAMS})
|
||||
option(BUILD_EXAMPLES "Build examples" ${BUILD_PROGRAMS})
|
||||
option(BUILD_ORM "Build orm" ON)
|
||||
option(COZ_PROFILING "Use coz for profiling" OFF)
|
||||
option(BUILD_DROGON_SHARED "Build drogon as a shared lib" OFF)
|
||||
|
||||
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)
|
||||
|
||||
set(DROGON_MAJOR_VERSION 1)
|
||||
set(DROGON_MINOR_VERSION 6)
|
||||
set(DROGON_PATCH_VERSION 0)
|
||||
set(DROGON_VERSION
|
||||
${DROGON_MAJOR_VERSION}.${DROGON_MINOR_VERSION}.${DROGON_PATCH_VERSION})
|
||||
set(DROGON_VERSION_STRING "${DROGON_VERSION}")
|
||||
|
||||
# Offer the user the choice of overriding the installation directories
|
||||
set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
|
||||
set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
|
||||
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
set(DEF_INSTALL_DROGON_CMAKE_DIR lib/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>")
|
||||
endif ()
|
||||
|
||||
if (BUILD_DROGON_SHARED)
|
||||
set(BUILD_TRANTOR_SHARED TRUE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
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")
|
||||
add_library(${PROJECT_NAME} SHARED)
|
||||
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 ()
|
||||
else (BUILD_DROGON_SHARED)
|
||||
add_library(${PROJECT_NAME} STATIC)
|
||||
endif (BUILD_DROGON_SHARED)
|
||||
|
||||
if (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 (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
|
||||
set(DROGON_CXX_STANDARD 20)
|
||||
elseif (HAS_ANY AND HAS_STRING_VIEW)
|
||||
set(DROGON_CXX_STANDARD 17)
|
||||
else ()
|
||||
set(DROGON_CXX_STANDARD 14)
|
||||
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:${PROJECT_SOURCE_DIR}/trantor>
|
||||
$<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)
|
||||
|
||||
add_subdirectory(trantor)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC trantor)
|
||||
|
||||
if (NOT WIN32)
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dl)
|
||||
endif (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
else (NOT WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi)
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (DROGON_CXX_STANDARD EQUAL 14)
|
||||
# With C++14, use boost to support any and string_view
|
||||
message(STATUS "use c++14")
|
||||
find_package(Boost 1.61.0 REQUIRED)
|
||||
message(STATUS "boost include dir:" ${Boost_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::boost)
|
||||
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${Boost_INCLUDE_DIR})
|
||||
elseif (DROGON_CXX_STANDARD EQUAL 17)
|
||||
message(STATUS "use c++17")
|
||||
else ()
|
||||
message(STATUS "use c++20")
|
||||
endif ()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/)
|
||||
|
||||
# jsoncpp
|
||||
find_package(Jsoncpp REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_lib)
|
||||
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${JSONCPP_INCLUDE_DIRS})
|
||||
|
||||
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)
|
||||
try_compile(ossp_uuid ${CMAKE_BINARY_DIR}/cmaketest
|
||||
${PROJECT_SOURCE_DIR}/cmake/tests/ossp_uuid_lib_test.cc
|
||||
LINK_LIBRARIES UUID_lib)
|
||||
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")
|
||||
endif ()
|
||||
endif (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
|
||||
AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD"
|
||||
AND NOT WIN32)
|
||||
|
||||
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)
|
||||
|
||||
set(DROGON_SOURCES
|
||||
lib/src/AOPAdvice.cc
|
||||
lib/src/CacheFile.cc
|
||||
lib/src/ConfigLoader.cc
|
||||
lib/src/Cookie.cc
|
||||
lib/src/DrClassMap.cc
|
||||
lib/src/DrTemplateBase.cc
|
||||
lib/src/FiltersFunction.cc
|
||||
lib/src/HttpAppFrameworkImpl.cc
|
||||
lib/src/HttpBinder.cc
|
||||
lib/src/HttpClientImpl.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/HttpSimpleControllersRouter.cc
|
||||
lib/src/HttpUtils.cc
|
||||
lib/src/HttpViewData.cc
|
||||
lib/src/IntranetIpFilter.cc
|
||||
lib/src/ListenerManager.cc
|
||||
lib/src/LocalHostFilter.cc
|
||||
lib/src/MultiPart.cc
|
||||
lib/src/NotFound.cc
|
||||
lib/src/PluginsManager.cc
|
||||
lib/src/SecureSSLRedirector.cc
|
||||
lib/src/AccessLogger.cc
|
||||
lib/src/SessionManager.cc
|
||||
lib/src/StaticFileRouter.cc
|
||||
lib/src/TaskTimeoutFlag.cc
|
||||
lib/src/Utilities.cc
|
||||
lib/src/WebSocketClientImpl.cc
|
||||
lib/src/WebSocketConnectionImpl.cc
|
||||
lib/src/WebsocketControllersRouter.cc)
|
||||
|
||||
if (NOT WIN32)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/SharedLibManager.cc)
|
||||
else (NOT WIN32)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES} third_party/mman-win32/mman.c)
|
||||
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)
|
||||
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)
|
||||
endif (libpq_supports_batch)
|
||||
endif (pg_FOUND)
|
||||
endif (BUILD_POSTGRESQL)
|
||||
|
||||
if (BUILD_MYSQL)
|
||||
# Find mysql, only mariadb client liberary is supported
|
||||
find_package(MySQL)
|
||||
if (MySQL_FOUND)
|
||||
message(STATUS "Ok! We find the mariadb!")
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE MySQL_lib)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES}
|
||||
orm_lib/src/mysql_impl/MysqlConnection.cc
|
||||
orm_lib/src/mysql_impl/MysqlResultImpl.cc)
|
||||
endif (MySQL_FOUND)
|
||||
endif (BUILD_MYSQL)
|
||||
|
||||
if (BUILD_SQLITE)
|
||||
# Find sqlite3.
|
||||
find_package(SQLite3)
|
||||
if (SQLite3_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite3_lib)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES}
|
||||
orm_lib/src/sqlite3_impl/Sqlite3Connection.cc
|
||||
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.cc)
|
||||
endif (SQLite3_FOUND)
|
||||
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/RedisConnection.cc
|
||||
nosql_lib/redis/src/RedisResult.cc
|
||||
nosql_lib/redis/src/RedisClientLockFree.cc
|
||||
nosql_lib/redis/src/RedisClientManager.cc
|
||||
nosql_lib/redis/src/RedisTransactionImpl.cc)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
find_package(OpenSSL)
|
||||
if (OpenSSL_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
else (OpenSSL_FOUND)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/ssl_funcs/Md5.cc
|
||||
lib/src/ssl_funcs/Sha1.cc)
|
||||
endif (OpenSSL_FOUND)
|
||||
|
||||
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/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)
|
||||
if (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
set(DROGON_SOURCES
|
||||
${DROGON_SOURCES}
|
||||
orm_lib/src/DbClientManager.cc)
|
||||
else (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/DbClientManagerSkipped.cc)
|
||||
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${DROGON_SOURCES})
|
||||
|
||||
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 MySQL_FOUND OR SQLite3_FOUND)
|
||||
if (pg_FOUND)
|
||||
option(USE_POSTGRESQL "Enable PostgreSQL" ON)
|
||||
else (pg_FOUND)
|
||||
option(USE_POSTGRESQL "Disable PostgreSQL" OFF)
|
||||
endif (pg_FOUND)
|
||||
|
||||
if (MySQL_FOUND)
|
||||
option(USE_MYSQL "Enable Mysql" ON)
|
||||
else (MySQL_FOUND)
|
||||
option(USE_MYSQL "DisableMysql" OFF)
|
||||
endif (MySQL_FOUND)
|
||||
|
||||
if (SQLite3_FOUND)
|
||||
option(USE_SQLITE3 "Enable Sqlite3" ON)
|
||||
else (SQLite3_FOUND)
|
||||
option(USE_SQLITE3 "Disable Sqlite3" OFF)
|
||||
endif (SQLite3_FOUND)
|
||||
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
|
||||
|
||||
set(COMPILER_COMMAND ${CMAKE_CXX_COMPILER})
|
||||
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 (MySQL_FOUND)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/mysql_impl/test)
|
||||
endif (MySQL_FOUND)
|
||||
if (SQLite3_FOUND)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/sqlite3_impl/test)
|
||||
endif (SQLite3_FOUND)
|
||||
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)
|
||||
|
||||
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
|
||||
${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
|
||||
install(FILES ${DROGON_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon)
|
||||
|
||||
set(ORM_HEADERS
|
||||
orm_lib/inc/drogon/orm/ArrayParser.h
|
||||
orm_lib/inc/drogon/orm/Criteria.h
|
||||
orm_lib/inc/drogon/orm/DbClient.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/RedisException.h)
|
||||
install(FILES ${NOSQL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/nosql)
|
||||
|
||||
set(DROGON_UTIL_HEADERS
|
||||
lib/inc/drogon/utils/FunctionTraits.h
|
||||
lib/inc/drogon/utils/Utilities.h
|
||||
lib/inc/drogon/utils/any.h
|
||||
lib/inc/drogon/utils/string_view.h
|
||||
lib/inc/drogon/utils/optional.h
|
||||
lib/inc/drogon/utils/coroutine.h
|
||||
lib/inc/drogon/utils/HttpConstraint.h
|
||||
lib/inc/drogon/utils/OStringStream.h)
|
||||
install(FILES ${DROGON_UTIL_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
|
||||
|
||||
set(DROGON_PLUGIN_HEADERS lib/inc/drogon/plugins/Plugin.h
|
||||
lib/inc/drogon/plugins/SecureSSLRedirector.h
|
||||
lib/inc/drogon/plugins/AccessLogger.h)
|
||||
install(FILES ${DROGON_PLUGIN_HEADERS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
|
||||
|
||||
source_group("Public API"
|
||||
FILES
|
||||
${DROGON_HEADERS}
|
||||
${ORM_HEADERS}
|
||||
${DROGON_UTIL_HEADERS}
|
||||
${DROGON_PLUGIN_HEADERS}
|
||||
${NOSQL_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/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)
|
||||
|
78
modules/drogon/drogon/CONTRIBUTING.md
Normal file
78
modules/drogon/drogon/CONTRIBUTING.md
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
|
||||
DocsForge](https://drogon.docsforge.com/master/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.
|
837
modules/drogon/drogon/ChangeLog.md
Normal file
837
modules/drogon/drogon/ChangeLog.md
Normal file
@ -0,0 +1,837 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.6.0] - 2021-05-15
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add option to set default handler.
|
||||
|
||||
- Add the setTimeout() method to the DbClient class and the RedisClient class.
|
||||
|
||||
- Add the validateCert parameter to the newWebSocketClient method.
|
||||
|
||||
### Changed
|
||||
|
||||
- A few mini changes to drogon_ctl command.
|
||||
|
||||
- Improve the MultiPartParser class.
|
||||
|
||||
- Add GNU -Werror & fix warnings.
|
||||
|
||||
- Enhancements on files part.
|
||||
|
||||
- Add version/soversion to shared library.
|
||||
|
||||
- Disallow coroutines to be resolved as plain subroutine handlers.
|
||||
|
||||
- Send the content-length header even if the body(POST,PUT,OPTIONS,PATCH) is empty.
|
||||
|
||||
- Use make_exception_ptr instead of throw/catch when possible.
|
||||
|
||||
- Remove duplicated inclusion.
|
||||
|
||||
- Print error before terminating in AsyncTask.
|
||||
|
||||
- Allow users to override drogon Find modules.
|
||||
|
||||
- Use two-phase construction for the DbClientImpl and the RedisClientImpl.
|
||||
|
||||
- Add support 'select <db>' for redis.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug of the Transaction class.
|
||||
|
||||
- Copy CoroMapper.h to installation location.
|
||||
|
||||
- Remove the related request from the buffer if it's not sent after the timeout.
|
||||
|
||||
- Fix ORM with SQLite3 not compiling on Arch Linux.
|
||||
|
||||
- Fix an error when constructing RedisClientImpl objects.
|
||||
|
||||
- Fix coroutine frame leak upon assigning to awaitable.
|
||||
|
||||
- Set running flag to true before installing plugins.
|
||||
|
||||
- Fix double free in coroutine exception handling.
|
||||
|
||||
## [1.5.1] - 2021-04-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug of reflection failure.
|
||||
|
||||
## [1.5.0] - 2021-04-10
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add option to disable signal handling.
|
||||
|
||||
- Added newFileResponse Support for buffers in memory.
|
||||
|
||||
- Add a method to HttpRequest to set the user_agent header.
|
||||
|
||||
- Catch exceptions thrown by handlers.
|
||||
|
||||
### Changed
|
||||
|
||||
- Add convert method to models.
|
||||
|
||||
- Add Arch Dockerfile.
|
||||
|
||||
- Add Redis support.
|
||||
|
||||
- Print error and exit when IP parsing failed in server startup.
|
||||
|
||||
- Use a canonical way of calling max() function on Windows.
|
||||
|
||||
- Remove an assertion statement in the HttpClientImpl class.
|
||||
|
||||
- Send ping messages by default for WebSockets.
|
||||
|
||||
- Use canonical cmake logic for cross-compilation.
|
||||
|
||||
- set make job count to the number of threads in GitHub Actions workflow.
|
||||
|
||||
- Use lambda instead of std::bind in HttpServer.
|
||||
|
||||
- Add exports macro to allow Shared Library with hidden symbols by default.
|
||||
|
||||
- Remove repeated class names on relationships from the model generator.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix compile warnings in SQL client.
|
||||
|
||||
- Fix compilation errors for the TimeFilter example.
|
||||
|
||||
- Fix build.sh missing nproc error in build for macOS.
|
||||
|
||||
- Fix a bug when creating sqlite3 models.
|
||||
|
||||
- Fix two building corner cases, CMake quality of life improvements.
|
||||
|
||||
- Add CoroMapper to models' friends.
|
||||
|
||||
## [1.4.1] - 2021-03-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug of DbClientImpl class that can lead to a crash when database connections are breaking.
|
||||
|
||||
## [1.4.0] - 2021-03-05
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add coroutine support.
|
||||
|
||||
- Add default value interface to SqlBinder for MySQL and PostgreSQL.
|
||||
|
||||
- Support SNI in the HttpClient class.
|
||||
|
||||
- Validate certificate in HttpClient.
|
||||
|
||||
- HttpRequest: add a feature to avoid URL encoding of the path.
|
||||
|
||||
### Changed
|
||||
|
||||
- Handle cross-compiling properly.
|
||||
|
||||
- Lowercase all HTTP headers, add webp and avif types.
|
||||
|
||||
- Modify FindMySQL.cmake
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an error in the HttpClient class when a response has no content-length.
|
||||
|
||||
- Return 404 or 405 responses correctly.
|
||||
|
||||
- Fix compilation errors on vs2019.
|
||||
|
||||
- Fix stack use after scope error in client_example.
|
||||
|
||||
- Fix the error when the SSL handshake fails.
|
||||
|
||||
## [1.3.0] - 2021-01-16
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add an option for setting float precision in Json string.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix brotli link order.
|
||||
|
||||
- Fix cmake with drogonctl cross-compilation.
|
||||
|
||||
- sqlite3: Insert into stmtsMap_ as string_view.
|
||||
|
||||
- Fix some bugs when creating models via drogon_ctl.
|
||||
|
||||
- Fix an error in sqlite3 ORM generator.
|
||||
|
||||
- Fix an error with missing composite key to sqlite3 ORM generator.
|
||||
|
||||
### Changed
|
||||
|
||||
- Remove the use of std::filesystem to adapt to old compilers.
|
||||
|
||||
- Add github actions.
|
||||
|
||||
- Serve wasm files with the correct MIME type.
|
||||
|
||||
## [1.2.0] - 2020-12-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix error when receiving response without content-length header.
|
||||
|
||||
- Fix a stack-overflow error when high concurrency happening on sqlite3.
|
||||
|
||||
- Fix MinGW ORM building by enabling htonll and ntohll.
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify the WebSocketTest controller to create a simple chat room.
|
||||
|
||||
- Add support for OpenBSD.
|
||||
|
||||
- Return 400 if the content-length is invalid.
|
||||
|
||||
- Don't send content type in a 304 response.
|
||||
|
||||
- Add the reuse_port option to app() interface.
|
||||
|
||||
- Add the 'std::optional' support in the SqlBinder class and the Session class.
|
||||
|
||||
- Add implicit page resolving capability.
|
||||
|
||||
## [1.1.0] - 2020-10-31
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix failing to connect to DB if parameters contains spaces.
|
||||
|
||||
- Fix a CMAKE bug when SHARED and EXAMPLES are on.
|
||||
|
||||
- Fix the HttpServer::isWebSocket method.
|
||||
|
||||
- Find MariaDB client library correctly on Ubuntu 20.04.
|
||||
|
||||
- Fix a bug when creating sqlite3 database models.
|
||||
|
||||
- Fix a bug in the Mapper::insertFuture method.
|
||||
|
||||
### Changed
|
||||
|
||||
- Disable TLS1.0/1.1 on HTTPS by default.
|
||||
|
||||
- Use explicit lambda capture lists.
|
||||
|
||||
- Modify the procedure of the app().run() method.
|
||||
|
||||
- Support namespaces when creating view source files.
|
||||
|
||||
- Add --path-to-namespace option to drogon_ctl for creating views.
|
||||
|
||||
- Add the Host and Sec-WebSocket-Version headers when connecting to a websocket server.
|
||||
|
||||
## [1.0.0] - 2020-09-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an issue of simple_reverse_proxy when handling chunked transfer-encoding.
|
||||
|
||||
- Fix a bug when losting connection to MySQL server during query.
|
||||
|
||||
- Remove the expired std::iterator template.
|
||||
|
||||
- Fix a bug when creating models in some special cases.
|
||||
|
||||
### API changes list
|
||||
|
||||
- Modify methods related to headers.
|
||||
|
||||
- Remove the expired std::iterator template.
|
||||
|
||||
- Add getListeners() method to the HttpAppFramework class.
|
||||
|
||||
- Remove the useless method stat() from the PluginBase class.
|
||||
|
||||
- Add ConfigLoader::ConfigLoader(const Json::Value &data).
|
||||
|
||||
### Changed
|
||||
|
||||
- Add support for status code 418.
|
||||
|
||||
- Modify session handling.
|
||||
|
||||
- Modify the FileUpload.csp in simple_example to avoid CORS.
|
||||
|
||||
- remove execution permission on /tmp/drogon.lock.
|
||||
|
||||
## [1.0.0-beta21] - 2020-08-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify the Result class in ORM.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix zlib link error on Windows for the latest vcpkg.
|
||||
|
||||
## [1.0.0-beta20] - 2020-08-15
|
||||
|
||||
### API changes list
|
||||
|
||||
- Provide users with a method to change the session ID of a session.
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify parseContentType function.
|
||||
|
||||
- Modify the docker file to build release version in docker.
|
||||
|
||||
- Set session to requests for websockets.
|
||||
|
||||
- Modify parseContentType function.
|
||||
|
||||
- Change the return value type of the mktime() function in models.
|
||||
|
||||
- Fix compilation warning of sprintf function.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug when saving uploaded files on Windows.
|
||||
|
||||
- Fix a MySQL issue when connections are lost.
|
||||
|
||||
- Resolve an issue when sending big files (>=2GB) on Windows.
|
||||
|
||||
- Fix boost::string_view compilation error of MysqlConnection class.
|
||||
|
||||
- Set the response Access-Control-Allow-Headers header correctly for CORS.
|
||||
|
||||
- Fix a bug in drogon_ctl when creating a model, that causes to write source files multiple times.
|
||||
|
||||
## [1.0.0-beta19] - 2020-07-16
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add a method to disable unicode escaping in json string.
|
||||
|
||||
- Add a timeout parameter when sending HTTP requests.
|
||||
|
||||
- Add the getJsonError method.
|
||||
|
||||
### Changed
|
||||
|
||||
- Remove the restriction on the location of layout tags in views.
|
||||
|
||||
- Add a way to set the character set when creating DbClient objects.
|
||||
|
||||
- Make `GET` as the only method for accessing static files.
|
||||
|
||||
- Modify the 404 pages generator.
|
||||
|
||||
- Modify the DbClient class.
|
||||
|
||||
- Optimize the HttpResponse class.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Properly handle chunked encoding requests.
|
||||
|
||||
- Destroy DNS resolver of HttpClient in the correct thread.
|
||||
|
||||
- Add the header <cctype> to resolve build errors in VS2017.
|
||||
|
||||
## [1.0.0-beta18] - 2020-06-14
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add a new joinpoint of AOP for modification on each HTTP response.
|
||||
|
||||
- Add a method for the TERM signal handling.
|
||||
|
||||
- Add getContextRef method to the WebSocketConnection class.
|
||||
|
||||
### Changed
|
||||
|
||||
- Create a class template for publish subscribe pattern.
|
||||
|
||||
- Add contribution recommendations.
|
||||
|
||||
- Send a close message when closing a web socket connection.
|
||||
|
||||
- Add additional formats for getHttpDate function.
|
||||
|
||||
- Make app().run() method callable on a non-main thread.
|
||||
|
||||
- Add digest filter in examples.
|
||||
|
||||
- Use string_view to parse multipart/form-data requests.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix building of ORM on FreeBSD.
|
||||
|
||||
- Fix a Mysql connection error on Windows.
|
||||
|
||||
- Fix a bug in ListenerManager::getIOLoop().
|
||||
|
||||
- Fix the count() method of Mysql ORM.
|
||||
|
||||
- Fix a compilation issue on windows.
|
||||
|
||||
- Fix model generation for PostgreSQL primary keys.
|
||||
|
||||
- Fix a bug with quoted column names in sqlite3 databases.
|
||||
|
||||
## [1.0.0-beta17] - 2020-05-22
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add methods to get DbClient connection status
|
||||
|
||||
### Changed
|
||||
|
||||
- Add causal profiling with coz
|
||||
|
||||
- Add filters on static file locations
|
||||
|
||||
- Pass data from view to its layout container
|
||||
|
||||
- Add additional HttpStatusCodes and implement a custom error handler
|
||||
|
||||
- Modify drogon_ctl to show more compilation information
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug in drogon_ctl (when size of a line is larger than buffer size)
|
||||
|
||||
- Fix a connection bug of MariaDB clients
|
||||
|
||||
## [1.0.0-beta16] - 2020-04-27
|
||||
|
||||
### API changes list
|
||||
|
||||
- Standardize Row and Result api in ORM
|
||||
|
||||
### Changed
|
||||
|
||||
- Add support for brotli compression
|
||||
|
||||
- Parse content-type of HTTP requests
|
||||
|
||||
- Remove non standard macros
|
||||
|
||||
- Support url safe base64 codec
|
||||
|
||||
## [1.0.0-beta15] - 2020-03-28
|
||||
|
||||
### API changes list
|
||||
|
||||
- Modify the Attributes interface of the HttpRequest class
|
||||
|
||||
- Add the getHomePage() method to HttpAppFramework
|
||||
|
||||
### Changed
|
||||
|
||||
- Support br compression files
|
||||
|
||||
- Update Content-Type support for PDF
|
||||
|
||||
- Add support for MSVC 2015
|
||||
|
||||
- Optimize the rendering of HTTP responses
|
||||
|
||||
- Update the Dynamic Views Loading, add the `layout` tag
|
||||
|
||||
- Graceful shutdown
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix error when finding the jsoncpp library
|
||||
|
||||
- Fix the 'many to many' relationship in ORM
|
||||
|
||||
- Fix a bug when creating json responses
|
||||
|
||||
- Fix a bug on filters with WebSocketControllers
|
||||
|
||||
- Fix a fatal bug in the MysqlConnection class
|
||||
|
||||
- Fix crash with partial matched url
|
||||
|
||||
- Fix null jsonObject from newHttpJsonRequest
|
||||
|
||||
## [1.0.0-beta14] - 2020-02-17
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Added
|
||||
|
||||
- Add IOLoop access function
|
||||
|
||||
### Changed
|
||||
|
||||
- Add support for regular expressions when routing
|
||||
|
||||
- Add location configuration for static resources
|
||||
|
||||
- Port drogon to Windows
|
||||
|
||||
- Support 'password' keyword in configuration files
|
||||
|
||||
- Remove get_version.sh
|
||||
|
||||
- Modify dynamic view loading algorithm, add 'layout' tag for view generation.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an issue of out-of-range (#334)
|
||||
|
||||
- Fix a bug in views generation (#341)
|
||||
|
||||
## [1.0.0-beta13] - 2020-01-04
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Changed
|
||||
|
||||
- Add some unit tests (based on gtest)
|
||||
|
||||
- Add a reverse proxy example
|
||||
|
||||
- Make a patch to support the ossp UUID library
|
||||
|
||||
- Make shared linking possible
|
||||
|
||||
- Add the drogon::OStringStream class
|
||||
|
||||
- Optimize ORM
|
||||
|
||||
- Modify singleton logic of DrClassMap
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an error in the batch mode of libpq
|
||||
|
||||
- Fix an error when clients use HTTP1.0
|
||||
|
||||
## [1.0.0-beta12] - 2019-11-30
|
||||
|
||||
### Changed
|
||||
|
||||
- Make dg_ctl a symlink
|
||||
|
||||
- Modify some code styles
|
||||
|
||||
- Explicitly set path to '/' for JSESSIONID cookie
|
||||
|
||||
- Handle gzip errors safely
|
||||
|
||||
- Add the SecureSSLRedirector plugin
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug in dg_ctl for creating models of sqlite3
|
||||
|
||||
- Reset the flag used to parse json to false before recycling HttpRequest objects
|
||||
|
||||
## [1.0.0-beta11] - 2019-11-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Delete useless log output
|
||||
|
||||
## [1.0.0-beta10] - 2019-11-04
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Changed
|
||||
|
||||
- Add the headers configuration option for static files
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix(compilation on alpine): Replace u_short alias.
|
||||
|
||||
|
||||
## [1.0.0-beta9] - 2019-10-28
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add interfaces for accessing content of attachments.
|
||||
|
||||
- Add option to disable setting the 404 status code of the custom 404 page.
|
||||
|
||||
- Make user can use any string as a placeholder's name in routing patterns.
|
||||
|
||||
- Add type conversion methods to the HttpRequest and HttpResponse classes.
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify cmake configuration.
|
||||
|
||||
- Modify the quit() method.
|
||||
|
||||
- Implement relationships in ORM.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix size_t underflow of drogon_ctl.
|
||||
|
||||
- Fix some race conditions.
|
||||
|
||||
- Fix a busy loop bug when connections to MySQL server are timeout.
|
||||
|
||||
|
||||
## [1.0.0-beta8] - 2019-10-03
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add length() method to the Field class.
|
||||
|
||||
- Add `as<bool>()` function template specialization to the Field class.
|
||||
|
||||
- Add add attribute store methods to the HttpRequest class.
|
||||
|
||||
- Add the setCustomContentTypeString() method to the HttpRequest class.
|
||||
|
||||
- Add thread storage.
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Use .find('x') instead of .find("x") in a string search.
|
||||
|
||||
- Add the ability to create restful API controllers.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug of creating models for MySQL.
|
||||
|
||||
- Fix a bug when HTTP method is PUT.
|
||||
|
||||
- Fix a bug when using 'is null' substatement in ORM.
|
||||
|
||||
- Fix a sqlite3 bug when some SQL errors occur.
|
||||
|
||||
- Fix bug with parsing json.
|
||||
|
||||
- Fix url decode.
|
||||
|
||||
- Fix a error in HttpClient.
|
||||
|
||||
- Fix a error in setThreadNum method.
|
||||
|
||||
- Fix some race conditions.
|
||||
|
||||
## [1.0.0-beta7] - 2019-08-31
|
||||
|
||||
### API changes list
|
||||
|
||||
- Remove the default value parameter of some methods (#220)
|
||||
|
||||
### Changed
|
||||
|
||||
- Optimize DNS in HttpClient and WebSocketClient (support c-ares library).
|
||||
|
||||
- Reduce dependencies between declarations.
|
||||
|
||||
- Add database tests in the travis CI and add test cases to database tests.
|
||||
|
||||
- Reduce size of docker image.
|
||||
|
||||
- Make the framework API support chained calls.
|
||||
|
||||
- Add a synchronous join point for AOP.
|
||||
|
||||
- Modify the CMakeLists to modern cmake style.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix bugs in default return values of functions(#220),
|
||||
|
||||
- Fix a bug in the cmake configuration file when there's '+' in the building path.
|
||||
|
||||
- Fix a bug in drogon_ctl (when creating orm models)
|
||||
|
||||
|
||||
## [1.0.0-beta6] - 2019-08-08
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify the 'create view' sub-command of drogon_ctl
|
||||
|
||||
- Optimize the transmission of pipelining responses.
|
||||
|
||||
- Add the DrogonConfig.cmake file so that users can use drogon with the `find_package(Drogon)` command.
|
||||
|
||||
## [1.0.0-beta5] - 2019-08-01
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Added
|
||||
|
||||
- Add two methods to control if the Server header or the Date header is sent to clients with HTTP responses.
|
||||
* void HttpAppFramework::enableServerHeader(bool);
|
||||
* void HttpAppFramework::enableDateHeader(bool);
|
||||
|
||||
### Changed
|
||||
|
||||
- Support high performance batch mode of libpq.
|
||||
|
||||
### Fixed
|
||||
|
||||
- None
|
||||
|
||||
## [1.0.0-beta4] - 2019-07-30
|
||||
|
||||
### API changes list
|
||||
|
||||
- HttpRequest::query() returns a const reference of std::string instead of a string_view
|
||||
- WebSocketConnection::setContext(), WebSocketConnection::getContext(), etc.
|
||||
- Remove the config.h from public API.
|
||||
|
||||
### Added
|
||||
|
||||
- None
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify the CMakeLists.txt
|
||||
- Modify the get_version.sh
|
||||
|
||||
### Fixed
|
||||
|
||||
- None
|
||||
|
||||
## [1.0.0-beta3] - 2019-07-28
|
||||
|
||||
### API changes list
|
||||
|
||||
- None
|
||||
|
||||
### Added
|
||||
|
||||
- Add a README file for examples.
|
||||
- Add some managers to reduce the size of the HttpAppFrameworkImpl code.
|
||||
- Add missing wasm ContentType.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update the submodule - trantor.
|
||||
- Optimize processing of HTTP pipelining.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix an error in the HttpClient class when sending a request using the HEAD method.
|
||||
|
||||
## [1.0.0-beta2] - 2019-07-10
|
||||
|
||||
### API changes list
|
||||
|
||||
- Add setBody methods to the HttpRequest class.
|
||||
- Add the setContentTypeCodeAndCustomString method to the HttpResponse class.
|
||||
|
||||
### Added
|
||||
|
||||
- Add stress testing command to drogon_ctl.
|
||||
- Add -v, -h parameters to drogon_ctl.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update the submodule - trantor.
|
||||
- Modify the handling of CORS.
|
||||
- Optimize the htmlTranslate method and the Field class.
|
||||
- Make all listeners share IO threads in the MacOS/Unix system.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug of the IsPlugin class.
|
||||
- Use default constructor of string_view to reset _statusMessage to fix a warning on GCC 9.1 on Arch Linux.
|
||||
|
||||
## [1.0.0-beta1] - 2019-06-11
|
||||
|
||||
[Unreleased]: https://github.com/an-tao/drogon/compare/v1.6.0...HEAD
|
||||
|
||||
[1.6.0]: https://github.com/an-tao/drogon/compare/v1.5.1...v1.6.0
|
||||
|
||||
[1.5.1]: https://github.com/an-tao/drogon/compare/v1.5.0...v1.5.1
|
||||
|
||||
[1.5.0]: https://github.com/an-tao/drogon/compare/v1.4.1...v1.5.0
|
||||
|
||||
[1.4.1]: https://github.com/an-tao/drogon/compare/v1.4.0...v1.4.1
|
||||
|
||||
[1.4.0]: https://github.com/an-tao/drogon/compare/v1.3.0...v1.4.0
|
||||
|
||||
[1.3.0]: https://github.com/an-tao/drogon/compare/v1.2.0...v1.3.0
|
||||
|
||||
[1.2.0]: https://github.com/an-tao/drogon/compare/v1.1.0...v1.2.0
|
||||
|
||||
[1.1.0]: https://github.com/an-tao/drogon/compare/v1.0.0...v1.1.0
|
||||
|
||||
[1.0.0]: https://github.com/an-tao/drogon/compare/v1.0.0-beta21...v1.0.0
|
||||
|
||||
[1.0.0-beta21]: https://github.com/an-tao/drogon/compare/v1.0.0-beta20...v1.0.0-beta21
|
||||
|
||||
[1.0.0-beta20]: https://github.com/an-tao/drogon/compare/v1.0.0-beta19...v1.0.0-beta20
|
||||
|
||||
[1.0.0-beta19]: https://github.com/an-tao/drogon/compare/v1.0.0-beta18...v1.0.0-beta19
|
||||
|
||||
[1.0.0-beta18]: https://github.com/an-tao/drogon/compare/v1.0.0-beta17...v1.0.0-beta18
|
||||
|
||||
[1.0.0-beta17]: https://github.com/an-tao/drogon/compare/v1.0.0-beta16...v1.0.0-beta17
|
||||
|
||||
[1.0.0-beta16]: https://github.com/an-tao/drogon/compare/v1.0.0-beta15...v1.0.0-beta16
|
||||
|
||||
[1.0.0-beta15]: https://github.com/an-tao/drogon/compare/v1.0.0-beta14...v1.0.0-beta15
|
||||
|
||||
[1.0.0-beta14]: https://github.com/an-tao/drogon/compare/v1.0.0-beta13...v1.0.0-beta14
|
||||
|
||||
[1.0.0-beta13]: https://github.com/an-tao/drogon/compare/v1.0.0-beta12...v1.0.0-beta13
|
||||
|
||||
[1.0.0-beta12]: https://github.com/an-tao/drogon/compare/v1.0.0-beta11...v1.0.0-beta12
|
||||
|
||||
[1.0.0-beta11]: https://github.com/an-tao/drogon/compare/v1.0.0-beta10...v1.0.0-beta11
|
||||
|
||||
[1.0.0-beta10]: https://github.com/an-tao/drogon/compare/v1.0.0-beta9...v1.0.0-beta10
|
||||
|
||||
[1.0.0-beta9]: https://github.com/an-tao/drogon/compare/v1.0.0-beta8...v1.0.0-beta9
|
||||
|
||||
[1.0.0-beta8]: https://github.com/an-tao/drogon/compare/v1.0.0-beta7...v1.0.0-beta8
|
||||
|
||||
[1.0.0-beta7]: https://github.com/an-tao/drogon/compare/v1.0.0-beta6...v1.0.0-beta7
|
||||
|
||||
[1.0.0-beta6]: https://github.com/an-tao/drogon/compare/v1.0.0-beta5...v1.0.0-beta6
|
||||
|
||||
[1.0.0-beta5]: https://github.com/an-tao/drogon/compare/v1.0.0-beta4...v1.0.0-beta5
|
||||
|
||||
[1.0.0-beta4]: https://github.com/an-tao/drogon/compare/v1.0.0-beta3...v1.0.0-beta4
|
||||
|
||||
[1.0.0-beta3]: https://github.com/an-tao/drogon/compare/v1.0.0-beta2...v1.0.0-beta3
|
||||
|
||||
[1.0.0-beta2]: https://github.com/an-tao/drogon/compare/v1.0.0-beta1...v1.0.0-beta2
|
||||
|
||||
[1.0.0-beta1]: https://github.com/an-tao/drogon/releases/tag/v1.0.0-beta1
|
1
modules/drogon/drogon/HEAD
Normal file
1
modules/drogon/drogon/HEAD
Normal file
@ -0,0 +1 @@
|
||||
834e3eabdd0441ad2bc80c02e8bbfc3b8312c213
|
21
modules/drogon/drogon/LICENSE
Normal file
21
modules/drogon/drogon/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2021 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.
|
191
modules/drogon/drogon/README.md
Executable file
191
modules/drogon/drogon/README.md
Executable file
@ -0,0 +1,191 @@
|
||||
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
|
||||
|
||||
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
|
||||
![Build Status](https://github.com/an-tao/drogon/workflows/Build%20Drogon/badge.svg?branch=master)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/12ffuf6j5vankgyb/branch/master?svg=true)](https://ci.appveyor.com/project/an-tao/drogon/branch/master)
|
||||
[![Total alerts](https://img.shields.io/lgtm/alerts/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/alerts/)
|
||||
[![Join the chat at https://gitter.im/drogon-web/community](https://badges.gitter.im/drogon-web/community.svg)](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Join the telegram group at https://t.me/joinchat/_mMNGv0748ZkMDAx](https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md)
|
||||
### Overview
|
||||
**Drogon** is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like.
|
||||
|
||||
Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, 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 build-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:
|
||||
virtual 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:
|
||||
virtual 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) or [DocsForge](https://drogon.docsforge.com/master/overview/)**
|
||||
|
||||
## Contributions
|
||||
Every contribution is welcome. Please refer to the [contribution guidelines](CONTRIBUTING.md) for more information.
|
199
modules/drogon/drogon/README.zh-CN.md
Executable file
199
modules/drogon/drogon/README.zh-CN.md
Executable file
@ -0,0 +1,199 @@
|
||||
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
|
||||
|
||||
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
|
||||
![Build Status](https://github.com/an-tao/drogon/workflows/Build%20Drogon/badge.svg?branch=master)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/12ffuf6j5vankgyb/branch/master?svg=true)](https://ci.appveyor.com/project/an-tao/drogon/branch/master)
|
||||
[![Total alerts](https://img.shields.io/lgtm/alerts/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/alerts/)
|
||||
[![Join the chat at https://gitter.im/drogon-web/community](https://badges.gitter.im/drogon-web/community.svg)](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Join the telegram group at https://t.me/joinchat/_mMNGv0748ZkMDAx](https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
[English](./README.md) | 简体中文 | [繁體中文](./README.zh-TW.md)
|
||||
|
||||
**Drogon**是一个基于C++14/17的Http应用框架,使用Drogon可以方便的使用C++构建各种类型的Web应用服务端程序。
|
||||
本版本库是github上[Drogon工程](https://github.com/an-tao/drogon)的镜像库。**Drogon**是作者非常喜欢的美剧《权力的游戏》中的一条龙的名字(汉译作卓耿),和龙有关但并不是dragon的误写,为了不至于引起不必要的误会这里说明一下。
|
||||
|
||||
Drogon是一个跨平台框架,它支持Linux,也支持macOS、FreeBSD,OpenBSD,和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:
|
||||
virtual 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:
|
||||
virtual 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-概述)或者[doxiz](https://doxiz.com/drogon/master/overview/)以获取更多的信息**
|
||||
|
||||
## 贡献方式
|
||||
|
||||
欢迎您的贡献。 请阅读[贡献指南](CONTRIBUTING.md)以获取更多的信息。
|
||||
|
||||
## QQ交流群:1137909452
|
||||
|
||||
欢迎交流探讨。
|
199
modules/drogon/drogon/README.zh-TW.md
Normal file
199
modules/drogon/drogon/README.zh-TW.md
Normal file
@ -0,0 +1,199 @@
|
||||
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
|
||||
|
||||
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
|
||||
![Build Status](https://github.com/an-tao/drogon/workflows/Build%20Drogon/badge.svg?branch=master)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/12ffuf6j5vankgyb/branch/master?svg=true)](https://ci.appveyor.com/project/an-tao/drogon/branch/master)
|
||||
[![Total alerts](https://img.shields.io/lgtm/alerts/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/alerts/)
|
||||
[![Join the chat at https://gitter.im/drogon-web/community](https://badges.gitter.im/drogon-web/community.svg)](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Join the telegram group at https://t.me/joinchat/_mMNGv0748ZkMDAx](https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||
|
||||
[English](./README.md) | [简体中文](./README.zh-CN.md) | 繁體中文
|
||||
|
||||
**Drogon**是一個基於C++14/17的Http應用框架,使用Drogon可以方便的使用C++構建各種類型的Web App伺服器程式。
|
||||
本版本庫是github上[Drogon](https://github.com/an-tao/drogon)的鏡像庫。 **Drogon**是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(漢譯作卓耿),和龍有關但並不是dragon的誤寫,為了不至於引起不必要的誤會這裡說明一下。
|
||||
|
||||
Drogon是一個跨平台框架,它支援Linux,也支援macOS、FreeBSD/OpenBSD和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:
|
||||
virtual 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:
|
||||
virtual 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-概述)或者[doxiz](https://doxiz.com/drogon/master/overview/)以獲取更多的信息**
|
||||
|
||||
## 貢獻方式
|
||||
|
||||
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以獲取更多的信息。
|
||||
|
||||
## QQ交流群:1137909452
|
||||
|
||||
歡迎交流探討。
|
101
modules/drogon/drogon/build.sh
Executable file
101
modules/drogon/drogon/build.sh
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_DROGON_SHARED=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 ..."
|
||||
sudo $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 [ "$1" = "-t" ]; then
|
||||
build_drogon 1
|
||||
elif [ "$1" = "-tshared" ]; then
|
||||
build_drogon 2
|
||||
else
|
||||
build_drogon 0
|
||||
fi
|
60
modules/drogon/drogon/cmake/DrogonUtilities.cmake
Normal file
60
modules/drogon/drogon/cmake/DrogonUtilities.cmake
Normal file
@ -0,0 +1,60 @@
|
||||
# ##############################################################################
|
||||
# function drogon_create_views(target source_path output_path
|
||||
# [use_path_as_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})
|
||||
add_custom_command(OUTPUT ${ARGV2}/${outputFile}.h ${ARGV2}/${outputFile}.cc
|
||||
COMMAND drogon_ctl
|
||||
ARGS
|
||||
create
|
||||
view
|
||||
${inFile}
|
||||
--path-to-namespace
|
||||
-o
|
||||
${ARGV2}
|
||||
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)
|
79
modules/drogon/drogon/cmake/ParseAndAddDrogonTests.cmake
Normal file
79
modules/drogon/drogon/cmake/ParseAndAddDrogonTests.cmake
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()
|
56
modules/drogon/drogon/cmake/templates/DrogonConfig.cmake.in
Normal file
56
modules/drogon/drogon/cmake/templates/DrogonConfig.cmake.in
Normal file
@ -0,0 +1,56 @@
|
||||
# - 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(@Boost_FOUND@)
|
||||
find_dependency(Boost)
|
||||
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(@BUILD_DROGON_SHARED@)
|
||||
find_dependency(Threads)
|
||||
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")
|
||||
endif()
|
||||
|
||||
get_target_property(DROGON_INCLUDE_DIRS Drogon::Drogon INTERFACE_INCLUDE_DIRECTORIES)
|
||||
set(DROGON_LIBRARIES Drogon::Drogon)
|
||||
set(DROGON_EXECUTABLE drogon_ctl)
|
14
modules/drogon/drogon/cmake/templates/config.h.in
Normal file
14
modules/drogon/drogon/cmake/templates/config.h.in
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#cmakedefine01 USE_POSTGRESQL
|
||||
#cmakedefine01 LIBPQ_SUPPORTS_BATCH_MODE
|
||||
#cmakedefine01 USE_MYSQL
|
||||
#cmakedefine01 USE_SQLITE3
|
||||
#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
modules/drogon/drogon/cmake/templates/version.h.in
Normal file
5
modules/drogon/drogon/cmake/templates/version.h.in
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@"
|
@ -0,0 +1,7 @@
|
||||
#include <uuid.h>
|
||||
int main()
|
||||
{
|
||||
uuid_t uu;
|
||||
uuid_generate(uu);
|
||||
return 0;
|
||||
}
|
8
modules/drogon/drogon/cmake/tests/ossp_uuid_lib_test.cc
Normal file
8
modules/drogon/drogon/cmake/tests/ossp_uuid_lib_test.cc
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;
|
||||
}
|
12
modules/drogon/drogon/cmake/tests/test_libpq_batch_mode.cc
Normal file
12
modules/drogon/drogon/cmake/tests/test_libpq_batch_mode.cc
Normal file
@ -0,0 +1,12 @@
|
||||
#include <libpq-fe.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
PQisInBatchMode(NULL);
|
||||
PQbatchIsAborted(NULL);
|
||||
PQqueriesInBatch(NULL);
|
||||
PQbeginBatchMode(NULL);
|
||||
PQendBatchMode(NULL);
|
||||
PQsendEndBatch(NULL);
|
||||
PQgetNextQuery(NULL);
|
||||
}
|
50
modules/drogon/drogon/cmake_modules/FindBrotli.cmake
Normal file
50
modules/drogon/drogon/cmake_modules/FindBrotli.cmake
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)
|
||||
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
|
||||
find_library(BROTLIENC_LIBRARY NAMES brotlienc)
|
||||
|
||||
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)
|
40
modules/drogon/drogon/cmake_modules/FindHiredis.cmake
Normal file
40
modules/drogon/drogon/cmake_modules/FindHiredis.cmake
Normal file
@ -0,0 +1,40 @@
|
||||
# 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)
|
||||
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)
|
68
modules/drogon/drogon/cmake_modules/FindJsoncpp.cmake
Executable file
68
modules/drogon/drogon/cmake_modules/FindJsoncpp.cmake
Executable file
@ -0,0 +1,68 @@
|
||||
# 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)
|
||||
exec_program(
|
||||
cat
|
||||
ARGS
|
||||
"${JSONCPP_INCLUDE_DIRS}/json/version.h |grep JSONCPP_VERSION_STRING|sed s'/.*define/define/'|awk '{printf $3}'|sed s'/\"//g'"
|
||||
OUTPUT_VARIABLE
|
||||
jsoncpp_ver)
|
||||
message(STATUS "jsoncpp verson:" ${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()
|
||||
add_library(Jsoncpp_lib INTERFACE IMPORTED)
|
||||
set_target_properties(Jsoncpp_lib
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${JSONCPP_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES
|
||||
"${JSONCPP_LIBRARIES}")
|
||||
|
||||
endif(Jsoncpp_FOUND)
|
122
modules/drogon/drogon/cmake_modules/FindMySQL.cmake
Normal file
122
modules/drogon/drogon/cmake_modules/FindMySQL.cmake
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
modules/drogon/drogon/cmake_modules/FindSQLite3.cmake
Normal file
43
modules/drogon/drogon/cmake_modules/FindSQLite3.cmake
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
modules/drogon/drogon/cmake_modules/FindUUID.cmake
Executable file
118
modules/drogon/drogon/cmake_modules/FindUUID.cmake
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(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
|
||||
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)
|
||||
set(UUID_LIBRARY "")
|
||||
endif(NOT UUID_LIBRARY AND BSD)
|
||||
|
||||
set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR})
|
||||
set(UUID_LIBRARIES ${UUID_LIBRARY})
|
||||
|
||||
if(UUID_INCLUDE_DIRS)
|
||||
if(BSD OR UUID_LIBRARIES)
|
||||
set(UUID_FOUND TRUE)
|
||||
endif(BSD OR UUID_LIBRARIES)
|
||||
endif(UUID_INCLUDE_DIRS)
|
||||
|
||||
if(UUID_FOUND)
|
||||
if(NOT UUID_FIND_QUIETLY)
|
||||
message(STATUS "Found UUID: ${UUID_LIBRARIES}")
|
||||
endif(NOT UUID_FIND_QUIETLY)
|
||||
else(UUID_FOUND)
|
||||
if(UUID_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find UUID")
|
||||
endif(UUID_FIND_REQUIRED)
|
||||
endif(UUID_FOUND)
|
||||
|
||||
# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced
|
||||
# view
|
||||
mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
|
||||
|
||||
endif(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
|
||||
|
||||
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(UUID_FOUND)
|
||||
set(UUID_LIBRARIES)
|
||||
set(UUID_INCLUDE_DIRS)
|
||||
endif(UUID_FOUND)
|
23
modules/drogon/drogon/cmake_modules/Findcoz-profiler.cmake
Normal file
23
modules/drogon/drogon/cmake_modules/Findcoz-profiler.cmake
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
modules/drogon/drogon/cmake_modules/Findpg.cmake
Normal file
27
modules/drogon/drogon/cmake_modules/Findpg.cmake
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
modules/drogon/drogon/conanfile.txt
Normal file
16
modules/drogon/drogon/conanfile.txt
Normal file
@ -0,0 +1,16 @@
|
||||
[requires]
|
||||
jsoncpp/1.9.4
|
||||
zlib/1.2.11
|
||||
gtest/1.10.0
|
||||
sqlite3/3.34.1
|
||||
#libpq/13.2
|
||||
openssl/1.1.1j
|
||||
hiredis/1.0.0
|
||||
brotli/1.0.9
|
||||
|
||||
[generators]
|
||||
cmake_paths
|
||||
|
||||
[options]
|
||||
|
||||
[imports]
|
306
modules/drogon/drogon/config.example.json
Normal file
306
modules/drogon/drogon/config.example.json
Normal file
@ -0,0 +1,306 @@
|
||||
/* 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.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.0 by default, in seconds, the timeout for executing a SQL query.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0
|
||||
}
|
||||
],
|
||||
"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,
|
||||
//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,
|
||||
//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"
|
||||
],
|
||||
//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": "",
|
||||
//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": {
|
||||
//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"
|
||||
},
|
||||
//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
|
||||
},
|
||||
//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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
14
modules/drogon/drogon/config/drogon/config.h
Normal file
14
modules/drogon/drogon/config/drogon/config.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#define USE_POSTGRESQL 0
|
||||
#define LIBPQ_SUPPORTS_BATCH_MODE 0
|
||||
#define USE_MYSQL 0
|
||||
#define USE_SQLITE3 0
|
||||
#define OpenSSL_FOUND
|
||||
/* #undef Boost_FOUND */
|
||||
|
||||
#define COMPILATION_FLAGS "-std=c++17"
|
||||
#define COMPILER_COMMAND "/usr/bin/c++"
|
||||
#define COMPILER_ID "GNU"
|
||||
|
||||
#define INCLUDING_DIRS " -I/usr/include -I/usr/local/include"
|
42
modules/drogon/drogon/config/drogon/exports.h
Normal file
42
modules/drogon/drogon/config/drogon/exports.h
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef DROGON_EXPORT_H
|
||||
#define DROGON_EXPORT_H
|
||||
|
||||
#ifdef DROGON_STATIC_DEFINE
|
||||
# define DROGON_EXPORT
|
||||
# define DROGON_NO_EXPORT
|
||||
#else
|
||||
# ifndef DROGON_EXPORT
|
||||
# ifdef drogon_EXPORTS
|
||||
/* We are building this library */
|
||||
# define DROGON_EXPORT
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define DROGON_EXPORT
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef DROGON_NO_EXPORT
|
||||
# define DROGON_NO_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef DROGON_DEPRECATED
|
||||
# define DROGON_DEPRECATED __attribute__ ((__deprecated__))
|
||||
#endif
|
||||
|
||||
#ifndef DROGON_DEPRECATED_EXPORT
|
||||
# define DROGON_DEPRECATED_EXPORT DROGON_EXPORT DROGON_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifndef DROGON_DEPRECATED_NO_EXPORT
|
||||
# define DROGON_DEPRECATED_NO_EXPORT DROGON_NO_EXPORT DROGON_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if 0 /* DEFINE_NO_DEPRECATED */
|
||||
# ifndef DROGON_NO_DEPRECATED
|
||||
# define DROGON_NO_DEPRECATED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* DROGON_EXPORT_H */
|
5
modules/drogon/drogon/config/drogon/version.h
Normal file
5
modules/drogon/drogon/config/drogon/version.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define MAJOR 1
|
||||
#define MINOR 6
|
||||
#define PATCH 0
|
||||
#define DROGON_VERSION "1.6.0"
|
||||
#define DROGON_VERSION_SHA1 ""
|
21
modules/drogon/drogon/docker/arch/Dockerfile
Normal file
21
modules/drogon/drogon/docker/arch/Dockerfile
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 --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
|
27
modules/drogon/drogon/docker/ubuntu/Dockerfile
Normal file
27
modules/drogon/drogon/docker/ubuntu/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
||||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update -yqq \
|
||||
&& apt-get install -yqq --no-install-recommends software-properties-common \
|
||||
sudo curl wget cmake pkg-config locales git gcc-8 g++-8 \
|
||||
openssl libssl-dev libjsoncpp-dev uuid-dev zlib1g-dev libc-ares-dev\
|
||||
postgresql-server-dev-all libmariadbclient-dev libsqlite3-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-8 \
|
||||
CXX=g++-8 \
|
||||
AR=gcc-ar-8 \
|
||||
RANLIB=gcc-ranlib-8 \
|
||||
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
|
BIN
modules/drogon/drogon/drogon.jpg
Normal file
BIN
modules/drogon/drogon/drogon.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
81
modules/drogon/drogon/drogon_ctl/CMakeLists.txt
Executable file
81
modules/drogon/drogon/drogon_ctl/CMakeLists.txt
Executable file
@ -0,0 +1,81 @@
|
||||
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_DROGON_SHARED)
|
||||
set(DROGON_FILE $<TARGET_FILE:drogon>)
|
||||
set(TRANTOR_FILE $<TARGET_FILE:trantor>)
|
||||
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)
|
||||
endif(WIN32)
|
||||
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)
|
40
modules/drogon/drogon/drogon_ctl/CommandHandler.h
Normal file
40
modules/drogon/drogon/drogon_ctl/CommandHandler.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
* 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
modules/drogon/drogon/drogon_ctl/CopyDlls.cmake
Normal file
8
modules/drogon/drogon/drogon_ctl/CopyDlls.cmake
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
modules/drogon/drogon/drogon_ctl/cmd.cc
Normal file
56
modules/drogon/drogon/drogon_ctl/cmd.cc
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
modules/drogon/drogon/drogon_ctl/cmd.h
Executable file
21
modules/drogon/drogon/drogon_ctl/cmd.h
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);
|
55
modules/drogon/drogon/drogon_ctl/create.cc
Normal file
55
modules/drogon/drogon/drogon_ctl/create.cc
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
*
|
||||
* @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\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);
|
||||
}
|
37
modules/drogon/drogon/drogon_ctl/create.h
Normal file
37
modules/drogon/drogon/drogon_ctl/create.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "create some source files(Use 'drogon_ctl help create' for more "
|
||||
"information)";
|
||||
}
|
||||
virtual bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual std::string detail() override;
|
||||
};
|
||||
} // namespace drogon_ctl
|
451
modules/drogon/drogon/drogon_ctl/create_controller.cc
Normal file
451
modules/drogon/drogon/drogon_ctl/create_controller.cc
Normal file
@ -0,0 +1,451 @@
|
||||
/**
|
||||
*
|
||||
* 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 << "#include <drogon/HttpSimpleController.h>\n";
|
||||
file << "using namespace drogon;\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 << " virtual 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";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\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 << "}";
|
||||
}
|
||||
|
||||
void create_controller::newWebsockControllerHeaderFile(
|
||||
std::ofstream &file,
|
||||
const std::string &className)
|
||||
{
|
||||
file << "#pragma once\n";
|
||||
file << "#include <drogon/WebSocketController.h>\n";
|
||||
file << "using namespace drogon;\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
|
||||
<< " virtual void handleNewMessage(const WebSocketConnectionPtr&,\n";
|
||||
file << " std::string &&,\n";
|
||||
file << " const WebSocketMessageType &) "
|
||||
"override;\n";
|
||||
file << " virtual void handleNewConnection(const HttpRequestPtr &,\n";
|
||||
file << " const "
|
||||
"WebSocketConnectionPtr&)override;\n";
|
||||
file << " virtual 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";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\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 << "void " << class_name
|
||||
<< "::handleNewConnection(const HttpRequestPtr &req,const "
|
||||
"WebSocketConnectionPtr& wsConnPtr)\n";
|
||||
file << "{\n";
|
||||
file << " //write your application logic here\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 << "#include <drogon/HttpController.h>\n";
|
||||
file << "using namespace drogon;\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";
|
||||
auto pos = className.rfind("::");
|
||||
auto class_name = className;
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
auto namespacename = className.substr(0, pos);
|
||||
file << "using namespace " << namespacename << ";\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;
|
||||
}
|
66
modules/drogon/drogon/drogon_ctl/create_controller.h
Normal file
66
modules/drogon/drogon/drogon_ctl/create_controller.h
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual 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
|
117
modules/drogon/drogon/drogon_ctl/create_filter.cc
Normal file
117
modules/drogon/drogon/drogon_ctl/create_filter.cc
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
34
modules/drogon/drogon/drogon_ctl/create_filter.h
Normal file
34
modules/drogon/drogon/drogon_ctl/create_filter.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "create filter class files";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
};
|
||||
} // namespace drogon_ctl
|
1333
modules/drogon/drogon/drogon_ctl/create_model.cc
Normal file
1333
modules/drogon/drogon/drogon_ctl/create_model.cc
Normal file
File diff suppressed because it is too large
Load Diff
403
modules/drogon/drogon/drogon_ctl/create_model.h
Normal file
403
modules/drogon/drogon/drogon_ctl/create_model.h
Normal file
@ -0,0 +1,403 @@
|
||||
/**
|
||||
*
|
||||
* 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(), tolower);
|
||||
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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual 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
|
117
modules/drogon/drogon/drogon_ctl/create_plugin.cc
Normal file
117
modules/drogon/drogon/drogon_ctl/create_plugin.cc
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
34
modules/drogon/drogon/drogon_ctl/create_plugin.h
Normal file
34
modules/drogon/drogon/drogon_ctl/create_plugin.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "create plugin class files";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
};
|
||||
} // namespace drogon_ctl
|
110
modules/drogon/drogon/drogon_ctl/create_project.cc
Normal file
110
modules/drogon/drogon/drogon_ctl/create_project.cc
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
*
|
||||
* 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 newConfigFile(std::ofstream &configFile)
|
||||
{
|
||||
auto templ = DrTemplateBase::newTemplate("config");
|
||||
configFile << templ->genText();
|
||||
}
|
||||
static void newModelConfigFile(std::ofstream &configFile)
|
||||
{
|
||||
auto templ = DrTemplateBase::newTemplate("model_json");
|
||||
configFile << templ->genText();
|
||||
}
|
||||
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");
|
||||
|
||||
std::ofstream gitFile(".gitignore", std::ofstream::out);
|
||||
newGitIgFile(gitFile);
|
||||
std::ofstream configFile("config.json", std::ofstream::out);
|
||||
newConfigFile(configFile);
|
||||
std::ofstream modelConfigFile("models/model.json", std::ofstream::out);
|
||||
newModelConfigFile(modelConfigFile);
|
||||
}
|
34
modules/drogon/drogon/drogon_ctl/create_project.h
Normal file
34
modules/drogon/drogon/drogon_ctl/create_project.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "create a project";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string outputPath_{"."};
|
||||
void createProject(const std::string &projectName);
|
||||
};
|
||||
} // namespace drogon_ctl
|
547
modules/drogon/drogon/drogon_ctl/create_view.cc
Normal file
547
modules/drogon/drogon/drogon_ctl/create_view.cc
Normal file
@ -0,0 +1,547 @@
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
<< "<<*any_cast<const char *>(&val);\n";
|
||||
oSrcFile << " }else "
|
||||
"if(val.type()==typeid(std::string)||val.type()==typeid(const "
|
||||
"std::string)){\n";
|
||||
oSrcFile << " " << streamName
|
||||
<< "<<*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)
|
||||
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;
|
||||
createViewFile(file);
|
||||
}
|
||||
}
|
||||
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(),
|
||||
::tolower);
|
||||
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";
|
||||
}
|
43
modules/drogon/drogon/drogon_ctl/create_view.h
Normal file
43
modules/drogon/drogon/drogon_ctl/create_view.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
* @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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual 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
|
69
modules/drogon/drogon/drogon_ctl/help.cc
Normal file
69
modules/drogon/drogon/drogon_ctl/help.cc
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
modules/drogon/drogon/drogon_ctl/help.h
Normal file
35
modules/drogon/drogon/drogon_ctl/help.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "display this message";
|
||||
}
|
||||
virtual bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace drogon_ctl
|
49
modules/drogon/drogon/drogon_ctl/main.cc
Executable file
49
modules/drogon/drogon/drogon_ctl/main.cc
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;
|
||||
}
|
324
modules/drogon/drogon/drogon_ctl/press.cc
Normal file
324
modules/drogon/drogon/drogon_ctl/press.cc
Normal file
@ -0,0 +1,324 @@
|
||||
/**
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#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 keep alive(default: no)\n"
|
||||
" -q no progress indication(default: no)\n\n"
|
||||
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
|
||||
"http://localhost:8080/index.html\n";
|
||||
}
|
||||
|
||||
void outputErrorAndExit(const 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")
|
||||
// {
|
||||
// keepAlive_ = true;
|
||||
// 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());
|
||||
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()
|
||||
{
|
||||
static std::mutex mtx;
|
||||
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;
|
||||
size_t 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);
|
||||
}
|
74
modules/drogon/drogon/drogon_ctl/press.h
Normal file
74
modules/drogon/drogon/drogon_ctl/press.h
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "Do stress testing(Use 'drogon_ctl help press' for more "
|
||||
"information)";
|
||||
}
|
||||
virtual bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual std::string detail() override;
|
||||
|
||||
private:
|
||||
size_t numOfThreads_{1};
|
||||
size_t numOfRequests_{1};
|
||||
size_t numOfConnections_{1};
|
||||
// bool keepAlive_ = false;
|
||||
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
|
68
modules/drogon/drogon/drogon_ctl/templates/cmake.csp
Normal file
68
modules/drogon/drogon/drogon_ctl/templates/cmake.csp
Normal file
@ -0,0 +1,68 @@
|
||||
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 (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)
|
||||
# With C++14, use boost to support any and string_view
|
||||
message(STATUS "use c++14")
|
||||
find_package(Boost 1.61.0 REQUIRED)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
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)
|
||||
|
||||
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)
|
297
modules/drogon/drogon/drogon_ctl/templates/config.csp
Normal file
297
modules/drogon/drogon/drogon_ctl/templates/config.csp
Normal file
@ -0,0 +1,297 @@
|
||||
/* 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.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.0 by default, in seconds, the timeout for executing a SQL query.
|
||||
//zero or negative value means no timeout.
|
||||
"timeout": -1.0
|
||||
}
|
||||
],
|
||||
"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,
|
||||
//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,
|
||||
//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"
|
||||
],
|
||||
//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": "",
|
||||
//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": {
|
||||
//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"
|
||||
},
|
||||
//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
|
||||
},
|
||||
//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": {}
|
||||
}
|
10
modules/drogon/drogon/drogon_ctl/templates/demoMain.csp
Normal file
10
modules/drogon/drogon/drogon_ctl/templates/demoMain.csp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <drogon/drogon.h>
|
||||
int main() {
|
||||
//Set HTTP listener address and port
|
||||
drogon::app().addListener("0.0.0.0",80);
|
||||
//Load config file
|
||||
//drogon::app().loadConfigFile("../config.json");
|
||||
//Run HTTP framework,the method will block in the internal event loop
|
||||
drogon::app().run();
|
||||
return 0;
|
||||
}
|
30
modules/drogon/drogon/drogon_ctl/templates/filter_cc.csp
Normal file
30
modules/drogon/drogon/drogon_ctl/templates/filter_cc.csp
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
modules/drogon/drogon/drogon_ctl/templates/filter_h.csp
Normal file
32
modules/drogon/drogon/drogon_ctl/templates/filter_h.csp
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]]() {}
|
||||
virtual void doFilter(const HttpRequestPtr &req,
|
||||
FilterCallback &&fcb,
|
||||
FilterChainCallback &&fccb) override;
|
||||
};
|
||||
|
||||
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
|
||||
}
|
||||
<%c++}%>
|
561
modules/drogon/drogon/drogon_ctl/templates/gitignore.csp
Normal file
561
modules/drogon/drogon/drogon_ctl/templates/gitignore.csp
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++
|
1732
modules/drogon/drogon/drogon_ctl/templates/model_cc.csp
Normal file
1732
modules/drogon/drogon/drogon_ctl/templates/model_cc.csp
Normal file
File diff suppressed because it is too large
Load Diff
558
modules/drogon/drogon/drogon_ctl/templates/model_h.csp
Normal file
558
modules/drogon/drogon/drogon_ctl/templates/model_h.csp
Normal file
@ -0,0 +1,558 @@
|
||||
<%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>
|
||||
#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 <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace drogon::orm;
|
||||
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 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(), ' ');
|
||||
%>
|
||||
void get{%alias%}(const DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||
{%alind%} const ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||
{%relationshipClassInde%} const 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(), ' ');
|
||||
%>
|
||||
void get{%alias%}(const DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||
{%alind%} const ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||
{%relationshipClassInde%} const 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(), ' ');
|
||||
%>
|
||||
void get{%alias%}(const DbClientPtr &clientPtr,
|
||||
{%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||
{%alind%} const ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||
%>
|
||||
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||
{%relationshipClassInde%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
|
||||
<%c++
|
||||
}
|
||||
}
|
||||
}
|
||||
%>
|
||||
private:
|
||||
friend Mapper<[[className]]>;
|
||||
#ifdef __cpp_impl_coroutine
|
||||
friend 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 = sprintf(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
modules/drogon/drogon/drogon_ctl/templates/model_json.csp
Normal file
104
modules/drogon/drogon/drogon_ctl/templates/model_json.csp
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
modules/drogon/drogon/drogon_ctl/templates/plugin_cc.csp
Normal file
23
modules/drogon/drogon/drogon_ctl/templates/plugin_cc.csp
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
modules/drogon/drogon/drogon_ctl/templates/plugin_h.csp
Normal file
35
modules/drogon/drogon/drogon_ctl/templates/plugin_h.csp
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.
|
||||
virtual 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.
|
||||
virtual void shutdown() override;
|
||||
};
|
||||
|
||||
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
|
||||
}
|
||||
<%c++}%>
|
@ -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++
|
||||
}
|
||||
}
|
||||
%>
|
||||
});
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
<%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_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";
|
||||
}
|
||||
%>
|
@ -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)
|
||||
{
|
||||
}
|
@ -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));
|
||||
}
|
@ -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";
|
||||
}
|
||||
%>
|
@ -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";
|
||||
}
|
||||
%>
|
67
modules/drogon/drogon/drogon_ctl/version.cc
Normal file
67
modules/drogon/drogon/drogon_ctl/version.cc
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
*
|
||||
* 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 <trantor/net/Resolver.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace drogon_ctl;
|
||||
static const char banner[] =
|
||||
" _ \n"
|
||||
" __| |_ __ ___ __ _ ___ _ __ \n"
|
||||
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
|
||||
"| (_| | | | (_) | (_| | (_) | | | |\n"
|
||||
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
|
||||
" |___/ \n";
|
||||
|
||||
void version::handleCommand(std::vector<std::string> ¶meters)
|
||||
{
|
||||
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") << " (batch mode: "
|
||||
<< (LIBPQ_SUPPORTS_BATCH_MODE ? "yes)\n" : "no)\n")
|
||||
<< " mariadb: " << (USE_MYSQL ? "yes\n" : "no\n")
|
||||
<< " sqlite3: " << (USE_SQLITE3 ? "yes\n" : "no\n");
|
||||
#ifdef OpenSSL_FOUND
|
||||
std::cout << " openssl: yes\n";
|
||||
#else
|
||||
std::cout << " openssl: no\n";
|
||||
#endif
|
||||
#ifdef USE_BROTLI
|
||||
std::cout << " brotli: yes\n";
|
||||
#else
|
||||
std::cout << " brotli: no\n";
|
||||
#endif
|
||||
#ifdef Boost_FOUND
|
||||
std::cout << " boost: yes\n";
|
||||
#else
|
||||
std::cout << " boost: no\n";
|
||||
#endif
|
||||
#ifdef USE_REDIS
|
||||
std::cout << " hiredis: yes\n";
|
||||
#else
|
||||
std::cout << " hiredis: no\n";
|
||||
#endif
|
||||
std::cout << " c-ares: "
|
||||
<< (trantor::Resolver::isCAresUsed() ? "yes\n" : "no\n");
|
||||
}
|
38
modules/drogon/drogon/drogon_ctl/version.h
Normal file
38
modules/drogon/drogon/drogon_ctl/version.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
*
|
||||
* 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:
|
||||
virtual void handleCommand(std::vector<std::string> ¶meters) override;
|
||||
virtual std::string script() override
|
||||
{
|
||||
return "display version of this tool";
|
||||
}
|
||||
virtual bool isTopCommand() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
version()
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace drogon_ctl
|
35
modules/drogon/drogon/examples/CMakeLists.txt
Executable file
35
modules/drogon/drogon/examples/CMakeLists.txt
Executable file
@ -0,0 +1,35 @@
|
||||
link_libraries(${PROJECT_NAME})
|
||||
|
||||
set(benchmark_sources benchmark/BenchmarkCtrl.cc benchmark/JsonCtrl.cc
|
||||
benchmark/main.cc)
|
||||
|
||||
add_executable(client client_example/main.cc)
|
||||
add_executable(websocket_client websocket_client/WebSocketClient.cc)
|
||||
add_executable(benchmark ${benchmark_sources})
|
||||
add_executable(helloworld helloworld/main.cc
|
||||
helloworld/HelloController.cc
|
||||
helloworld/HelloViewController.cc)
|
||||
drogon_create_views(helloworld
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/helloworld
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_executable(file_upload file_upload/file_upload.cc)
|
||||
drogon_create_views(file_upload
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/file_upload
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_executable(login_session login_session/main.cc)
|
||||
drogon_create_views(login_session
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/login_session
|
||||
${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(example_targets
|
||||
benchmark
|
||||
client
|
||||
websocket_client
|
||||
helloworld
|
||||
file_upload
|
||||
login_session)
|
||||
|
||||
set_property(TARGET ${example_targets}
|
||||
PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD})
|
||||
set_property(TARGET ${example_targets} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
set_property(TARGET ${example_targets} PROPERTY CXX_EXTENSIONS OFF)
|
21
modules/drogon/drogon/examples/README.md
Normal file
21
modules/drogon/drogon/examples/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Drogon Examples
|
||||
|
||||
The following examples can help you understand how to use Drogon:
|
||||
|
||||
1. [helloworld](https://github.com/an-tao/drogon/tree/master/examples/helloworld) - The multuple ways of "Hello, World!"
|
||||
2. [client_example](https://github.com/an-tao/drogon/tree/master/examples/client_example/main.cc) - A client example.
|
||||
3. [websocket_client](https://github.com/an-tao/drogon/tree/master/examples/websocket_client/WebSocketClient.cc) - An example on how to use the WebSocket client
|
||||
4. [login_session](https://github.com/an-tao/drogon/tree/master/examples/login_session) - How to use the built-in session system to handle login and out
|
||||
5. [file_upload](https://github.com/an-tao/drogon/tree/master/examples/file_upload) - How to handle file uploads in Drogon
|
||||
6. [simple_reverse_proxy](https://github.com/an-tao/drogon/tree/master/examples/simple_reverse_proxy) - A Example showing how to use drogon as a http reverse
|
||||
proxy with a simple round robin.
|
||||
7. [benchmark](https://github.com/an-tao/drogon/tree/master/examples/benchmark) - Basic benchmark example. see [wiki benchmarks](https://github.com/an-tao/drogon/wiki/13-Benchmarks)
|
||||
|
||||
|
||||
### [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) test suite
|
||||
|
||||
I created a benchmark suite for the `tfb`, see [here](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/C%2B%2B/drogon) for details.
|
||||
|
||||
### Another test suite
|
||||
|
||||
I also created a test suite for another web frameworks benchmark repository, see [here](https://github.com/the-benchmarker/web-frameworks/tree/master/cpp/drogon), in this project, drogon is used as a sub-module (locally include in the project).
|
11
modules/drogon/drogon/examples/benchmark/BenchmarkCtrl.cc
Normal file
11
modules/drogon/drogon/examples/benchmark/BenchmarkCtrl.cc
Normal file
@ -0,0 +1,11 @@
|
||||
#include "BenchmarkCtrl.h"
|
||||
void BenchmarkCtrl::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);
|
||||
}
|
13
modules/drogon/drogon/examples/benchmark/BenchmarkCtrl.h
Normal file
13
modules/drogon/drogon/examples/benchmark/BenchmarkCtrl.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class BenchmarkCtrl : public drogon::HttpSimpleController<BenchmarkCtrl>
|
||||
{
|
||||
public:
|
||||
virtual void asyncHandleHttpRequest(
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||
PATH_LIST_BEGIN
|
||||
PATH_ADD("/benchmark", Get);
|
||||
PATH_LIST_END
|
||||
};
|
10
modules/drogon/drogon/examples/benchmark/JsonCtrl.cc
Normal file
10
modules/drogon/drogon/examples/benchmark/JsonCtrl.cc
Normal file
@ -0,0 +1,10 @@
|
||||
#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);
|
||||
}
|
14
modules/drogon/drogon/examples/benchmark/JsonCtrl.h
Normal file
14
modules/drogon/drogon/examples/benchmark/JsonCtrl.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
using namespace drogon;
|
||||
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
||||
{
|
||||
public:
|
||||
virtual 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
|
||||
};
|
22
modules/drogon/drogon/examples/benchmark/main.cc
Normal file
22
modules/drogon/drogon/examples/benchmark/main.cc
Normal file
@ -0,0 +1,22 @@
|
||||
#include <drogon/drogon.h>
|
||||
|
||||
using namespace drogon;
|
||||
int main()
|
||||
{
|
||||
app()
|
||||
.setLogPath("./")
|
||||
.setLogLevel(trantor::Logger::kWarn)
|
||||
.addListener("0.0.0.0", 7770)
|
||||
.setThreadNum(0)
|
||||
.registerSyncAdvice([](const HttpRequestPtr &req) -> HttpResponsePtr {
|
||||
const auto &path = req->path();
|
||||
if (path.length() == 1 && path[0] == '/')
|
||||
{
|
||||
auto response = HttpResponse::newHttpResponse();
|
||||
response->setBody("<p>Hello, world!</p>");
|
||||
return response;
|
||||
}
|
||||
return nullptr;
|
||||
})
|
||||
.run();
|
||||
}
|
42
modules/drogon/drogon/examples/client_example/main.cc
Normal file
42
modules/drogon/drogon/examples/client_example/main.cc
Normal file
@ -0,0 +1,42 @@
|
||||
#include <drogon/drogon.h>
|
||||
#include <iostream>
|
||||
#include <future>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
int nth_resp = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
|
||||
{
|
||||
auto client = HttpClient::newHttpClient("http://www.baidu.com");
|
||||
auto req = HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Get);
|
||||
req->setPath("/s");
|
||||
req->setParameter("wd", "wx");
|
||||
req->setParameter("oq", "wx");
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
client->sendRequest(
|
||||
req, [](ReqResult result, const HttpResponsePtr &response) {
|
||||
std::cout << "receive response!" << std::endl;
|
||||
// auto headers=response.
|
||||
++nth_resp;
|
||||
std::cout << response->getBody() << std::endl;
|
||||
auto cookies = response->cookies();
|
||||
for (auto const &cookie : cookies)
|
||||
{
|
||||
std::cout << cookie.first << "="
|
||||
<< cookie.second.value()
|
||||
<< ":domain=" << cookie.second.domain()
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << "count=" << nth_resp << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
app().run();
|
||||
}
|
83
modules/drogon/drogon/examples/file_upload/FileUpload.csp
Normal file
83
modules/drogon/drogon/examples/file_upload/FileUpload.csp
Normal file
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>File upload</title>
|
||||
<script type="text/javascript">
|
||||
var xhr;
|
||||
//File uploading method
|
||||
function UpladFile() {
|
||||
var fileObj = document.getElementById("file").files[0]; // js get file object
|
||||
var url = "/upload_endpoint";
|
||||
|
||||
var form = new FormData(); // FormData object
|
||||
form.append("file", fileObj); // File object
|
||||
|
||||
xhr = new XMLHttpRequest(); // XMLHttpRequest object
|
||||
xhr.open("post", url, true); //post
|
||||
xhr.onload = uploadComplete;
|
||||
xhr.onerror = uploadFailed;
|
||||
|
||||
xhr.upload.onprogress = progressFunction;
|
||||
xhr.upload.onloadstart = function(){
|
||||
ot = new Date().getTime();
|
||||
oloaded = 0;
|
||||
};
|
||||
|
||||
xhr.send(form);
|
||||
}
|
||||
|
||||
function uploadComplete(evt) {
|
||||
var data = evt.target.responseText;
|
||||
alert("File have been uploaded.\n" + data);
|
||||
}
|
||||
|
||||
function uploadFailed(evt) {
|
||||
alert("Upload failed!");
|
||||
}
|
||||
|
||||
function cancleUploadFile(){
|
||||
xhr.abort();
|
||||
}
|
||||
|
||||
function progressFunction(evt) {
|
||||
var progressBar = document.getElementById("progressBar");
|
||||
var percentageDiv = document.getElementById("percentage");
|
||||
if (evt.lengthComputable) {//
|
||||
progressBar.max = evt.total;
|
||||
progressBar.value = evt.loaded;
|
||||
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
|
||||
}
|
||||
var time = document.getElementById("time");
|
||||
var nt = new Date().getTime();
|
||||
var pertime = (nt-ot)/1000;
|
||||
ot = new Date().getTime();
|
||||
var perload = evt.loaded - oloaded;
|
||||
oloaded = evt.loaded;
|
||||
var speed = perload/pertime;
|
||||
var bspeed = speed;
|
||||
var units = 'b/s';
|
||||
if(speed/1024>1){
|
||||
speed = speed/1024;
|
||||
units = 'k/s';
|
||||
}
|
||||
if(speed/1024>1){
|
||||
speed = speed/1024;
|
||||
units = 'M/s';
|
||||
}
|
||||
speed = speed.toFixed(1);
|
||||
var resttime = ((evt.total-evt.loaded)/bspeed).toFixed(1);
|
||||
time.innerHTML = ',Speed: '+speed+units+', the remaining time: '+resttime+'s';
|
||||
if(bspeed==0) time.innerHTML = 'Upload cancelled';
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
|
||||
<span id="percentage"></span><span id="time"></span>
|
||||
<br /><br />
|
||||
<input type="file" id="file" name="myfile" />
|
||||
<input type="button" onclick="UpladFile()" value="Upload" />
|
||||
<input type="button" onclick="cancleUploadFile()" value="Cancel" />
|
||||
</body>
|
||||
</html>
|
46
modules/drogon/drogon/examples/file_upload/file_upload.cc
Normal file
46
modules/drogon/drogon/examples/file_upload/file_upload.cc
Normal file
@ -0,0 +1,46 @@
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
|
||||
int main()
|
||||
{
|
||||
app().registerHandler(
|
||||
"/",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
auto resp = HttpResponse::newHttpViewResponse("FileUpload");
|
||||
callback(resp);
|
||||
});
|
||||
|
||||
app().registerHandler(
|
||||
"/upload_endpoint",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
MultiPartParser fileUpload;
|
||||
if (fileUpload.parse(req) != 0 || fileUpload.getFiles().size() != 1)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("Must only be 1 file");
|
||||
resp->setStatusCode(k403Forbidden);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &file = fileUpload.getFiles()[0];
|
||||
auto md5 = file.getMd5();
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody(
|
||||
"The server has calculated the file's MD5 hash to be " + md5);
|
||||
file.save();
|
||||
LOG_INFO << "The uploaded file have been saved to the ./uploads "
|
||||
"directory";
|
||||
callback(resp);
|
||||
},
|
||||
{Post});
|
||||
|
||||
LOG_INFO << "Server running on 127.0.0.1:8848";
|
||||
app()
|
||||
.setClientMaxBodySize(20 * 2000 * 2000)
|
||||
.setUploadPath("./uploads")
|
||||
.addListener("127.0.0.1", 8848)
|
||||
.run();
|
||||
}
|
40
modules/drogon/drogon/examples/helloworld/HelloController.cc
Normal file
40
modules/drogon/drogon/examples/helloworld/HelloController.cc
Normal file
@ -0,0 +1,40 @@
|
||||
#include <drogon/HttpController.h>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
// HttpControllers are automatically added to Drogon upon Drogon initializing.
|
||||
class SayHello : public HttpController<SayHello>
|
||||
{
|
||||
public:
|
||||
METHOD_LIST_BEGIN
|
||||
// Drogon automatically appends the namespce and name of the controller to
|
||||
// the handlers of the controller. In this example, although we are adding
|
||||
// a handler to /. But because it is a part of the SayHello controller. It
|
||||
// ends up in path /SayHello/ (IMOPRTANT! It is /SayHello/ not /SayHello
|
||||
// they are different paths).
|
||||
METHOD_ADD(SayHello::genericHello, "/", Get);
|
||||
// Same for /hello. It ends up at /SayHello/hello
|
||||
METHOD_ADD(SayHello::personalizedHello, "/hello", Get);
|
||||
METHOD_LIST_END
|
||||
|
||||
protected:
|
||||
void genericHello(const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody(
|
||||
"Hello, this is a generic hello message from the SayHello "
|
||||
"controller");
|
||||
callback(resp);
|
||||
}
|
||||
|
||||
void personalizedHello(
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody(
|
||||
"Hi there, this is another hello from the SayHello Controller");
|
||||
callback(resp);
|
||||
}
|
||||
};
|
24
modules/drogon/drogon/examples/helloworld/HelloView.csp
Normal file
24
modules/drogon/drogon/examples/helloworld/HelloView.csp
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<%c++
|
||||
auto name=@@.get<std::string>("name");
|
||||
bool nameIsEmpty = name == "";
|
||||
if (nameIsEmpty)
|
||||
name = "anonymous";
|
||||
auto message = "Hello, " + name + " from a CSP template";
|
||||
%>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>[[ name ]]</title>
|
||||
</head>
|
||||
<body>
|
||||
<%c++ $$<<message; %>
|
||||
<%c++
|
||||
if (nameIsEmpty)
|
||||
{
|
||||
$$ << "<br>"
|
||||
<< "You can revisit the same page and append ?name=<i>your_name</i> to change the name";
|
||||
}
|
||||
%>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,29 @@
|
||||
#include <drogon/HttpSimpleController.h>
|
||||
#include <drogon/HttpResponse.h>
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
// HttpSimpleController does not allow registration of multiple handlers.
|
||||
// Instead, it has one handler - asyncHandleHttpRequest. The
|
||||
// HttpSimpleController is a lightweight class designed to handle really simple
|
||||
// cases.
|
||||
class HelloViewController : public HttpSimpleController<HelloViewController>
|
||||
{
|
||||
public:
|
||||
PATH_LIST_BEGIN
|
||||
// Also unlike HttpContoller, HttpSimpleController does not automatically
|
||||
// prepend the namespace and class name to the path. Thus the path of this
|
||||
// controller is at "/view".
|
||||
PATH_ADD("/view")
|
||||
PATH_LIST_END
|
||||
|
||||
void asyncHandleHttpRequest(
|
||||
const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) override
|
||||
{
|
||||
HttpViewData data;
|
||||
data["name"] = req->getParameter("name");
|
||||
auto resp = HttpResponse::newHttpViewResponse("HelloView", data);
|
||||
callback(resp);
|
||||
}
|
||||
};
|
70
modules/drogon/drogon/examples/helloworld/main.cc
Normal file
70
modules/drogon/drogon/examples/helloworld/main.cc
Normal file
@ -0,0 +1,70 @@
|
||||
#include <drogon/drogon.h>
|
||||
using namespace drogon;
|
||||
|
||||
int main()
|
||||
{
|
||||
// `registerHandler()` adds a handler to the desired path. The handler is
|
||||
// responsible for generating a HTTP response upon an HTTP request being
|
||||
// sent to Drogon
|
||||
app().registerHandler(
|
||||
"/",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("Hello, World!");
|
||||
callback(resp);
|
||||
},
|
||||
{Get});
|
||||
|
||||
// `registrHandler()` also supports parsing and passing the path as
|
||||
// parameters to the handler. Parameters are specified using {}. The text
|
||||
// indide {} does not correspond to the index of parameter passed to the
|
||||
// handler (nor it has any meaning). Instead, it is only to make it easier
|
||||
// for users to recognize the function of each parameter.
|
||||
app().registerHandler(
|
||||
"/user/{user-name}",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const std::string &name) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("Hello, " + name + "!");
|
||||
callback(resp);
|
||||
},
|
||||
{Get});
|
||||
|
||||
// You can aslo specsify that the parameter is in the query section of the
|
||||
// URL!
|
||||
app().registerHandler(
|
||||
"/hello?user={user-name}",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||
const std::string &name) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setBody("Hello, " + name + "!");
|
||||
callback(resp);
|
||||
},
|
||||
{Get});
|
||||
|
||||
// Or, if you want to, instead of asking drogon to parse it fot you. You can
|
||||
// parse the request yourselves.
|
||||
app().registerHandler(
|
||||
"/hello_user",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
std::string name = req->getParameter("user");
|
||||
if (name == "")
|
||||
resp->setBody("Please tell me your name");
|
||||
else
|
||||
resp->setBody("Hello, " + name + "!");
|
||||
callback(resp);
|
||||
},
|
||||
{Get});
|
||||
|
||||
// Ask Drogon to listern on 127.0.0.1 port 8848. Drogon supports listerning
|
||||
// on multuiple IP addresses by adding multiple listeners. For example, if
|
||||
// you want the server also Listen on 127.0.0.1 port 5555. Just add another
|
||||
// line of addListener("127.0.0.1", 5555)
|
||||
LOG_INFO << "Server running on 127.0.0.1:8848";
|
||||
app().addListener("127.0.0.1", 8848).run();
|
||||
}
|
22
modules/drogon/drogon/examples/login_session/LoginPage.csp
Normal file
22
modules/drogon/drogon/examples/login_session/LoginPage.csp
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>session example</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/login" method="post">
|
||||
<div class="container">
|
||||
<label for="user"><b>Username</b></label>
|
||||
<input type="text" placeholder="Enter Username" name="user" required>
|
||||
|
||||
<label for="passwd"><b>Password</b></label>
|
||||
<input type="password" placeholder="Enter Password" name="passwd" required>
|
||||
|
||||
<button type="submit">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p>Please login with the credential<br>Username: user<br>Password: password123</p>
|
||||
</body>
|
||||
</html>
|
16
modules/drogon/drogon/examples/login_session/LogoutPage.csp
Normal file
16
modules/drogon/drogon/examples/login_session/LogoutPage.csp
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>session example</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/logout" method="post">
|
||||
<div class="container">
|
||||
<button type="submit">Logout</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p>You can logout now</p>
|
||||
</body>
|
||||
</html>
|
67
modules/drogon/drogon/examples/login_session/main.cc
Normal file
67
modules/drogon/drogon/examples/login_session/main.cc
Normal file
@ -0,0 +1,67 @@
|
||||
#include <drogon/drogon.h>
|
||||
#include <chrono>
|
||||
using namespace drogon;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
app().registerHandler(
|
||||
"/",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
bool logined =
|
||||
req->session()->getOptional<bool>("logined").value_or(false);
|
||||
HttpResponsePtr resp;
|
||||
if (logined == false)
|
||||
resp = HttpResponse::newHttpViewResponse("LoginPage");
|
||||
else
|
||||
resp = HttpResponse::newHttpViewResponse("LogoutPage");
|
||||
callback(resp);
|
||||
});
|
||||
|
||||
app().registerHandler(
|
||||
"/logout",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
HttpResponsePtr resp = HttpResponse::newHttpResponse();
|
||||
req->session()->erase("logined");
|
||||
resp->setBody("<script>window.location.href = \"/\";</script>");
|
||||
callback(resp);
|
||||
},
|
||||
{Post});
|
||||
|
||||
app().registerHandler(
|
||||
"/login",
|
||||
[](const HttpRequestPtr &req,
|
||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||
HttpResponsePtr resp = HttpResponse::newHttpResponse();
|
||||
std::string user = req->getParameter("user");
|
||||
std::string passwd = req->getParameter("passwd");
|
||||
|
||||
// NOTE: Do not, ever, use MD5 for password hash. We only use it
|
||||
// because Drogon is not a cryptography library, so deosn't come
|
||||
// with a better hash. Use Argon2 or BCrypt in a real product.
|
||||
// username: user, pasword: password123
|
||||
if (user == "user" && utils::getMd5("jadsjhdsajkh" + passwd) ==
|
||||
"5B5299CF4CEAE2D523315694B82573C9")
|
||||
{
|
||||
req->session()->insert("logined", true);
|
||||
resp->setBody("<script>window.location.href = \"/\";</script>");
|
||||
callback(resp);
|
||||
}
|
||||
else
|
||||
{
|
||||
resp->setStatusCode(k401Unauthorized);
|
||||
resp->setBody("<script>window.location.href = \"/\";</script>");
|
||||
callback(resp);
|
||||
}
|
||||
},
|
||||
{Post});
|
||||
|
||||
LOG_INFO << "Server running on 127.0.0.1:8848";
|
||||
app()
|
||||
// All sessions are good for 24 Hrs
|
||||
.enableSession(24h)
|
||||
.addListener("127.0.0.1", 8848)
|
||||
.run();
|
||||
}
|
36
modules/drogon/drogon/examples/simple_reverse_proxy/.gitignore
vendored
Normal file
36
modules/drogon/drogon/examples/simple_reverse_proxy/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
# 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
|
||||
.idea
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user