mirror of
https://github.com/drogonframework/drogon.git
synced 2025-06-25 00:01:17 -04:00
Compare commits
No commits in common. "master" and "v1.9.0" have entirely different histories.
@ -75,7 +75,6 @@ IndentCaseLabels: true
|
|||||||
IndentPPDirectives: None
|
IndentPPDirectives: None
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
InsertNewlineAtEOF: true
|
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
JavaScriptWrapImports: true
|
JavaScriptWrapImports: true
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
83
.github/workflows/cmake.yml
vendored
83
.github/workflows/cmake.yml
vendored
@ -17,7 +17,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
windows:
|
windows:
|
||||||
name: windows/msvc - ${{ matrix.link }}
|
name: windows/msvc - ${{ matrix.link }}
|
||||||
runs-on: windows-2022
|
runs-on: windows-2019
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@ -53,7 +53,6 @@ jobs:
|
|||||||
-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" \
|
-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" \
|
||||||
-DBUILD_CTL=ON \
|
-DBUILD_CTL=ON \
|
||||||
-DBUILD_EXAMPLES=ON \
|
-DBUILD_EXAMPLES=ON \
|
||||||
-DUSE_SPDLOG=ON \
|
|
||||||
-DCMAKE_INSTALL_PREFIX=../install \
|
-DCMAKE_INSTALL_PREFIX=../install \
|
||||||
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW \
|
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW \
|
||||||
-DCMAKE_CXX_STANDARD=17
|
-DCMAKE_CXX_STANDARD=17
|
||||||
@ -66,11 +65,8 @@ jobs:
|
|||||||
run: ./test.sh -w
|
run: ./test.sh -w
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-${{ matrix.osver }}
|
name: macos/clang
|
||||||
strategy:
|
runs-on: macos-latest
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
osver: [13, 14, 15]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Drogon source code
|
- name: Checkout Drogon source code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -79,8 +75,8 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
# Already installed: brotli, zlib, lz4, sqlite3
|
# Already installed: brotli, zlib, postgresql@14, lz4, sqlite3
|
||||||
run: brew install ninja jsoncpp mariadb hiredis redis spdlog postgresql@14
|
run: brew install ninja jsoncpp mariadb hiredis redis
|
||||||
|
|
||||||
- name: Create Build Environment & Configure Cmake
|
- name: Create Build Environment & Configure Cmake
|
||||||
# Some projects don't allow in-source building, so create a separate build directory
|
# Some projects don't allow in-source building, so create a separate build directory
|
||||||
@ -89,7 +85,6 @@ jobs:
|
|||||||
cmake -B build -G Ninja \
|
cmake -B build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DBUILD_TESTING=on \
|
-DBUILD_TESTING=on \
|
||||||
-DUSE_SPDLOG=ON \
|
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
-DBUILD_SHARED_LIBS=OFF
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
@ -99,6 +94,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Prepare for testing
|
- name: Prepare for testing
|
||||||
run: |
|
run: |
|
||||||
|
brew tap homebrew/services
|
||||||
brew services restart postgresql@14
|
brew services restart postgresql@14
|
||||||
brew services start mariadb
|
brew services start mariadb
|
||||||
brew services start redis
|
brew services start redis
|
||||||
@ -116,44 +112,18 @@ jobs:
|
|||||||
run: ./test.sh -t
|
run: ./test.sh -t
|
||||||
|
|
||||||
ubuntu:
|
ubuntu:
|
||||||
|
name: ${{ matrix.buildname }}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
link: [SHARED, STATIC]
|
|
||||||
compiler:
|
|
||||||
- cxx: g++
|
|
||||||
ver: 9
|
|
||||||
- cxx: g++
|
|
||||||
ver: 10
|
|
||||||
- cxx: g++
|
|
||||||
ver: 11
|
|
||||||
- cxx: g++
|
|
||||||
ver: 12
|
|
||||||
- cxx: g++
|
|
||||||
ver: 13
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 11
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 12
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 13
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 14
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 15
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 16
|
|
||||||
- cxx: clang++
|
|
||||||
ver: 17
|
|
||||||
include:
|
include:
|
||||||
- link: STATIC
|
- buildname: "ubuntu-22.04/gcc"
|
||||||
compiler:
|
link: SHARED
|
||||||
cxx: g++
|
- buildname: "ubuntu-22.04/gcc"
|
||||||
ver: 13
|
link: STATIC
|
||||||
feature: coroutines
|
- buildname: "ubuntu-22.04/coroutines"
|
||||||
env:
|
link: STATIC
|
||||||
CXX: ${{ matrix.compiler.cxx }}-${{ matrix.compiler.ver }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Drogon source code
|
- name: Checkout Drogon source code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -168,31 +138,12 @@ jobs:
|
|||||||
# These aren't available or don't work well in vcpkg
|
# These aren't available or don't work well in vcpkg
|
||||||
sudo apt-get install -y libjsoncpp-dev uuid-dev libssl-dev zlib1g-dev libsqlite3-dev
|
sudo apt-get install -y libjsoncpp-dev uuid-dev libssl-dev zlib1g-dev libsqlite3-dev
|
||||||
sudo apt-get install -y ninja-build libbrotli-dev
|
sudo apt-get install -y ninja-build libbrotli-dev
|
||||||
sudo apt-get install -y libspdlog-dev
|
|
||||||
|
|
||||||
- name: Install postgresql
|
- name: Install postgresql
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get --purge remove postgresql postgresql-doc postgresql-common postgresql-client-common
|
sudo apt-get --purge remove postgresql postgresql-doc postgresql-common postgresql-client-common
|
||||||
sudo apt-get -y install postgresql-all
|
sudo apt-get -y install postgresql-all
|
||||||
|
|
||||||
- name: Install g++-13
|
|
||||||
if: startsWith(matrix.compiler.cxx, 'g++') && matrix.compiler.ver == 13
|
|
||||||
run: |
|
|
||||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
|
||||||
sudo apt-get install g++-${{ matrix.compiler.ver }}
|
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
|
|
||||||
|
|
||||||
- name: Install Clang
|
|
||||||
if: startsWith(matrix.compiler.cxx, 'clang') && matrix.compiler.ver < 13
|
|
||||||
run: sudo apt-get install clang-${{ matrix.compiler.ver }}
|
|
||||||
|
|
||||||
- name: Install Clang
|
|
||||||
if: startsWith(matrix.compiler.cxx, 'clang') && matrix.compiler.ver >= 13
|
|
||||||
run: |
|
|
||||||
wget https://apt.llvm.org/llvm.sh
|
|
||||||
chmod +x ./llvm.sh
|
|
||||||
sudo ./llvm.sh ${{ matrix.compiler.ver }}
|
|
||||||
|
|
||||||
- name: Export `shared`
|
- name: Export `shared`
|
||||||
run: |
|
run: |
|
||||||
[[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF"
|
[[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF"
|
||||||
@ -201,24 +152,22 @@ jobs:
|
|||||||
- name: Create Build Environment & Configure Cmake
|
- name: Create Build Environment & Configure Cmake
|
||||||
# Some projects don't allow in-source building, so create a separate build directory
|
# Some projects don't allow in-source building, so create a separate build directory
|
||||||
# We'll use this as our working directory for all subsequent commands
|
# We'll use this as our working directory for all subsequent commands
|
||||||
if: matrix.compiler.feature != 'coroutines'
|
if: matrix.buildname != 'ubuntu-22.04/coroutines'
|
||||||
run: |
|
run: |
|
||||||
cmake -B build -G Ninja \
|
cmake -B build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DBUILD_TESTING=on \
|
-DBUILD_TESTING=on \
|
||||||
-DUSE_SPDLOG=ON \
|
|
||||||
-DBUILD_SHARED_LIBS=$shared
|
-DBUILD_SHARED_LIBS=$shared
|
||||||
- name: Create Build Environment & Configure Cmake (coroutines)
|
- name: Create Build Environment & Configure Cmake (coroutines)
|
||||||
# Some projects don't allow in-source building, so create a separate build directory
|
# Some projects don't allow in-source building, so create a separate build directory
|
||||||
# We'll use this as our working directory for all subsequent commands
|
# We'll use this as our working directory for all subsequent commands
|
||||||
if: matrix.compiler.feature == 'coroutines'
|
if: matrix.buildname == 'ubuntu-22.04/coroutines'
|
||||||
run: |
|
run: |
|
||||||
cmake -B build -G Ninja \
|
cmake -B build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DBUILD_TESTING=on \
|
-DBUILD_TESTING=on \
|
||||||
-DUSE_SPDLOG=ON \
|
|
||||||
-DCMAKE_CXX_FLAGS="-fcoroutines" \
|
-DCMAKE_CXX_FLAGS="-fcoroutines" \
|
||||||
-DBUILD_SHARED_LIBS=$shared \
|
-DBUILD_SHARED_LIBS=$shared
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ./build
|
working-directory: ./build
|
||||||
|
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@ -60,7 +60,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@ -75,6 +75,6 @@ jobs:
|
|||||||
run: ninja && sudo ninja install
|
run: ninja && sudo ninja install
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v2
|
||||||
with:
|
with:
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
|
15
.github/workflows/codespell.yml
vendored
15
.github/workflows/codespell.yml
vendored
@ -1,15 +0,0 @@
|
|||||||
# Look for typos in the codebase using codespell.
|
|
||||||
# https://github.com/codespell-project/codespell#readme
|
|
||||||
name: codespell
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
pull_request:
|
|
||||||
branches: [master]
|
|
||||||
jobs:
|
|
||||||
codespell:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- run: sudo apt-get install -y codespell
|
|
||||||
- run: codespell --ignore-words-list="coo,folx,ot,statics,xwindows,NotIn,aNULL," --skip="*.csp"
|
|
20
.github/workflows/cpp.yml
vendored
20
.github/workflows/cpp.yml
vendored
@ -17,25 +17,5 @@ jobs:
|
|||||||
- name: Install dos2unix
|
- name: Install dos2unix
|
||||||
run: sudo apt-get install -y dos2unix
|
run: sudo apt-get install -y dos2unix
|
||||||
|
|
||||||
- name: Install clang-format-17
|
|
||||||
run: |
|
|
||||||
wget https://apt.llvm.org/llvm.sh
|
|
||||||
chmod +x ./llvm.sh
|
|
||||||
sudo ./llvm.sh 17
|
|
||||||
sudo apt-get install -y clang-format-17
|
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: ./format.sh && git diff --exit-code
|
run: ./format.sh && git diff --exit-code
|
||||||
env:
|
|
||||||
CLANG_FORMAT: clang-format-17
|
|
||||||
|
|
||||||
cpplint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install cpplint
|
|
||||||
run: pip install cpplint
|
|
||||||
|
|
||||||
- name: Run lint
|
|
||||||
run: cpplint --recursive .
|
|
||||||
|
28
.github/workflows/docker-publish.yml
vendored
28
.github/workflows/docker-publish.yml
vendored
@ -1,28 +0,0 @@
|
|||||||
name: Build and Push Docker Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [created] # 当新版本被创建时触发
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Build Docker image
|
|
||||||
run: |
|
|
||||||
cd docker/ubuntu
|
|
||||||
docker build -t drogonframework/drogon:latest .
|
|
||||||
|
|
||||||
- name: Push Docker image
|
|
||||||
run: |
|
|
||||||
docker push drogonframework/drogon:latest
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -35,6 +35,7 @@ build/
|
|||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
cmake-build-debug-visual-studio/
|
cmake-build-debug-visual-studio/
|
||||||
.idea/
|
.idea/
|
||||||
|
lib/inc/drogon/version.h
|
||||||
html/
|
html/
|
||||||
latex/
|
latex/
|
||||||
.vscode
|
.vscode
|
||||||
|
1
.gitmodules
vendored
1
.gitmodules
vendored
@ -1,4 +1,3 @@
|
|||||||
[submodule "trantor"]
|
[submodule "trantor"]
|
||||||
path = trantor
|
path = trantor
|
||||||
url = https://github.com/an-tao/trantor.git
|
url = https://github.com/an-tao/trantor.git
|
||||||
branch = master
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.5...3.31)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
project(drogon)
|
project(drogon)
|
||||||
|
|
||||||
@ -13,7 +13,6 @@ option(BUILD_DOC "Build Doxygen documentation" OFF)
|
|||||||
option(BUILD_BROTLI "Build Brotli" ON)
|
option(BUILD_BROTLI "Build Brotli" ON)
|
||||||
option(BUILD_YAML_CONFIG "Build yaml config" ON)
|
option(BUILD_YAML_CONFIG "Build yaml config" ON)
|
||||||
option(USE_SUBMODULE "Use trantor as a submodule" ON)
|
option(USE_SUBMODULE "Use trantor as a submodule" ON)
|
||||||
option(USE_STATIC_LIBS_ONLY "Use only static libraries as dependencies" OFF)
|
|
||||||
|
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
CMAKE_DEPENDENT_OPTION(BUILD_POSTGRESQL "Build with postgresql support" ON "BUILD_ORM" OFF)
|
CMAKE_DEPENDENT_OPTION(BUILD_POSTGRESQL "Build with postgresql support" ON "BUILD_ORM" OFF)
|
||||||
@ -21,11 +20,10 @@ CMAKE_DEPENDENT_OPTION(LIBPQ_BATCH_MODE "Use batch mode for libpq" ON "BUILD_POS
|
|||||||
CMAKE_DEPENDENT_OPTION(BUILD_MYSQL "Build with mysql support" ON "BUILD_ORM" 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_SQLITE "Build with sqlite3 support" ON "BUILD_ORM" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(BUILD_REDIS "Build with redis support" ON "BUILD_ORM" OFF)
|
CMAKE_DEPENDENT_OPTION(BUILD_REDIS "Build with redis support" ON "BUILD_ORM" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(USE_SPDLOG "Allow using the spdlog logging library" OFF "USE_SUBMODULE" OFF)
|
|
||||||
|
|
||||||
set(DROGON_MAJOR_VERSION 1)
|
set(DROGON_MAJOR_VERSION 1)
|
||||||
set(DROGON_MINOR_VERSION 9)
|
set(DROGON_MINOR_VERSION 9)
|
||||||
set(DROGON_PATCH_VERSION 11)
|
set(DROGON_PATCH_VERSION 0)
|
||||||
set(DROGON_VERSION
|
set(DROGON_VERSION
|
||||||
${DROGON_MAJOR_VERSION}.${DROGON_MINOR_VERSION}.${DROGON_PATCH_VERSION})
|
${DROGON_MAJOR_VERSION}.${DROGON_MINOR_VERSION}.${DROGON_PATCH_VERSION})
|
||||||
set(DROGON_VERSION_STRING "${DROGON_VERSION}")
|
set(DROGON_VERSION_STRING "${DROGON_VERSION}")
|
||||||
@ -42,15 +40,9 @@ set(INSTALL_DROGON_CMAKE_DIR ${DEF_INSTALL_DROGON_CMAKE_DIR}
|
|||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
# Force MSVC to use UTF-8 because that's what we use. Otherwise it uses
|
# 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.
|
# the default of whatever Windows sets and causes encoding issues.
|
||||||
message(STATUS "You are using MSVC. Forcing to use UTF-8")
|
message(STATUS "You are using MSVC. Forceing to use UTF-8")
|
||||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||||
if (MSVC_VERSION GREATER_EQUAL 1914)
|
|
||||||
# Tells Visual Studio 2017 (15.7+) and newer to correctly set the value of the standard __cplusplus macro,
|
|
||||||
# instead of leaving it to 199711L and settings the effective c++ version in _MSVC_LANG
|
|
||||||
# Dropping support for older versions of VS would allow to only rely on __cplusplus
|
|
||||||
add_compile_options("/Zc:__cplusplus")
|
|
||||||
endif()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library(${PROJECT_NAME})
|
add_library(${PROJECT_NAME})
|
||||||
@ -67,7 +59,7 @@ if (BUILD_SHARED_LIBS)
|
|||||||
SOVERSION ${DROGON_MAJOR_VERSION})
|
SOVERSION ${DROGON_MAJOR_VERSION})
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC rpcrt4 crypt32 advapi32 ws2_32)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Rpcrt4 ws2_32 crypt32 Advapi32)
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||||
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
|
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
|
||||||
# We export class to facilitate maintenance, thus if you compile
|
# We export class to facilitate maintenance, thus if you compile
|
||||||
@ -78,19 +70,6 @@ if (BUILD_SHARED_LIBS)
|
|||||||
endif ()
|
endif ()
|
||||||
endif (BUILD_SHARED_LIBS)
|
endif (BUILD_SHARED_LIBS)
|
||||||
|
|
||||||
if(USE_STATIC_LIBS_ONLY)
|
|
||||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
|
||||||
endif(USE_STATIC_LIBS_ONLY)
|
|
||||||
|
|
||||||
if(USE_SPDLOG)
|
|
||||||
find_package(spdlog CONFIG)
|
|
||||||
if(spdlog_FOUND)
|
|
||||||
message(STATUS "spdlog found!")
|
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog_header_only)
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC DROGON_SPDLOG_SUPPORT SPDLOG_FMT_EXTERNAL FMT_HEADER_ONLY)
|
|
||||||
endif(spdlog_FOUND)
|
|
||||||
endif(USE_SPDLOG)
|
|
||||||
|
|
||||||
if (NOT ${CMAKE_PLATFORM_NAME} STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
if (NOT ${CMAKE_PLATFORM_NAME} STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror)
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror)
|
||||||
endif ()
|
endif ()
|
||||||
@ -121,7 +100,6 @@ endif()
|
|||||||
target_include_directories(
|
target_include_directories(
|
||||||
${PROJECT_NAME}
|
${PROJECT_NAME}
|
||||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/inc>
|
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/inc>
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/lib/inc>
|
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/orm_lib/inc>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/orm_lib/inc>
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/nosql_lib/redis/inc>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/nosql_lib/redis/inc>
|
||||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
||||||
@ -147,7 +125,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
|||||||
elseif (NOT WIN32 AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
elseif (NOT WIN32 AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE dl)
|
target_link_libraries(${PROJECT_NAME} PRIVATE dl)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi ws2_32 iphlpapi)
|
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/)
|
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/)
|
||||||
@ -259,7 +237,7 @@ set(DROGON_SOURCES
|
|||||||
lib/src/Cookie.cc
|
lib/src/Cookie.cc
|
||||||
lib/src/DrClassMap.cc
|
lib/src/DrClassMap.cc
|
||||||
lib/src/DrTemplateBase.cc
|
lib/src/DrTemplateBase.cc
|
||||||
lib/src/MiddlewaresFunction.cc
|
lib/src/FiltersFunction.cc
|
||||||
lib/src/FixedWindowRateLimiter.cc
|
lib/src/FixedWindowRateLimiter.cc
|
||||||
lib/src/GlobalFilters.cc
|
lib/src/GlobalFilters.cc
|
||||||
lib/src/Histogram.cc
|
lib/src/Histogram.cc
|
||||||
@ -267,17 +245,15 @@ set(DROGON_SOURCES
|
|||||||
lib/src/HttpAppFrameworkImpl.cc
|
lib/src/HttpAppFrameworkImpl.cc
|
||||||
lib/src/HttpBinder.cc
|
lib/src/HttpBinder.cc
|
||||||
lib/src/HttpClientImpl.cc
|
lib/src/HttpClientImpl.cc
|
||||||
lib/src/HttpConnectionLimit.cc
|
|
||||||
lib/src/HttpControllerBinder.cc
|
|
||||||
lib/src/HttpControllersRouter.cc
|
lib/src/HttpControllersRouter.cc
|
||||||
lib/src/HttpFileImpl.cc
|
lib/src/HttpFileImpl.cc
|
||||||
lib/src/HttpFileUploadRequest.cc
|
lib/src/HttpFileUploadRequest.cc
|
||||||
lib/src/HttpRequestImpl.cc
|
lib/src/HttpRequestImpl.cc
|
||||||
lib/src/HttpRequestParser.cc
|
lib/src/HttpRequestParser.cc
|
||||||
lib/src/RequestStream.cc
|
|
||||||
lib/src/HttpResponseImpl.cc
|
lib/src/HttpResponseImpl.cc
|
||||||
lib/src/HttpResponseParser.cc
|
lib/src/HttpResponseParser.cc
|
||||||
lib/src/HttpServer.cc
|
lib/src/HttpServer.cc
|
||||||
|
lib/src/HttpSimpleControllersRouter.cc
|
||||||
lib/src/HttpUtils.cc
|
lib/src/HttpUtils.cc
|
||||||
lib/src/HttpViewData.cc
|
lib/src/HttpViewData.cc
|
||||||
lib/src/IntranetIpFilter.cc
|
lib/src/IntranetIpFilter.cc
|
||||||
@ -285,7 +261,6 @@ set(DROGON_SOURCES
|
|||||||
lib/src/ListenerManager.cc
|
lib/src/ListenerManager.cc
|
||||||
lib/src/LocalHostFilter.cc
|
lib/src/LocalHostFilter.cc
|
||||||
lib/src/MultiPart.cc
|
lib/src/MultiPart.cc
|
||||||
lib/src/MultipartStreamParser.cc
|
|
||||||
lib/src/NotFound.cc
|
lib/src/NotFound.cc
|
||||||
lib/src/PluginsManager.cc
|
lib/src/PluginsManager.cc
|
||||||
lib/src/PromExporter.cc
|
lib/src/PromExporter.cc
|
||||||
@ -303,18 +278,16 @@ set(DROGON_SOURCES
|
|||||||
lib/src/Utilities.cc
|
lib/src/Utilities.cc
|
||||||
lib/src/WebSocketClientImpl.cc
|
lib/src/WebSocketClientImpl.cc
|
||||||
lib/src/WebSocketConnectionImpl.cc
|
lib/src/WebSocketConnectionImpl.cc
|
||||||
|
lib/src/WebsocketControllersRouter.cc
|
||||||
lib/src/YamlConfigAdapter.cc
|
lib/src/YamlConfigAdapter.cc
|
||||||
lib/src/drogon_test.cc)
|
lib/src/drogon_test.cc)
|
||||||
set(private_headers
|
set(private_headers
|
||||||
lib/src/AOPAdvice.h
|
lib/src/AOPAdvice.h
|
||||||
lib/src/CacheFile.h
|
lib/src/CacheFile.h
|
||||||
lib/src/ConfigLoader.h
|
lib/src/ConfigLoader.h
|
||||||
lib/src/ControllerBinderBase.h
|
lib/src/FiltersFunction.h
|
||||||
lib/src/MiddlewaresFunction.h
|
|
||||||
lib/src/HttpAppFrameworkImpl.h
|
lib/src/HttpAppFrameworkImpl.h
|
||||||
lib/src/HttpClientImpl.h
|
lib/src/HttpClientImpl.h
|
||||||
lib/src/HttpConnectionLimit.h
|
|
||||||
lib/src/HttpControllerBinder.h
|
|
||||||
lib/src/HttpControllersRouter.h
|
lib/src/HttpControllersRouter.h
|
||||||
lib/src/HttpFileImpl.h
|
lib/src/HttpFileImpl.h
|
||||||
lib/src/HttpFileUploadRequest.h
|
lib/src/HttpFileUploadRequest.h
|
||||||
@ -324,6 +297,7 @@ set(private_headers
|
|||||||
lib/src/HttpResponseImpl.h
|
lib/src/HttpResponseImpl.h
|
||||||
lib/src/HttpResponseParser.h
|
lib/src/HttpResponseParser.h
|
||||||
lib/src/HttpServer.h
|
lib/src/HttpServer.h
|
||||||
|
lib/src/HttpSimpleControllersRouter.h
|
||||||
lib/src/HttpUtils.h
|
lib/src/HttpUtils.h
|
||||||
lib/src/impl_forwards.h
|
lib/src/impl_forwards.h
|
||||||
lib/src/ListenerManager.h
|
lib/src/ListenerManager.h
|
||||||
@ -334,30 +308,30 @@ set(private_headers
|
|||||||
lib/src/TaskTimeoutFlag.h
|
lib/src/TaskTimeoutFlag.h
|
||||||
lib/src/WebSocketClientImpl.h
|
lib/src/WebSocketClientImpl.h
|
||||||
lib/src/WebSocketConnectionImpl.h
|
lib/src/WebSocketConnectionImpl.h
|
||||||
|
lib/src/WebsocketControllersRouter.h
|
||||||
lib/src/FixedWindowRateLimiter.h
|
lib/src/FixedWindowRateLimiter.h
|
||||||
lib/src/SlidingWindowRateLimiter.h
|
lib/src/SlidingWindowRateLimiter.h
|
||||||
lib/src/TokenBucketRateLimiter.h
|
lib/src/TokenBucketRateLimiter.h
|
||||||
lib/src/ConfigAdapterManager.h
|
lib/src/ConfigAdapterManager.h
|
||||||
lib/src/JsonConfigAdapter.h
|
lib/src/JsonConfigAdapter.h
|
||||||
lib/src/YamlConfigAdapter.h
|
lib/src/YamlConfigAdapter.h
|
||||||
lib/src/ConfigAdapter.h
|
lib/src/ConfigAdapter.h)
|
||||||
lib/src/MultipartStreamParser.h)
|
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
if (NOT WIN32)
|
||||||
set(DROGON_SOURCES
|
set(DROGON_SOURCES
|
||||||
${DROGON_SOURCES}
|
${DROGON_SOURCES}
|
||||||
lib/src/SharedLibManager.cc)
|
lib/src/SharedLibManager.cc)
|
||||||
set(private_headers
|
set(private_headers
|
||||||
${private_headers}
|
${private_headers}
|
||||||
lib/src/SharedLibManager.h)
|
lib/src/SharedLibManager.h)
|
||||||
elseif(WIN32)
|
else (NOT WIN32)
|
||||||
set(DROGON_SOURCES
|
set(DROGON_SOURCES
|
||||||
${DROGON_SOURCES}
|
${DROGON_SOURCES}
|
||||||
third_party/mman-win32/mman.c)
|
third_party/mman-win32/mman.c)
|
||||||
set(private_headers
|
set(private_headers
|
||||||
${private_headers}
|
${private_headers}
|
||||||
third_party/mman-win32/mman.h)
|
third_party/mman-win32/mman.h)
|
||||||
endif()
|
endif (NOT WIN32)
|
||||||
|
|
||||||
if (BUILD_POSTGRESQL)
|
if (BUILD_POSTGRESQL)
|
||||||
# find postgres
|
# find postgres
|
||||||
@ -511,7 +485,7 @@ execute_process(COMMAND "git" rev-parse HEAD
|
|||||||
OUTPUT_VARIABLE GIT_SHA1
|
OUTPUT_VARIABLE GIT_SHA1
|
||||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/version.h.in"
|
configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/version.h.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/lib/inc/drogon/version.h" @ONLY)
|
"${PROJECT_SOURCE_DIR}/lib/inc/drogon/version.h" @ONLY)
|
||||||
|
|
||||||
if (DROGON_CXX_STANDARD EQUAL 20)
|
if (DROGON_CXX_STANDARD EQUAL 20)
|
||||||
option(USE_COROUTINE "Enable C++20 coroutine support" ON)
|
option(USE_COROUTINE "Enable C++20 coroutine support" ON)
|
||||||
@ -566,9 +540,7 @@ set(DROGON_HEADERS
|
|||||||
lib/inc/drogon/HttpClient.h
|
lib/inc/drogon/HttpClient.h
|
||||||
lib/inc/drogon/HttpController.h
|
lib/inc/drogon/HttpController.h
|
||||||
lib/inc/drogon/HttpFilter.h
|
lib/inc/drogon/HttpFilter.h
|
||||||
lib/inc/drogon/HttpMiddleware.h
|
|
||||||
lib/inc/drogon/HttpRequest.h
|
lib/inc/drogon/HttpRequest.h
|
||||||
lib/inc/drogon/RequestStream.h
|
|
||||||
lib/inc/drogon/HttpResponse.h
|
lib/inc/drogon/HttpResponse.h
|
||||||
lib/inc/drogon/HttpSimpleController.h
|
lib/inc/drogon/HttpSimpleController.h
|
||||||
lib/inc/drogon/HttpTypes.h
|
lib/inc/drogon/HttpTypes.h
|
||||||
@ -584,7 +556,7 @@ set(DROGON_HEADERS
|
|||||||
lib/inc/drogon/WebSocketConnection.h
|
lib/inc/drogon/WebSocketConnection.h
|
||||||
lib/inc/drogon/WebSocketController.h
|
lib/inc/drogon/WebSocketController.h
|
||||||
lib/inc/drogon/drogon.h
|
lib/inc/drogon/drogon.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/lib/inc/drogon/version.h
|
lib/inc/drogon/version.h
|
||||||
lib/inc/drogon/drogon_callbacks.h
|
lib/inc/drogon/drogon_callbacks.h
|
||||||
lib/inc/drogon/PubSubService.h
|
lib/inc/drogon/PubSubService.h
|
||||||
lib/inc/drogon/drogon_test.h
|
lib/inc/drogon/drogon_test.h
|
||||||
@ -693,7 +665,6 @@ set(ORM_HEADERS
|
|||||||
orm_lib/inc/drogon/orm/BaseBuilder.h
|
orm_lib/inc/drogon/orm/BaseBuilder.h
|
||||||
orm_lib/inc/drogon/orm/Criteria.h
|
orm_lib/inc/drogon/orm/Criteria.h
|
||||||
orm_lib/inc/drogon/orm/DbClient.h
|
orm_lib/inc/drogon/orm/DbClient.h
|
||||||
orm_lib/inc/drogon/orm/DbConfig.h
|
|
||||||
orm_lib/inc/drogon/orm/DbListener.h
|
orm_lib/inc/drogon/orm/DbListener.h
|
||||||
orm_lib/inc/drogon/orm/DbTypes.h
|
orm_lib/inc/drogon/orm/DbTypes.h
|
||||||
orm_lib/inc/drogon/orm/Exception.h
|
orm_lib/inc/drogon/orm/Exception.h
|
||||||
|
36
CPPLINT.cfg
36
CPPLINT.cfg
@ -1,36 +0,0 @@
|
|||||||
# Stop searching for additional config files.
|
|
||||||
set noparent
|
|
||||||
|
|
||||||
exclude_files=trantor
|
|
||||||
exclude_files=build
|
|
||||||
|
|
||||||
# Use non-const reference rather than a pointer.
|
|
||||||
filter=-runtime/references
|
|
||||||
|
|
||||||
# CHECK macros are from Drogon, not Google Test.
|
|
||||||
filter=-readability/check
|
|
||||||
|
|
||||||
# Don't warn about the use of C++11 or C++17 features.
|
|
||||||
filter=-build/c++11
|
|
||||||
filter=-build/c++17
|
|
||||||
|
|
||||||
filter=-build/include_subdir
|
|
||||||
|
|
||||||
# We prioritize clang-format for now.
|
|
||||||
filter=-whitespace
|
|
||||||
|
|
||||||
# We don't require a username in TODO comments.
|
|
||||||
filter=-readability/todo
|
|
||||||
|
|
||||||
# TODO: Fix these.
|
|
||||||
filter=-legal/copyright
|
|
||||||
filter=-build/namespaces
|
|
||||||
filter=-build/include
|
|
||||||
filter=-build/include_what_you_use
|
|
||||||
filter=-runtime/explicit
|
|
||||||
filter=-runtime/string
|
|
||||||
filter=-runtime/int
|
|
||||||
filter=-readability/casting
|
|
||||||
filter=-readability/braces
|
|
||||||
filter=-readability/fn_size
|
|
||||||
filter=-runtime/threadsafe_fn
|
|
385
ChangeLog.md
385
ChangeLog.md
@ -4,355 +4,6 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [1.9.11] - 2025-06-20
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add a new overload for execSqlCoro.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Do not write to source directory during build.
|
|
||||||
|
|
||||||
- Improve Postgres connection stability.
|
|
||||||
|
|
||||||
- Add handleFatalError in handleClosed.
|
|
||||||
|
|
||||||
- Add -o|--output option to drogon_ctl create models.
|
|
||||||
|
|
||||||
- Add qrcode for WeChat official account to the README file.
|
|
||||||
|
|
||||||
- Support for iOS compiling.
|
|
||||||
|
|
||||||
- Add cors example to demonstrate cross-origin support in drogon.
|
|
||||||
|
|
||||||
- Add support for continuation frame in WebSocketMessageParser.
|
|
||||||
|
|
||||||
- Add RawParameter API to pass raw SQL parameters.
|
|
||||||
|
|
||||||
- Upgrade Windows image and re-enable tests on Windows.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix a bug in isAutoCreationClass<T>.
|
|
||||||
|
|
||||||
- Fix CI on MacOS.
|
|
||||||
|
|
||||||
- Fix issue with precision loss of double-type parameters in ORM inputs.
|
|
||||||
|
|
||||||
|
|
||||||
## [1.9.10] - 2025-02-20
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add setConnectionCallback.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- ORM:Avoid unnecessary copies when returning search results.
|
|
||||||
|
|
||||||
- Improve the zh-TW README translation.
|
|
||||||
|
|
||||||
- Make quit function thread safe.
|
|
||||||
|
|
||||||
- Added path_exempt in AccessLogger plugin config to exclude desired paths.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix the issue in view generation by including the missing header file.
|
|
||||||
|
|
||||||
- Fix ci: codespell.
|
|
||||||
|
|
||||||
## [1.9.9] - 2025-01-01
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Added Partitioned flag for cookies.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Update FindFilesystem.cmake to check for GNU instead of GCC for CMAKE_CXX_COMPILER_ID.
|
|
||||||
|
|
||||||
- Update README.
|
|
||||||
|
|
||||||
- Chore(workflow/cmake.yml): upgrade macos runner.
|
|
||||||
|
|
||||||
- Add emptiness check to the LogStream &operator<< with std::string_view.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix a bug in plugin Redirector.
|
|
||||||
|
|
||||||
- Fix CMAKE issues mentioned in #2144 and a linking problem which manifest with gcc12.3 when building with shared libs.
|
|
||||||
|
|
||||||
- Fix: Remove dependency on locales being installed on the system.
|
|
||||||
|
|
||||||
## [1.9.8] - 2024-10-27
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add in-place base64 encode and decode.
|
|
||||||
|
|
||||||
- Add check the client connection status.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Add Hodor whitelists.
|
|
||||||
|
|
||||||
- Include exception header for std::exception_ptr.
|
|
||||||
|
|
||||||
- Add support for escaped identifiers in Postgresql.
|
|
||||||
|
|
||||||
- Remove content-length header from 101 Switching Protocols response.
|
|
||||||
|
|
||||||
- Remove websocketResponseTest from windows shared library env.
|
|
||||||
|
|
||||||
- Optimize query params and allow for empty values.
|
|
||||||
|
|
||||||
- Replace rejection sampling and remove use of rand().
|
|
||||||
|
|
||||||
- Add sending customized http requests to drogon_ctl.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix coroutine continuation handle.
|
|
||||||
|
|
||||||
- Fix some bugs in plugin PromExporter.
|
|
||||||
|
|
||||||
- Fix a bug after removing content-length header in some responses.
|
|
||||||
|
|
||||||
## [1.9.7] - 2024-09-10
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add coroutine mutex.
|
|
||||||
|
|
||||||
- Add requestsBufferSize function.
|
|
||||||
|
|
||||||
- Refine SQLite3 error types with new exception handling.
|
|
||||||
|
|
||||||
- Add a new method to reload SSL files on the fly.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Allow MultiPartParser to be movable.
|
|
||||||
|
|
||||||
- Add quotes to the table name in the ORM generator.
|
|
||||||
|
|
||||||
- Change stoi to stoul in the Field class.
|
|
||||||
|
|
||||||
- Modernize cookies.
|
|
||||||
|
|
||||||
- Change a log level.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Use correct libraries when compiling statically.
|
|
||||||
|
|
||||||
## [1.9.6] - 2024-07-20
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add setsockopt to HttpServer.
|
|
||||||
|
|
||||||
- Support request stream.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Allow MultiPartParser to parse PATCH requests.
|
|
||||||
|
|
||||||
- Add an example of prometheus.
|
|
||||||
|
|
||||||
- Delay parsing json for HttpClient.
|
|
||||||
|
|
||||||
- Update README.md.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix some compilation warnings.
|
|
||||||
|
|
||||||
- Fix typo in yaml config.
|
|
||||||
|
|
||||||
## [1.9.5] - 2024-06-08
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Fix an error in the yaml format config file.
|
|
||||||
|
|
||||||
- Support postgresql connection options.
|
|
||||||
|
|
||||||
- Add regex support for websocket controller.
|
|
||||||
|
|
||||||
- Add the registerMiddleware method.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Add the conan badge to readme files.
|
|
||||||
|
|
||||||
- Install gcc in ci.
|
|
||||||
|
|
||||||
- Intention to present an alternative to improve the performance of a method in models.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix an error in the yaml format config file.
|
|
||||||
|
|
||||||
- Fix CI on Windows.
|
|
||||||
|
|
||||||
- Fix some spelling errors.
|
|
||||||
|
|
||||||
## [1.9.4] - 2024-05-04
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Add client cert support for websocket.
|
|
||||||
|
|
||||||
- Add JSON send overloads for WebSocket connections.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Minor enhancement: move some smart pointers around instead of copying them.
|
|
||||||
|
|
||||||
- Remove the request shared_ptr from the multipart parser.
|
|
||||||
|
|
||||||
- Fix typo in HttpAppFrameworkImpl.cc.
|
|
||||||
|
|
||||||
- Avoid string copy and lowercasing on every request.
|
|
||||||
|
|
||||||
- Implemented database reconnection loop.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Bypass clang thread_local error.
|
|
||||||
|
|
||||||
## [1.9.3] - 2024-02-09
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Added getParameter() and getOptionalParameter().
|
|
||||||
|
|
||||||
- Change drogon::MultiPartParser's parameters data type.
|
|
||||||
|
|
||||||
- Use std::string_view for WebSockets.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Add support for gentoo linux, dev-db/mariadb contains mysql.
|
|
||||||
|
|
||||||
- Introduce cpplint to the CI.
|
|
||||||
|
|
||||||
- Enable readability/alt_tokens for cpplint.
|
|
||||||
|
|
||||||
- Use clang-format-17.
|
|
||||||
|
|
||||||
- Add newline at EOF.
|
|
||||||
|
|
||||||
- Enable readability/inheritance for cpplint.
|
|
||||||
|
|
||||||
- Enable build/explicit_make_pair for cpplint.
|
|
||||||
|
|
||||||
- Enable build/include_order for cpplint.
|
|
||||||
|
|
||||||
- Enable build/header_guard for cpplint.
|
|
||||||
|
|
||||||
- Enable build/storage_class for cpplint.
|
|
||||||
|
|
||||||
- Enable readability/multiline_string for cpplint.
|
|
||||||
|
|
||||||
- Alias the safe hashmap template.
|
|
||||||
|
|
||||||
- Simplify traits in utils.
|
|
||||||
|
|
||||||
- Enhancement: extend drogon::ContentType for file handling.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix a wrong place of return.
|
|
||||||
|
|
||||||
- Fix drogon::util::fromString().
|
|
||||||
|
|
||||||
## [1.9.2] - 2024-01-18
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Feature: Integrate spdlog as logging backend.
|
|
||||||
|
|
||||||
- Support asynchronous sending of chunked responses.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Modify the configuration file templates in drogon_ctl.
|
|
||||||
|
|
||||||
- Use execute_process instead of exec_program in FindJsoncpp.cmake.
|
|
||||||
|
|
||||||
- GitHub Action to find typos in the codebase using codespell.
|
|
||||||
|
|
||||||
- add discord link to readme.
|
|
||||||
|
|
||||||
- Add -k option to the drogon_ctl when running the press command.
|
|
||||||
|
|
||||||
- Refine request routing process.
|
|
||||||
|
|
||||||
- Add CI tests with more compilers.
|
|
||||||
|
|
||||||
- Avoid a race condition in database listener tests.
|
|
||||||
|
|
||||||
- Remove macos-11 CI; not supported by Homebrew.
|
|
||||||
|
|
||||||
- Bump github/codeql-action from 2 to 3.
|
|
||||||
|
|
||||||
- Move the RealIpResolver plugin to the PreRouting join point.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix: typo on Mapper method.
|
|
||||||
|
|
||||||
- Fix a error of coroutines on Windows.
|
|
||||||
|
|
||||||
- Fix ORM: The original way did not handle exceptions correctly.
|
|
||||||
|
|
||||||
- Remove the default ctor of the Row class in ORM.
|
|
||||||
|
|
||||||
- Set the url of trantor to the official repository.
|
|
||||||
|
|
||||||
- Fix htonll/ntohll redefinition.
|
|
||||||
|
|
||||||
- Fix building with MSYS2.
|
|
||||||
|
|
||||||
- Fix name issue when cross-compiling.
|
|
||||||
|
|
||||||
## [1.9.1] - 2023-11-27
|
|
||||||
|
|
||||||
### API changes list
|
|
||||||
|
|
||||||
- Pass HttpRequestPtr to custom error handlers.
|
|
||||||
|
|
||||||
- Provide some functions for incrementing the value of given columns.
|
|
||||||
|
|
||||||
- Return HttpAppFramework by setExceptionHandler.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Custom sessions.
|
|
||||||
|
|
||||||
- Use the constexpr if instead of std::enable_if.
|
|
||||||
|
|
||||||
- Make id generator consistent.
|
|
||||||
|
|
||||||
- Update test_cmake.csp.
|
|
||||||
|
|
||||||
- Simplify drogon test with c++17.
|
|
||||||
|
|
||||||
- Remove unused and undefined overloads of isBase64.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix build due to trantor commit out of date and address warnings.
|
|
||||||
|
|
||||||
- Fix a bug of the GlobalFilters plugin.
|
|
||||||
|
|
||||||
- Fix: uuid formatting.
|
|
||||||
|
|
||||||
## [1.9.0] - 2023-10-29
|
## [1.9.0] - 2023-10-29
|
||||||
|
|
||||||
### API changes list
|
### API changes list
|
||||||
@ -388,7 +39,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Add isHead() method to HttpRequest, to preserve information about the original method for use in the controller.
|
- Add isHead() method to HttpRequest, to preserve information about the original method for use in the controller.
|
||||||
|
|
||||||
- Allow omitting template parameter in execCommandSync.
|
- Allow omitting template paremeter in execCommandSync.
|
||||||
|
|
||||||
- Add a method to HttpRequest to access the matched routing parameters.
|
- Add a method to HttpRequest to access the matched routing parameters.
|
||||||
|
|
||||||
@ -520,7 +171,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Remove unused CI files and Jekyll config.
|
- Remove unused CI files and Jekyll config.
|
||||||
|
|
||||||
- Ensure that all filters, AOP advice, and handlers are executed within the IO threads.
|
- Ensure that all filters, AOP advices, and handlers are executed within the IO threads.
|
||||||
|
|
||||||
- Update test.sh and build.sh by appending prefix "X" to string variable comparisons.
|
- Update test.sh and build.sh by appending prefix "X" to string variable comparisons.
|
||||||
|
|
||||||
@ -852,7 +503,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Check HTTP client is not sending requests in sync mode on the same event loop.
|
- Check HTTP client is not sending requests in sync mode on the same event loop.
|
||||||
|
|
||||||
- Start listening after beginning advice.
|
- Start listening after beginning advices.
|
||||||
|
|
||||||
- Allow using json_cpp in other sublibraries.
|
- Allow using json_cpp in other sublibraries.
|
||||||
|
|
||||||
@ -954,7 +605,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Return on redis connection errors
|
- Return on redis connection errors
|
||||||
|
|
||||||
- Fix(MultiPart): Does not respect quotes in Content-Disposition header
|
- Fix(MutliPart): Does not respect quotes in Content-Disposition header
|
||||||
|
|
||||||
- Fix(cmake): error in FindFilesystem
|
- Fix(cmake): error in FindFilesystem
|
||||||
|
|
||||||
@ -1112,7 +763,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Use two-phase construction for the DbClientImpl and the RedisClientImpl.
|
- Use two-phase construction for the DbClientImpl and the RedisClientImpl.
|
||||||
|
|
||||||
- Add support 'select <db>' for redis.
|
- Add support 'select <db>' for redis.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -1422,7 +1073,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- Destroy DNS resolver of HttpClient in the correct thread.
|
- Destroy DNS resolver of HttpClient in the correct thread.
|
||||||
|
|
||||||
- Add the header <cctype> to resolve build errors in VS2017.
|
- Add the header <cctype> to resolve build errors in VS2017.
|
||||||
|
|
||||||
## [1.0.0-beta18] - 2020-06-14
|
## [1.0.0-beta18] - 2020-06-14
|
||||||
|
|
||||||
@ -1842,29 +1493,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## [1.0.0-beta1] - 2019-06-11
|
## [1.0.0-beta1] - 2019-06-11
|
||||||
|
|
||||||
[Unreleased]: https://github.com/an-tao/drogon/compare/v1.9.11...HEAD
|
[Unreleased]: https://github.com/an-tao/drogon/compare/v1.9.0...HEAD
|
||||||
|
|
||||||
[1.9.11]: https://github.com/an-tao/drogon/compare/v1.9.10...v1.9.11
|
|
||||||
|
|
||||||
[1.9.10]: https://github.com/an-tao/drogon/compare/v1.9.9...v1.9.10
|
|
||||||
|
|
||||||
[1.9.9]: https://github.com/an-tao/drogon/compare/v1.9.8...v1.9.9
|
|
||||||
|
|
||||||
[1.9.8]: https://github.com/an-tao/drogon/compare/v1.9.7...v1.9.8
|
|
||||||
|
|
||||||
[1.9.7]: https://github.com/an-tao/drogon/compare/v1.9.6...v1.9.7
|
|
||||||
|
|
||||||
[1.9.6]: https://github.com/an-tao/drogon/compare/v1.9.5...v1.9.6
|
|
||||||
|
|
||||||
[1.9.5]: https://github.com/an-tao/drogon/compare/v1.9.4...v1.9.5
|
|
||||||
|
|
||||||
[1.9.4]: https://github.com/an-tao/drogon/compare/v1.9.3...v1.9.4
|
|
||||||
|
|
||||||
[1.9.3]: https://github.com/an-tao/drogon/compare/v1.9.2...v1.9.3
|
|
||||||
|
|
||||||
[1.9.2]: https://github.com/an-tao/drogon/compare/v1.9.1...v1.9.2
|
|
||||||
|
|
||||||
[1.9.1]: https://github.com/an-tao/drogon/compare/v1.9.0...v1.9.1
|
|
||||||
|
|
||||||
[1.9.0]: https://github.com/an-tao/drogon/compare/v1.9.0-rc.1...v1.9.0
|
[1.9.0]: https://github.com/an-tao/drogon/compare/v1.9.0-rc.1...v1.9.0
|
||||||
|
|
||||||
|
11
README.md
11
README.md
@ -1,14 +1,13 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://github.com/drogonframework/drogon/actions)
|
[](https://github.com/drogonframework/drogon/actions)
|
||||||
[](https://conan.io/center/recipes/drogon)
|
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||||
[](https://discord.gg/3DvHY6Ewuj)
|
|
||||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||||
|
|
||||||
English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md)
|
English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md)
|
||||||
### Overview
|
### Overview
|
||||||
**Drogon** is a C++17/20 based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon from the American TV series *Game of Thrones*, which I really enjoy.
|
**Drogon** is a C++17/20 based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like.
|
||||||
|
|
||||||
Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows. Its main features are as follows:
|
Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows. Its main features are as follows:
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD
|
|||||||
* Support ARM Architecture;
|
* Support ARM Architecture;
|
||||||
* Provide a convenient lightweight ORM implementation that supports for regular object-to-database bidirectional mapping;
|
* 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 plugins which can be installed by the configuration file at load time;
|
||||||
* Support AOP with built-in joinpoints.
|
* Support AOP with build-in joinpoints.
|
||||||
* Support C++ coroutines
|
* Support C++ coroutines
|
||||||
|
|
||||||
## A very simple example
|
## A very simple example
|
||||||
@ -183,7 +182,7 @@ As you can see, users can use the `HttpController` to map paths and parameters a
|
|||||||
|
|
||||||
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.
|
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 [documentation](https://drogonframework.github.io/drogon-docs/#/) on GitHub**.
|
After compiling all of the above source files, we get a very simple web application. This is a good start. **For more information, please visit the [wiki](https://github.com/an-tao/drogon/wiki/ENG-01-Overview)**
|
||||||
|
|
||||||
## Cross-compilation
|
## Cross-compilation
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://github.com/drogonframework/drogon/actions)
|
[](https://github.com/drogonframework/drogon/actions)
|
||||||
[](https://conan.io/center/recipes/drogon)
|
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||||
[](https://discord.gg/3DvHY6Ewuj)
|
|
||||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||||
|
|
||||||
[English](./README.md) | 简体中文 | [繁體中文](./README.zh-TW.md)
|
[English](./README.md) | 简体中文 | [繁體中文](./README.zh-TW.md)
|
||||||
@ -186,7 +185,7 @@ class User : public drogon::HttpController<User>
|
|||||||
|
|
||||||
另外,你可以发现前面所有的处理函数接口都是异步的,处理器的响应是通过回调对象返回的。这种设计是出于对高性能的考虑,因为在异步模式下,可以使用少量的线程(比如和处理器核心数相等的线程)处理大量的并发请求。
|
另外,你可以发现前面所有的处理函数接口都是异步的,处理器的响应是通过回调对象返回的。这种设计是出于对高性能的考虑,因为在异步模式下,可以使用少量的线程(比如和处理器核心数相等的线程)处理大量的并发请求。
|
||||||
|
|
||||||
编译上述的所有源文件后,我们得到了一个非常简单的web应用程序,这是一个不错的开始。**请访问GitHub上的[文档](https://drogonframework.github.io/drogon-docs/#/CHN/CHN-01-%E6%A6%82%E8%BF%B0)**
|
编译上述的所有源文件后,我们得到了一个非常简单的web应用程序,这是一个不错的开始。**请访问[wiki](https://github.com/an-tao/drogon/wiki/CHN-01-概述)**
|
||||||
|
|
||||||
## 贡献方式
|
## 贡献方式
|
||||||
|
|
||||||
@ -197,9 +196,3 @@ class User : public drogon::HttpController<User>
|
|||||||
## QQ交流群:1137909452
|
## QQ交流群:1137909452
|
||||||
|
|
||||||
欢迎交流探讨。
|
欢迎交流探讨。
|
||||||
|
|
||||||
## 微信公众号:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
会不定期推送一些Drogon的使用技巧和更新信息,欢迎关注。
|
|
@ -1,49 +1,47 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://github.com/drogonframework/drogon/actions)
|
[](https://github.com/drogonframework/drogon/actions)
|
||||||
[](https://conan.io/center/recipes/drogon)
|
[](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
[](https://t.me/joinchat/_mMNGv0748ZkMDAx)
|
||||||
[](https://discord.gg/3DvHY6Ewuj)
|
|
||||||
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
[](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
|
||||||
|
|
||||||
[English](./README.md) | [简体中文](./README.zh-CN.md) | 繁體中文
|
[English](./README.md) | [简体中文](./README.zh-CN.md) | 繁體中文
|
||||||
|
|
||||||
**Drogon** 是一個基於 C++17/20 的 HTTP 應用程式框架,使用 Drogon 可以方便地用 C++ 建立各種類型的 Web App 伺服器端程式。
|
**Drogon**是一個基於C++17/20的Http應用框架,使用Drogon可以方便的使用C++構建各種類型的Web App伺服器程式。
|
||||||
|
本版本庫是github上[Drogon](https://github.com/an-tao/drogon)的鏡像庫。 **Drogon**是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(漢譯作卓耿),和龍有關但並不是dragon的誤寫,為了不至於引起不必要的誤會這裡說明一下。
|
||||||
|
|
||||||
這個版本庫是 GitHub 上 [Drogon](https://github.com/an-tao/drogon) 的鏡像庫。**Drogon** 是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(中文譯作卓耿),和龍有關但並不是 dragon 的誤寫,為了避免不必要的誤會在此說明。
|
Drogon是一個跨平台框架,它支援Linux,也支援macOS、FreeBSD/OpenBSD、HaikuOS和Windows。它的主要特點如下:
|
||||||
|
|
||||||
Drogon 是一個跨平台框架,支援 Linux、macOS、FreeBSD/OpenBSD、HaikuOS 和 Windows。主要特點如下:
|
* 網路層使用基於epoll(macOS/FreeBSD下是kqueue)的非阻塞IO框架,提供高並發、高性能的網路IO。詳細請見[TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite);
|
||||||
|
* 全異步程式設計;
|
||||||
* 網路層使用基於 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)完全去耦;
|
||||||
* 支援 HTTP 1.0/1.1(伺服器端和用戶端);
|
* 支援cookies和內建的session;
|
||||||
* 基於樣板(template)實作的簡單反射機制,使主程式框架、控制器(controller)和視圖(view)完全解耦;
|
* 支援後端渲染,把控制器生成的數據交給視圖生成Html頁面,視圖由CSP模板文件描述,通過CSP標籤把C++程式碼嵌入到Html頁面,由drogon的指令列工具在編譯階段自動生成C++程式碼並編譯;
|
||||||
* 支援 cookies 和內建的 session;
|
* 支援運行期的視圖頁面動態加載(動態編譯和載入so文件);
|
||||||
* 支援後端算繪,將控制器產生的資料交給視圖產生 HTML 頁面,視圖由 CSP 樣板檔案描述,透過 CSP 標籤將 C++ 程式碼嵌入 HTML 頁面,由 drogon 的命令列工具在編譯階段自動產生 C++ 程式碼並編譯;
|
* 非常方便靈活的路徑(path)到控制器處理函數(handler)的映射方案;
|
||||||
* 支援執行期的視圖頁面動態載入(動態編譯和載入 so 檔案);
|
* 支援過濾器(filter)鏈,方便在控制器之前執行統一的邏輯(如登錄驗證、Http Method約束驗證等);
|
||||||
* 非常方便靈活的路徑(path)到控制器處理函式(handler)的對應方案;
|
* 支援https(基於OpenSSL);
|
||||||
* 支援過濾器(filter)鏈,方便在控制器之前執行統一的邏輯(如登入驗證、HTTP Method 限制驗證等);
|
* 支援websocket(server端和client端);
|
||||||
* 支援 HTTPS(基於 OpenSSL);
|
* 支援Json格式的請求和回應, 方便開發Restful API;
|
||||||
* 支援 WebSocket(伺服器端和用戶端);
|
* 支援文件下載和上傳,支援sendfile系統呼叫;
|
||||||
* 支援 JSON 格式的請求和回應,方便開發 RESTful API;
|
* 支援gzip/brotli壓縮傳輸;
|
||||||
* 支援檔案下載和上傳,支援 `sendfile` 系統呼叫;
|
* 支援pipelining;
|
||||||
* 支援 Gzip/Brotli 壓縮傳輸;
|
* 提供一個輕量的指令列工具drogon_ctl,幫助簡化各種類的創造和視圖程式碼的生成過程;
|
||||||
* 支援 pipelining;
|
* 非同步的讀寫資料庫,目前支援PostgreSQL和MySQL(MariaDB)資料庫;
|
||||||
* 提供輕量的命令列工具 `drogon_ctl`,幫助簡化各種類別的建立和視圖程式碼的產生過程;
|
* 支援異步讀寫Redis;
|
||||||
* 非同步的讀寫資料庫,目前支援 PostgreSQL 和 MySQL(MariaDB)資料庫;
|
* 基於執行序池實現sqlite3資料庫的異步讀寫,提供與上文資料庫相同的接口;
|
||||||
* 支援非同步讀寫 Redis;
|
* 支援ARM架構;
|
||||||
* 基於執行緒池實作 sqlite3 資料庫的非同步讀寫,提供與上述資料庫相同的介面;
|
* 方便的輕量級ORM實現,一般物件到資料庫的雙向映射;
|
||||||
* 支援 ARM 架構;
|
* 支援外掛,可通過設定文件在載入時動態載入;
|
||||||
* 方便的輕量級 ORM 實現,一般物件到資料庫的雙向對應;
|
* 支援內建插入點的AOP
|
||||||
* 支援外掛,可透過設定檔案在載入時動態載入;
|
* 支援C++ coroutine
|
||||||
* 支援內建插入點的 AOP;
|
|
||||||
* 支援 C++ coroutine。
|
|
||||||
|
|
||||||
## 一個非常簡單的例子
|
## 一個非常簡單的例子
|
||||||
|
|
||||||
不像大多數 C++ 框架,drogon 的主程式可以非常簡單。Drogon 使用了一些小技巧使主程式和控制器解耦。控制器的路由設定可以在控制器類別中定義或在設定檔案中完成。
|
不像大多數C++框架那樣,drogon的主程式可以非常簡單。 Drogon使用了一些小技巧使主程式和控制器去耦. 控制器的路由設定可以在控制器類別中定義或者設定文件中完成.
|
||||||
|
|
||||||
下面是一個典型主程式的樣子:
|
下面是一個典型的主程式的樣子:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#include <drogon/drogon.h>
|
#include <drogon/drogon.h>
|
||||||
@ -59,7 +57,7 @@ int main()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果使用設定檔案,可以進一步簡化成:
|
如果使用設定文件,可以進一步簡化成這樣:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#include <drogon/drogon.h>
|
#include <drogon/drogon.h>
|
||||||
@ -70,7 +68,7 @@ int main()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
當然,Drogon 也提供了一些函式,讓使用者可以在 `main()` 函式中直接加入控制器邏輯,例如,使用者可以註冊一個 lambda 處理常式到 drogon 框架中,如下所示:
|
當然,Drogon也提供了一些函數,使使用者可以在main()函數中直接添加控制器邏輯,比如,使用者可以註冊一個lambda處理器到drogon框架中,如下所示:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
app().registerHandler("/test?username={name}",
|
app().registerHandler("/test?username={name}",
|
||||||
@ -87,7 +85,9 @@ app().registerHandler("/test?username={name}",
|
|||||||
{Get,"LoginFilter"});
|
{Get,"LoginFilter"});
|
||||||
```
|
```
|
||||||
|
|
||||||
這看起來很方便,但不適用於複雜的場景,試想如果有數十個或數百個處理函式要註冊進框架,`main()` 函式將變得難以閱讀。顯然,讓每個包含處理函式的類別在自己的定義中完成註冊是更好的選擇。所以,除非你的應用邏輯非常簡單,我們不建議使用上述介面,更好的做法是建立一個 HttpSimpleController 類別,如下:
|
|
||||||
|
這看起來是很方便,但是這並不適用於復雜的場景,試想假如有數十個或者數百個處理函數要註冊進框架,main()函數將膨脹到不可讀的程度。顯然,讓每個包含處理函數的類在自己的定義中完成註冊是更好的選擇。所以,除非你的應用邏輯非常簡單,我們不推薦使用上述接口,更好的實踐是,我們可以創造一個HttpSimpleController類別,如下:
|
||||||
|
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
/// The TestCtrl.h file
|
/// The TestCtrl.h file
|
||||||
@ -116,9 +116,9 @@ void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**上述程式的大部分程式碼都可以由 `drogon_ctl` 指令產生**(使用指令 `drogon_ctl create controller TestCtr`)。使用者只需要加入自己的業務邏輯。在這個範例中,當用戶端存取 URL `http://ip/test` 時,控制器簡單地回傳一個 `Hello, world!` 頁面。
|
**上面程式的大部分程式碼都可以由`drogon_ctl`指令創造**(這個指令是`drogon_ctl create controller TestCtr`)。使用者所需做的就是添加自己的業務邏輯。在這個例子中,當客戶端訪問URL`http://ip/test`時,控制器簡單的回傳了一個`Hello, world!`頁面。
|
||||||
|
|
||||||
對於 JSON 格式的回應,我們可以這樣建立控制器:
|
對於JSON格式的回應,我們可以像下面這樣創造控制器:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
/// The header file
|
/// The header file
|
||||||
@ -147,7 +147,7 @@ void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
讓我們更進一步,透過 HttpController 類別建立一個 RESTful API 的範例,如下所示(省略實作檔案):
|
讓我們更進一步,通過HttpController類別創造一個RESTful API的例子,如下所示(忽略了實做文件):
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
/// The header file
|
/// The header file
|
||||||
@ -181,18 +181,18 @@ class User : public drogon::HttpController<User>
|
|||||||
} // namespace api
|
} // namespace api
|
||||||
```
|
```
|
||||||
|
|
||||||
如你所見,透過 `HttpController` 類別,使用者可以同時對應路徑和路徑參數,這對 RESTful API 應用來說非常方便。
|
如你所見,通過`HttpController`類別,使用者可以同時映射路徑和路徑參數,這對RESTful API應用來說非常方便。
|
||||||
|
|
||||||
另外,你可以發現前面所有的處理函式介面都是非同步的,處理器的回應是透過回呼物件回傳的。這種設計是考慮到效能,因為在非同步模式下,可以使用少量的執行緒(例如和處理器核心數相等的執行緒)處理大量的並行請求。
|
另外,你可以發現前面所有的處理函數接口都是異步的,處理器的回應是通過回調對象回傳的。這種設計是出於對高性能的考慮,因為在異步模式下,可以使用少量的執行序(比如和處理器核心數相等的執行序)處理大量的並發請求。
|
||||||
|
|
||||||
編譯上述所有原始檔案後,我們得到了一個非常簡單的網頁應用程式,這是一個不錯的開始。**請瀏覽 GitHub 上的[文件](https://drogonframework.github.io/drogon-docs/#/CHN/CHN-01-%E6%A6%82%E8%BF%B0)**
|
編譯上述的所有源文件後,我們得到了一個非常簡單的web應用程式,這是一個不錯的開始。 **請瀏覽[wiki](https://github.com/an-tao/drogon/wiki/CHN-01-概述)**
|
||||||
|
|
||||||
## 貢獻方式
|
## 貢獻方式
|
||||||
|
|
||||||
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以取得更多資訊。
|
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以獲取更多的信息。
|
||||||
|
|
||||||
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
|
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
|
||||||
|
|
||||||
## QQ 交流群:1137909452
|
## QQ交流群:1137909452
|
||||||
|
|
||||||
歡迎交流討論。
|
歡迎交流探討。
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
# ParseAndAddDrogonTests(${PROJECT_NAME}) #
|
# ParseAndAddDrogonTests(${PROJECT_NAME}) #
|
||||||
#==================================================================================================#
|
#==================================================================================================#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5...3.31)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
# This removes the contents between
|
# This removes the contents between
|
||||||
# - block comments (i.e. /* ... */)
|
# - block comments (i.e. /* ... */)
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define MAJOR @DROGON_MAJOR_VERSION@
|
#define MAJOR @DROGON_MAJOR_VERSION@
|
||||||
#define MINOR @DROGON_MINOR_VERSION@
|
#define MINOR @DROGON_MINOR_VERSION@
|
||||||
#define PATCH @DROGON_PATCH_VERSION@
|
#define PATCH @DROGON_PATCH_VERSION@
|
||||||
|
@ -102,7 +102,7 @@ if(TARGET std::filesystem)
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Ignore filesystem check if version too low
|
# Ignore fileystem check if version too low
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.10)
|
if(CMAKE_VERSION VERSION_LESS 3.10)
|
||||||
set(CXX_FILESYSTEM_HAVE_FS FALSE CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
set(CXX_FILESYSTEM_HAVE_FS FALSE CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
||||||
set(Filesystem_FOUND FALSE CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
set(Filesystem_FOUND FALSE CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||||
@ -212,7 +212,7 @@ if(CXX_FILESYSTEM_HAVE_FS)
|
|||||||
]] code @ONLY)
|
]] code @ONLY)
|
||||||
|
|
||||||
# HACK: Needed to compile correctly on Yocto Linux
|
# HACK: Needed to compile correctly on Yocto Linux
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GCC" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
|
||||||
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||||
set(CMAKE_REQUIRED_FLAGS ${prev_req_flags} -std=c++17)
|
set(CMAKE_REQUIRED_FLAGS ${prev_req_flags} -std=c++17)
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -44,16 +44,13 @@ if(Jsoncpp_FOUND)
|
|||||||
message(FATAL_ERROR "Error: jsoncpp lib is too old.....stop")
|
message(FATAL_ERROR "Error: jsoncpp lib is too old.....stop")
|
||||||
endif()
|
endif()
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
execute_process(
|
exec_program(
|
||||||
COMMAND cat ${JSONCPP_INCLUDE_DIRS}/json/version.h
|
cat
|
||||||
COMMAND grep JSONCPP_VERSION_STRING
|
ARGS
|
||||||
COMMAND sed -e "s/.*define/define/"
|
"${JSONCPP_INCLUDE_DIRS}/json/version.h |grep JSONCPP_VERSION_STRING|sed s'/.*define/define/'|awk '{printf $3}'|sed s'/\"//g'"
|
||||||
COMMAND awk "{ printf \$3 }"
|
OUTPUT_VARIABLE
|
||||||
COMMAND sed -e "s/\"//g"
|
jsoncpp_ver)
|
||||||
OUTPUT_VARIABLE jsoncpp_ver)
|
message(STATUS "jsoncpp verson:" ${jsoncpp_ver})
|
||||||
if(NOT Jsoncpp_FIND_QUIETLY)
|
|
||||||
message(STATUS "jsoncpp version:" ${jsoncpp_ver})
|
|
||||||
endif()
|
|
||||||
if(jsoncpp_ver LESS 1.7)
|
if(jsoncpp_ver LESS 1.7)
|
||||||
message(
|
message(
|
||||||
FATAL_ERROR
|
FATAL_ERROR
|
||||||
|
@ -27,26 +27,6 @@
|
|||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
|
|
||||||
# -------------- FIND MYSQL_INCLUDE_DIRS ------------------
|
# -------------- FIND MYSQL_INCLUDE_DIRS ------------------
|
||||||
find_path(MARIADB_INCLUDE_DIRS
|
|
||||||
NAMES mysql.h
|
|
||||||
PATH_SUFFIXES mariadb
|
|
||||||
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)
|
|
||||||
|
|
||||||
find_path(MYSQL_INCLUDE_DIRS
|
find_path(MYSQL_INCLUDE_DIRS
|
||||||
NAMES mysql.h
|
NAMES mysql.h
|
||||||
PATH_SUFFIXES mysql
|
PATH_SUFFIXES mysql
|
||||||
@ -67,9 +47,7 @@ find_path(MYSQL_INCLUDE_DIRS
|
|||||||
$ENV{ProgramFiles}/MySQL/*/include
|
$ENV{ProgramFiles}/MySQL/*/include
|
||||||
$ENV{SystemDrive}/MySQL/*/include)
|
$ENV{SystemDrive}/MySQL/*/include)
|
||||||
|
|
||||||
if(EXISTS "${MARIADB_INCLUDE_DIRS}/mysql.h")
|
if(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql.h")
|
||||||
set(MYSQL_INCLUDE_DIRS ${MARIADB_INCLUDE_DIRS})
|
|
||||||
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql.h")
|
|
||||||
|
|
||||||
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql/mysql.h")
|
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql/mysql.h")
|
||||||
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIRS}/mysql)
|
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIRS}/mysql)
|
||||||
@ -99,7 +77,7 @@ if(WIN32)
|
|||||||
$ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
|
$ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
|
||||||
else(WIN32)
|
else(WIN32)
|
||||||
find_library(MYSQL_LIBRARIES
|
find_library(MYSQL_LIBRARIES
|
||||||
NAMES mysqlclient_r mariadbclient mariadb
|
NAMES mysqlclient_r mariadbclient
|
||||||
PATHS /usr/lib/mysql
|
PATHS /usr/lib/mysql
|
||||||
/usr/lib/mariadb
|
/usr/lib/mariadb
|
||||||
/usr/local/lib/mysql
|
/usr/local/lib/mysql
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"db_clients": [
|
"db_clients": [
|
||||||
{
|
{
|
||||||
//name: Name of the client,'default' by default
|
//name: Name of the client,'default' by default
|
||||||
"name": "default",
|
//"name":"",
|
||||||
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||||
"rdbms": "postgresql",
|
"rdbms": "postgresql",
|
||||||
//filename: Sqlite3 db file name
|
//filename: Sqlite3 db file name
|
||||||
@ -66,18 +66,15 @@
|
|||||||
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
||||||
//zero or negative value means no timeout.
|
//zero or negative value means no timeout.
|
||||||
"timeout": -1.0,
|
"timeout": -1.0,
|
||||||
//auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
//"auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||||
//the wiki for more details.
|
// the wiki for more details.
|
||||||
"auto_batch": false
|
"auto_batch": false
|
||||||
//connect_options: extra options for the connection. Only works for PostgreSQL now.
|
|
||||||
//For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
|
|
||||||
//"connect_options": { "statement_timeout": "1s" }
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"redis_clients": [
|
"redis_clients": [
|
||||||
{
|
{
|
||||||
//name: Name of the client,'default' by default
|
//name: Name of the client,'default' by default
|
||||||
"name": "default",
|
//"name":"",
|
||||||
//host: Server IP, 127.0.0.1 by default
|
//host: Server IP, 127.0.0.1 by default
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
//port: Server port, 6379 by default
|
//port: Server port, 6379 by default
|
||||||
@ -106,14 +103,10 @@
|
|||||||
//enable_session: False by default
|
//enable_session: False by default
|
||||||
"enable_session": true,
|
"enable_session": true,
|
||||||
"session_timeout": 0,
|
"session_timeout": 0,
|
||||||
//string value of SameSite attribute of the Set-Cookie HTTP response header
|
//string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||||
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||||
"session_same_site": "Null",
|
"session_same_site" : "Null",
|
||||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
//document_root: Root path of HTTP document, defaut path is ./
|
||||||
"session_cookie_key": "JSESSIONID",
|
|
||||||
//session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
"session_max_age": -1,
|
|
||||||
//document_root: Root path of HTTP document, default path is ./
|
|
||||||
"document_root": "./",
|
"document_root": "./",
|
||||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
//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
|
//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
|
||||||
@ -187,7 +180,7 @@
|
|||||||
],
|
],
|
||||||
//max_connections: maximum number of connections, 100000 by default
|
//max_connections: maximum number of connections, 100000 by default
|
||||||
"max_connections": 100000,
|
"max_connections": 100000,
|
||||||
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
//max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||||
"max_connections_per_ip": 0,
|
"max_connections_per_ip": 0,
|
||||||
//Load_dynamic_views: False by default, when set to true, drogon
|
//Load_dynamic_views: False by default, when set to true, drogon
|
||||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
@ -217,8 +210,6 @@
|
|||||||
},
|
},
|
||||||
//log: Set log output, drogon output logs to stdout by default
|
//log: Set log output, drogon output logs to stdout by default
|
||||||
"log": {
|
"log": {
|
||||||
//use_spdlog: Use spdlog library to log
|
|
||||||
"use_spdlog": false,
|
|
||||||
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||||
//"log_path": "./",
|
//"log_path": "./",
|
||||||
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||||
@ -310,10 +301,7 @@
|
|||||||
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||||
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||||
// will be rejected.
|
// will be rejected.
|
||||||
"enabled_compressed_request": false,
|
"enabled_compressed_request": false
|
||||||
// enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
|
|
||||||
// See the wiki for more details.
|
|
||||||
"enable_request_stream": false,
|
|
||||||
},
|
},
|
||||||
//plugins: Define all plugins running in the application
|
//plugins: Define all plugins running in the application
|
||||||
"plugins": [
|
"plugins": [
|
||||||
@ -327,22 +315,6 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"path": "/metrics"
|
"path": "/metrics"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "drogon::plugin::AccessLogger",
|
|
||||||
"dependencies": [],
|
|
||||||
"config": {
|
|
||||||
"use_spdlog": false,
|
|
||||||
"log_path": "",
|
|
||||||
"log_format": "",
|
|
||||||
"log_file": "access.log",
|
|
||||||
"log_size_limit": 0,
|
|
||||||
"use_local_time": true,
|
|
||||||
"log_index": 0,
|
|
||||||
// "show_microseconds": true,
|
|
||||||
// "custom_time_format": "",
|
|
||||||
// "use_real_ip": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
# 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`.
|
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||||
# ssl:
|
# ssl:
|
||||||
# cert: ../../trantor/trantor/tests/server.crt
|
# cert: ../../trantor/trantor/tests/server.pem
|
||||||
# key: ../../trantor/trantor/tests/server.key
|
# key: ../../trantor/trantor/tests/server.pem
|
||||||
# conf: [
|
# conf: [
|
||||||
# # [Options, -SessionTicket],
|
# # [Options, -SessionTicket],
|
||||||
# # [Options, Compression]
|
# # [Options, Compression]
|
||||||
@ -30,11 +30,11 @@
|
|||||||
# ]
|
# ]
|
||||||
# db_clients:
|
# db_clients:
|
||||||
# # name: Name of the client,'default' by default
|
# # name: Name of the client,'default' by default
|
||||||
# - name: default
|
# - name: ''
|
||||||
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||||
# rdbms: postgresql
|
# rdbms: postgresql
|
||||||
# # filename: Sqlite3 db file name
|
# # filename: Sqlite3 db file name
|
||||||
# # filename: ''
|
# # filename: '',
|
||||||
# # host: Server address,localhost by default
|
# # host: Server address,localhost by default
|
||||||
# host: 127.0.0.1
|
# host: 127.0.0.1
|
||||||
# # port: Server port, 5432 by default
|
# # port: Server port, 5432 by default
|
||||||
@ -50,23 +50,19 @@
|
|||||||
# is_fast: false
|
# is_fast: false
|
||||||
# # client_encoding: The character set used by the client. it is empty string by default which
|
# # client_encoding: The character set used by the client. it is empty string by default which
|
||||||
# # means use the default character set.
|
# # means use the default character set.
|
||||||
# # client_encoding: ''
|
# # client_encoding: '',
|
||||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
# # 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.
|
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||||
# number_of_connections: 1
|
# number_of_connections: 1
|
||||||
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
||||||
# # zero or negative value means no timeout.
|
# # zero or negative value means no timeout.
|
||||||
# timeout: -1
|
# timeout: -1
|
||||||
# # auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
# # "auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||||
# # the wiki for more details.
|
# # the wiki for more details.
|
||||||
# auto_batch: false
|
# auto_batch: false
|
||||||
# # connect_options: extra options for the connection. Only works for PostgreSQL now.
|
|
||||||
# # For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
|
|
||||||
# # connect_options:
|
|
||||||
# # statement_timeout: '1s'
|
|
||||||
# redis_clients:
|
# redis_clients:
|
||||||
# # name: Name of the client,'default' by default
|
# # name: Name of the client,'default' by default
|
||||||
# - name: default
|
# - name: ''
|
||||||
# # host: Server IP, 127.0.0.1 by default
|
# # host: Server IP, 127.0.0.1 by default
|
||||||
# host: 127.0.0.1
|
# host: 127.0.0.1
|
||||||
# # port: Server port, 6379 by default
|
# # port: Server port, 6379 by default
|
||||||
@ -93,14 +89,10 @@ app:
|
|||||||
# enable_session: False by default
|
# enable_session: False by default
|
||||||
enable_session: true
|
enable_session: true
|
||||||
session_timeout: 0
|
session_timeout: 0
|
||||||
# string value of SameSite attribute of the Set-Cookie HTTP response header
|
# string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||||
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||||
session_same_site: 'Null'
|
session_same_site: 'Null'
|
||||||
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
# document_root: Root path of HTTP document, defaut path is ./
|
||||||
session_cookie_key: 'JSESSIONID'
|
|
||||||
# session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
session_max_age: -1
|
|
||||||
# document_root: Root path of HTTP document, default path is ./
|
|
||||||
document_root: ./
|
document_root: ./
|
||||||
# home_page: Set the HTML file of the home page, the default value is "index.html"
|
# 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
|
# 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
|
||||||
@ -140,10 +132,8 @@ app:
|
|||||||
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||||
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||||
mime: {
|
mime: {
|
||||||
# text/markdown: md
|
# text/markdown: md,
|
||||||
# text/gemini:
|
# text/gemini: [gmi, gemini]
|
||||||
# - gmi
|
|
||||||
# - gemini
|
|
||||||
}
|
}
|
||||||
# locations: An array of locations of static files for GET requests.
|
# locations: An array of locations of static files for GET requests.
|
||||||
locations:
|
locations:
|
||||||
@ -167,7 +157,7 @@ app:
|
|||||||
filters: []
|
filters: []
|
||||||
# max_connections: maximum number of connections, 100000 by default
|
# max_connections: maximum number of connections, 100000 by default
|
||||||
max_connections: 100000
|
max_connections: 100000
|
||||||
# max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
# max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||||
max_connections_per_ip: 0
|
max_connections_per_ip: 0
|
||||||
# Load_dynamic_views: False by default, when set to true, drogon
|
# Load_dynamic_views: False by default, when set to true, drogon
|
||||||
# compiles and loads dynamically "CSP View Files" in directories defined
|
# compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
@ -195,8 +185,6 @@ app:
|
|||||||
precision_type: significant
|
precision_type: significant
|
||||||
# log: Set log output, drogon output logs to stdout by default
|
# log: Set log output, drogon output logs to stdout by default
|
||||||
log:
|
log:
|
||||||
# use_spdlog: Use spdlog library to log
|
|
||||||
use_spdlog: false
|
|
||||||
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||||
# log_path: ./
|
# log_path: ./
|
||||||
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||||
@ -205,9 +193,6 @@ app:
|
|||||||
# log_size_limit: 100000000 bytes by default,
|
# log_size_limit: 100000000 bytes by default,
|
||||||
# When the log file size reaches "log_size_limit", the log file is switched.
|
# When the log file size reaches "log_size_limit", the log file is switched.
|
||||||
log_size_limit: 100000000
|
log_size_limit: 100000000
|
||||||
# max_files: 0 by default,
|
|
||||||
# When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
|
|
||||||
max_files: 0
|
|
||||||
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||||
# The TRACE level is only valid when built in DEBUG mode.
|
# The TRACE level is only valid when built in DEBUG mode.
|
||||||
log_level: DEBUG
|
log_level: DEBUG
|
||||||
@ -230,14 +215,14 @@ app:
|
|||||||
# 0 means cache forever, the negative value means no cache
|
# 0 means cache forever, the negative value means no cache
|
||||||
static_files_cache_time: 5
|
static_files_cache_time: 5
|
||||||
# simple_controllers_map: Used to configure mapping from path to simple controller
|
# simple_controllers_map: Used to configure mapping from path to simple controller
|
||||||
# simple_controllers_map:
|
simple_controllers_map:
|
||||||
# - path: /path/name
|
- path: /path/name
|
||||||
# controller: controllerClassName
|
controller: controllerClassName
|
||||||
# http_methods:
|
http_methods:
|
||||||
# - get
|
- get
|
||||||
# - post
|
- post
|
||||||
# filters:
|
filters:
|
||||||
# - FilterClassName
|
- FilterClassName
|
||||||
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||||
# of the connection without read or write
|
# of the connection without read or write
|
||||||
idle_connection_timeout: 60
|
idle_connection_timeout: 60
|
||||||
@ -278,37 +263,23 @@ app:
|
|||||||
client_max_websocket_message_size: 128K
|
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: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||||
reuse_port: false
|
reuse_port: false
|
||||||
# enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
# enabled_compresed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||||
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||||
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||||
# will be rejected.
|
# will be rejected.
|
||||||
enabled_compressed_request: false
|
enabled_compresed_request: false
|
||||||
# enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
|
|
||||||
# See the wiki for more details.
|
|
||||||
enable_request_stream: false
|
|
||||||
# plugins: Define all plugins running in the application
|
# plugins: Define all plugins running in the application
|
||||||
plugins:
|
plugins:
|
||||||
# name: The class name of the plugin
|
# name: The class name of the plugin
|
||||||
- name: drogon::plugin::PromExporter
|
- name: '' # drogon::plugin::SecureSSLRedirector
|
||||||
# dependencies: Plugins that the plugin depends on. It can be commented out
|
# dependencies: Plugins that the plugin depends on. It can be commented out
|
||||||
dependencies: []
|
dependencies: []
|
||||||
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||||
# It can be commented out
|
# It can be commented out
|
||||||
config:
|
config:
|
||||||
path: /metrics
|
ssl_redirect_exempt:
|
||||||
- name: drogon::plugin::AccessLogger
|
- .*\.jpg
|
||||||
dependencies: []
|
secure_ssl_host: 'localhost:8849'
|
||||||
config:
|
|
||||||
use_spdlog: false
|
|
||||||
log_path: ''
|
|
||||||
log_format: ''
|
|
||||||
log_file: access.log
|
|
||||||
log_size_limit: 0
|
|
||||||
use_local_time: true
|
|
||||||
log_index: 0
|
|
||||||
# show_microseconds: true
|
|
||||||
# custom_time_format: ''
|
|
||||||
# use_real_ip: false
|
|
||||||
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||||
custom_config:
|
custom_config:
|
||||||
realm: drogonRealm
|
realm: drogonRealm
|
||||||
@ -316,3 +287,4 @@ custom_config:
|
|||||||
credentials:
|
credentials:
|
||||||
- user: drogon
|
- user: drogon
|
||||||
password: dr0g0n
|
password: dr0g0n
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ target_link_libraries(drogon_ctl PRIVATE ${PROJECT_NAME})
|
|||||||
target_include_directories(drogon_ctl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(drogon_ctl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
add_dependencies(drogon_ctl _drogon_ctl)
|
add_dependencies(drogon_ctl _drogon_ctl)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(drogon_ctl PRIVATE ws2_32 rpcrt4 iphlpapi)
|
target_link_libraries(drogon_ctl PRIVATE ws2_32 Rpcrt4 iphlpapi)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(drogon_ctl PRIVATE resolv)
|
target_link_libraries(drogon_ctl PRIVATE resolv)
|
||||||
|
@ -42,8 +42,7 @@ std::string create::detail()
|
|||||||
"create a plugin named class_name\n\n"
|
"create a plugin named class_name\n\n"
|
||||||
"drogon_ctl create project <project_name> //"
|
"drogon_ctl create project <project_name> //"
|
||||||
"create a project named project_name\n\n"
|
"create a project named project_name\n\n"
|
||||||
"drogon_ctl create model <model_path> [-o <output path>] "
|
"drogon_ctl create model <model_path> [--table=<table_name>] [-f]//"
|
||||||
"[--table=<table_name>] [-f]//"
|
|
||||||
"create model classes in model_path\n";
|
"create model classes in model_path\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,17 +66,6 @@ static std::string escapeConnString(const std::string &str)
|
|||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string drogon_ctl::escapeIdentifier(const std::string &identifier,
|
|
||||||
const std::string &rdbms)
|
|
||||||
{
|
|
||||||
if (rdbms != "postgresql")
|
|
||||||
{
|
|
||||||
return identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "\\\"" + identifier + "\\\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::map<std::string, std::vector<ConvertMethod>> getConvertMethods(
|
static std::map<std::string, std::vector<ConvertMethod>> getConvertMethods(
|
||||||
const Json::Value &convertColumns)
|
const Json::Value &convertColumns)
|
||||||
{
|
{
|
||||||
@ -177,7 +166,7 @@ void create_model::createModelClassFromPG(
|
|||||||
auto className = nameTransform(tableName, true);
|
auto className = nameTransform(tableName, true);
|
||||||
HttpViewData data;
|
HttpViewData data;
|
||||||
data["className"] = className;
|
data["className"] = className;
|
||||||
data["tableName"] = tableName;
|
data["tableName"] = toLower(tableName);
|
||||||
data["hasPrimaryKey"] = (int)0;
|
data["hasPrimaryKey"] = (int)0;
|
||||||
data["primaryKeyName"] = "";
|
data["primaryKeyName"] = "";
|
||||||
data["dbName"] = dbname_;
|
data["dbName"] = dbname_;
|
||||||
@ -189,10 +178,10 @@ void create_model::createModelClassFromPG(
|
|||||||
data["schema"] = schema;
|
data["schema"] = schema;
|
||||||
}
|
}
|
||||||
std::vector<ColumnInfo> cols;
|
std::vector<ColumnInfo> cols;
|
||||||
*client << "SELECT * "
|
*client << "SELECT * \
|
||||||
"FROM information_schema.columns "
|
FROM information_schema.columns \
|
||||||
"WHERE table_schema = $1 "
|
WHERE table_schema = $1 \
|
||||||
"AND table_name = $2"
|
AND table_name = $2"
|
||||||
<< schema << tableName << Mode::Blocking >>
|
<< schema << tableName << Mode::Blocking >>
|
||||||
[&](const Result &r) {
|
[&](const Result &r) {
|
||||||
if (r.size() == 0)
|
if (r.size() == 0)
|
||||||
@ -295,14 +284,14 @@ void create_model::createModelClassFromPG(
|
|||||||
exit(1);
|
exit(1);
|
||||||
};
|
};
|
||||||
size_t pkNumber = 0;
|
size_t pkNumber = 0;
|
||||||
*client << "SELECT "
|
*client << "SELECT \
|
||||||
"pg_constraint.conname AS pk_name,"
|
pg_constraint.conname AS pk_name,\
|
||||||
"pg_constraint.conkey AS pk_vector "
|
pg_constraint.conkey AS pk_vector \
|
||||||
"FROM pg_constraint "
|
FROM pg_constraint \
|
||||||
"INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid "
|
INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid \
|
||||||
"WHERE "
|
WHERE \
|
||||||
"pg_class.relname = $1 "
|
pg_class.relname = $1 \
|
||||||
"AND pg_constraint.contype = 'p'"
|
AND pg_constraint.contype = 'p'"
|
||||||
<< tableName << Mode::Blocking >>
|
<< tableName << Mode::Blocking >>
|
||||||
[&](bool isNull,
|
[&](bool isNull,
|
||||||
const std::string &pkName,
|
const std::string &pkName,
|
||||||
@ -319,18 +308,16 @@ void create_model::createModelClassFromPG(
|
|||||||
data["hasPrimaryKey"] = (int)pkNumber;
|
data["hasPrimaryKey"] = (int)pkNumber;
|
||||||
if (pkNumber == 1)
|
if (pkNumber == 1)
|
||||||
{
|
{
|
||||||
*client << "SELECT "
|
*client << "SELECT \
|
||||||
"pg_attribute.attname AS colname,"
|
pg_attribute.attname AS colname,\
|
||||||
"pg_type.typname AS typename,"
|
pg_type.typname AS typename,\
|
||||||
"pg_constraint.contype AS contype "
|
pg_constraint.contype AS contype \
|
||||||
"FROM pg_constraint "
|
FROM pg_constraint \
|
||||||
"INNER JOIN pg_class ON pg_constraint.conrelid = "
|
INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid \
|
||||||
"pg_class.oid "
|
INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid \
|
||||||
"INNER JOIN pg_attribute ON pg_attribute.attrelid = "
|
AND pg_attribute.attnum = pg_constraint.conkey [ 1 ] \
|
||||||
"pg_class.oid "
|
INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid \
|
||||||
"AND pg_attribute.attnum = pg_constraint.conkey [ 1 ] "
|
WHERE pg_class.relname = $1 and pg_constraint.contype='p'"
|
||||||
"INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid "
|
|
||||||
"WHERE pg_class.relname = $1 and pg_constraint.contype='p'"
|
|
||||||
<< tableName << Mode::Blocking >>
|
<< tableName << Mode::Blocking >>
|
||||||
[&](bool isNull,
|
[&](bool isNull,
|
||||||
const std::string &colName,
|
const std::string &colName,
|
||||||
@ -358,20 +345,16 @@ void create_model::createModelClassFromPG(
|
|||||||
std::vector<std::string> pkNames, pkTypes, pkValNames;
|
std::vector<std::string> pkNames, pkTypes, pkValNames;
|
||||||
for (size_t i = 1; i <= pkNumber; ++i)
|
for (size_t i = 1; i <= pkNumber; ++i)
|
||||||
{
|
{
|
||||||
*client << "SELECT "
|
*client << "SELECT \
|
||||||
"pg_attribute.attname AS colname,"
|
pg_attribute.attname AS colname,\
|
||||||
"pg_type.typname AS typename,"
|
pg_type.typname AS typename,\
|
||||||
"pg_constraint.contype AS contype "
|
pg_constraint.contype AS contype \
|
||||||
"FROM pg_constraint "
|
FROM pg_constraint \
|
||||||
"INNER JOIN pg_class ON pg_constraint.conrelid = "
|
INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid \
|
||||||
"pg_class.oid "
|
INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid \
|
||||||
"INNER JOIN pg_attribute ON pg_attribute.attrelid = "
|
AND pg_attribute.attnum = pg_constraint.conkey [ $1 ] \
|
||||||
"pg_class.oid "
|
INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid \
|
||||||
"AND pg_attribute.attnum = pg_constraint.conkey [ $1 ] "
|
WHERE pg_class.relname = $2 and pg_constraint.contype='p'"
|
||||||
"INNER JOIN pg_type ON pg_type.oid = "
|
|
||||||
"pg_attribute.atttypid "
|
|
||||||
"WHERE pg_class.relname = $2 and "
|
|
||||||
"pg_constraint.contype='p'"
|
|
||||||
<< (int)i << tableName << Mode::Blocking >>
|
<< (int)i << tableName << Mode::Blocking >>
|
||||||
[&](bool isNull, std::string colName, const std::string &type) {
|
[&](bool isNull, std::string colName, const std::string &type) {
|
||||||
if (isNull)
|
if (isNull)
|
||||||
@ -471,7 +454,7 @@ void create_model::createModelClassFromMysql(
|
|||||||
data["convertMethods"] = convertMethods;
|
data["convertMethods"] = convertMethods;
|
||||||
std::vector<ColumnInfo> cols;
|
std::vector<ColumnInfo> cols;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
*client << "desc `" + tableName + "`" << Mode::Blocking >>
|
*client << "desc " + tableName << Mode::Blocking >>
|
||||||
[&i, &cols](bool isNull,
|
[&i, &cols](bool isNull,
|
||||||
const std::string &field,
|
const std::string &field,
|
||||||
const std::string &type,
|
const std::string &type,
|
||||||
@ -826,7 +809,6 @@ void create_model::createModel(const std::string &path,
|
|||||||
auto restfulApiConfig = config["restful_api_controllers"];
|
auto restfulApiConfig = config["restful_api_controllers"];
|
||||||
auto relationships = getRelationships(config["relationships"]);
|
auto relationships = getRelationships(config["relationships"]);
|
||||||
auto convertMethods = getConvertMethods(config["convert"]);
|
auto convertMethods = getConvertMethods(config["convert"]);
|
||||||
drogon::utils::createPath(path);
|
|
||||||
if (dbType == "postgresql")
|
if (dbType == "postgresql")
|
||||||
{
|
{
|
||||||
#if USE_POSTGRESQL
|
#if USE_POSTGRESQL
|
||||||
@ -1174,9 +1156,7 @@ void create_model::createModel(const std::string &path,
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
infile >> configJsonRoot;
|
infile >> configJsonRoot;
|
||||||
createModel(outputPath_.empty() ? path : outputPath_,
|
createModel(path, configJsonRoot, singleModelName);
|
||||||
configJsonRoot,
|
|
||||||
singleModelName);
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &exception)
|
catch (const std::exception &exception)
|
||||||
{
|
{
|
||||||
@ -1214,22 +1194,6 @@ void create_model::handleCommand(std::vector<std::string> ¶meters)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &path : parameters)
|
for (auto const &path : parameters)
|
||||||
{
|
{
|
||||||
createModel(path, singleModelName);
|
createModel(path, singleModelName);
|
||||||
|
@ -78,9 +78,6 @@ inline std::string nameTransform(const std::string &origName, bool isType)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string escapeIdentifier(const std::string &identifier,
|
|
||||||
const std::string &rdbms);
|
|
||||||
|
|
||||||
class PivotTable
|
class PivotTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -429,6 +426,5 @@ class create_model : public DrObject<create_model>, public CommandHandler
|
|||||||
const Json::Value &restfulApiConfig);
|
const Json::Value &restfulApiConfig);
|
||||||
std::string dbname_;
|
std::string dbname_;
|
||||||
bool forceOverwrite_{false};
|
bool forceOverwrite_{false};
|
||||||
std::string outputPath_;
|
|
||||||
};
|
};
|
||||||
} // namespace drogon_ctl
|
} // namespace drogon_ctl
|
||||||
|
@ -411,7 +411,6 @@ void create_view::newViewSourceFile(std::ofstream &file,
|
|||||||
"automatically,don't modify it!\n";
|
"automatically,don't modify it!\n";
|
||||||
file << "#include \"" << namespacePrefix << className << ".h\"\n";
|
file << "#include \"" << namespacePrefix << className << ".h\"\n";
|
||||||
file << "#include <drogon/utils/OStringStream.h>\n";
|
file << "#include <drogon/utils/OStringStream.h>\n";
|
||||||
file << "#include <drogon/utils/Utilities.h>\n";
|
|
||||||
file << "#include <string>\n";
|
file << "#include <string>\n";
|
||||||
file << "#include <map>\n";
|
file << "#include <map>\n";
|
||||||
file << "#include <vector>\n";
|
file << "#include <vector>\n";
|
||||||
|
@ -18,11 +18,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <cstdlib>
|
#include <stdlib.h>
|
||||||
#include <json/json.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -36,11 +32,10 @@ std::string press::detail()
|
|||||||
" -n num number of requests(default : 1)\n"
|
" -n num number of requests(default : 1)\n"
|
||||||
" -t num number of threads(default : 1)\n"
|
" -t num number of threads(default : 1)\n"
|
||||||
" -c num concurrent connections(default : 1)\n"
|
" -c num concurrent connections(default : 1)\n"
|
||||||
" -k disable SSL certificate validation(default: enable)\n"
|
// " -k keep alive(default: no)\n"
|
||||||
" -f customize http request json file(default: disenable)\n"
|
" -q no progress indication(default: no)\n\n"
|
||||||
" -q no progress indication(default: show)\n\n"
|
|
||||||
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
|
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
|
||||||
"http://localhost:8080/index.html -f ./http_request.json\n";
|
"http://localhost:8080/index.html\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void outputErrorAndExit(const std::string_view &err)
|
void outputErrorAndExit(const std::string_view &err)
|
||||||
@ -156,29 +151,11 @@ void press::handleCommand(std::vector<std::string> ¶meters)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (param.find("-f") == 0)
|
// else if (param == "-k")
|
||||||
{
|
// {
|
||||||
if (param == "-f")
|
// keepAlive_ = true;
|
||||||
{
|
// continue;
|
||||||
++iter;
|
// }
|
||||||
if (iter == parameters.end())
|
|
||||||
{
|
|
||||||
outputErrorAndExit("No http request json file!");
|
|
||||||
}
|
|
||||||
httpRequestJsonFile_ = *iter;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
httpRequestJsonFile_ = param.substr(2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (param == "-k")
|
|
||||||
{
|
|
||||||
certValidation_ = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (param == "-q")
|
else if (param == "-q")
|
||||||
{
|
{
|
||||||
processIndication_ = false;
|
processIndication_ = false;
|
||||||
@ -201,7 +178,7 @@ void press::handleCommand(std::vector<std::string> ¶meters)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto pos = url_.find("://");
|
auto pos = url_.find("://");
|
||||||
auto posOfPath = url_.find('/', pos + 3);
|
auto posOfPath = url_.find("/", pos + 3);
|
||||||
if (posOfPath == std::string::npos)
|
if (posOfPath == std::string::npos)
|
||||||
{
|
{
|
||||||
host_ = url_;
|
host_ = url_;
|
||||||
@ -213,118 +190,6 @@ void press::handleCommand(std::vector<std::string> ¶meters)
|
|||||||
path_ = url_.substr(posOfPath);
|
path_ = url_.substr(posOfPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
http_request.json
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"header": {
|
|
||||||
"token": "e2e9d0fe-dd14-4eaf-8ac1-0997730a805d"
|
|
||||||
},
|
|
||||||
"body": {
|
|
||||||
"passwd": "123456",
|
|
||||||
"account": "10001"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (!httpRequestJsonFile_.empty())
|
|
||||||
{
|
|
||||||
Json::Value httpRequestJson;
|
|
||||||
std::ifstream httpRequestFile(httpRequestJsonFile_,
|
|
||||||
std::ifstream::binary);
|
|
||||||
if (!httpRequestFile.is_open())
|
|
||||||
{
|
|
||||||
outputErrorAndExit(std::string{"No "} + httpRequestJsonFile_);
|
|
||||||
}
|
|
||||||
httpRequestFile >> httpRequestJson;
|
|
||||||
|
|
||||||
if (!httpRequestJson.isMember("method"))
|
|
||||||
{
|
|
||||||
outputErrorAndExit("No contain method");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto methodStr = httpRequestJson["method"].asString();
|
|
||||||
std::transform(methodStr.begin(),
|
|
||||||
methodStr.end(),
|
|
||||||
methodStr.begin(),
|
|
||||||
::toupper);
|
|
||||||
|
|
||||||
auto toHttpMethod = [&]() -> drogon::HttpMethod {
|
|
||||||
if (methodStr == "GET")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Get;
|
|
||||||
}
|
|
||||||
else if (methodStr == "POST")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Post;
|
|
||||||
}
|
|
||||||
else if (methodStr == "HEAD")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Head;
|
|
||||||
}
|
|
||||||
else if (methodStr == "PUT")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Put;
|
|
||||||
}
|
|
||||||
else if (methodStr == "DELETE")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Delete;
|
|
||||||
}
|
|
||||||
else if (methodStr == "OPTIONS")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Options;
|
|
||||||
}
|
|
||||||
else if (methodStr == "PATCH")
|
|
||||||
{
|
|
||||||
return drogon::HttpMethod::Patch;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outputErrorAndExit("invalid method");
|
|
||||||
}
|
|
||||||
return drogon::HttpMethod::Get;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> header;
|
|
||||||
if (httpRequestJson.isMember("header"))
|
|
||||||
{
|
|
||||||
auto &jsonValue = httpRequestJson["header"];
|
|
||||||
for (const auto &key : jsonValue.getMemberNames())
|
|
||||||
{
|
|
||||||
if (jsonValue[key].isString())
|
|
||||||
{
|
|
||||||
header[key] = jsonValue[key].asString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
header[key] = jsonValue[key].toStyledString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string body;
|
|
||||||
if (httpRequestJson.isMember("body"))
|
|
||||||
{
|
|
||||||
Json::FastWriter fastWriter;
|
|
||||||
body = fastWriter.write(httpRequestJson["body"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
createHttpRequestFunc_ = [this,
|
|
||||||
method = toHttpMethod(),
|
|
||||||
body = std::move(body),
|
|
||||||
header =
|
|
||||||
std::move(header)]() -> HttpRequestPtr {
|
|
||||||
auto request = HttpRequest::newHttpRequest();
|
|
||||||
request->setPath(path_);
|
|
||||||
request->setMethod(method);
|
|
||||||
for (const auto &[field, val] : header)
|
|
||||||
request->addHeader(field, val);
|
|
||||||
if (!body.empty())
|
|
||||||
request->setBody(body);
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::cout << "host=" << host_ << std::endl;
|
// std::cout << "host=" << host_ << std::endl;
|
||||||
// std::cout << "path=" << path_ << std::endl;
|
// std::cout << "path=" << path_ << std::endl;
|
||||||
doTesting();
|
doTesting();
|
||||||
@ -351,10 +216,8 @@ void press::createRequestAndClients()
|
|||||||
loopPool_->start();
|
loopPool_->start();
|
||||||
for (size_t i = 0; i < numOfConnections_; ++i)
|
for (size_t i = 0; i < numOfConnections_; ++i)
|
||||||
{
|
{
|
||||||
auto client = HttpClient::newHttpClient(host_,
|
auto client =
|
||||||
loopPool_->getNextLoop(),
|
HttpClient::newHttpClient(host_, loopPool_->getNextLoop());
|
||||||
false,
|
|
||||||
certValidation_);
|
|
||||||
client->enableCookies();
|
client->enableCookies();
|
||||||
clients_.push_back(client);
|
clients_.push_back(client);
|
||||||
}
|
}
|
||||||
@ -367,19 +230,9 @@ void press::sendRequest(const HttpClientPtr &client)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto request = HttpRequest::newHttpRequest();
|
||||||
HttpRequestPtr request;
|
|
||||||
if (createHttpRequestFunc_)
|
|
||||||
{
|
|
||||||
request = createHttpRequestFunc_();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request = HttpRequest::newHttpRequest();
|
|
||||||
request->setPath(path_);
|
request->setPath(path_);
|
||||||
request->setMethod(Get);
|
request->setMethod(Get);
|
||||||
}
|
|
||||||
|
|
||||||
// std::cout << "send!" << std::endl;
|
// std::cout << "send!" << std::endl;
|
||||||
client->sendRequest(
|
client->sendRequest(
|
||||||
request,
|
request,
|
||||||
@ -431,6 +284,7 @@ void press::sendRequest(const HttpClientPtr &client)
|
|||||||
|
|
||||||
void press::outputResults()
|
void press::outputResults()
|
||||||
{
|
{
|
||||||
|
static std::mutex mtx;
|
||||||
size_t totalSent = 0;
|
size_t totalSent = 0;
|
||||||
size_t totalRecv = 0;
|
size_t totalRecv = 0;
|
||||||
for (auto &client : clients_)
|
for (auto &client : clients_)
|
||||||
@ -442,7 +296,7 @@ void press::outputResults()
|
|||||||
auto microSecs = now.microSecondsSinceEpoch() -
|
auto microSecs = now.microSecondsSinceEpoch() -
|
||||||
statistics_.startDate_.microSecondsSinceEpoch();
|
statistics_.startDate_.microSecondsSinceEpoch();
|
||||||
double seconds = (double)microSecs / 1000000.0;
|
double seconds = (double)microSecs / 1000000.0;
|
||||||
auto rps = static_cast<size_t>(statistics_.numOfGoodResponse_ / seconds);
|
size_t rps = static_cast<size_t>(statistics_.numOfGoodResponse_ / seconds);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "TOTALS: " << numOfConnections_ << " connect, "
|
std::cout << "TOTALS: " << numOfConnections_ << " connect, "
|
||||||
<< numOfRequests_ << " requests, "
|
<< numOfRequests_ << " requests, "
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include <drogon/HttpClient.h>
|
#include <drogon/HttpClient.h>
|
||||||
#include <trantor/utils/Date.h>
|
#include <trantor/utils/Date.h>
|
||||||
#include <trantor/net/EventLoopThreadPool.h>
|
#include <trantor/net/EventLoopThreadPool.h>
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -63,9 +62,7 @@ class press : public DrObject<press>, public CommandHandler
|
|||||||
size_t numOfThreads_{1};
|
size_t numOfThreads_{1};
|
||||||
size_t numOfRequests_{1};
|
size_t numOfRequests_{1};
|
||||||
size_t numOfConnections_{1};
|
size_t numOfConnections_{1};
|
||||||
std::string httpRequestJsonFile_;
|
// bool keepAlive_ = false;
|
||||||
std::function<HttpRequestPtr()> createHttpRequestFunc_;
|
|
||||||
bool certValidation_{true};
|
|
||||||
bool processIndication_{true};
|
bool processIndication_{true};
|
||||||
std::string url_;
|
std::string url_;
|
||||||
std::string host_;
|
std::string host_;
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"db_clients": [
|
"db_clients": [
|
||||||
{
|
{
|
||||||
//name: Name of the client,'default' by default
|
//name: Name of the client,'default' by default
|
||||||
"name": "default",
|
//"name":"",
|
||||||
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||||
"rdbms": "postgresql",
|
"rdbms": "postgresql",
|
||||||
//filename: Sqlite3 db file name
|
//filename: Sqlite3 db file name
|
||||||
@ -66,18 +66,15 @@
|
|||||||
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
|
||||||
//zero or negative value means no timeout.
|
//zero or negative value means no timeout.
|
||||||
"timeout": -1.0,
|
"timeout": -1.0,
|
||||||
//auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
//"auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||||
//the wiki for more details.
|
// the wiki for more details.
|
||||||
"auto_batch": false
|
"auto_batch": false
|
||||||
//connect_options: extra options for the connection. Only works for PostgreSQL now.
|
|
||||||
//For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
|
|
||||||
//"connect_options": { "statement_timeout": "1s" }
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"redis_clients": [
|
"redis_clients": [
|
||||||
{
|
{
|
||||||
//name: Name of the client,'default' by default
|
//name: Name of the client,'default' by default
|
||||||
"name": "default",
|
//"name":"",
|
||||||
//host: Server IP, 127.0.0.1 by default
|
//host: Server IP, 127.0.0.1 by default
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
//port: Server port, 6379 by default
|
//port: Server port, 6379 by default
|
||||||
@ -106,14 +103,10 @@
|
|||||||
//enable_session: False by default
|
//enable_session: False by default
|
||||||
"enable_session": false,
|
"enable_session": false,
|
||||||
"session_timeout": 0,
|
"session_timeout": 0,
|
||||||
//string value of SameSite attribute of the Set-Cookie HTTP response header
|
//string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||||
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||||
"session_same_site" : "Null",
|
"session_same_site" : "Null",
|
||||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
//document_root: Root path of HTTP document, defaut path is ./
|
||||||
"session_cookie_key": "JSESSIONID",
|
|
||||||
//session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
"session_max_age": -1,
|
|
||||||
//document_root: Root path of HTTP document, default path is ./
|
|
||||||
"document_root": "./",
|
"document_root": "./",
|
||||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
//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
|
//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
|
||||||
@ -153,8 +146,8 @@
|
|||||||
"apk",
|
"apk",
|
||||||
"cur",
|
"cur",
|
||||||
"xml",
|
"xml",
|
||||||
"webp",
|
"svg",
|
||||||
"svg"
|
"webp"
|
||||||
],
|
],
|
||||||
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||||
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||||
@ -187,7 +180,7 @@
|
|||||||
],
|
],
|
||||||
//max_connections: maximum number of connections, 100000 by default
|
//max_connections: maximum number of connections, 100000 by default
|
||||||
"max_connections": 100000,
|
"max_connections": 100000,
|
||||||
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
//max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||||
"max_connections_per_ip": 0,
|
"max_connections_per_ip": 0,
|
||||||
//Load_dynamic_views: False by default, when set to true, drogon
|
//Load_dynamic_views: False by default, when set to true, drogon
|
||||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
@ -217,8 +210,6 @@
|
|||||||
},
|
},
|
||||||
//log: Set log output, drogon output logs to stdout by default
|
//log: Set log output, drogon output logs to stdout by default
|
||||||
"log": {
|
"log": {
|
||||||
//use_spdlog: Use spdlog library to log
|
|
||||||
"use_spdlog": false,
|
|
||||||
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||||
//"log_path": "./",
|
//"log_path": "./",
|
||||||
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||||
@ -253,19 +244,19 @@
|
|||||||
//0 means cache forever, the negative value means no cache
|
//0 means cache forever, the negative value means no cache
|
||||||
"static_files_cache_time": 5,
|
"static_files_cache_time": 5,
|
||||||
//simple_controllers_map: Used to configure mapping from path to simple controller
|
//simple_controllers_map: Used to configure mapping from path to simple controller
|
||||||
//"simple_controllers_map": [
|
"simple_controllers_map": [
|
||||||
// {
|
{
|
||||||
// "path": "/path/name",
|
"path": "/path/name",
|
||||||
// "controller": "controllerClassName",
|
"controller": "controllerClassName",
|
||||||
// "http_methods": [
|
"http_methods": [
|
||||||
// "get",
|
"get",
|
||||||
// "post"
|
"post"
|
||||||
// ],
|
],
|
||||||
// "filters": [
|
"filters": [
|
||||||
// "FilterClassName"
|
"FilterClassName"
|
||||||
// ]
|
]
|
||||||
// }
|
}
|
||||||
//],
|
],
|
||||||
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||||
//of the connection without read or write
|
//of the connection without read or write
|
||||||
"idle_connection_timeout": 60,
|
"idle_connection_timeout": 60,
|
||||||
@ -310,38 +301,22 @@
|
|||||||
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||||
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||||
// will be rejected.
|
// will be rejected.
|
||||||
"enabled_compressed_request": false,
|
"enabled_compressed_request": false
|
||||||
// enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
|
|
||||||
// See the wiki for more details.
|
|
||||||
"enable_request_stream": false,
|
|
||||||
},
|
},
|
||||||
//plugins: Define all plugins running in the application
|
//plugins: Define all plugins running in the application
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
//name: The class name of the plugin
|
//name: The class name of the plugin
|
||||||
"name": "drogon::plugin::PromExporter",
|
//"name": "drogon::plugin::SecureSSLRedirector",
|
||||||
//dependencies: Plugins that the plugin depends on. It can be commented out
|
//dependencies: Plugins that the plugin depends on. It can be commented out
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||||
//It can be commented out
|
//It can be commented out
|
||||||
"config": {
|
"config": {
|
||||||
"path": "/metrics"
|
"ssl_redirect_exempt": [
|
||||||
}
|
".*\\.jpg"
|
||||||
},
|
],
|
||||||
{
|
"secure_ssl_host": "localhost:8849"
|
||||||
"name": "drogon::plugin::AccessLogger",
|
|
||||||
"dependencies": [],
|
|
||||||
"config": {
|
|
||||||
"use_spdlog": false,
|
|
||||||
"log_path": "",
|
|
||||||
"log_format": "",
|
|
||||||
"log_file": "access.log",
|
|
||||||
"log_size_limit": 0,
|
|
||||||
"use_local_time": true,
|
|
||||||
"log_index": 0,
|
|
||||||
// "show_microseconds": true,
|
|
||||||
// "custom_time_format": "",
|
|
||||||
// "use_real_ip": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
|
# 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`.
|
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
|
||||||
# ssl:
|
# ssl:
|
||||||
# cert: ../../trantor/trantor/tests/server.crt
|
# cert: ../../trantor/trantor/tests/server.pem
|
||||||
# key: ../../trantor/trantor/tests/server.key
|
# key: ../../trantor/trantor/tests/server.pem
|
||||||
# conf: [
|
# conf: [
|
||||||
# # [Options, -SessionTicket],
|
# # [Options, -SessionTicket],
|
||||||
# # [Options, Compression]
|
# # [Options, Compression]
|
||||||
@ -30,11 +30,11 @@
|
|||||||
# ]
|
# ]
|
||||||
# db_clients:
|
# db_clients:
|
||||||
# # name: Name of the client,'default' by default
|
# # name: Name of the client,'default' by default
|
||||||
# - name: default
|
# - name: ''
|
||||||
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
|
||||||
# rdbms: postgresql
|
# rdbms: postgresql
|
||||||
# # filename: Sqlite3 db file name
|
# # filename: Sqlite3 db file name
|
||||||
# # filename: ''
|
# # filename: '',
|
||||||
# # host: Server address,localhost by default
|
# # host: Server address,localhost by default
|
||||||
# host: 127.0.0.1
|
# host: 127.0.0.1
|
||||||
# # port: Server port, 5432 by default
|
# # port: Server port, 5432 by default
|
||||||
@ -50,23 +50,19 @@
|
|||||||
# is_fast: false
|
# is_fast: false
|
||||||
# # client_encoding: The character set used by the client. it is empty string by default which
|
# # client_encoding: The character set used by the client. it is empty string by default which
|
||||||
# # means use the default character set.
|
# # means use the default character set.
|
||||||
# # client_encoding: ''
|
# # client_encoding: '',
|
||||||
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
|
# # 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.
|
# # connections per IO thread, otherwise it is the total number of all connections.
|
||||||
# number_of_connections: 1
|
# number_of_connections: 1
|
||||||
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
|
||||||
# # zero or negative value means no timeout.
|
# # zero or negative value means no timeout.
|
||||||
# timeout: -1
|
# timeout: -1
|
||||||
# # auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
# # "auto_batch": this feature is only available for the PostgreSQL driver(version >= 14.0), see
|
||||||
# # the wiki for more details.
|
# # the wiki for more details.
|
||||||
# auto_batch: false
|
# auto_batch: false
|
||||||
# # connect_options: extra options for the connection. Only works for PostgreSQL now.
|
|
||||||
# # For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
|
|
||||||
# # connect_options:
|
|
||||||
# # statement_timeout: '1s'
|
|
||||||
# redis_clients:
|
# redis_clients:
|
||||||
# # name: Name of the client,'default' by default
|
# # name: Name of the client,'default' by default
|
||||||
# - name: default
|
# - name: ''
|
||||||
# # host: Server IP, 127.0.0.1 by default
|
# # host: Server IP, 127.0.0.1 by default
|
||||||
# host: 127.0.0.1
|
# host: 127.0.0.1
|
||||||
# # port: Server port, 6379 by default
|
# # port: Server port, 6379 by default
|
||||||
@ -91,16 +87,12 @@ app:
|
|||||||
# is the number of CPU cores
|
# is the number of CPU cores
|
||||||
number_of_threads: 1
|
number_of_threads: 1
|
||||||
# enable_session: False by default
|
# enable_session: False by default
|
||||||
enable_session: false
|
enable_session: true
|
||||||
session_timeout: 0
|
session_timeout: 0
|
||||||
# string value of SameSite attribute of the Set-Cookie HTTP response header
|
# string value of SameSite attribute of the Set-Cookie HTTP respone header
|
||||||
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
|
||||||
session_same_site: 'Null'
|
session_same_site: 'Null'
|
||||||
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
# document_root: Root path of HTTP document, defaut path is ./
|
||||||
session_cookie_key: 'JSESSIONID'
|
|
||||||
# session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
session_max_age: -1
|
|
||||||
# document_root: Root path of HTTP document, default path is ./
|
|
||||||
document_root: ./
|
document_root: ./
|
||||||
# home_page: Set the HTML file of the home page, the default value is "index.html"
|
# 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
|
# 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
|
||||||
@ -140,10 +132,8 @@ app:
|
|||||||
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
|
||||||
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
|
||||||
mime: {
|
mime: {
|
||||||
# text/markdown: md
|
# text/markdown: md,
|
||||||
# text/gemini:
|
# text/gemini: [gmi, gemini]
|
||||||
# - gmi
|
|
||||||
# - gemini
|
|
||||||
}
|
}
|
||||||
# locations: An array of locations of static files for GET requests.
|
# locations: An array of locations of static files for GET requests.
|
||||||
locations:
|
locations:
|
||||||
@ -167,7 +157,7 @@ app:
|
|||||||
filters: []
|
filters: []
|
||||||
# max_connections: maximum number of connections, 100000 by default
|
# max_connections: maximum number of connections, 100000 by default
|
||||||
max_connections: 100000
|
max_connections: 100000
|
||||||
# max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
# max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||||
max_connections_per_ip: 0
|
max_connections_per_ip: 0
|
||||||
# Load_dynamic_views: False by default, when set to true, drogon
|
# Load_dynamic_views: False by default, when set to true, drogon
|
||||||
# compiles and loads dynamically "CSP View Files" in directories defined
|
# compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
@ -195,8 +185,6 @@ app:
|
|||||||
precision_type: significant
|
precision_type: significant
|
||||||
# log: Set log output, drogon output logs to stdout by default
|
# log: Set log output, drogon output logs to stdout by default
|
||||||
log:
|
log:
|
||||||
# use_spdlog: Use spdlog library to log
|
|
||||||
use_spdlog: false
|
|
||||||
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
|
||||||
# log_path: ./
|
# log_path: ./
|
||||||
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
|
||||||
@ -205,9 +193,6 @@ app:
|
|||||||
# log_size_limit: 100000000 bytes by default,
|
# log_size_limit: 100000000 bytes by default,
|
||||||
# When the log file size reaches "log_size_limit", the log file is switched.
|
# When the log file size reaches "log_size_limit", the log file is switched.
|
||||||
log_size_limit: 100000000
|
log_size_limit: 100000000
|
||||||
# max_files: 0 by default,
|
|
||||||
# When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
|
|
||||||
max_files: 0
|
|
||||||
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
|
||||||
# The TRACE level is only valid when built in DEBUG mode.
|
# The TRACE level is only valid when built in DEBUG mode.
|
||||||
log_level: DEBUG
|
log_level: DEBUG
|
||||||
@ -230,14 +215,14 @@ app:
|
|||||||
# 0 means cache forever, the negative value means no cache
|
# 0 means cache forever, the negative value means no cache
|
||||||
static_files_cache_time: 5
|
static_files_cache_time: 5
|
||||||
# simple_controllers_map: Used to configure mapping from path to simple controller
|
# simple_controllers_map: Used to configure mapping from path to simple controller
|
||||||
# simple_controllers_map:
|
simple_controllers_map:
|
||||||
# - path: /path/name
|
- path: /path/name
|
||||||
# controller: controllerClassName
|
controller: controllerClassName
|
||||||
# http_methods:
|
http_methods:
|
||||||
# - get
|
- get
|
||||||
# - post
|
- post
|
||||||
# filters:
|
filters:
|
||||||
# - FilterClassName
|
- FilterClassName
|
||||||
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||||
# of the connection without read or write
|
# of the connection without read or write
|
||||||
idle_connection_timeout: 60
|
idle_connection_timeout: 60
|
||||||
@ -278,36 +263,28 @@ app:
|
|||||||
client_max_websocket_message_size: 128K
|
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: Defaults to false, users can run multiple processes listening on the same port at the same time.
|
||||||
reuse_port: false
|
reuse_port: false
|
||||||
# enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
# enabled_compresed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
|
||||||
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
|
||||||
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
|
||||||
# will be rejected.
|
# will be rejected.
|
||||||
enabled_compressed_request: false
|
enabled_compresed_request: false
|
||||||
# enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
|
|
||||||
# See the wiki for more details.
|
|
||||||
enable_request_stream: false
|
|
||||||
# plugins: Define all plugins running in the application
|
# plugins: Define all plugins running in the application
|
||||||
plugins:
|
plugins:
|
||||||
# name: The class name of the plugin
|
# name: The class name of the plugin
|
||||||
- name: drogon::plugin::PromExporter
|
- name: '' # drogon::plugin::SecureSSLRedirector
|
||||||
# dependencies: Plugins that the plugin depends on. It can be commented out
|
# dependencies: Plugins that the plugin depends on. It can be commented out
|
||||||
dependencies: []
|
dependencies: []
|
||||||
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||||
# It can be commented out
|
# It can be commented out
|
||||||
config:
|
config:
|
||||||
path: /metrics
|
ssl_redirect_exempt:
|
||||||
- name: drogon::plugin::AccessLogger
|
- .*\.jpg
|
||||||
dependencies: []
|
secure_ssl_host: 'localhost:8849'
|
||||||
config:
|
|
||||||
use_spdlog: false
|
|
||||||
log_path: ''
|
|
||||||
log_format: ''
|
|
||||||
log_file: access.log
|
|
||||||
log_size_limit: 0
|
|
||||||
use_local_time: true
|
|
||||||
log_index: 0
|
|
||||||
# show_microseconds: true
|
|
||||||
# custom_time_format: ''
|
|
||||||
# use_real_ip: false
|
|
||||||
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
|
||||||
custom_config: {}
|
custom_config:
|
||||||
|
realm: drogonRealm
|
||||||
|
opaque: drogonOpaque
|
||||||
|
credentials:
|
||||||
|
- user: drogon
|
||||||
|
password: dr0g0n
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ else
|
|||||||
|
|
||||||
<%c++for(auto col:cols){
|
<%c++for(auto col:cols){
|
||||||
%>
|
%>
|
||||||
const std::string [[className]]::Cols::_{%col.colName_%} = "{%escapeIdentifier(col.colName_, rdbms)%}";
|
const std::string [[className]]::Cols::_{%col.colName_%} = "{%col.colName_%}";
|
||||||
<%c++
|
<%c++
|
||||||
}%>
|
}%>
|
||||||
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
|
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
|
||||||
@ -102,7 +102,7 @@ if(!schema.empty())
|
|||||||
{
|
{
|
||||||
$$<<schema<<".";
|
$$<<schema<<".";
|
||||||
}
|
}
|
||||||
%>{%escapeIdentifier(@@.get<std::string>("tableName"), rdbms)%}";
|
%>[[tableName]]";
|
||||||
|
|
||||||
const std::vector<typename [[className]]::MetaData> [[className]]::metaData_={
|
const std::vector<typename [[className]]::MetaData> [[className]]::metaData_={
|
||||||
<%c++for(size_t i=0;i<cols.size();i++){
|
<%c++for(size_t i=0;i<cols.size();i++){
|
||||||
@ -975,7 +975,7 @@ void [[className]]::updateByJson(const Json::Value &pJson) noexcept(false)
|
|||||||
{
|
{
|
||||||
$$<<"const "<<col.colType_<<" &"<<className<<"::getValueOf"<<col.colTypeName_<<"() const noexcept\n";
|
$$<<"const "<<col.colType_<<" &"<<className<<"::getValueOf"<<col.colTypeName_<<"() const noexcept\n";
|
||||||
$$<<"{\n";
|
$$<<"{\n";
|
||||||
$$<<" static const "<<col.colType_<<" defaultValue = "<<col.colType_<<"();\n";
|
$$<<" const static "<<col.colType_<<" defaultValue = "<<col.colType_<<"();\n";
|
||||||
$$<<" if("<<col.colValName_<<"_)\n";
|
$$<<" if("<<col.colValName_<<"_)\n";
|
||||||
$$<<" return *"<<col.colValName_<<"_;\n";
|
$$<<" return *"<<col.colValName_<<"_;\n";
|
||||||
$$<<" return defaultValue;\n";
|
$$<<" return defaultValue;\n";
|
||||||
@ -984,7 +984,7 @@ void [[className]]::updateByJson(const Json::Value &pJson) noexcept(false)
|
|||||||
{
|
{
|
||||||
$$<<"std::string "<<className<<"::getValueOf"<<col.colTypeName_<<"AsString() const noexcept\n";
|
$$<<"std::string "<<className<<"::getValueOf"<<col.colTypeName_<<"AsString() const noexcept\n";
|
||||||
$$<<"{\n";
|
$$<<"{\n";
|
||||||
$$<<" static const std::string defaultValue = std::string();\n";
|
$$<<" const static std::string defaultValue = std::string();\n";
|
||||||
$$<<" if("<<col.colValName_<<"_)\n";
|
$$<<" if("<<col.colValName_<<"_)\n";
|
||||||
$$<<" return std::string("<<col.colValName_<<"_->data(),"<<col.colValName_<<"_->size());\n";
|
$$<<" return std::string("<<col.colValName_<<"_->data(),"<<col.colValName_<<"_->size());\n";
|
||||||
$$<<" return defaultValue;\n";
|
$$<<" return defaultValue;\n";
|
||||||
@ -1534,7 +1534,8 @@ if(!col.notNull_){%>
|
|||||||
if(col.colType_ == "std::string" && col.colLength_>0)
|
if(col.colType_ == "std::string" && col.colLength_>0)
|
||||||
{
|
{
|
||||||
%>
|
%>
|
||||||
if(pJson.isString() && std::strlen(pJson.asCString()) > {%col.colLength_%})
|
// asString().length() creates a string object, is there any better way to validate the length?
|
||||||
|
if(pJson.isString() && pJson.asString().length() > {%col.colLength_%})
|
||||||
{
|
{
|
||||||
err="String length exceeds limit for the " +
|
err="String length exceeds limit for the " +
|
||||||
fieldName +
|
fieldName +
|
||||||
@ -1567,54 +1568,64 @@ for(auto &relationship : relationships)
|
|||||||
auto relationshipValName=nameTransform(name, false);
|
auto relationshipValName=nameTransform(name, false);
|
||||||
auto alias=relationship.targetTableAlias();
|
auto alias=relationship.targetTableAlias();
|
||||||
auto aliasValName=nameTransform(alias, false);
|
auto aliasValName=nameTransform(alias, false);
|
||||||
|
if(relationship.type() == Relationship::Type::HasOne)
|
||||||
|
{
|
||||||
if(!alias.empty())
|
if(!alias.empty())
|
||||||
{
|
{
|
||||||
if(alias[0] <= 'z' && alias[0] >= 'a')
|
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||||
{
|
{
|
||||||
alias[0] += ('A' - 'a');
|
alias[0] += ('A' - 'a');
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alias = relationshipClassName;
|
|
||||||
}
|
}
|
||||||
std::string alind(alias.length(), ' ');
|
std::string alind(alias.length(), ' ');
|
||||||
if(relationship.type() == Relationship::Type::HasOne)
|
|
||||||
{
|
|
||||||
%>
|
%>
|
||||||
{%relationshipClassName%} [[className]]::get{%alias%}(const DbClientPtr &clientPtr) const {
|
|
||||||
static const std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
|
||||||
if(rdbms=="postgresql")
|
|
||||||
{
|
|
||||||
$$<<"$1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$$<<"?";
|
|
||||||
}%>";
|
|
||||||
Result r(nullptr);
|
|
||||||
{
|
|
||||||
auto binder = *clientPtr << sql;
|
|
||||||
binder << *{%nameTransform(relationship.originalKey(), false)%}_ << Mode::Blocking >>
|
|
||||||
[&r](const Result &result) { r = result; };
|
|
||||||
binder.exec();
|
|
||||||
}
|
|
||||||
if (r.size() == 0)
|
|
||||||
{
|
|
||||||
throw UnexpectedRows("0 rows found");
|
|
||||||
}
|
|
||||||
else if (r.size() > 1)
|
|
||||||
{
|
|
||||||
throw UnexpectedRows("Found more than one row");
|
|
||||||
}
|
|
||||||
return {%relationshipClassName%}(r[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{%relationshipClassName%} [[className]]::get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
|
std::shared_ptr<std::promise<{%relationshipClassName%}>> pro(new std::promise<{%relationshipClassName%}>);
|
||||||
|
std::future<{%relationshipClassName%}> f = pro->get_future();
|
||||||
|
get{%alias%}(clientPtr, [&pro] ({%relationshipClassName%} result) {
|
||||||
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
pro->set_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
|
});
|
||||||
|
return f.get();
|
||||||
|
}
|
||||||
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
||||||
{%indentStr%} {%alind%} const std::function<void({%relationshipClassName%})> &rcb,
|
{%indentStr%} {%alind%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||||
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||||
|
%>
|
||||||
|
{%relationshipClassName%} [[className]]::get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
|
std::shared_ptr<std::promise<{%relationshipClassName%}>> pro(new std::promise<{%relationshipClassName%}>);
|
||||||
|
std::future<{%relationshipClassName%}> f = pro->get_future();
|
||||||
|
get{%relationshipClassName%}(clientPtr, [&pro] ({%relationshipClassName%} result) {
|
||||||
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
pro->set_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
|
});
|
||||||
|
return f.get();
|
||||||
|
}
|
||||||
|
void [[className]]::get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const std::function<void({%relationshipClassName%})> &rcb,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
%>
|
||||||
{
|
{
|
||||||
static const std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
const static std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
||||||
if(rdbms=="postgresql")
|
if(rdbms=="postgresql")
|
||||||
{
|
{
|
||||||
$$<<"$1";
|
$$<<"$1";
|
||||||
@ -1645,38 +1656,61 @@ void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
|||||||
}
|
}
|
||||||
else if(relationship.type() == Relationship::Type::HasMany)
|
else if(relationship.type() == Relationship::Type::HasMany)
|
||||||
{
|
{
|
||||||
|
if(!alias.empty())
|
||||||
|
{
|
||||||
|
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||||
|
{
|
||||||
|
alias[0] += ('A' - 'a');
|
||||||
|
}
|
||||||
|
std::string alind(alias.length(), ' ');
|
||||||
%>
|
%>
|
||||||
std::vector<{%relationshipClassName%}> [[className]]::get{%alias%}(const DbClientPtr &clientPtr) const {
|
std::vector<{%relationshipClassName%}> [[className]]::get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
static const std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
std::shared_ptr<std::promise<std::vector<{%relationshipClassName%}>>> pro(new std::promise<std::vector<{%relationshipClassName%}>>);
|
||||||
if(rdbms=="postgresql")
|
std::future<std::vector<{%relationshipClassName%}>> f = pro->get_future();
|
||||||
{
|
get{%alias%}(clientPtr, [&pro] (std::vector<{%relationshipClassName%}> result) {
|
||||||
$$<<"$1";
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
}
|
}
|
||||||
else
|
catch (...) {
|
||||||
{
|
pro->set_exception(std::current_exception());
|
||||||
$$<<"?";
|
|
||||||
}%>";
|
|
||||||
Result r(nullptr);
|
|
||||||
{
|
|
||||||
auto binder = *clientPtr << sql;
|
|
||||||
binder << *{%nameTransform(relationship.originalKey(), false)%}_ << Mode::Blocking >>
|
|
||||||
[&r](const Result &result) { r = result; };
|
|
||||||
binder.exec();
|
|
||||||
}
|
}
|
||||||
std::vector<{%relationshipClassName%}> ret;
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
ret.reserve(r.size());
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
for (auto const &row : r)
|
});
|
||||||
{
|
return f.get();
|
||||||
ret.emplace_back({%relationshipClassName%}(row));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
||||||
{%indentStr%} {%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
{%indentStr%} {%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||||
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||||
|
%>
|
||||||
|
std::vector<{%relationshipClassName%}> [[className]]::get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
|
std::shared_ptr<std::promise<std::vector<{%relationshipClassName%}>>> pro(new std::promise<std::vector<{%relationshipClassName%}>>);
|
||||||
|
std::future<std::vector<{%relationshipClassName%}>> f = pro->get_future();
|
||||||
|
get{%relationshipClassName%}(clientPtr, [&pro] (std::vector<{%relationshipClassName%}> result) {
|
||||||
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
pro->set_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
|
});
|
||||||
|
return f.get();
|
||||||
|
}
|
||||||
|
void [[className]]::get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
%>
|
||||||
{
|
{
|
||||||
static const std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
const static std::string sql = "select * from {%name%} where {%relationship.targetKey()%} = <%c++
|
||||||
if(rdbms=="postgresql")
|
if(rdbms=="postgresql")
|
||||||
{
|
{
|
||||||
$$<<"$1";
|
$$<<"$1";
|
||||||
@ -1706,39 +1740,61 @@ void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
|||||||
auto pivotTableClassName=nameTransform(pivotTableName, true);
|
auto pivotTableClassName=nameTransform(pivotTableName, true);
|
||||||
auto &pivotOriginalKey=relationship.pivotTable().originalKey();
|
auto &pivotOriginalKey=relationship.pivotTable().originalKey();
|
||||||
auto &pivotTargetKey=relationship.pivotTable().targetKey();
|
auto &pivotTargetKey=relationship.pivotTable().targetKey();
|
||||||
|
if(!alias.empty())
|
||||||
|
{
|
||||||
|
if(alias[0] <= 'z' && alias[0] >= 'a')
|
||||||
|
{
|
||||||
|
alias[0] += ('A' - 'a');
|
||||||
|
}
|
||||||
|
std::string alind(alias.length(), ' ');
|
||||||
%>
|
%>
|
||||||
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> [[className]]::get{%alias%}(const DbClientPtr &clientPtr) const {
|
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> [[className]]::get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
static const std::string sql = "select * from {%name%},{%pivotTableName%} where {%pivotTableName%}.{%pivotOriginalKey%} = <%c++
|
std::shared_ptr<std::promise<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>>> pro(new std::promise<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>>);
|
||||||
if(rdbms=="postgresql")
|
std::future<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>> f = pro->get_future();
|
||||||
{
|
get{%alias%}(clientPtr, [&pro] (std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> result) {
|
||||||
$$<<"$1";
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
}
|
}
|
||||||
else
|
catch (...) {
|
||||||
{
|
pro->set_exception(std::current_exception());
|
||||||
$$<<"?";
|
|
||||||
}%> and {%pivotTableName%}.{%pivotTargetKey%} = {%name%}.{%relationship.targetKey()%}";
|
|
||||||
Result r(nullptr);
|
|
||||||
{
|
|
||||||
auto binder = *clientPtr << sql;
|
|
||||||
binder << *{%nameTransform(relationship.originalKey(), false)%}_ << Mode::Blocking >>
|
|
||||||
[&r](const Result &result) { r = result; };
|
|
||||||
binder.exec();
|
|
||||||
}
|
}
|
||||||
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> ret;
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
ret.reserve(r.size());
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
for (auto const &row : r)
|
});
|
||||||
{
|
return f.get();
|
||||||
ret.emplace_back(std::pair<{%relationshipClassName%},{%pivotTableClassName%}>(
|
|
||||||
{%relationshipClassName%}(row),{%pivotTableClassName%}(row,{%relationshipClassName%}::getColumnNumber())));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
void [[className]]::get{%alias%}(const DbClientPtr &clientPtr,
|
||||||
{%indentStr%} {%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
{%indentStr%} {%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||||
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
{%indentStr%} {%alind%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string relationshipClassInde(relationshipClassName.length(), ' ');
|
||||||
|
%>
|
||||||
|
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> [[className]]::get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const {
|
||||||
|
std::shared_ptr<std::promise<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>>> pro(new std::promise<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>>);
|
||||||
|
std::future<std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>> f = pro->get_future();
|
||||||
|
get{%relationshipClassName%}(clientPtr, [&pro] (std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> result) {
|
||||||
|
try {
|
||||||
|
pro->set_value(result);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
pro->set_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}, [&pro] (const DrogonDbException &err) {
|
||||||
|
pro->set_exception(std::make_exception_ptr(err));
|
||||||
|
});
|
||||||
|
return f.get();
|
||||||
|
}
|
||||||
|
void [[className]]::get{%relationshipClassName%}(const DbClientPtr &clientPtr,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
|
||||||
|
{%indentStr%} {%relationshipClassInde%} const ExceptionCallback &ecb) const
|
||||||
|
<%c++
|
||||||
|
}
|
||||||
|
%>
|
||||||
{
|
{
|
||||||
static const std::string sql = "select * from {%name%},{%pivotTableName%} where {%pivotTableName%}.{%pivotOriginalKey%} = <%c++
|
const static std::string sql = "select * from {%name%},{%pivotTableName%} where {%pivotTableName%}.{%pivotOriginalKey%} = <%c++
|
||||||
if(rdbms=="postgresql")
|
if(rdbms=="postgresql")
|
||||||
{
|
{
|
||||||
$$<<"$1";
|
$$<<"$1";
|
||||||
|
@ -86,11 +86,11 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
|
|||||||
%>
|
%>
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int primaryKeyNumber;
|
const static int primaryKeyNumber;
|
||||||
static const std::string tableName;
|
const static std::string tableName;
|
||||||
static const bool hasPrimaryKey;
|
const static bool hasPrimaryKey;
|
||||||
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
|
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
|
||||||
static const std::string primaryKeyName;
|
const static std::string primaryKeyName;
|
||||||
<%c++if(!@@.get<std::string>("primaryKeyType").empty()){%>
|
<%c++if(!@@.get<std::string>("primaryKeyType").empty()){%>
|
||||||
using PrimaryKeyType = [[primaryKeyType]];
|
using PrimaryKeyType = [[primaryKeyType]];
|
||||||
const PrimaryKeyType &getPrimaryKey() const;
|
const PrimaryKeyType &getPrimaryKey() const;
|
||||||
@ -108,7 +108,7 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
|
|||||||
typelist += ",";
|
typelist += ",";
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
static const std::vector<std::string> primaryKeyName;
|
const static std::vector<std::string> primaryKeyName;
|
||||||
using PrimaryKeyType = std::tuple<{%typelist%}>;//<%c++
|
using PrimaryKeyType = std::tuple<{%typelist%}>;//<%c++
|
||||||
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
|
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
|
||||||
for(size_t i=0;i<pkName.size();i++)
|
for(size_t i=0;i<pkName.size();i++)
|
||||||
|
@ -6,7 +6,7 @@ add_executable(${PROJECT_NAME} test_main.cc)
|
|||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
# If you include the drogon source code locally in your project, use this method
|
# If you include the drogon source code locally in your project, use this method
|
||||||
# to add drogon
|
# to add drogon
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
# target_link_libraries(${PROJECT_NAME}_test PRIVATE drogon)
|
||||||
#
|
#
|
||||||
# and comment out the following lines
|
# and comment out the following lines
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
||||||
|
@ -31,11 +31,6 @@ add_executable(redis_simple redis/main.cc
|
|||||||
add_executable(redis_chat redis_chat/main.cc
|
add_executable(redis_chat redis_chat/main.cc
|
||||||
redis_chat/controllers/Chat.cc)
|
redis_chat/controllers/Chat.cc)
|
||||||
|
|
||||||
add_executable(async_stream async_stream/main.cc
|
|
||||||
async_stream/RequestStreamExampleCtrl.cc)
|
|
||||||
|
|
||||||
add_executable(cors cors/main.cc)
|
|
||||||
|
|
||||||
set(example_targets
|
set(example_targets
|
||||||
benchmark
|
benchmark
|
||||||
client
|
client
|
||||||
@ -46,13 +41,11 @@ set(example_targets
|
|||||||
login_session
|
login_session
|
||||||
jsonstore
|
jsonstore
|
||||||
redis_simple
|
redis_simple
|
||||||
redis_chat
|
redis_chat)
|
||||||
async_stream
|
|
||||||
cors)
|
|
||||||
|
|
||||||
# Add warnings for our example targets--some warnings (such as -Wunused-parameter) only appear
|
# Add warnings for our example targets--some warnings (such as -Wunused-parameter) only appear
|
||||||
# when the templated functions are instantiated at their point of use.
|
# when the templated functions are instantiated at their point of use.
|
||||||
if(NOT ${CMAKE_PLATFORM_NAME} STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||||
foreach(target ${example_targets})
|
foreach(target ${example_targets})
|
||||||
target_compile_options(${target} PRIVATE -Wall -Wextra -Werror)
|
target_compile_options(${target} PRIVATE -Wall -Wextra -Werror)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -2,21 +2,19 @@
|
|||||||
|
|
||||||
The following examples can help you understand how to use Drogon:
|
The following examples can help you understand how to use Drogon:
|
||||||
|
|
||||||
1. [helloworld](https://github.com/drogonframework/drogon/tree/master/examples/helloworld) - The multiple ways of "Hello, World!"
|
1. [helloworld](https://github.com/an-tao/drogon/tree/master/examples/helloworld) - The multiple ways of "Hello, World!"
|
||||||
2. [client_example](https://github.com/drogonframework/drogon/tree/master/examples/client_example/main.cc) - A client example
|
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/drogonframework/drogon/tree/master/examples/websocket_client/WebSocketClient.cc) - An example on how to use the WebSocket client
|
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/drogonframework/drogon/tree/master/examples/login_session) - How to use the built-in session system to handle login and out
|
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/drogonframework/drogon/tree/master/examples/file_upload) - How to handle file uploads in Drogon
|
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/drogonframework/drogon/tree/master/examples/simple_reverse_proxy) - An example showing how to use Drogon as a HTTP reverse
|
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
|
proxy with a simple round robin.
|
||||||
7. [benchmark](https://github.com/drogonframework/drogon/tree/master/examples/benchmark) - Basic benchmark(https://github.com/drogonframework/drogon/wiki/13-Benchmarks) example
|
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)
|
||||||
8. [jsonstore](https://github.com/drogonframework/drogon/tree/master/examples/jsonstore) - Implementation of a [jsonstore](https://github.com/bluzi/jsonstore)-like storage service that is concurrent and stores in memory. Serving as a showcase on how to build a minimally useful RESTful APIs in Drogon
|
8. [jsonstore](https://github.com/an-tao/drogon/tree/master/examples/jsonstore) - Implementation of a [jsonstore](https://github.com/bluzi/jsonstore)-like storage service that is concurrent and stores in memory. Serving as a showcase on how to build a minimally useful RESTful APIs in Drogon.
|
||||||
9. [redis](https://github.com/drogonframework/drogon/tree/master/examples/redis) - A simple example of Redis
|
9. [redis](https://github.com/an-tao/drogon/tree/master/examples/redis) - A simple example of Redis
|
||||||
10. [websocket_server](https://github.com/drogonframework/drogon/tree/master/examples/websocket_server) - A example websocket chat room server
|
10. [websocket_server](https://github.com/drogonframework/drogon/tree/master/examples/websocket_server) - Example WebSocker chat room server
|
||||||
11. [redis_cache](https://github.com/drogonframework/drogon/tree/master/examples/redis_cache) - An example for using coroutines of Redis clients
|
11. [redis_cache](https://github.com/an-tao/drogon/tree/master/examples/redis_cache) - An example for using coroutines of redis clients
|
||||||
12. [redis_chat](https://github.com/drogonframework/drogon/tree/master/examples/redis_chat) - A chatroom server built with websocket and Redis pub/sub service
|
12. [redis_chat](https://github.com/an-tao/drogon/tree/master/examples/redis_chat) - A chatroom server built with websocket and redis pub/sub service.
|
||||||
13. [prometheus_example](https://github.com/drogonframework/drogon/tree/master/examples/prometheus_example) - An example of how to use the Prometheus exporter in Drogon
|
|
||||||
14. [cors](https://github.com/drogonframework/drogon/tree/master/examples/cors) - An example demonstrating how to implement CORS (Cross-Origin Resource Sharing) support in Drogon
|
|
||||||
|
|
||||||
### [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) test suite
|
### [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) test suite
|
||||||
|
|
||||||
@ -24,4 +22,4 @@ I created a benchmark suite for the `tfb`, see [here](https://github.com/TechEmp
|
|||||||
|
|
||||||
### Another test suite
|
### 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).
|
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).
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
#include <drogon/drogon.h>
|
|
||||||
#include <drogon/HttpController.h>
|
|
||||||
#include <drogon/HttpRequest.h>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
class StreamEchoReader : public RequestStreamReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StreamEchoReader(ResponseStreamPtr respStream)
|
|
||||||
: respStream_(std::move(respStream))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStreamData(const char *data, size_t length) override
|
|
||||||
{
|
|
||||||
LOG_INFO << "onStreamData[" << length << "]";
|
|
||||||
respStream_->send({data, length});
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStreamFinish(std::exception_ptr ptr) override
|
|
||||||
{
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::rethrow_exception(ptr);
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "onStreamError: " << e.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_INFO << "onStreamFinish";
|
|
||||||
}
|
|
||||||
respStream_->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ResponseStreamPtr respStream_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RequestStreamExampleCtrl : public HttpController<RequestStreamExampleCtrl>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
METHOD_LIST_BEGIN
|
|
||||||
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_echo, "/stream_echo", Post);
|
|
||||||
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_upload,
|
|
||||||
"/stream_upload",
|
|
||||||
Post);
|
|
||||||
METHOD_LIST_END
|
|
||||||
|
|
||||||
void stream_echo(
|
|
||||||
const HttpRequestPtr &,
|
|
||||||
RequestStreamPtr &&stream,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) const
|
|
||||||
{
|
|
||||||
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
|
|
||||||
[stream](ResponseStreamPtr respStream) {
|
|
||||||
stream->setStreamReader(
|
|
||||||
std::make_shared<StreamEchoReader>(std::move(respStream)));
|
|
||||||
});
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stream_upload(
|
|
||||||
const HttpRequestPtr &req,
|
|
||||||
RequestStreamPtr &&stream,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) const
|
|
||||||
{
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
MultipartHeader header;
|
|
||||||
std::string tmpName;
|
|
||||||
std::ofstream file;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto files = std::make_shared<std::vector<Entry>>();
|
|
||||||
auto reader = RequestStreamReader::newMultipartReader(
|
|
||||||
req,
|
|
||||||
[files](MultipartHeader &&header) {
|
|
||||||
LOG_INFO << "Multipart name: " << header.name
|
|
||||||
<< ", filename:" << header.filename
|
|
||||||
<< ", contentType:" << header.contentType;
|
|
||||||
|
|
||||||
files->push_back({std::move(header)});
|
|
||||||
auto tmpName = drogon::utils::genRandomString(40);
|
|
||||||
if (!files->back().header.filename.empty())
|
|
||||||
{
|
|
||||||
files->back().tmpName = tmpName;
|
|
||||||
files->back().file.open("uploads/" + tmpName,
|
|
||||||
std::ios::trunc);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[files](const char *data, size_t length) {
|
|
||||||
if (files->back().tmpName.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto ¤tFile = files->back().file;
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
LOG_INFO << "file finish";
|
|
||||||
if (currentFile.is_open())
|
|
||||||
{
|
|
||||||
currentFile.flush();
|
|
||||||
currentFile.close();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG_INFO << "data[" << length << "]: ";
|
|
||||||
if (currentFile.is_open())
|
|
||||||
{
|
|
||||||
LOG_INFO << "write file";
|
|
||||||
currentFile.write(data, length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "file not open";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[files, callback = std::move(callback)](std::exception_ptr ex) {
|
|
||||||
if (ex)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::rethrow_exception(std::move(ex));
|
|
||||||
}
|
|
||||||
catch (const StreamError &e)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "stream error: " << e.what();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "multipart error: " << e.what();
|
|
||||||
}
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setStatusCode(k400BadRequest);
|
|
||||||
resp->setBody("error\n");
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_INFO << "stream finish, received " << files->size()
|
|
||||||
<< " files";
|
|
||||||
Json::Value respJson;
|
|
||||||
for (const auto &item : *files)
|
|
||||||
{
|
|
||||||
if (item.tmpName.empty())
|
|
||||||
continue;
|
|
||||||
Json::Value entry;
|
|
||||||
entry["name"] = item.header.name;
|
|
||||||
entry["filename"] = item.header.filename;
|
|
||||||
entry["tmpName"] = item.tmpName;
|
|
||||||
respJson.append(entry);
|
|
||||||
}
|
|
||||||
auto resp = HttpResponse::newHttpJsonResponse(respJson);
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream->setStreamReader(std::move(reader));
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,113 +0,0 @@
|
|||||||
#include <drogon/drogon.h>
|
|
||||||
#include <chrono>
|
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <trantor/utils/Logger.h>
|
|
||||||
#include <trantor/net/callbacks.h>
|
|
||||||
#include <trantor/net/TcpConnection.h>
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
std::mutex mutex;
|
|
||||||
std::unordered_map<trantor::TcpConnectionPtr, std::function<void()>>
|
|
||||||
connMapping;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
app().registerHandler(
|
|
||||||
"/stream",
|
|
||||||
[](const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
|
||||||
const auto &weakConnPtr = req->getConnectionPtr();
|
|
||||||
if (auto connPtr = weakConnPtr.lock())
|
|
||||||
{
|
|
||||||
std::lock_guard lk(mutex);
|
|
||||||
connMapping.emplace(std::move(connPtr), [] {
|
|
||||||
LOG_INFO << "call stop or other options!!!!";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
|
|
||||||
[](drogon::ResponseStreamPtr stream) {
|
|
||||||
std::thread([stream =
|
|
||||||
std::shared_ptr<drogon::ResponseStream>{
|
|
||||||
std::move(stream)}]() mutable {
|
|
||||||
std::cout << std::boolalpha << stream->send("hello ")
|
|
||||||
<< std::endl;
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
||||||
std::cout << std::boolalpha << stream->send("world");
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
||||||
stream->close();
|
|
||||||
}).detach();
|
|
||||||
});
|
|
||||||
resp->setContentTypeCodeAndCustomString(
|
|
||||||
ContentType::CT_APPLICATION_JSON, "application/json");
|
|
||||||
callback(resp);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example: register a stream-mode function handler
|
|
||||||
app().registerHandler(
|
|
||||||
"/stream_req",
|
|
||||||
[](const HttpRequestPtr &req,
|
|
||||||
RequestStreamPtr &&stream,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
LOG_INFO << "stream mode is not enabled";
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setStatusCode(k400BadRequest);
|
|
||||||
resp->setBody("no stream");
|
|
||||||
callback(resp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reader = RequestStreamReader::newReader(
|
|
||||||
[](const char *data, size_t length) {
|
|
||||||
LOG_INFO << "piece[" << length
|
|
||||||
<< "]: " << std::string_view{data, length};
|
|
||||||
},
|
|
||||||
[callback = std::move(callback)](std::exception_ptr ex) {
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
if (ex)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::rethrow_exception(std::move(ex));
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "stream error: " << e.what();
|
|
||||||
}
|
|
||||||
resp->setStatusCode(k400BadRequest);
|
|
||||||
resp->setBody("error\n");
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_INFO << "stream finish";
|
|
||||||
resp->setBody("success\n");
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream->setStreamReader(std::move(reader));
|
|
||||||
},
|
|
||||||
{Post});
|
|
||||||
|
|
||||||
LOG_INFO << "Server running on 127.0.0.1:8848";
|
|
||||||
app().enableRequestStream(); // This is for request stream.
|
|
||||||
app().setConnectionCallback([](const trantor::TcpConnectionPtr &conn) {
|
|
||||||
if (conn->disconnected())
|
|
||||||
{
|
|
||||||
std::lock_guard lk(mutex);
|
|
||||||
if (auto it = connMapping.find(conn); it != connMapping.end())
|
|
||||||
{
|
|
||||||
LOG_INFO << "disconnect";
|
|
||||||
connMapping[conn]();
|
|
||||||
connMapping.erase(conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app().addListener("127.0.0.1", 8848).run();
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ using namespace drogon;
|
|||||||
class BenchmarkCtrl : public drogon::HttpSimpleController<BenchmarkCtrl>
|
class BenchmarkCtrl : public drogon::HttpSimpleController<BenchmarkCtrl>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void asyncHandleHttpRequest(
|
virtual void asyncHandleHttpRequest(
|
||||||
const HttpRequestPtr &req,
|
const HttpRequestPtr &req,
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) override;
|
std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||||
PATH_LIST_BEGIN
|
PATH_LIST_BEGIN
|
||||||
|
@ -6,6 +6,6 @@ void JsonCtrl::asyncHandleHttpRequest(
|
|||||||
{
|
{
|
||||||
Json::Value ret;
|
Json::Value ret;
|
||||||
ret["message"] = "Hello, World!";
|
ret["message"] = "Hello, World!";
|
||||||
auto resp = HttpResponse::newHttpJsonResponse(std::move(ret));
|
auto resp = HttpResponse::newHttpJsonResponse(ret);
|
||||||
callback(resp);
|
callback(resp);
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ using namespace drogon;
|
|||||||
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void asyncHandleHttpRequest(
|
virtual void asyncHandleHttpRequest(
|
||||||
const HttpRequestPtr &req,
|
const HttpRequestPtr &req,
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) override;
|
std::function<void(const HttpResponsePtr &)> &&callback) override;
|
||||||
PATH_LIST_BEGIN
|
PATH_LIST_BEGIN
|
||||||
|
@ -72,8 +72,6 @@ int main()
|
|||||||
std::cout << "count=" << nth_resp << std::endl;
|
std::cout << "count=" << nth_resp << std::endl;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
std::cout << "requestsBufferSize:" << client->requestsBufferSize()
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app().run();
|
app().run();
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
#include <drogon/HttpAppFramework.h>
|
|
||||||
#include <drogon/HttpResponse.h>
|
|
||||||
#include <drogon/drogon.h>
|
|
||||||
#include "trantor/utils/Logger.h"
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
/// Configure Cross-Origin Resource Sharing (CORS) support.
|
|
||||||
///
|
|
||||||
/// This function registers both synchronous pre-processing advice for handling
|
|
||||||
/// OPTIONS preflight requests and post-handling advice to inject CORS headers
|
|
||||||
/// into all responses dynamically based on the incoming request headers.
|
|
||||||
void setupCors()
|
|
||||||
{
|
|
||||||
// Register sync advice to handle CORS preflight (OPTIONS) requests
|
|
||||||
drogon::app().registerSyncAdvice([](const drogon::HttpRequestPtr &req)
|
|
||||||
-> drogon::HttpResponsePtr {
|
|
||||||
if (req->method() == drogon::HttpMethod::Options)
|
|
||||||
{
|
|
||||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
|
||||||
|
|
||||||
// Set Access-Control-Allow-Origin header based on the Origin
|
|
||||||
// request header
|
|
||||||
const auto &origin = req->getHeader("Origin");
|
|
||||||
if (!origin.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set Access-Control-Allow-Methods based on the requested method
|
|
||||||
const auto &requestMethod =
|
|
||||||
req->getHeader("Access-Control-Request-Method");
|
|
||||||
if (!requestMethod.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow credentials to be included in cross-origin requests
|
|
||||||
resp->addHeader("Access-Control-Allow-Credentials", "true");
|
|
||||||
|
|
||||||
// Set allowed headers from the Access-Control-Request-Headers
|
|
||||||
// header
|
|
||||||
const auto &requestHeaders =
|
|
||||||
req->getHeader("Access-Control-Request-Headers");
|
|
||||||
if (!requestHeaders.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::move(resp);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register post-handling advice to add CORS headers to all responses
|
|
||||||
drogon::app().registerPostHandlingAdvice(
|
|
||||||
[](const drogon::HttpRequestPtr &req,
|
|
||||||
const drogon::HttpResponsePtr &resp) -> void {
|
|
||||||
// Set Access-Control-Allow-Origin based on the Origin request
|
|
||||||
// header
|
|
||||||
const auto &origin = req->getHeader("Origin");
|
|
||||||
if (!origin.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Origin", origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflect the requested Access-Control-Request-Method back in the
|
|
||||||
// response
|
|
||||||
const auto &requestMethod =
|
|
||||||
req->getHeader("Access-Control-Request-Method");
|
|
||||||
if (!requestMethod.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow credentials to be included in cross-origin requests
|
|
||||||
resp->addHeader("Access-Control-Allow-Credentials", "true");
|
|
||||||
|
|
||||||
// Reflect the requested Access-Control-Request-Headers back
|
|
||||||
const auto &requestHeaders =
|
|
||||||
req->getHeader("Access-Control-Request-Headers");
|
|
||||||
if (!requestHeaders.empty())
|
|
||||||
{
|
|
||||||
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main function to start the Drogon application with CORS-enabled routes.
|
|
||||||
* This example includes:
|
|
||||||
* - A simple GET endpoint `/hello` that returns a greeting message.
|
|
||||||
* - A POST endpoint `/echo` that echoes back the request body.
|
|
||||||
* You can test with curl to test the CORS support:
|
|
||||||
*
|
|
||||||
```
|
|
||||||
curl -i -X OPTIONS http://localhost:8000/echo \
|
|
||||||
-H "Origin: http://localhost:3000" \
|
|
||||||
-H "Access-Control-Request-Method: POST" \
|
|
||||||
-H "Access-Control-Request-Headers: Content-Type"
|
|
||||||
```
|
|
||||||
or
|
|
||||||
```
|
|
||||||
curl -i -X POST http://localhost:8000/echo \
|
|
||||||
-H "Origin: http://localhost:3000" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"key":"value"}'
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Listen on port 8000 for all interfaces
|
|
||||||
app().addListener("0.0.0.0", 8000);
|
|
||||||
|
|
||||||
// Setup CORS support
|
|
||||||
setupCors();
|
|
||||||
|
|
||||||
// Register /hello route for GET and OPTIONS methods
|
|
||||||
app().registerHandler(
|
|
||||||
"/hello",
|
|
||||||
[](const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setBody("Hello from Drogon!");
|
|
||||||
|
|
||||||
// Log client IP address
|
|
||||||
LOG_INFO << "Request to /hello from " << req->getPeerAddr().toIp();
|
|
||||||
|
|
||||||
callback(resp);
|
|
||||||
},
|
|
||||||
{Get, Options});
|
|
||||||
|
|
||||||
// Register /echo route for POST and OPTIONS methods
|
|
||||||
app().registerHandler(
|
|
||||||
"/echo",
|
|
||||||
[](const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setBody(std::string("Echo: ").append(req->getBody()));
|
|
||||||
|
|
||||||
// Log client IP and request body
|
|
||||||
LOG_INFO << "Request to /echo from " << req->getPeerAddr().toIp();
|
|
||||||
LOG_INFO << "Echo content: " << req->getBody();
|
|
||||||
|
|
||||||
callback(resp);
|
|
||||||
},
|
|
||||||
{Post, Options});
|
|
||||||
|
|
||||||
// Start the application main loop
|
|
||||||
app().run();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,11 +1,3 @@
|
|||||||
#include <trantor/utils/Logger.h>
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#else
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <drogon/drogon.h>
|
#include <drogon/drogon.h>
|
||||||
using namespace drogon;
|
using namespace drogon;
|
||||||
|
|
||||||
@ -16,10 +8,8 @@ int main()
|
|||||||
// sent to Drogon
|
// sent to Drogon
|
||||||
app().registerHandler(
|
app().registerHandler(
|
||||||
"/",
|
"/",
|
||||||
[](const HttpRequestPtr &request,
|
[](const HttpRequestPtr &,
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
std::function<void(const HttpResponsePtr &)> &&callback) {
|
||||||
LOG_INFO << "connected:"
|
|
||||||
<< (request->connected() ? "true" : "false");
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
auto resp = HttpResponse::newHttpResponse();
|
||||||
resp->setBody("Hello, World!");
|
resp->setBody("Hello, World!");
|
||||||
callback(resp);
|
callback(resp);
|
||||||
@ -71,23 +61,6 @@ int main()
|
|||||||
},
|
},
|
||||||
{Get});
|
{Get});
|
||||||
|
|
||||||
app()
|
|
||||||
.setBeforeListenSockOptCallback([](int fd) {
|
|
||||||
LOG_INFO << "setBeforeListenSockOptCallback:" << fd;
|
|
||||||
#ifdef _WIN32
|
|
||||||
#elif __linux__
|
|
||||||
int enable = 1;
|
|
||||||
if (setsockopt(
|
|
||||||
fd, IPPROTO_TCP, TCP_FASTOPEN, &enable, sizeof(enable)) ==
|
|
||||||
-1)
|
|
||||||
{
|
|
||||||
LOG_INFO << "setsockopt TCP_FASTOPEN failed";
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
})
|
|
||||||
.setAfterAcceptSockOptCallback([](int) {});
|
|
||||||
|
|
||||||
// Ask Drogon to listen on 127.0.0.1 port 8848. Drogon supports listening
|
// Ask Drogon to listen on 127.0.0.1 port 8848. Drogon supports listening
|
||||||
// on multiple IP addresses by adding multiple listeners. For example, if
|
// on multiple 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
|
// you want the server also listen on 127.0.0.1 port 5555. Just add another
|
||||||
|
@ -24,7 +24,7 @@ Create a new JSON object associated with the token
|
|||||||
|
|
||||||
* **method**: POST
|
* **method**: POST
|
||||||
* **URL params**: None
|
* **URL params**: None
|
||||||
* **Body**: The initial JSON object to store
|
* **Body**: The inital JSON object to store
|
||||||
* **Success response**
|
* **Success response**
|
||||||
* **Code**: 200
|
* **Code**: 200
|
||||||
* **Content**: `{"ok":true}`
|
* **Content**: `{"ok":true}`
|
||||||
@ -121,7 +121,7 @@ Creating new data
|
|||||||
> {"ok":true}
|
> {"ok":true}
|
||||||
Retrieving value of data["foo"]["bar"]
|
Retrieving value of data["foo"]["bar"]
|
||||||
> 42
|
> 42
|
||||||
Modifying data
|
Modifing data
|
||||||
> {"ok":true}
|
> {"ok":true}
|
||||||
Now data["foo"]["bar"] no longer exists
|
Now data["foo"]["bar"] no longer exists
|
||||||
> {"ok":false}
|
> {"ok":false}
|
||||||
|
561
examples/prometheus_example/.gitignore
vendored
561
examples/prometheus_example/.gitignore
vendored
@ -1,561 +0,0 @@
|
|||||||
# 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++
|
|
@ -1,75 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
project(prometheus_example CXX)
|
|
||||||
|
|
||||||
include(CheckIncludeFileCXX)
|
|
||||||
|
|
||||||
check_include_file_cxx(any HAS_ANY)
|
|
||||||
check_include_file_cxx(string_view HAS_STRING_VIEW)
|
|
||||||
check_include_file_cxx(coroutine HAS_COROUTINE)
|
|
||||||
if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "")
|
|
||||||
# Do nothing
|
|
||||||
elseif (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
elseif (HAS_ANY AND HAS_STRING_VIEW)
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
else ()
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} main.cc)
|
|
||||||
|
|
||||||
# ##############################################################################
|
|
||||||
# If you include the drogon source code locally in your project, use this method
|
|
||||||
# to add drogon
|
|
||||||
# add_subdirectory(drogon)
|
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
|
||||||
#
|
|
||||||
# and comment out the following lines
|
|
||||||
find_package(Drogon CONFIG REQUIRED)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
|
||||||
|
|
||||||
# ##############################################################################
|
|
||||||
|
|
||||||
if (CMAKE_CXX_STANDARD LESS 17)
|
|
||||||
message(FATAL_ERROR "c++17 or higher is required")
|
|
||||||
elseif (CMAKE_CXX_STANDARD LESS 20)
|
|
||||||
message(STATUS "use c++17")
|
|
||||||
else ()
|
|
||||||
message(STATUS "use c++20")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
aux_source_directory(controllers CTL_SRC)
|
|
||||||
aux_source_directory(filters FILTER_SRC)
|
|
||||||
aux_source_directory(plugins PLUGIN_SRC)
|
|
||||||
aux_source_directory(models MODEL_SRC)
|
|
||||||
|
|
||||||
drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
# use the following line to create views with namespaces.
|
|
||||||
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
|
||||||
# ${CMAKE_CURRENT_BINARY_DIR} TRUE)
|
|
||||||
# use the following line to create views with namespace CHANGE_ME prefixed
|
|
||||||
# and path namespaces.
|
|
||||||
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
|
|
||||||
# ${CMAKE_CURRENT_BINARY_DIR} TRUE CHANGE_ME)
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/models)
|
|
||||||
target_sources(${PROJECT_NAME}
|
|
||||||
PRIVATE
|
|
||||||
${SRC_DIR}
|
|
||||||
${CTL_SRC}
|
|
||||||
${FILTER_SRC}
|
|
||||||
${PLUGIN_SRC}
|
|
||||||
${MODEL_SRC})
|
|
||||||
# ##############################################################################
|
|
||||||
# uncomment the following line for dynamically loading views
|
|
||||||
# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON)
|
|
||||||
|
|
||||||
# ##############################################################################
|
|
||||||
|
|
||||||
add_subdirectory(test)
|
|
@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
|
|
||||||
"listeners": [
|
|
||||||
{
|
|
||||||
"address": "0.0.0.0",
|
|
||||||
"port": 5555,
|
|
||||||
"https": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "drogon::plugin::PromExporter",
|
|
||||||
"dependencies": [],
|
|
||||||
"config": {
|
|
||||||
"path": "/metrics",
|
|
||||||
"collectors":[
|
|
||||||
{
|
|
||||||
"name": "http_requests_total",
|
|
||||||
"help": "The total number of http requests",
|
|
||||||
"type": "counter",
|
|
||||||
"labels": ["method", "path"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "http_request_duration_seconds",
|
|
||||||
"help": "The processing time of http requests, in seconds",
|
|
||||||
"type": "histogram",
|
|
||||||
"labels": ["method", "path"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#include "PromTestCtrl.h"
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
void PromTestCtrl::fast(const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
|
||||||
{
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setBody("Hello, world!");
|
|
||||||
callback(resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
drogon::AsyncTask PromTestCtrl::slow(
|
|
||||||
const HttpRequestPtr req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> callback)
|
|
||||||
{
|
|
||||||
// sleep for a random time between 1 and 3 seconds
|
|
||||||
static std::once_flag flag;
|
|
||||||
std::call_once(flag, []() { srand(time(nullptr)); });
|
|
||||||
auto duration = 1 + (rand() % 3);
|
|
||||||
auto loop = trantor::EventLoop::getEventLoopOfCurrentThread();
|
|
||||||
co_await drogon::sleepCoro(loop, std::chrono::seconds(duration));
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setBody("Hello, world!");
|
|
||||||
callback(resp);
|
|
||||||
co_return;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <drogon/HttpController.h>
|
|
||||||
#include <drogon/utils/coroutine.h>
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
class PromTestCtrl : public drogon::HttpController<PromTestCtrl>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
METHOD_LIST_BEGIN
|
|
||||||
ADD_METHOD_TO(PromTestCtrl::fast, "/fast", "PromStat");
|
|
||||||
ADD_METHOD_TO(PromTestCtrl::slow, "/slow", "PromStat");
|
|
||||||
METHOD_LIST_END
|
|
||||||
|
|
||||||
void fast(const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback);
|
|
||||||
drogon::AsyncTask slow(
|
|
||||||
const HttpRequestPtr req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> callback);
|
|
||||||
};
|
|
@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* PromStat.cc
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PromStat.h"
|
|
||||||
#include <drogon/plugins/PromExporter.h>
|
|
||||||
#include <drogon/utils/monitoring/Counter.h>
|
|
||||||
#include <drogon/utils/monitoring/Histogram.h>
|
|
||||||
#include <drogon/HttpAppFramework.h>
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
using namespace std::literals::chrono_literals;
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
Task<HttpResponsePtr> PromStat::invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextAwaiter &&next)
|
|
||||||
{
|
|
||||||
std::string path{req->matchedPathPattern()};
|
|
||||||
auto method = req->methodString();
|
|
||||||
auto promExporter = app().getPlugin<drogon::plugin::PromExporter>();
|
|
||||||
if (promExporter)
|
|
||||||
{
|
|
||||||
auto collector =
|
|
||||||
promExporter->getCollector<drogon::monitoring::Counter>(
|
|
||||||
"http_requests_total");
|
|
||||||
if (collector)
|
|
||||||
{
|
|
||||||
collector->metric({method, path})->increment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto start = trantor::Date::date();
|
|
||||||
auto resp = co_await next;
|
|
||||||
if (promExporter)
|
|
||||||
{
|
|
||||||
auto collector =
|
|
||||||
promExporter->getCollector<drogon::monitoring::Histogram>(
|
|
||||||
"http_request_duration_seconds");
|
|
||||||
if (collector)
|
|
||||||
{
|
|
||||||
static const std::vector<double> boundaries{
|
|
||||||
0.0001, 0.001, 0.01, 0.1, 0.5, 1, 2, 3};
|
|
||||||
auto end = trantor::Date::date();
|
|
||||||
auto duration =
|
|
||||||
end.microSecondsSinceEpoch() - start.microSecondsSinceEpoch();
|
|
||||||
collector->metric({method, path}, boundaries, 1h, 6)
|
|
||||||
->observe((double)duration / 1000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
co_return resp;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* PromStat.h
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <drogon/HttpMiddleware.h>
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
class PromStat : public HttpCoroMiddleware<PromStat>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PromStat()
|
|
||||||
{
|
|
||||||
void(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~PromStat()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task<HttpResponsePtr> invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextAwaiter &&next) override;
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
#include <drogon/drogon.h>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
drogon::app().loadConfigFile("../config.json").run();
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
project(prometheus_example_test CXX)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} test_main.cc)
|
|
||||||
|
|
||||||
# ##############################################################################
|
|
||||||
# If you include the drogon source code locally in your project, use this method
|
|
||||||
# to add drogon
|
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
|
||||||
#
|
|
||||||
# and comment out the following lines
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
|
||||||
|
|
||||||
ParseAndAddDrogonTests(${PROJECT_NAME})
|
|
@ -1,32 +0,0 @@
|
|||||||
#define DROGON_TEST_MAIN
|
|
||||||
#include <drogon/drogon_test.h>
|
|
||||||
#include <drogon/drogon.h>
|
|
||||||
|
|
||||||
DROGON_TEST(BasicTest)
|
|
||||||
{
|
|
||||||
// Add your tests here
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
using namespace drogon;
|
|
||||||
|
|
||||||
std::promise<void> p1;
|
|
||||||
std::future<void> f1 = p1.get_future();
|
|
||||||
|
|
||||||
// Start the main loop on another thread
|
|
||||||
std::thread thr([&]() {
|
|
||||||
// Queues the promise to be fulfilled after starting the loop
|
|
||||||
app().getLoop()->queueInLoop([&p1]() { p1.set_value(); });
|
|
||||||
app().run();
|
|
||||||
});
|
|
||||||
|
|
||||||
// The future is only satisfied after the event loop started
|
|
||||||
f1.get();
|
|
||||||
int status = test::run(argc, argv);
|
|
||||||
|
|
||||||
// Ask the event loop to shutdown and wait
|
|
||||||
app().getLoop()->queueInLoop([]() { app().quit(); });
|
|
||||||
thr.join();
|
|
||||||
return status;
|
|
||||||
}
|
|
@ -7,12 +7,13 @@ using namespace drogon;
|
|||||||
class WsClient : public drogon::WebSocketController<WsClient>
|
class WsClient : public drogon::WebSocketController<WsClient>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void handleNewMessage(const WebSocketConnectionPtr &,
|
virtual void handleNewMessage(const WebSocketConnectionPtr &,
|
||||||
std::string &&,
|
std::string &&,
|
||||||
const WebSocketMessageType &) override;
|
const WebSocketMessageType &) override;
|
||||||
void handleNewConnection(const HttpRequestPtr &,
|
virtual void handleNewConnection(const HttpRequestPtr &,
|
||||||
|
const WebSocketConnectionPtr &) override;
|
||||||
|
virtual void handleConnectionClosed(
|
||||||
const WebSocketConnectionPtr &) override;
|
const WebSocketConnectionPtr &) override;
|
||||||
void handleConnectionClosed(const WebSocketConnectionPtr &) override;
|
|
||||||
WS_PATH_LIST_BEGIN
|
WS_PATH_LIST_BEGIN
|
||||||
WS_PATH_ADD("/sub");
|
WS_PATH_ADD("/sub");
|
||||||
WS_PATH_ADD("/pub");
|
WS_PATH_ADD("/pub");
|
||||||
|
@ -41,11 +41,7 @@
|
|||||||
//enable_session: False by default
|
//enable_session: False by default
|
||||||
"enable_session": false,
|
"enable_session": false,
|
||||||
"session_timeout": 0,
|
"session_timeout": 0,
|
||||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
//document_root: Root path of HTTP document, defaut path is ./
|
||||||
"session_cookie_key": "JSESSIONID",
|
|
||||||
//session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
"session_max_age": -1,
|
|
||||||
//document_root: Root path of HTTP document, default path is ./
|
|
||||||
"document_root": "./",
|
"document_root": "./",
|
||||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
//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
|
//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
|
||||||
@ -111,7 +107,7 @@
|
|||||||
],
|
],
|
||||||
//max_connections: maximum number of connections, 100000 by default
|
//max_connections: maximum number of connections, 100000 by default
|
||||||
"max_connections": 100000,
|
"max_connections": 100000,
|
||||||
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
|
//max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
|
||||||
"max_connections_per_ip": 0,
|
"max_connections_per_ip": 0,
|
||||||
//Load_dynamic_views: False by default, when set to true, drogon
|
//Load_dynamic_views: False by default, when set to true, drogon
|
||||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
|
@ -10,7 +10,7 @@ using namespace drogon;
|
|||||||
class TimeFilter : public drogon::HttpFilter<TimeFilter>
|
class TimeFilter : public drogon::HttpFilter<TimeFilter>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void doFilter(const HttpRequestPtr &req,
|
virtual void doFilter(const HttpRequestPtr &req,
|
||||||
FilterCallback &&cb,
|
FilterCallback &&cb,
|
||||||
FilterChainCallback &&ccb) override;
|
FilterChainCallback &&ccb) override;
|
||||||
|
|
||||||
|
@ -7,12 +7,13 @@ using namespace drogon;
|
|||||||
class Chat : public drogon::WebSocketController<Chat>
|
class Chat : public drogon::WebSocketController<Chat>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void handleNewMessage(const WebSocketConnectionPtr &,
|
virtual void handleNewMessage(const WebSocketConnectionPtr &,
|
||||||
std::string &&,
|
std::string &&,
|
||||||
const WebSocketMessageType &) override;
|
const WebSocketMessageType &) override;
|
||||||
void handleNewConnection(const HttpRequestPtr &,
|
virtual void handleNewConnection(const HttpRequestPtr &,
|
||||||
|
const WebSocketConnectionPtr &) override;
|
||||||
|
virtual void handleConnectionClosed(
|
||||||
const WebSocketConnectionPtr &) override;
|
const WebSocketConnectionPtr &) override;
|
||||||
void handleConnectionClosed(const WebSocketConnectionPtr &) override;
|
|
||||||
WS_PATH_LIST_BEGIN
|
WS_PATH_LIST_BEGIN
|
||||||
WS_PATH_ADD("/chat");
|
WS_PATH_ADD("/chat");
|
||||||
WS_PATH_LIST_END
|
WS_PATH_LIST_END
|
||||||
|
@ -22,11 +22,7 @@
|
|||||||
//enable_session: False by default
|
//enable_session: False by default
|
||||||
"enable_session": false,
|
"enable_session": false,
|
||||||
"session_timeout": 0,
|
"session_timeout": 0,
|
||||||
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
|
//document_root: Root path of HTTP document, defaut path is ./
|
||||||
"session_cookie_key": "JSESSIONID",
|
|
||||||
//session_max_age: The max age of the session cookie, -1 by default
|
|
||||||
"session_max_age": -1,
|
|
||||||
//document_root: Root path of HTTP document, default path is ./
|
|
||||||
"document_root": "./",
|
"document_root": "./",
|
||||||
//home_page: Set the HTML file of the home page, the default value is "index.html"
|
//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
|
//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
|
||||||
@ -64,7 +60,7 @@
|
|||||||
],
|
],
|
||||||
//max_connections: maximum connections number, 100000 by default
|
//max_connections: maximum connections number, 100000 by default
|
||||||
"max_connections": 100000,
|
"max_connections": 100000,
|
||||||
//max_connections_per_ip: maximum connections number per client,0 by default which means no limit
|
//max_connections_per_ip: maximum connections number per clinet,0 by default which means no limit
|
||||||
"max_connections_per_ip": 0,
|
"max_connections_per_ip": 0,
|
||||||
//Load_dynamic_views: False by default, when set to true, drogon
|
//Load_dynamic_views: False by default, when set to true, drogon
|
||||||
//compiles and loads dynamically "CSP View Files" in directories defined
|
//compiles and loads dynamically "CSP View Files" in directories defined
|
||||||
|
@ -6,15 +6,15 @@ using namespace drogon;
|
|||||||
class WebSocketChat : public drogon::WebSocketController<WebSocketChat>
|
class WebSocketChat : public drogon::WebSocketController<WebSocketChat>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void handleNewMessage(const WebSocketConnectionPtr &,
|
virtual void handleNewMessage(const WebSocketConnectionPtr &,
|
||||||
std::string &&,
|
std::string &&,
|
||||||
const WebSocketMessageType &) override;
|
const WebSocketMessageType &) override;
|
||||||
void handleConnectionClosed(const WebSocketConnectionPtr &) override;
|
virtual void handleConnectionClosed(
|
||||||
void handleNewConnection(const HttpRequestPtr &,
|
const WebSocketConnectionPtr &) override;
|
||||||
|
virtual void handleNewConnection(const HttpRequestPtr &,
|
||||||
const WebSocketConnectionPtr &) override;
|
const WebSocketConnectionPtr &) override;
|
||||||
WS_PATH_LIST_BEGIN
|
WS_PATH_LIST_BEGIN
|
||||||
WS_PATH_ADD("/chat", Get);
|
WS_PATH_ADD("/chat", Get);
|
||||||
WS_ADD_PATH_VIA_REGEX("/[^/]*", Get);
|
|
||||||
WS_PATH_LIST_END
|
WS_PATH_LIST_END
|
||||||
private:
|
private:
|
||||||
PubSubService<std::string> chatRooms_;
|
PubSubService<std::string> chatRooms_;
|
||||||
@ -60,7 +60,7 @@ void WebSocketChat::handleNewConnection(const HttpRequestPtr &req,
|
|||||||
s.id_ = chatRooms_.subscribe(s.chatRoomName_,
|
s.id_ = chatRooms_.subscribe(s.chatRoomName_,
|
||||||
[conn](const std::string &topic,
|
[conn](const std::string &topic,
|
||||||
const std::string &message) {
|
const std::string &message) {
|
||||||
// Suppress unused variable warning
|
// Supress unused variable warning
|
||||||
(void)topic;
|
(void)topic;
|
||||||
conn->send(message);
|
conn->send(message);
|
||||||
});
|
});
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
# You can customize the clang-format path by setting the CLANG_FORMAT environment variable
|
# You can customize the clang-format path by setting the CLANG_FORMAT environment variable
|
||||||
CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
|
CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
|
||||||
|
|
||||||
# Check if clang-format version is 17 to avoid inconsistent formatting
|
# Check if clang-format version is 14 to avoid inconsistent formatting
|
||||||
$CLANG_FORMAT --version
|
$CLANG_FORMAT --version
|
||||||
if [[ ! $($CLANG_FORMAT --version) =~ "version 17" ]]; then
|
if [[ ! $($CLANG_FORMAT --version) =~ "version 14" ]]; then
|
||||||
echo "Error: clang-format version must be 17"
|
echo "Error: clang-format version must be 14"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class Attributes
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
const T &get(const std::string &key) const
|
const T &get(const std::string &key) const
|
||||||
{
|
{
|
||||||
static const T nullVal = T();
|
const static T nullVal = T();
|
||||||
auto it = attributesMap_.find(key);
|
auto it = attributesMap_.find(key);
|
||||||
if (it != attributesMap_.end())
|
if (it != attributesMap_.end())
|
||||||
{
|
{
|
||||||
@ -96,7 +96,7 @@ class Attributes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return true if the data identified by the key exists.
|
* @brief Retrun true if the data identified by the key exists.
|
||||||
*/
|
*/
|
||||||
bool find(const std::string &key)
|
bool find(const std::string &key)
|
||||||
{
|
{
|
||||||
|
@ -81,11 +81,7 @@ class CacheMap
|
|||||||
* number of wheels
|
* number of wheels
|
||||||
* @param bucketsNumPerWheel
|
* @param bucketsNumPerWheel
|
||||||
* buckets number per wheel
|
* buckets number per wheel
|
||||||
* @param fnOnInsert
|
* The max delay of the CacheMap is about
|
||||||
* function to execute on insertion
|
|
||||||
* @param fnOnErase
|
|
||||||
* function to execute on erase
|
|
||||||
* @details The max delay of the CacheMap is about
|
|
||||||
* tickInterval*(bucketsNumPerWheel^wheelsNum) seconds.
|
* tickInterval*(bucketsNumPerWheel^wheelsNum) seconds.
|
||||||
*/
|
*/
|
||||||
CacheMap(trantor::EventLoop *loop,
|
CacheMap(trantor::EventLoop *loop,
|
||||||
|
@ -36,7 +36,12 @@ class DROGON_EXPORT Cookie
|
|||||||
* @param key key of the cookie
|
* @param key key of the cookie
|
||||||
* @param value value of the cookie
|
* @param value value of the cookie
|
||||||
*/
|
*/
|
||||||
Cookie(std::string key, std::string value)
|
Cookie(const std::string &key, const std::string &value)
|
||||||
|
: key_(key), value_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Cookie(std::string &&key, std::string &&value)
|
||||||
: key_(std::move(key)), value_(std::move(value))
|
: key_(std::move(key)), value_(std::move(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -84,9 +89,6 @@ class DROGON_EXPORT Cookie
|
|||||||
domain_ = domain;
|
domain_ = domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the domain of the cookie.
|
|
||||||
*/
|
|
||||||
void setDomain(std::string &&domain)
|
void setDomain(std::string &&domain)
|
||||||
{
|
{
|
||||||
domain_ = std::move(domain);
|
domain_ = std::move(domain);
|
||||||
@ -100,9 +102,6 @@ class DROGON_EXPORT Cookie
|
|||||||
path_ = path;
|
path_ = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the path of the cookie.
|
|
||||||
*/
|
|
||||||
void setPath(std::string &&path)
|
void setPath(std::string &&path)
|
||||||
{
|
{
|
||||||
path_ = std::move(path);
|
path_ = std::move(path);
|
||||||
@ -116,9 +115,6 @@ class DROGON_EXPORT Cookie
|
|||||||
key_ = key;
|
key_ = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the key of the cookie.
|
|
||||||
*/
|
|
||||||
void setKey(std::string &&key)
|
void setKey(std::string &&key)
|
||||||
{
|
{
|
||||||
key_ = std::move(key);
|
key_ = std::move(key);
|
||||||
@ -132,9 +128,6 @@ class DROGON_EXPORT Cookie
|
|||||||
value_ = value;
|
value_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the value of the cookie.
|
|
||||||
*/
|
|
||||||
void setValue(std::string &&value)
|
void setValue(std::string &&value)
|
||||||
{
|
{
|
||||||
value_ = std::move(value);
|
value_ = std::move(value);
|
||||||
@ -156,18 +149,6 @@ class DROGON_EXPORT Cookie
|
|||||||
sameSite_ = sameSite;
|
sameSite_ = sameSite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the partitioned status of the cookie
|
|
||||||
*/
|
|
||||||
void setPartitioned(bool partitioned)
|
|
||||||
{
|
|
||||||
partitioned_ = partitioned;
|
|
||||||
if (partitioned)
|
|
||||||
{
|
|
||||||
setSecure(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the string value of the cookie
|
* @brief Get the string value of the cookie
|
||||||
*/
|
*/
|
||||||
@ -294,17 +275,6 @@ class DROGON_EXPORT Cookie
|
|||||||
return secure_;
|
return secure_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if the cookie is partitioned.
|
|
||||||
*
|
|
||||||
* @return true means the cookie is partitioned.
|
|
||||||
* @return false means the cookie is not partitioned.
|
|
||||||
*/
|
|
||||||
bool isPartitioned() const
|
|
||||||
{
|
|
||||||
return partitioned_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the max-age of the cookie
|
* @brief Get the max-age of the cookie
|
||||||
*/
|
*/
|
||||||
@ -348,7 +318,7 @@ class DROGON_EXPORT Cookie
|
|||||||
* str2. so the function doesn't apply tolower to the second argument
|
* str2. so the function doesn't apply tolower to the second argument
|
||||||
* str2 as it's always in lower case.
|
* str2 as it's always in lower case.
|
||||||
*
|
*
|
||||||
* @return true if both strings are equal ignoring case
|
* @return true if both strings are equall ignoring case
|
||||||
*/
|
*/
|
||||||
static bool stricmp(const std::string_view str1,
|
static bool stricmp(const std::string_view str1,
|
||||||
const std::string_view str2)
|
const std::string_view str2)
|
||||||
@ -373,15 +343,21 @@ class DROGON_EXPORT Cookie
|
|||||||
* @brief Converts a string value to its associated enum class SameSite
|
* @brief Converts a string value to its associated enum class SameSite
|
||||||
* value
|
* value
|
||||||
*/
|
*/
|
||||||
static SameSite convertString2SameSite(std::string_view sameSite)
|
static SameSite convertString2SameSite(const std::string_view &sameSite)
|
||||||
{
|
{
|
||||||
if (stricmp(sameSite, "lax"))
|
if (stricmp(sameSite, "lax"))
|
||||||
|
{
|
||||||
return Cookie::SameSite::kLax;
|
return Cookie::SameSite::kLax;
|
||||||
if (stricmp(sameSite, "strict"))
|
}
|
||||||
|
else if (stricmp(sameSite, "strict"))
|
||||||
|
{
|
||||||
return Cookie::SameSite::kStrict;
|
return Cookie::SameSite::kStrict;
|
||||||
if (stricmp(sameSite, "none"))
|
}
|
||||||
|
else if (stricmp(sameSite, "none"))
|
||||||
|
{
|
||||||
return Cookie::SameSite::kNone;
|
return Cookie::SameSite::kNone;
|
||||||
if (!stricmp(sameSite, "null"))
|
}
|
||||||
|
else if (!stricmp(sameSite, "null"))
|
||||||
{
|
{
|
||||||
LOG_WARN
|
LOG_WARN
|
||||||
<< "'" << sameSite
|
<< "'" << sameSite
|
||||||
@ -396,20 +372,34 @@ class DROGON_EXPORT Cookie
|
|||||||
* @brief Converts an enum class SameSite value to its associated string
|
* @brief Converts an enum class SameSite value to its associated string
|
||||||
* value
|
* value
|
||||||
*/
|
*/
|
||||||
static std::string_view convertSameSite2String(SameSite sameSite)
|
static const std::string_view &convertSameSite2String(SameSite sameSite)
|
||||||
{
|
{
|
||||||
switch (sameSite)
|
switch (sameSite)
|
||||||
{
|
{
|
||||||
case SameSite::kLax:
|
case SameSite::kLax:
|
||||||
return "Lax";
|
{
|
||||||
|
static std::string_view sv{"Lax"};
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
case SameSite::kStrict:
|
case SameSite::kStrict:
|
||||||
return "Strict";
|
{
|
||||||
|
static std::string_view sv{"Strict"};
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
case SameSite::kNone:
|
case SameSite::kNone:
|
||||||
return "None";
|
{
|
||||||
|
static std::string_view sv{"None"};
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
case SameSite::kNull:
|
case SameSite::kNull:
|
||||||
return "Null";
|
{
|
||||||
default:
|
static std::string_view sv{"Null"};
|
||||||
return "UNDEFINED";
|
return sv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static std::string_view sv{"UNDEFINED"};
|
||||||
|
return sv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +407,6 @@ class DROGON_EXPORT Cookie
|
|||||||
trantor::Date expiresDate_{(std::numeric_limits<int64_t>::max)()};
|
trantor::Date expiresDate_{(std::numeric_limits<int64_t>::max)()};
|
||||||
bool httpOnly_{true};
|
bool httpOnly_{true};
|
||||||
bool secure_{false};
|
bool secure_{false};
|
||||||
bool partitioned_{false};
|
|
||||||
std::string domain_;
|
std::string domain_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
std::string key_;
|
std::string key_;
|
||||||
|
@ -138,7 +138,7 @@ class DROGON_EXPORT DrClassMap
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
static std::unordered_map<std::string,
|
static std::unordered_map<std::string,
|
||||||
std::pair<DrAllocFunc, DrSharedAllocFunc>> &
|
std::pair<DrAllocFunc, DrSharedAllocFunc>>
|
||||||
getMap();
|
&getMap();
|
||||||
};
|
};
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -57,26 +57,6 @@ class DROGON_EXPORT DrObjectBase
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct isAutoCreationClass
|
|
||||||
{
|
|
||||||
template <class C>
|
|
||||||
static constexpr auto check(C *) -> std::enable_if_t<
|
|
||||||
std::is_same_v<decltype(C::isAutoCreation), const bool>,
|
|
||||||
bool>
|
|
||||||
{
|
|
||||||
return C::isAutoCreation;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename>
|
|
||||||
static constexpr bool check(...)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr bool value = check<T>(nullptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a class template to
|
* a class template to
|
||||||
* implement the reflection function of creating the class object by class name
|
* implement the reflection function of creating the class object by class name
|
||||||
@ -122,9 +102,9 @@ class DrObject : public virtual DrObjectBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename D>
|
template <typename D>
|
||||||
void registerClass()
|
typename std::enable_if<std::is_default_constructible<D>::value,
|
||||||
{
|
void>::type
|
||||||
if constexpr (std::is_default_constructible<D>::value)
|
registerClass()
|
||||||
{
|
{
|
||||||
DrClassMap::registerClass(
|
DrClassMap::registerClass(
|
||||||
className(),
|
className(),
|
||||||
@ -133,11 +113,12 @@ class DrObject : public virtual DrObjectBase
|
|||||||
return std::make_shared<T>();
|
return std::make_shared<T>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if constexpr (isAutoCreationClass<D>::value)
|
|
||||||
|
template <typename D>
|
||||||
|
typename std::enable_if<!std::is_default_constructible<D>::value,
|
||||||
|
void>::type
|
||||||
|
registerClass()
|
||||||
{
|
{
|
||||||
static_assert(std::is_default_constructible<D>::value,
|
|
||||||
"Class is not default constructable!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <drogon/HttpRequest.h>
|
#include <drogon/HttpRequest.h>
|
||||||
#include <drogon/HttpResponse.h>
|
#include <drogon/HttpResponse.h>
|
||||||
#include <drogon/orm/DbClient.h>
|
#include <drogon/orm/DbClient.h>
|
||||||
#include <drogon/orm/DbConfig.h>
|
|
||||||
#include <drogon/nosql/RedisClient.h>
|
#include <drogon/nosql/RedisClient.h>
|
||||||
#include <drogon/Cookie.h>
|
#include <drogon/Cookie.h>
|
||||||
#include <trantor/net/Resolver.h>
|
#include <trantor/net/Resolver.h>
|
||||||
@ -43,16 +42,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__MACH__) && \
|
|
||||||
(defined(__ENVIRONMENT_IPHONE_OS__) || \
|
|
||||||
defined(__IPHONE_OS_VERSION_MIN_REQUIRED))
|
|
||||||
// iOS
|
|
||||||
#define TARGET_OS_IOS 1
|
|
||||||
#else
|
|
||||||
// not iOS
|
|
||||||
#define TARGET_OS_IOS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace drogon
|
namespace drogon
|
||||||
{
|
{
|
||||||
// the drogon banner
|
// the drogon banner
|
||||||
@ -77,8 +66,6 @@ using ExceptionHandler =
|
|||||||
using DefaultHandler =
|
using DefaultHandler =
|
||||||
std::function<void(const HttpRequestPtr &,
|
std::function<void(const HttpRequestPtr &,
|
||||||
std::function<void(const HttpResponsePtr &)> &&)>;
|
std::function<void(const HttpResponsePtr &)> &&)>;
|
||||||
using HttpHandlerInfo = std::tuple<std::string, HttpMethod, std::string>;
|
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
class HttpAppFramework;
|
class HttpAppFramework;
|
||||||
|
|
||||||
@ -157,7 +144,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual trantor::EventLoop *getLoop() const = 0;
|
virtual trantor::EventLoop *getLoop() const = 0;
|
||||||
|
|
||||||
/// Get an IO loop with id. E.g. 0 <= id < \#Total thread-loops
|
/// Get an IO loop with id. E.g. 0 <= id < #Total thread-loops
|
||||||
/**
|
/**
|
||||||
* @note
|
* @note
|
||||||
* The event loop is one of the network IO loops. Use the loop
|
* The event loop is one of the network IO loops. Use the loop
|
||||||
@ -184,19 +171,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* be sent to the client to provide a custom layout.
|
* be sent to the client to provide a custom layout.
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &setCustomErrorHandler(
|
virtual HttpAppFramework &setCustomErrorHandler(
|
||||||
std::function<HttpResponsePtr(HttpStatusCode,
|
std::function<HttpResponsePtr(HttpStatusCode)> &&resp_generator) = 0;
|
||||||
const HttpRequestPtr &req)>
|
|
||||||
&&resp_generator) = 0;
|
|
||||||
|
|
||||||
HttpAppFramework &setCustomErrorHandler(
|
|
||||||
std::function<HttpResponsePtr(HttpStatusCode)> &&resp_generator)
|
|
||||||
{
|
|
||||||
return setCustomErrorHandler(
|
|
||||||
[cb = std::move(resp_generator)](HttpStatusCode code,
|
|
||||||
const HttpRequestPtr &) {
|
|
||||||
return cb(code);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get custom error handler
|
/// Get custom error handler
|
||||||
/**
|
/**
|
||||||
@ -204,9 +179,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* setCustomErrorHandler. If none was provided, the default error handler is
|
* setCustomErrorHandler. If none was provided, the default error handler is
|
||||||
* returned.
|
* returned.
|
||||||
*/
|
*/
|
||||||
virtual const std::function<HttpResponsePtr(HttpStatusCode,
|
virtual const std::function<HttpResponsePtr(HttpStatusCode)>
|
||||||
const HttpRequestPtr &req)> &
|
&getCustomErrorHandler() const = 0;
|
||||||
getCustomErrorHandler() const = 0;
|
|
||||||
|
|
||||||
/// Get the plugin object registered in the framework
|
/// Get the plugin object registered in the framework
|
||||||
/**
|
/**
|
||||||
@ -333,7 +307,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
[Check Method]---------------->[405]----------->+
|
[Check Method]---------------->[405]----------->+
|
||||||
| |
|
| |
|
||||||
v |
|
v |
|
||||||
[Filters/Middlewares]------>[Filter callback]------>+
|
[Filters]------->[Filter callback]----------->+
|
||||||
| |
|
| |
|
||||||
v Y |
|
v Y |
|
||||||
[Is OPTIONS method?]------------->[200]----------->+
|
[Is OPTIONS method?]------------->[200]----------->+
|
||||||
@ -346,9 +320,6 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
| |
|
| |
|
||||||
v |
|
v |
|
||||||
Post-handling join point o---------------------------------------->+
|
Post-handling join point o---------------------------------------->+
|
||||||
| |
|
|
||||||
v |
|
|
||||||
[Middlewares post logic]--->[Middleware callback]--->+
|
|
||||||
|
|
||||||
@endcode
|
@endcode
|
||||||
*
|
*
|
||||||
@ -359,7 +330,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
|
|
||||||
/// Register an advice called before routing
|
/// Register an advice called before routing
|
||||||
/**
|
/**
|
||||||
* @param advice is called after all the synchronous advice return
|
* @param advice is called after all the synchronous advices return
|
||||||
* nullptr and before the request is routed to any handler. The parameters
|
* nullptr and before the request is routed to any handler. The parameters
|
||||||
* of the advice are same as those of the doFilter method of the Filter
|
* of the advice are same as those of the doFilter method of the Filter
|
||||||
* class.
|
* class.
|
||||||
@ -382,7 +353,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
/// Register an advice called after routing
|
/// Register an advice called after routing
|
||||||
/**
|
/**
|
||||||
* @param advice is called immediately after the request matches a handler
|
* @param advice is called immediately after the request matches a handler
|
||||||
* path and before any filters/middlewares applies. The parameters
|
* path and before any 'doFilter' method of filters applies. The parameters
|
||||||
* of the advice are same as those of the doFilter method of the Filter
|
* of the advice are same as those of the doFilter method of the Filter
|
||||||
* class.
|
* class.
|
||||||
*/
|
*/
|
||||||
@ -404,8 +375,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
/// Register an advice called before the request is handled
|
/// Register an advice called before the request is handled
|
||||||
/**
|
/**
|
||||||
* @param advice is called immediately after the request is approved by all
|
* @param advice is called immediately after the request is approved by all
|
||||||
* filters/middlewares and before it is handled. The parameters of the
|
* filters and before it is handled. The parameters of the advice are
|
||||||
* advice are same as those of the doFilter method of the Filter class.
|
* same as those of the doFilter method of the Filter class.
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework ®isterPreHandlingAdvice(
|
virtual HttpAppFramework ®isterPreHandlingAdvice(
|
||||||
const std::function<void(const HttpRequestPtr &,
|
const std::function<void(const HttpRequestPtr &,
|
||||||
@ -455,14 +426,14 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
|
|
||||||
/// Load the configuration file with json format.
|
/// Load the configuration file with json format.
|
||||||
/**
|
/**
|
||||||
* @param fileName the configuration file
|
* @param filename the configuration file
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &loadConfigFile(
|
virtual HttpAppFramework &loadConfigFile(
|
||||||
const std::string &fileName) noexcept(false) = 0;
|
const std::string &fileName) noexcept(false) = 0;
|
||||||
|
|
||||||
/// Load the configuration from a Json::Value Object.
|
/// Load the configuration from a Json::Value Object.
|
||||||
/**
|
/**
|
||||||
* @param data Json::Value Object containing the configuration.
|
* @param Json::Value Object containing the configuration.
|
||||||
* @note Please refer to the configuration file for the content of the json
|
* @note Please refer to the configuration file for the content of the json
|
||||||
* object.
|
* object.
|
||||||
*/
|
*/
|
||||||
@ -471,7 +442,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
|
|
||||||
/// Load the configuration from a Json::Value Object.
|
/// Load the configuration from a Json::Value Object.
|
||||||
/**
|
/**
|
||||||
* @param data rvalue reference to a Json::Value object containing the
|
* @param rvalue reference to a Json::Value object containing the
|
||||||
* configuration.
|
* configuration.
|
||||||
* @note Please refer to the configuration file for the content of the json
|
* @note Please refer to the configuration file for the content of the json
|
||||||
* object.
|
* object.
|
||||||
@ -486,8 +457,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* called.
|
* called.
|
||||||
* @param ctrlName is the name of the controller. It includes the namespace
|
* @param ctrlName is the name of the controller. It includes the namespace
|
||||||
* to which the controller belongs.
|
* to which the controller belongs.
|
||||||
* @param constraints is a vector containing Http methods or middleware
|
* @param filtersAndMethods is a vector containing Http methods or filter
|
||||||
names
|
* name constraints.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* @code
|
* @code
|
||||||
@ -501,7 +472,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
virtual HttpAppFramework ®isterHttpSimpleController(
|
virtual HttpAppFramework ®isterHttpSimpleController(
|
||||||
const std::string &pathName,
|
const std::string &pathName,
|
||||||
const std::string &ctrlName,
|
const std::string &ctrlName,
|
||||||
const std::vector<internal::HttpConstraint> &constraints = {}) = 0;
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
|
std::vector<internal::HttpConstraint>{}) = 0;
|
||||||
|
|
||||||
/// Register a handler into the framework.
|
/// Register a handler into the framework.
|
||||||
/**
|
/**
|
||||||
@ -509,7 +481,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* pathPattern, the handler indicated by the function parameter is called.
|
* pathPattern, the handler indicated by the function parameter is called.
|
||||||
* @param function indicates any type of callable object with a valid
|
* @param function indicates any type of callable object with a valid
|
||||||
* processing interface.
|
* processing interface.
|
||||||
* @param constraints is the same as the third parameter in the above
|
* @param filtersAndMethods is the same as the third parameter in the above
|
||||||
* method.
|
* method.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
@ -535,7 +507,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
HttpAppFramework ®isterHandler(
|
HttpAppFramework ®isterHandler(
|
||||||
const std::string &pathPattern,
|
const std::string &pathPattern,
|
||||||
FUNCTION &&function,
|
FUNCTION &&function,
|
||||||
const std::vector<internal::HttpConstraint> &constraints = {},
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
|
std::vector<internal::HttpConstraint>{},
|
||||||
const std::string &handlerName = "")
|
const std::string &handlerName = "")
|
||||||
{
|
{
|
||||||
LOG_TRACE << "pathPattern:" << pathPattern;
|
LOG_TRACE << "pathPattern:" << pathPattern;
|
||||||
@ -545,16 +518,17 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
getLoop()->queueInLoop([binder]() { binder->createHandlerInstance(); });
|
getLoop()->queueInLoop([binder]() { binder->createHandlerInstance(); });
|
||||||
|
|
||||||
std::vector<HttpMethod> validMethods;
|
std::vector<HttpMethod> validMethods;
|
||||||
std::vector<std::string> middlewares;
|
std::vector<std::string> filters;
|
||||||
for (auto const &constraint : constraints)
|
for (auto const &filterOrMethod : filtersAndMethods)
|
||||||
{
|
{
|
||||||
if (constraint.type() == internal::ConstraintType::HttpMiddleware)
|
if (filterOrMethod.type() == internal::ConstraintType::HttpFilter)
|
||||||
{
|
{
|
||||||
middlewares.push_back(constraint.getMiddlewareName());
|
filters.push_back(filterOrMethod.getFilterName());
|
||||||
}
|
}
|
||||||
else if (constraint.type() == internal::ConstraintType::HttpMethod)
|
else if (filterOrMethod.type() ==
|
||||||
|
internal::ConstraintType::HttpMethod)
|
||||||
{
|
{
|
||||||
validMethods.push_back(constraint.getHttpMethod());
|
validMethods.push_back(filterOrMethod.getHttpMethod());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -563,7 +537,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
registerHttpController(
|
registerHttpController(
|
||||||
pathPattern, binder, validMethods, middlewares, handlerName);
|
pathPattern, binder, validMethods, filters, handlerName);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,8 +551,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* subexpression is sequentially mapped to a handler parameter.
|
* subexpression is sequentially mapped to a handler parameter.
|
||||||
* @param function indicates any type of callable object with a valid
|
* @param function indicates any type of callable object with a valid
|
||||||
* processing interface.
|
* processing interface.
|
||||||
* @param constraints is the same as the third parameter in the
|
* @param filtersAndMethods is the same as the third parameter in the above
|
||||||
* above method.
|
* method.
|
||||||
* @param handlerName a name for the handler.
|
* @param handlerName a name for the handler.
|
||||||
* @return HttpAppFramework&
|
* @return HttpAppFramework&
|
||||||
*/
|
*/
|
||||||
@ -586,7 +560,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
HttpAppFramework ®isterHandlerViaRegex(
|
HttpAppFramework ®isterHandlerViaRegex(
|
||||||
const std::string ®Exp,
|
const std::string ®Exp,
|
||||||
FUNCTION &&function,
|
FUNCTION &&function,
|
||||||
const std::vector<internal::HttpConstraint> &constraints = {},
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
|
std::vector<internal::HttpConstraint>{},
|
||||||
const std::string &handlerName = "")
|
const std::string &handlerName = "")
|
||||||
{
|
{
|
||||||
LOG_TRACE << "regex:" << regExp;
|
LOG_TRACE << "regex:" << regExp;
|
||||||
@ -596,16 +571,17 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
std::forward<FUNCTION>(function));
|
std::forward<FUNCTION>(function));
|
||||||
|
|
||||||
std::vector<HttpMethod> validMethods;
|
std::vector<HttpMethod> validMethods;
|
||||||
std::vector<std::string> middlewares;
|
std::vector<std::string> filters;
|
||||||
for (auto const &constraint : constraints)
|
for (auto const &filterOrMethod : filtersAndMethods)
|
||||||
{
|
{
|
||||||
if (constraint.type() == internal::ConstraintType::HttpMiddleware)
|
if (filterOrMethod.type() == internal::ConstraintType::HttpFilter)
|
||||||
{
|
{
|
||||||
middlewares.push_back(constraint.getMiddlewareName());
|
filters.push_back(filterOrMethod.getFilterName());
|
||||||
}
|
}
|
||||||
else if (constraint.type() == internal::ConstraintType::HttpMethod)
|
else if (filterOrMethod.type() ==
|
||||||
|
internal::ConstraintType::HttpMethod)
|
||||||
{
|
{
|
||||||
validMethods.push_back(constraint.getHttpMethod());
|
validMethods.push_back(filterOrMethod.getHttpMethod());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -614,7 +590,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
registerHttpControllerViaRegex(
|
registerHttpControllerViaRegex(
|
||||||
regExp, binder, validMethods, middlewares, handlerName);
|
regExp, binder, validMethods, filters, handlerName);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,18 +602,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
virtual HttpAppFramework ®isterWebSocketController(
|
virtual HttpAppFramework ®isterWebSocketController(
|
||||||
const std::string &pathName,
|
const std::string &pathName,
|
||||||
const std::string &ctrlName,
|
const std::string &ctrlName,
|
||||||
const std::vector<internal::HttpConstraint> &constraints = {}) = 0;
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
|
|
||||||
/// Register a WebSocketController into the framework.
|
|
||||||
/**
|
|
||||||
* The parameters of this method are the same as those in the
|
|
||||||
* registerHttpSimpleController() method but using regular
|
|
||||||
* expression string for path.
|
|
||||||
*/
|
|
||||||
virtual HttpAppFramework ®isterWebSocketControllerRegex(
|
|
||||||
const std::string ®Exp,
|
|
||||||
const std::string &ctrlName,
|
|
||||||
const std::vector<internal::HttpConstraint> &constraints =
|
|
||||||
std::vector<internal::HttpConstraint>{}) = 0;
|
std::vector<internal::HttpConstraint>{}) = 0;
|
||||||
|
|
||||||
/// Register controller objects created and initialized by the user
|
/// Register controller objects created and initialized by the user
|
||||||
@ -701,31 +666,13 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register middleware objects created and initialized by the user
|
|
||||||
/**
|
|
||||||
* This method is similar to the above method.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
HttpAppFramework ®isterMiddleware(
|
|
||||||
const std::shared_ptr<T> &middlewarePtr)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of<HttpMiddlewareBase, T>::value,
|
|
||||||
"Error! Only middleware objects can be registered here");
|
|
||||||
static_assert(!T::isAutoCreation,
|
|
||||||
"Middleware created and initialized "
|
|
||||||
"automatically by drogon cannot be "
|
|
||||||
"registered here");
|
|
||||||
DrClassMap::setSingleInstance(middlewarePtr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a default handler into the framework when no handler matches
|
/// Register a default handler into the framework when no handler matches
|
||||||
/// the request. If set, it is executed if the static file router does
|
/// the request. If set, it is executed if the static file router does
|
||||||
/// not find any file corresponding to the request. Thus it replaces
|
/// not find any file corresponding to the request. Thus it replaces
|
||||||
/// the default 404 not found response.
|
/// the default 404 not found response.
|
||||||
/**
|
/**
|
||||||
* @param handler function indicates any type of callable object with
|
* @param function indicates any type of callable object with a valid
|
||||||
* a valid processing interface.
|
* processing interface.
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &setDefaultHandler(DefaultHandler handler) = 0;
|
virtual HttpAppFramework &setDefaultHandler(DefaultHandler handler) = 0;
|
||||||
|
|
||||||
@ -784,7 +731,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* pattern of the handler;
|
* pattern of the handler;
|
||||||
* The last item in std::tuple is the description of the handler.
|
* The last item in std::tuple is the description of the handler.
|
||||||
*/
|
*/
|
||||||
virtual std::vector<HttpHandlerInfo> getHandlersInfo() const = 0;
|
virtual std::vector<std::tuple<std::string, HttpMethod, std::string>>
|
||||||
|
getHandlersInfo() const = 0;
|
||||||
|
|
||||||
/// Get the custom configuration defined by users in the configuration file.
|
/// Get the custom configuration defined by users in the configuration file.
|
||||||
virtual const Json::Value &getCustomConfig() const = 0;
|
virtual const Json::Value &getCustomConfig() const = 0;
|
||||||
@ -816,15 +764,6 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
const std::vector<std::pair<std::string, std::string>>
|
const std::vector<std::pair<std::string, std::string>>
|
||||||
&sslConfCmds) = 0;
|
&sslConfCmds) = 0;
|
||||||
|
|
||||||
/// Reload the global cert file and private key file for https server
|
|
||||||
/// Note: The goal of this method is not to make the framework
|
|
||||||
/// use the new SSL path, but rather to reload the new content
|
|
||||||
/// from the old path while the framework is still running.
|
|
||||||
/// Typically, when our SSL is about to expire,
|
|
||||||
/// we need to reload the SSL. The purpose of this function
|
|
||||||
/// is to use the new SSL certificate without stopping the framework.
|
|
||||||
virtual HttpAppFramework &reloadSSLFiles() = 0;
|
|
||||||
|
|
||||||
/// Add plugins
|
/// Add plugins
|
||||||
/**
|
/**
|
||||||
* @param configs The plugins array
|
* @param configs The plugins array
|
||||||
@ -854,9 +793,8 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* @param keyFile specify the cert file and the private key file for this
|
* @param keyFile specify the cert file and the private key file for this
|
||||||
* listener. If they are empty, the global configuration set by the above
|
* listener. If they are empty, the global configuration set by the above
|
||||||
* method is used.
|
* method is used.
|
||||||
* @param useOldTLS if true, the TLS1.0/1.1 are enabled for HTTPS
|
* @param useOldTLS If true, the TLS1.0/1.1 are enabled for HTTPS
|
||||||
* connections.
|
* connections.
|
||||||
* @param sslConfCmds vector of ssl configuration key/value pairs.
|
|
||||||
*
|
*
|
||||||
* @note
|
* @note
|
||||||
* This operation can be performed by an option in the configuration file.
|
* This operation can be performed by an option in the configuration file.
|
||||||
@ -875,7 +813,6 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
/**
|
/**
|
||||||
* @param timeout The number of seconds which is the timeout of a session
|
* @param timeout The number of seconds which is the timeout of a session
|
||||||
* @param sameSite The default value of SameSite attribute
|
* @param sameSite The default value of SameSite attribute
|
||||||
* @param cookieKey The key of the session cookie
|
|
||||||
*
|
*
|
||||||
* @note
|
* @note
|
||||||
* Session support is disabled by default.
|
* Session support is disabled by default.
|
||||||
@ -886,10 +823,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &enableSession(
|
virtual HttpAppFramework &enableSession(
|
||||||
const size_t timeout = 0,
|
const size_t timeout = 0,
|
||||||
Cookie::SameSite sameSite = Cookie::SameSite::kNull,
|
Cookie::SameSite sameSite = Cookie::SameSite::kNull) = 0;
|
||||||
const std::string &cookieKey = "JSESSIONID",
|
|
||||||
int maxAge = -1,
|
|
||||||
std::function<std::string()> idGeneratorCallback = nullptr) = 0;
|
|
||||||
|
|
||||||
/// A wrapper of the above method.
|
/// A wrapper of the above method.
|
||||||
/**
|
/**
|
||||||
@ -901,16 +835,9 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
inline HttpAppFramework &enableSession(
|
inline HttpAppFramework &enableSession(
|
||||||
const std::chrono::duration<double> &timeout,
|
const std::chrono::duration<double> &timeout,
|
||||||
Cookie::SameSite sameSite = Cookie::SameSite::kNull,
|
Cookie::SameSite sameSite = Cookie::SameSite::kNull)
|
||||||
const std::string &cookieKey = "JSESSIONID",
|
|
||||||
int maxAge = -1,
|
|
||||||
std::function<std::string()> idGeneratorCallback = nullptr)
|
|
||||||
{
|
{
|
||||||
return enableSession((size_t)timeout.count(),
|
return enableSession((size_t)timeout.count(), sameSite);
|
||||||
sameSite,
|
|
||||||
cookieKey,
|
|
||||||
maxAge,
|
|
||||||
idGeneratorCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an advice called when starting a new session.
|
/// Register an advice called when starting a new session.
|
||||||
@ -966,8 +893,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* extension can be accessed.
|
* extension can be accessed.
|
||||||
* @param isRecursive If it is set to false, files in sub directories can't
|
* @param isRecursive If it is set to false, files in sub directories can't
|
||||||
* be accessed.
|
* be accessed.
|
||||||
* @param middlewareNames The list of middlewares which acting on the
|
* @param filters The list of filters which acting on the location.
|
||||||
* location.
|
|
||||||
* @return HttpAppFramework&
|
* @return HttpAppFramework&
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &addALocation(
|
virtual HttpAppFramework &addALocation(
|
||||||
@ -977,7 +903,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
bool isCaseSensitive = false,
|
bool isCaseSensitive = false,
|
||||||
bool allowAll = true,
|
bool allowAll = true,
|
||||||
bool isRecursive = true,
|
bool isRecursive = true,
|
||||||
const std::vector<std::string> &middlewareNames = {}) = 0;
|
const std::vector<std::string> &filters = {}) = 0;
|
||||||
|
|
||||||
/// Set the path to store uploaded files.
|
/// Set the path to store uploaded files.
|
||||||
/**
|
/**
|
||||||
@ -1007,21 +933,21 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
virtual HttpAppFramework &setFileTypes(
|
virtual HttpAppFramework &setFileTypes(
|
||||||
const std::vector<std::string> &types) = 0;
|
const std::vector<std::string> &types) = 0;
|
||||||
|
|
||||||
#if !defined(_WIN32) && !TARGET_OS_IOS
|
/// Enable supporting for dynamic views loading.
|
||||||
/// Enable supporting for dynamic views loading.
|
/**
|
||||||
/**
|
|
||||||
*
|
*
|
||||||
* @param libPaths is a vector that contains paths to view files.
|
* @param libPaths is a vector that contains paths to view files.
|
||||||
*
|
*
|
||||||
* @param outputPath is the directory where the output source files locate.
|
* @param outputPath is the directory where the output source files locate. if
|
||||||
* If it is set to an empty string, drogon use libPaths as output paths. If
|
* it is set to an empty string, drogon use libPaths as output paths. If the
|
||||||
* the path isn't prefixed with /, it is the relative path of the current
|
* path isn't prefixed with /, it is relative path of the current working
|
||||||
* working directory.
|
* directory.
|
||||||
*
|
*
|
||||||
* @note
|
* @note
|
||||||
* It is disabled by default.
|
* It is disabled by default.
|
||||||
* This operation can be performed by an option in the configuration file.
|
* This operation can be performed by an option in the configuration file.
|
||||||
*/
|
*/
|
||||||
|
#ifndef _WIN32
|
||||||
virtual HttpAppFramework &enableDynamicViewsLoading(
|
virtual HttpAppFramework &enableDynamicViewsLoading(
|
||||||
const std::vector<std::string> &libPaths,
|
const std::vector<std::string> &libPaths,
|
||||||
const std::string &outputPath = "") = 0;
|
const std::string &outputPath = "") = 0;
|
||||||
@ -1074,14 +1000,11 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &enableRelaunchOnError() = 0;
|
virtual HttpAppFramework &enableRelaunchOnError() = 0;
|
||||||
|
|
||||||
|
/// Set the output path of logs.
|
||||||
/**
|
/**
|
||||||
* @brief Set the output path of logs.
|
* @param logPath The path to logs.
|
||||||
* @param logPath The path to logs - logs to console if empty.
|
* @param logfileBaseName The base name of log files.
|
||||||
* @param logfileBaseName The base name of log files - defaults to "drogon"
|
|
||||||
* if empty.
|
|
||||||
* @param logSize indicates the maximum size of a log file.
|
* @param logSize indicates the maximum size of a log file.
|
||||||
* @param maxFiles max count of log file - 0 = unlimited.
|
|
||||||
* @param useSpdlog Use spdlog for logging (if compiled-in).
|
|
||||||
*
|
*
|
||||||
* @note
|
* @note
|
||||||
* This operation can be performed by an option in the configuration file.
|
* This operation can be performed by an option in the configuration file.
|
||||||
@ -1090,11 +1013,10 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
const std::string &logPath,
|
const std::string &logPath,
|
||||||
const std::string &logfileBaseName = "",
|
const std::string &logfileBaseName = "",
|
||||||
size_t logSize = 100000000,
|
size_t logSize = 100000000,
|
||||||
size_t maxFiles = 0,
|
size_t maxFiles = 0) = 0;
|
||||||
bool useSpdlog = false) = 0;
|
|
||||||
|
|
||||||
|
/// Set the log level
|
||||||
/**
|
/**
|
||||||
* @brief Set the log level.
|
|
||||||
* @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is
|
* @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is
|
||||||
* DEBUG.
|
* DEBUG.
|
||||||
*
|
*
|
||||||
@ -1437,7 +1359,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual size_t getJsonParserStackLimit() const noexcept = 0;
|
virtual size_t getJsonParserStackLimit() const noexcept = 0;
|
||||||
/**
|
/**
|
||||||
* @brief This method is to enable or disable the unicode escaping (\\u) in
|
* @brief This method is to enable or disable the unicode escaping (\u) in
|
||||||
* the json string of HTTP responses or requests. it works (disable
|
* the json string of HTTP responses or requests. it works (disable
|
||||||
* successfully) when the version of JsonCpp >= 1.9.3, the unicode escaping
|
* successfully) when the version of JsonCpp >= 1.9.3, the unicode escaping
|
||||||
* is enabled by default.
|
* is enabled by default.
|
||||||
@ -1469,19 +1391,19 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*
|
*
|
||||||
* @return std::pair<size_t, std::string>
|
* @return std::pair<size_t, std::string>
|
||||||
*/
|
*/
|
||||||
virtual const std::pair<unsigned int, std::string> &
|
virtual const std::pair<unsigned int, std::string>
|
||||||
getFloatPrecisionInJson() const noexcept = 0;
|
&getFloatPrecisionInJson() const noexcept = 0;
|
||||||
/// Create a database client
|
/// Create a database client
|
||||||
/**
|
/**
|
||||||
* @param dbType The database type is one of
|
* @param dbType The database type is one of
|
||||||
* "postgresql","mysql","sqlite3".
|
* "postgresql","mysql","sqlite3".
|
||||||
* @param host IP or host name.
|
* @param host IP or host name.
|
||||||
* @param port The port on which the database server is listening.
|
* @param port The port on which the database server is listening.
|
||||||
* @param databaseName Database name
|
* @databaseName Database name
|
||||||
* @param userName User name
|
* @param userName User name
|
||||||
* @param password Password for the database server
|
* @param password Password for the database server
|
||||||
* @param connectionNum The number of connections to the database server.
|
* @param connectionNum The number of connections to the database server.
|
||||||
* It's valid only if @p isFast is false.
|
* It's valid only if @param isFast is false.
|
||||||
* @param filename The file name of sqlite3 database file.
|
* @param filename The file name of sqlite3 database file.
|
||||||
* @param name The client name.
|
* @param name The client name.
|
||||||
* @param isFast Indicates if the client is a fast database client.
|
* @param isFast Indicates if the client is a fast database client.
|
||||||
@ -1492,22 +1414,20 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
* @note
|
* @note
|
||||||
* This operation can be performed by an option in the configuration file.
|
* This operation can be performed by an option in the configuration file.
|
||||||
*/
|
*/
|
||||||
[[deprecated("Use addDbClient() instead")]] virtual HttpAppFramework &
|
virtual HttpAppFramework &createDbClient(
|
||||||
createDbClient(const std::string &dbType,
|
const std::string &dbType,
|
||||||
const std::string &host,
|
const std::string &host,
|
||||||
unsigned short port,
|
const unsigned short port,
|
||||||
const std::string &databaseName,
|
const std::string &databaseName,
|
||||||
const std::string &userName,
|
const std::string &userName,
|
||||||
const std::string &password,
|
const std::string &password,
|
||||||
size_t connectionNum = 1,
|
const size_t connectionNum = 1,
|
||||||
const std::string &filename = "",
|
const std::string &filename = "",
|
||||||
const std::string &name = "default",
|
const std::string &name = "default",
|
||||||
bool isFast = false,
|
const bool isFast = false,
|
||||||
const std::string &characterSet = "",
|
const std::string &characterSet = "",
|
||||||
double timeout = -1.0,
|
double timeout = -1.0,
|
||||||
bool autoBatch = false) = 0;
|
const bool autoBatch = false) = 0;
|
||||||
|
|
||||||
virtual HttpAppFramework &addDbClient(const orm::DbConfig &config) = 0;
|
|
||||||
|
|
||||||
/// Create a redis client
|
/// Create a redis client
|
||||||
/**
|
/**
|
||||||
@ -1588,7 +1508,7 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
/**
|
/**
|
||||||
* @brief handler will be called upon an exception escapes a request handler
|
* @brief handler will be called upon an exception escapes a request handler
|
||||||
*/
|
*/
|
||||||
virtual HttpAppFramework &setExceptionHandler(ExceptionHandler handler) = 0;
|
virtual void setExceptionHandler(ExceptionHandler handler) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief returns the excaption handler
|
* @brief returns the excaption handler
|
||||||
@ -1609,46 +1529,18 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual int64_t getConnectionCount() const = 0;
|
virtual int64_t getConnectionCount() const = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the before listen setsockopt callback.
|
|
||||||
*
|
|
||||||
* @param cb This callback will be called before the listen
|
|
||||||
*/
|
|
||||||
virtual HttpAppFramework &setBeforeListenSockOptCallback(
|
|
||||||
std::function<void(int)> cb) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the after accept setsockopt callback.
|
|
||||||
*
|
|
||||||
* @param cb This callback will be called after accept
|
|
||||||
*/
|
|
||||||
virtual HttpAppFramework &setAfterAcceptSockOptCallback(
|
|
||||||
std::function<void(int)> cb) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the client disconnect or connect callback.
|
|
||||||
*
|
|
||||||
* @param cb This callback will be called, when the client disconnect or
|
|
||||||
* connect
|
|
||||||
*/
|
|
||||||
virtual HttpAppFramework &setConnectionCallback(
|
|
||||||
std::function<void(const trantor::TcpConnectionPtr &)> cb) = 0;
|
|
||||||
|
|
||||||
virtual HttpAppFramework &enableRequestStream(bool enable = true) = 0;
|
|
||||||
virtual bool isRequestStreamEnabled() const = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void registerHttpController(
|
virtual void registerHttpController(
|
||||||
const std::string &pathPattern,
|
const std::string &pathPattern,
|
||||||
const internal::HttpBinderBasePtr &binder,
|
const internal::HttpBinderBasePtr &binder,
|
||||||
const std::vector<HttpMethod> &validMethods = {},
|
const std::vector<HttpMethod> &validMethods = std::vector<HttpMethod>(),
|
||||||
const std::vector<std::string> &middlewareNames = {},
|
const std::vector<std::string> &filters = std::vector<std::string>(),
|
||||||
const std::string &handlerName = "") = 0;
|
const std::string &handlerName = "") = 0;
|
||||||
virtual void registerHttpControllerViaRegex(
|
virtual void registerHttpControllerViaRegex(
|
||||||
const std::string ®Exp,
|
const std::string ®Exp,
|
||||||
const internal::HttpBinderBasePtr &binder,
|
const internal::HttpBinderBasePtr &binder,
|
||||||
const std::vector<HttpMethod> &validMethods,
|
const std::vector<HttpMethod> &validMethods,
|
||||||
const std::vector<std::string> &middlewareNames,
|
const std::vector<std::string> &filters,
|
||||||
const std::string &handlerName) = 0;
|
const std::string &handlerName) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,91 +70,6 @@ struct BinderArgTypeTraits<const T &>
|
|||||||
static const bool isValid = true;
|
static const bool isValid = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T getHandlerArgumentValue(std::string &&p)
|
|
||||||
{
|
|
||||||
if constexpr (internal::CanConstructFromString<T>::value)
|
|
||||||
{
|
|
||||||
return T(std::move(p));
|
|
||||||
}
|
|
||||||
else if constexpr (internal::CanConvertFromStringStream<T>::value)
|
|
||||||
{
|
|
||||||
T value{T()};
|
|
||||||
if (!p.empty())
|
|
||||||
{
|
|
||||||
std::stringstream ss(std::move(p));
|
|
||||||
ss >> value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
else if constexpr (internal::CanConvertFromString<T>::value)
|
|
||||||
{
|
|
||||||
T value;
|
|
||||||
value = p;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "Can't convert string to type " << typeid(T).name();
|
|
||||||
return T();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline std::string getHandlerArgumentValue<std::string>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::move(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline int getHandlerArgumentValue<int>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stoi(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline long getHandlerArgumentValue<long>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stol(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline long long getHandlerArgumentValue<long long>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stoll(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline unsigned long getHandlerArgumentValue<unsigned long>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stoul(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline unsigned long long getHandlerArgumentValue<unsigned long long>(
|
|
||||||
std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stoull(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline float getHandlerArgumentValue<float>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stof(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline double getHandlerArgumentValue<double>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stod(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline long double getHandlerArgumentValue<long double>(std::string &&p)
|
|
||||||
{
|
|
||||||
return std::stold(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HttpBinderBase
|
class HttpBinderBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -164,7 +79,6 @@ class HttpBinderBase
|
|||||||
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
|
std::function<void(const HttpResponsePtr &)> &&callback) = 0;
|
||||||
virtual size_t paramCount() = 0;
|
virtual size_t paramCount() = 0;
|
||||||
virtual const std::string &handlerName() const = 0;
|
virtual const std::string &handlerName() const = 0;
|
||||||
virtual bool isStreamHandler() = 0;
|
|
||||||
|
|
||||||
virtual ~HttpBinderBase()
|
virtual ~HttpBinderBase()
|
||||||
{
|
{
|
||||||
@ -219,11 +133,6 @@ class HttpBinder : public HttpBinderBase
|
|||||||
return traits::arity;
|
return traits::arity;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStreamHandler() override
|
|
||||||
{
|
|
||||||
return traits::isStreamHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpBinder(FUNCTION &&func) : func_(std::forward<FUNCTION>(func))
|
HttpBinder(FUNCTION &&func) : func_(std::forward<FUNCTION>(func))
|
||||||
{
|
{
|
||||||
static_assert(traits::isHTTPFunction,
|
static_assert(traits::isHTTPFunction,
|
||||||
@ -244,22 +153,27 @@ class HttpBinder : public HttpBinderBase
|
|||||||
|
|
||||||
template <bool isClassFunction = traits::isClassFunction,
|
template <bool isClassFunction = traits::isClassFunction,
|
||||||
bool isDrObjectClass = traits::isDrObjectClass>
|
bool isDrObjectClass = traits::isDrObjectClass>
|
||||||
void createHandlerInstance()
|
typename std::enable_if<isDrObjectClass && isClassFunction, void>::type
|
||||||
|
createHandlerInstance()
|
||||||
{
|
{
|
||||||
if constexpr (isClassFunction)
|
auto objPtr =
|
||||||
{
|
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||||
if constexpr (isDrObjectClass)
|
|
||||||
{
|
|
||||||
auto objPtr = DrClassMap::getSingleInstance<
|
|
||||||
typename traits::class_type>();
|
|
||||||
LOG_TRACE << "create handler class object: " << objPtr.get();
|
LOG_TRACE << "create handler class object: " << objPtr.get();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
template <bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isDrObjectClass = traits::isDrObjectClass>
|
||||||
|
typename std::enable_if<!isDrObjectClass && isClassFunction, void>::type
|
||||||
|
createHandlerInstance()
|
||||||
{
|
{
|
||||||
auto &obj = getControllerObj<typename traits::class_type>();
|
auto &obj = getControllerObj<typename traits::class_type>();
|
||||||
LOG_TRACE << "create handler class object: " << &obj;
|
LOG_TRACE << "create handler class object: " << &obj;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
template <bool isClassFunction = traits::isClassFunction>
|
||||||
|
typename std::enable_if<!isClassFunction, void>::type
|
||||||
|
createHandlerInstance()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -270,42 +184,95 @@ class HttpBinder : public HttpBinderBase
|
|||||||
static const size_t argument_count = traits::arity;
|
static const size_t argument_count = traits::arity;
|
||||||
std::string handlerName_;
|
std::string handlerName_;
|
||||||
|
|
||||||
template <typename... Values,
|
template <typename T>
|
||||||
std::size_t Boundary = argument_count,
|
typename std::enable_if<internal::CanConvertFromStringStream<T>::value,
|
||||||
bool isStreamHandler = traits::isStreamHandler,
|
void>::type
|
||||||
bool isCoroutine = traits::isCoroutine>
|
getHandlerArgumentValue(T &value, std::string &&p)
|
||||||
void run(std::deque<std::string> &pathArguments,
|
{
|
||||||
|
if (!p.empty())
|
||||||
|
{
|
||||||
|
std::stringstream ss(std::move(p));
|
||||||
|
ss >> value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<!(internal::CanConvertFromStringStream<T>::value),
|
||||||
|
void>::type
|
||||||
|
getHandlerArgumentValue(T &value, std::string &&p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(std::string &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(int &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stoi(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(long &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stol(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(long long &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stoll(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(unsigned long &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stoul(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(unsigned long long &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stoull(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(float &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stof(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(double &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stod(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getHandlerArgumentValue(long double &value, std::string &&p)
|
||||||
|
{
|
||||||
|
value = std::stold(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Values, std::size_t Boundary = argument_count>
|
||||||
|
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
||||||
|
std::deque<std::string> &pathArguments,
|
||||||
const HttpRequestPtr &req,
|
const HttpRequestPtr &req,
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
Values &&...values)
|
Values &&...values)
|
||||||
{
|
{
|
||||||
if constexpr (sizeof...(Values) < Boundary)
|
// Call this function recursively until parameter's count equals to the
|
||||||
{ // Call this function recursively until parameter's count equals to
|
// count of target function parameters
|
||||||
// the count of target function parameters
|
|
||||||
static_assert(
|
static_assert(
|
||||||
BinderArgTypeTraits<
|
BinderArgTypeTraits<nth_argument_type<sizeof...(Values)>>::isValid,
|
||||||
nth_argument_type<sizeof...(Values)>>::isValid,
|
|
||||||
"your handler argument type must be value type or const left "
|
"your handler argument type must be value type or const left "
|
||||||
"reference type or right reference type");
|
"reference type or right reference type");
|
||||||
using ValueType = std::remove_cv_t<
|
using ValueType =
|
||||||
std::remove_reference_t<nth_argument_type<sizeof...(Values)>>>;
|
typename std::remove_cv<typename std::remove_reference<
|
||||||
|
nth_argument_type<sizeof...(Values)>>::type>::type;
|
||||||
|
ValueType value = ValueType();
|
||||||
if (!pathArguments.empty())
|
if (!pathArguments.empty())
|
||||||
{
|
{
|
||||||
std::string v{std::move(pathArguments.front())};
|
std::string v = std::move(pathArguments.front());
|
||||||
pathArguments.pop_front();
|
pathArguments.pop_front();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!v.empty())
|
if (v.empty() == false)
|
||||||
{
|
getHandlerArgumentValue(value, std::move(v));
|
||||||
auto value =
|
|
||||||
getHandlerArgumentValue<ValueType>(std::move(v));
|
|
||||||
run(pathArguments,
|
|
||||||
req,
|
|
||||||
std::move(callback),
|
|
||||||
std::forward<Values>(values)...,
|
|
||||||
std::move(value));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@ -317,13 +284,7 @@ class HttpBinder : public HttpBinderBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto value = req->as<ValueType>();
|
value = req->as<ValueType>();
|
||||||
run(pathArguments,
|
|
||||||
req,
|
|
||||||
std::move(callback),
|
|
||||||
std::forward<Values>(values)...,
|
|
||||||
std::move(value));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@ -341,28 +302,25 @@ class HttpBinder : public HttpBinderBase
|
|||||||
req,
|
req,
|
||||||
std::move(callback),
|
std::move(callback),
|
||||||
std::forward<Values>(values)...,
|
std::forward<Values>(values)...,
|
||||||
ValueType());
|
std::move(value));
|
||||||
}
|
}
|
||||||
else if constexpr (sizeof...(Values) == Boundary)
|
|
||||||
{
|
template <typename... Values,
|
||||||
if constexpr (!isCoroutine)
|
std::size_t Boundary = argument_count,
|
||||||
|
bool isCoroutine = traits::isCoroutine>
|
||||||
|
typename std::enable_if<(sizeof...(Values) == Boundary) && !isCoroutine,
|
||||||
|
void>::type
|
||||||
|
run(std::deque<std::string> &,
|
||||||
|
const HttpRequestPtr &req,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
|
Values &&...values)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Explicit copy because `callFunction` moves it
|
// Explcit copy because `callFunction` moves it
|
||||||
auto cb = callback;
|
auto cb = callback;
|
||||||
if constexpr (isStreamHandler)
|
|
||||||
{
|
|
||||||
callFunction(req,
|
|
||||||
createRequestStream(req),
|
|
||||||
cb,
|
|
||||||
std::move(values)...);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callFunction(req, cb, std::move(values)...);
|
callFunction(req, cb, std::move(values)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (const std::exception &except)
|
catch (const std::exception &except)
|
||||||
{
|
{
|
||||||
handleException(except, req, std::move(callback));
|
handleException(except, req, std::move(callback));
|
||||||
@ -374,39 +332,40 @@ class HttpBinder : public HttpBinderBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
else
|
template <typename... Values,
|
||||||
|
std::size_t Boundary = argument_count,
|
||||||
|
bool isCoroutine = traits::isCoroutine>
|
||||||
|
typename std::enable_if<(sizeof...(Values) == Boundary) && isCoroutine,
|
||||||
|
void>::type
|
||||||
|
run(std::deque<std::string> &,
|
||||||
|
const HttpRequestPtr &req,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
|
Values &&...values)
|
||||||
{
|
{
|
||||||
static_assert(!isStreamHandler);
|
|
||||||
[this](HttpRequestPtr req,
|
[this](HttpRequestPtr req,
|
||||||
std::function<void(const HttpResponsePtr &)> callback,
|
std::function<void(const HttpResponsePtr &)> callback,
|
||||||
Values &&...values) -> AsyncTask {
|
Values &&...values) -> AsyncTask {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<
|
if constexpr (std::is_same_v<AsyncTask,
|
||||||
AsyncTask,
|
|
||||||
typename traits::return_type>)
|
typename traits::return_type>)
|
||||||
{
|
{
|
||||||
// Explicit copy because `callFunction` moves it
|
// Explcit copy because `callFunction` moves it
|
||||||
auto cb = callback;
|
auto cb = callback;
|
||||||
callFunction(req, cb, std::move(values)...);
|
callFunction(req, cb, std::move(values)...);
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_same_v<
|
else if constexpr (std::is_same_v<Task<>,
|
||||||
Task<>,
|
|
||||||
typename traits::return_type>)
|
typename traits::return_type>)
|
||||||
{
|
{
|
||||||
// Explicit copy because `callFunction` moves it
|
// Explcit copy because `callFunction` moves it
|
||||||
auto cb = callback;
|
auto cb = callback;
|
||||||
co_await callFunction(req,
|
co_await callFunction(req, cb, std::move(values)...);
|
||||||
cb,
|
|
||||||
std::move(values)...);
|
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_same_v<
|
else if constexpr (std::is_same_v<Task<HttpResponsePtr>,
|
||||||
Task<HttpResponsePtr>,
|
|
||||||
typename traits::return_type>)
|
typename traits::return_type>)
|
||||||
{
|
{
|
||||||
auto resp =
|
auto resp =
|
||||||
co_await callFunction(req,
|
co_await callFunction(req, std::move(values)...);
|
||||||
std::move(values)...);
|
|
||||||
callback(std::move(resp));
|
callback(std::move(resp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,69 +375,86 @@ class HttpBinder : public HttpBinderBase
|
|||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_ERROR
|
LOG_ERROR << "Exception not derived from std::exception";
|
||||||
<< "Exception not derived from std::exception";
|
|
||||||
}
|
}
|
||||||
co_return;
|
|
||||||
}(req, std::move(callback), std::move(values)...);
|
}(req, std::move(callback), std::move(values)...);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
template <typename... Values,
|
||||||
|
bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isDrObjectClass = traits::isDrObjectClass,
|
||||||
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
|
HttpRequestPtr>::value>
|
||||||
|
typename std::enable_if<isClassFunction && !isDrObjectClass && isNormal,
|
||||||
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
|
{
|
||||||
|
static auto &obj = getControllerObj<typename traits::class_type>();
|
||||||
|
return (obj.*func_)(req, std::move(values)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Values,
|
template <typename... Values,
|
||||||
bool isClassFunction = traits::isClassFunction,
|
bool isClassFunction = traits::isClassFunction,
|
||||||
bool isDrObjectClass = traits::isDrObjectClass,
|
bool isDrObjectClass = traits::isDrObjectClass,
|
||||||
bool isNormal = std::is_same_v<typename traits::first_param_type,
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
HttpRequestPtr>>
|
HttpRequestPtr>::value>
|
||||||
typename traits::return_type callFunction(const HttpRequestPtr &req,
|
typename std::enable_if<isClassFunction && isDrObjectClass && isNormal,
|
||||||
Values &&...values)
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
{
|
{
|
||||||
if constexpr (isNormal)
|
static auto objPtr =
|
||||||
{
|
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||||
if constexpr (isClassFunction)
|
|
||||||
{
|
|
||||||
if constexpr (!isDrObjectClass)
|
|
||||||
{
|
|
||||||
static auto &obj =
|
|
||||||
getControllerObj<typename traits::class_type>();
|
|
||||||
return (obj.*func_)(req, std::move(values)...);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static auto objPtr = DrClassMap::getSingleInstance<
|
|
||||||
typename traits::class_type>();
|
|
||||||
return (*objPtr.*func_)(req, std::move(values)...);
|
return (*objPtr.*func_)(req, std::move(values)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
template <typename... Values,
|
||||||
|
bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
|
HttpRequestPtr>::value>
|
||||||
|
typename std::enable_if<!isClassFunction && isNormal,
|
||||||
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
{
|
{
|
||||||
return func_(req, std::move(values)...);
|
return func_(req, std::move(values)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
template <typename... Values,
|
||||||
|
bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isDrObjectClass = traits::isDrObjectClass,
|
||||||
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
|
HttpRequestPtr>::value>
|
||||||
|
typename std::enable_if<isClassFunction && !isDrObjectClass && !isNormal,
|
||||||
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
{
|
{
|
||||||
if constexpr (isClassFunction)
|
static auto &obj = getControllerObj<typename traits::class_type>();
|
||||||
{
|
|
||||||
if constexpr (!isDrObjectClass)
|
|
||||||
{
|
|
||||||
static auto &obj =
|
|
||||||
getControllerObj<typename traits::class_type>();
|
|
||||||
return (obj.*func_)((*req), std::move(values)...);
|
return (obj.*func_)((*req), std::move(values)...);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
template <typename... Values,
|
||||||
|
bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isDrObjectClass = traits::isDrObjectClass,
|
||||||
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
|
HttpRequestPtr>::value>
|
||||||
|
typename std::enable_if<isClassFunction && isDrObjectClass && !isNormal,
|
||||||
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
{
|
{
|
||||||
static auto objPtr = DrClassMap::getSingleInstance<
|
static auto objPtr =
|
||||||
typename traits::class_type>();
|
DrClassMap::getSingleInstance<typename traits::class_type>();
|
||||||
return (*objPtr.*func_)((*req), std::move(values)...);
|
return (*objPtr.*func_)((*req), std::move(values)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
template <typename... Values,
|
||||||
|
bool isClassFunction = traits::isClassFunction,
|
||||||
|
bool isNormal = std::is_same<typename traits::first_param_type,
|
||||||
|
HttpRequestPtr>::value>
|
||||||
|
typename std::enable_if<!isClassFunction && !isNormal,
|
||||||
|
typename traits::return_type>::type
|
||||||
|
callFunction(const HttpRequestPtr &req, Values &&...values)
|
||||||
{
|
{
|
||||||
return func_((*req), std::move(values)...);
|
return func_((*req), std::move(values)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include <drogon/HttpRequest.h>
|
#include <drogon/HttpRequest.h>
|
||||||
#include <trantor/utils/NonCopyable.h>
|
#include <trantor/utils/NonCopyable.h>
|
||||||
#include <trantor/net/EventLoop.h>
|
#include <trantor/net/EventLoop.h>
|
||||||
#include <cstddef>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <future>
|
#include <future>
|
||||||
@ -64,7 +63,7 @@ struct HttpRespAwaiter : public CallbackAwaiter<HttpResponsePtr>
|
|||||||
* If the connection is broken, the client attempts to reconnect
|
* If the connection is broken, the client attempts to reconnect
|
||||||
* when calling the sendRequest method.
|
* when calling the sendRequest method.
|
||||||
*
|
*
|
||||||
* Using the static method newHttpClient(...) to get shared_ptr of the object
|
* Using the static mathod newHttpClient(...) to get shared_ptr of the object
|
||||||
* implementing the class, the shared_ptr is retained in the framework until all
|
* implementing the class, the shared_ptr is retained in the framework until all
|
||||||
* response callbacks are invoked without fear of accidental deconstruction.
|
* response callbacks are invoked without fear of accidental deconstruction.
|
||||||
*
|
*
|
||||||
@ -179,12 +178,6 @@ class DROGON_EXPORT HttpClient : public trantor::NonCopyable
|
|||||||
*/
|
*/
|
||||||
virtual void setSockOptCallback(std::function<void(int)> cb) = 0;
|
virtual void setSockOptCallback(std::function<void(int)> cb) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the number of unsent http requests in the current http
|
|
||||||
* client cache buffer
|
|
||||||
*/
|
|
||||||
virtual std::size_t requestsBufferSize() = 0;
|
|
||||||
|
|
||||||
/// Set the pipelining depth, which is the number of requests that are not
|
/// Set the pipelining depth, which is the number of requests that are not
|
||||||
/// responding.
|
/// responding.
|
||||||
/**
|
/**
|
||||||
@ -231,7 +224,7 @@ class DROGON_EXPORT HttpClient : public trantor::NonCopyable
|
|||||||
virtual void setUserAgent(const std::string &userAgent) = 0;
|
virtual void setUserAgent(const std::string &userAgent) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new HTTP client which use ip and port to connect to
|
* @brief Creaet a new HTTP client which use ip and port to connect to
|
||||||
* server
|
* server
|
||||||
*
|
*
|
||||||
* @param ip The ip address of the HTTP server
|
* @param ip The ip address of the HTTP server
|
||||||
@ -242,7 +235,7 @@ class DROGON_EXPORT HttpClient : public trantor::NonCopyable
|
|||||||
* HttpAppFramework's event loop, otherwise it runs in the loop identified
|
* HttpAppFramework's event loop, otherwise it runs in the loop identified
|
||||||
* by the parameter.
|
* by the parameter.
|
||||||
* @param useOldTLS If the parameter is set to true, the TLS1.0/1.1 are
|
* @param useOldTLS If the parameter is set to true, the TLS1.0/1.1 are
|
||||||
* enabled for HTTPS.
|
* eanbled for HTTPS.
|
||||||
* @param validateCert If the parameter is set to true, the client validates
|
* @param validateCert If the parameter is set to true, the client validates
|
||||||
* the server certificate when SSL handshaking.
|
* the server certificate when SSL handshaking.
|
||||||
* @return HttpClientPtr The smart pointer to the new client object.
|
* @return HttpClientPtr The smart pointer to the new client object.
|
||||||
|
@ -59,14 +59,15 @@ template <typename T, bool AutoCreation = true>
|
|||||||
class HttpController : public DrObject<T>, public HttpControllerBase
|
class HttpController : public DrObject<T>, public HttpControllerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr bool isAutoCreation = AutoCreation;
|
static const bool isAutoCreation = AutoCreation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename FUNCTION>
|
template <typename FUNCTION>
|
||||||
static void registerMethod(
|
static void registerMethod(
|
||||||
FUNCTION &&function,
|
FUNCTION &&function,
|
||||||
const std::string &pattern,
|
const std::string &pattern,
|
||||||
const std::vector<internal::HttpConstraint> &constraints = {},
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
|
std::vector<internal::HttpConstraint>{},
|
||||||
bool classNameInPath = true,
|
bool classNameInPath = true,
|
||||||
const std::string &handlerName = "")
|
const std::string &handlerName = "")
|
||||||
{
|
{
|
||||||
@ -87,12 +88,12 @@ class HttpController : public DrObject<T>, public HttpControllerBase
|
|||||||
if (pattern.empty() || pattern[0] == '/')
|
if (pattern.empty() || pattern[0] == '/')
|
||||||
app().registerHandler(path + pattern,
|
app().registerHandler(path + pattern,
|
||||||
std::forward<FUNCTION>(function),
|
std::forward<FUNCTION>(function),
|
||||||
constraints,
|
filtersAndMethods,
|
||||||
handlerName);
|
handlerName);
|
||||||
else
|
else
|
||||||
app().registerHandler(path + "/" + pattern,
|
app().registerHandler(path + "/" + pattern,
|
||||||
std::forward<FUNCTION>(function),
|
std::forward<FUNCTION>(function),
|
||||||
constraints,
|
filtersAndMethods,
|
||||||
handlerName);
|
handlerName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -104,7 +105,7 @@ class HttpController : public DrObject<T>, public HttpControllerBase
|
|||||||
}
|
}
|
||||||
app().registerHandler(path,
|
app().registerHandler(path,
|
||||||
std::forward<FUNCTION>(function),
|
std::forward<FUNCTION>(function),
|
||||||
constraints,
|
filtersAndMethods,
|
||||||
handlerName);
|
handlerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,13 +114,13 @@ class HttpController : public DrObject<T>, public HttpControllerBase
|
|||||||
static void registerMethodViaRegex(
|
static void registerMethodViaRegex(
|
||||||
FUNCTION &&function,
|
FUNCTION &&function,
|
||||||
const std::string ®Exp,
|
const std::string ®Exp,
|
||||||
const std::vector<internal::HttpConstraint> &constraints =
|
const std::vector<internal::HttpConstraint> &filtersAndMethods =
|
||||||
std::vector<internal::HttpConstraint>{},
|
std::vector<internal::HttpConstraint>{},
|
||||||
const std::string &handlerName = "")
|
const std::string &handlerName = "")
|
||||||
{
|
{
|
||||||
app().registerHandlerViaRegex(regExp,
|
app().registerHandlerViaRegex(regExp,
|
||||||
std::forward<FUNCTION>(function),
|
std::forward<FUNCTION>(function),
|
||||||
constraints,
|
filtersAndMethods,
|
||||||
handlerName);
|
handlerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <drogon/drogon_callbacks.h>
|
#include <drogon/drogon_callbacks.h>
|
||||||
#include <drogon/HttpRequest.h>
|
#include <drogon/HttpRequest.h>
|
||||||
#include <drogon/HttpResponse.h>
|
#include <drogon/HttpResponse.h>
|
||||||
#include <drogon/HttpMiddleware.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
@ -31,18 +30,17 @@ namespace drogon
|
|||||||
* @brief The abstract base class for filters
|
* @brief The abstract base class for filters
|
||||||
* For more details on the class, see the wiki site (the 'Filter' section)
|
* For more details on the class, see the wiki site (the 'Filter' section)
|
||||||
*/
|
*/
|
||||||
class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase,
|
class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase
|
||||||
public HttpMiddlewareBase
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// This virtual function should be overridden in subclasses.
|
/// This virtual function should be overrided in subclasses.
|
||||||
/**
|
/**
|
||||||
* This method is an asynchronous interface, user should return the result
|
* This method is an asynchronous interface, user should return the result
|
||||||
* via 'FilterCallback' or 'FilterChainCallback'.
|
* via 'FilterCallback' or 'FilterChainCallback'.
|
||||||
* @param req is the request object processed by the filter
|
* @param req is the request object processed by the filter
|
||||||
* @param fcb if this is called, the response object is send to the client
|
* @param fcb if this is called, the response object is send to the client
|
||||||
* by the callback, and doFilter methods of next filters and the handler
|
* by the callback, and doFilter methods of next filters and the handler
|
||||||
* registered on the path are not called anymore.
|
* registed on the path are not called anymore.
|
||||||
* @param fccb if this callback is called, the next filter's doFilter method
|
* @param fccb if this callback is called, the next filter's doFilter method
|
||||||
* or the handler registered on the path is called.
|
* or the handler registered on the path is called.
|
||||||
*/
|
*/
|
||||||
@ -50,24 +48,6 @@ class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase,
|
|||||||
FilterCallback &&fcb,
|
FilterCallback &&fcb,
|
||||||
FilterChainCallback &&fccb) = 0;
|
FilterChainCallback &&fccb) = 0;
|
||||||
~HttpFilterBase() override = default;
|
~HttpFilterBase() override = default;
|
||||||
|
|
||||||
private:
|
|
||||||
void invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextCallback &&nextCb,
|
|
||||||
MiddlewareCallback &&mcb) final
|
|
||||||
{
|
|
||||||
auto mcbPtr = std::make_shared<MiddlewareCallback>(std::move(mcb));
|
|
||||||
doFilter(
|
|
||||||
req,
|
|
||||||
[mcbPtr](const HttpResponsePtr &resp) {
|
|
||||||
(*mcbPtr)(resp);
|
|
||||||
}, // fcb, intercept the response
|
|
||||||
[nextCb = std::move(nextCb), mcbPtr]() mutable {
|
|
||||||
nextCb([mcbPtr = std::move(mcbPtr)](
|
|
||||||
const HttpResponsePtr &resp) { (*mcbPtr)(resp); });
|
|
||||||
} // fccb, call the next middleware
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +55,7 @@ class DROGON_EXPORT HttpFilterBase : public virtual DrObjectBase,
|
|||||||
*
|
*
|
||||||
* @tparam T The type of the implementation class
|
* @tparam T The type of the implementation class
|
||||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
* @tparam AutoCreation The flag for automatically creating, user can set this
|
||||||
* flag to false for classes that have non-default constructors.
|
* flag to false for classes that have nondefault constructors.
|
||||||
*/
|
*/
|
||||||
template <typename T, bool AutoCreation = true>
|
template <typename T, bool AutoCreation = true>
|
||||||
class HttpFilter : public DrObject<T>, public HttpFilterBase
|
class HttpFilter : public DrObject<T>, public HttpFilterBase
|
||||||
@ -85,6 +65,14 @@ class HttpFilter : public DrObject<T>, public HttpFilterBase
|
|||||||
~HttpFilter() override = default;
|
~HttpFilter() override = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
DROGON_EXPORT void handleException(
|
||||||
|
const std::exception &,
|
||||||
|
const HttpRequestPtr &,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
template <typename T, bool AutoCreation = true>
|
template <typename T, bool AutoCreation = true>
|
||||||
class HttpCoroFilter : public DrObject<T>, public HttpFilterBase
|
class HttpCoroFilter : public DrObject<T>, public HttpFilterBase
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* @file HttpMiddleware.h
|
|
||||||
* @author Nitromelon
|
|
||||||
*
|
|
||||||
* Copyright 2024, Nitromelon. All rights reserved.
|
|
||||||
* https://github.com/drogonframework/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <drogon/DrObject.h>
|
|
||||||
#include <drogon/drogon_callbacks.h>
|
|
||||||
#include <drogon/HttpRequest.h>
|
|
||||||
#include <drogon/HttpResponse.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
|
||||||
#include <drogon/utils/coroutine.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief The abstract base class for middleware
|
|
||||||
*/
|
|
||||||
class DROGON_EXPORT HttpMiddlewareBase : public virtual DrObjectBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* This virtual function should be overridden in subclasses.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* @code
|
|
||||||
* void invoke(const HttpRequestPtr &req,
|
|
||||||
* MiddlewareNextCallback &&nextCb,
|
|
||||||
* MiddlewareCallback &&mcb) override
|
|
||||||
* {
|
|
||||||
* if (req->path() == "/some/path") {
|
|
||||||
* // intercept directly
|
|
||||||
* mcb(HttpResponse::newNotFoundResponse(req));
|
|
||||||
* return;
|
|
||||||
* }
|
|
||||||
* // Do something before calling the next middleware
|
|
||||||
* nextCb([mcb = std::move(mcb)](const HttpResponsePtr &resp) {
|
|
||||||
* // Do something after the next middleware returns
|
|
||||||
* mcb(resp);
|
|
||||||
* });
|
|
||||||
* }
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
virtual void invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextCallback &&nextCb,
|
|
||||||
MiddlewareCallback &&mcb) = 0;
|
|
||||||
~HttpMiddlewareBase() override = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The reflection base class template for middlewares
|
|
||||||
*
|
|
||||||
* @tparam T The type of the implementation class
|
|
||||||
* @tparam AutoCreation The flag for automatically creating, user can set this
|
|
||||||
* flag to false for classes that have non-default constructors.
|
|
||||||
*/
|
|
||||||
template <typename T, bool AutoCreation = true>
|
|
||||||
class HttpMiddleware : public DrObject<T>, public HttpMiddlewareBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static constexpr bool isAutoCreation{AutoCreation};
|
|
||||||
~HttpMiddleware() override = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace internal
|
|
||||||
{
|
|
||||||
DROGON_EXPORT void handleException(
|
|
||||||
const std::exception &,
|
|
||||||
const HttpRequestPtr &,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
|
||||||
|
|
||||||
struct [[nodiscard]] MiddlewareNextAwaiter
|
|
||||||
: public CallbackAwaiter<HttpResponsePtr>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MiddlewareNextAwaiter(MiddlewareNextCallback &&nextCb)
|
|
||||||
: nextCb_(std::move(nextCb))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void await_suspend(std::coroutine_handle<> handle) noexcept
|
|
||||||
{
|
|
||||||
nextCb_([this, handle](const HttpResponsePtr &resp) {
|
|
||||||
setValue(resp);
|
|
||||||
handle.resume();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MiddlewareNextCallback nextCb_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, bool AutoCreation = true>
|
|
||||||
class HttpCoroMiddleware : public DrObject<T>, public HttpMiddlewareBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static constexpr bool isAutoCreation{AutoCreation};
|
|
||||||
~HttpCoroMiddleware() override = default;
|
|
||||||
|
|
||||||
void invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextCallback &&nextCb,
|
|
||||||
MiddlewareCallback &&mcb) final
|
|
||||||
{
|
|
||||||
drogon::async_run([this,
|
|
||||||
req,
|
|
||||||
nextCb = std::move(nextCb),
|
|
||||||
mcb = std::move(mcb)]() mutable -> drogon::Task<> {
|
|
||||||
HttpResponsePtr resp;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
resp = co_await invoke(req, {std::move(nextCb)});
|
|
||||||
}
|
|
||||||
catch (const std::exception &ex)
|
|
||||||
{
|
|
||||||
internal::handleException(ex, req, std::move(mcb));
|
|
||||||
co_return;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "Exception not derived from std::exception";
|
|
||||||
co_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mcb(resp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Task<HttpResponsePtr> invoke(const HttpRequestPtr &req,
|
|
||||||
MiddlewareNextAwaiter &&next) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace drogon
|
|
@ -30,7 +30,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <trantor/net/TcpConnection.h>
|
|
||||||
|
|
||||||
namespace drogon
|
namespace drogon
|
||||||
{
|
{
|
||||||
@ -137,7 +136,7 @@ class DROGON_EXPORT HttpRequest
|
|||||||
/// Get the header string identified by the key parameter.
|
/// Get the header string identified by the key parameter.
|
||||||
/**
|
/**
|
||||||
* @note
|
* @note
|
||||||
* If there is no the header, a empty string is returned.
|
* If there is no the header, a empty string is retured.
|
||||||
* The key is case insensitive
|
* The key is case insensitive
|
||||||
*/
|
*/
|
||||||
virtual const std::string &getHeader(std::string key) const = 0;
|
virtual const std::string &getHeader(std::string key) const = 0;
|
||||||
@ -163,34 +162,31 @@ class DROGON_EXPORT HttpRequest
|
|||||||
virtual const std::string &getCookie(const std::string &field) const = 0;
|
virtual const std::string &getCookie(const std::string &field) const = 0;
|
||||||
|
|
||||||
/// Get all headers of the request
|
/// Get all headers of the request
|
||||||
virtual const SafeStringMap<std::string> &headers() const = 0;
|
virtual const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&headers() const = 0;
|
||||||
|
|
||||||
/// Get all headers of the request
|
/// Get all headers of the request
|
||||||
const SafeStringMap<std::string> &getHeaders() const
|
const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&getHeaders() const
|
||||||
{
|
{
|
||||||
return headers();
|
return headers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all cookies of the request
|
/// Get all cookies of the request
|
||||||
virtual const SafeStringMap<std::string> &cookies() const = 0;
|
virtual const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&cookies() const = 0;
|
||||||
|
|
||||||
/// Get all cookies of the request
|
/// Get all cookies of the request
|
||||||
const SafeStringMap<std::string> &getCookies() const
|
const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&getCookies() const
|
||||||
{
|
{
|
||||||
return cookies();
|
return cookies();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return content length parsed from the Content-Length header
|
|
||||||
* If no Content-Length header, return null.
|
|
||||||
*/
|
|
||||||
virtual size_t realContentLength() const = 0;
|
|
||||||
|
|
||||||
size_t getRealContentLength() const
|
|
||||||
{
|
|
||||||
return realContentLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the query string of the request.
|
/// Get the query string of the request.
|
||||||
/**
|
/**
|
||||||
* The query string is the substring after the '?' in the URL string.
|
* The query string is the substring after the '?' in the URL string.
|
||||||
@ -273,7 +269,7 @@ class DROGON_EXPORT HttpRequest
|
|||||||
/// Return the enum type version of the request.
|
/// Return the enum type version of the request.
|
||||||
/**
|
/**
|
||||||
* kHttp10 means Http version is 1.0
|
* kHttp10 means Http version is 1.0
|
||||||
* kHttp11 means Http version is 1.1
|
* kHttp11 means Http verison is 1.1
|
||||||
*/
|
*/
|
||||||
virtual Version version() const = 0;
|
virtual Version version() const = 0;
|
||||||
|
|
||||||
@ -304,10 +300,14 @@ class DROGON_EXPORT HttpRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get parameters of the request.
|
/// Get parameters of the request.
|
||||||
virtual const SafeStringMap<std::string> ¶meters() const = 0;
|
virtual const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
¶meters() const = 0;
|
||||||
|
|
||||||
/// Get parameters of the request.
|
/// Get parameters of the request.
|
||||||
const SafeStringMap<std::string> &getParameters() const
|
const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&getParameters() const
|
||||||
{
|
{
|
||||||
return parameters();
|
return parameters();
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ class DROGON_EXPORT HttpRequest
|
|||||||
virtual const std::string &getParameter(const std::string &key) const = 0;
|
virtual const std::string &getParameter(const std::string &key) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the optional parameter identified by the @p key. if the
|
* @brief Get the optional parameter identified by the @param key. if the
|
||||||
* parameter doesn't exist, or the original parameter can't be converted to
|
* parameter doesn't exist, or the original parameter can't be converted to
|
||||||
* a T type object, an empty optional object is returned.
|
* a T type object, an empty optional object is returned.
|
||||||
*
|
*
|
||||||
@ -450,12 +450,13 @@ class DROGON_EXPORT HttpRequest
|
|||||||
virtual void setCustomContentTypeString(const std::string &type) = 0;
|
virtual void setCustomContentTypeString(const std::string &type) = 0;
|
||||||
|
|
||||||
/// Add a cookie
|
/// Add a cookie
|
||||||
virtual void addCookie(std::string key, std::string value) = 0;
|
virtual void addCookie(const std::string &key,
|
||||||
|
const std::string &value) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the request object to the pass-through mode or not. It's not
|
* @brief Set the request object to the pass-through mode or not. It's not
|
||||||
* by default when a new request object is created.
|
* by default when a new request object is created.
|
||||||
* In pass-through mode, no additional headers (including user-agent,
|
* In pass-through mode, no addtional headers (including user-agent,
|
||||||
* connection, etc.) are added to the request. This mode is useful for some
|
* connection, etc.) are added to the request. This mode is useful for some
|
||||||
* applications such as a proxy.
|
* applications such as a proxy.
|
||||||
*
|
*
|
||||||
@ -505,11 +506,6 @@ class DROGON_EXPORT HttpRequest
|
|||||||
virtual void setContentTypeString(const char *typeString,
|
virtual void setContentTypeString(const char *typeString,
|
||||||
size_t typeStringLength) = 0;
|
size_t typeStringLength) = 0;
|
||||||
|
|
||||||
virtual bool connected() const noexcept = 0;
|
|
||||||
|
|
||||||
virtual const std::weak_ptr<trantor::TcpConnection> &getConnectionPtr()
|
|
||||||
const noexcept = 0;
|
|
||||||
|
|
||||||
virtual ~HttpRequest()
|
virtual ~HttpRequest()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,8 @@
|
|||||||
|
|
||||||
#include <drogon/exports.h>
|
#include <drogon/exports.h>
|
||||||
#include <trantor/net/Certificate.h>
|
#include <trantor/net/Certificate.h>
|
||||||
#include <trantor/net/callbacks.h>
|
|
||||||
#include <trantor/net/AsyncStream.h>
|
|
||||||
#include <drogon/DrClassMap.h>
|
#include <drogon/DrClassMap.h>
|
||||||
#include <drogon/Cookie.h>
|
#include <drogon/Cookie.h>
|
||||||
#include <drogon/HttpRequest.h>
|
|
||||||
#include <drogon/HttpTypes.h>
|
#include <drogon/HttpTypes.h>
|
||||||
#include <drogon/HttpViewData.h>
|
#include <drogon/HttpViewData.h>
|
||||||
#include <drogon/utils/Utilities.h>
|
#include <drogon/utils/Utilities.h>
|
||||||
@ -71,48 +68,6 @@ inline HttpResponsePtr toResponse<Json::Value &>(Json::Value &pJson)
|
|||||||
return toResponse((const Json::Value &)pJson);
|
return toResponse((const Json::Value &)pJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DROGON_EXPORT ResponseStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit ResponseStream(trantor::AsyncStreamPtr asyncStream)
|
|
||||||
: asyncStream_(std::move(asyncStream))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~ResponseStream()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool send(const std::string &data)
|
|
||||||
{
|
|
||||||
if (!asyncStream_)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << std::hex << data.length() << "\r\n";
|
|
||||||
oss << data << "\r\n";
|
|
||||||
return asyncStream_->send(oss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
if (asyncStream_)
|
|
||||||
{
|
|
||||||
static std::string closeStream{"0\r\n\r\n"};
|
|
||||||
asyncStream_->send(closeStream);
|
|
||||||
asyncStream_->close();
|
|
||||||
asyncStream_.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
trantor::AsyncStreamPtr asyncStream_;
|
|
||||||
};
|
|
||||||
|
|
||||||
using ResponseStreamPtr = std::unique_ptr<ResponseStream>;
|
|
||||||
|
|
||||||
class DROGON_EXPORT HttpResponse
|
class DROGON_EXPORT HttpResponse
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -216,7 +171,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
setContentTypeCodeAndCustomString(type, typeString, N - 1);
|
setContentTypeCodeAndCustomString(type, typeString, N - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the response content type and the character set.
|
/// Set the reponse content type and the character set.
|
||||||
/// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
|
/// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
|
||||||
/// std::string &charSet = "utf-8") = 0;
|
/// std::string &charSet = "utf-8") = 0;
|
||||||
|
|
||||||
@ -231,7 +186,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
/// Get the header string identified by the key parameter.
|
/// Get the header string identified by the key parameter.
|
||||||
/**
|
/**
|
||||||
* @note
|
* @note
|
||||||
* If there is no the header, a empty string is returned.
|
* If there is no the header, a empty string is retured.
|
||||||
* The key is case insensitive
|
* The key is case insensitive
|
||||||
*/
|
*/
|
||||||
virtual const std::string &getHeader(std::string key) const = 0;
|
virtual const std::string &getHeader(std::string key) const = 0;
|
||||||
@ -244,10 +199,14 @@ class DROGON_EXPORT HttpResponse
|
|||||||
virtual void removeHeader(std::string key) = 0;
|
virtual void removeHeader(std::string key) = 0;
|
||||||
|
|
||||||
/// Get all headers of the response
|
/// Get all headers of the response
|
||||||
virtual const SafeStringMap<std::string> &headers() const = 0;
|
virtual const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&headers() const = 0;
|
||||||
|
|
||||||
/// Get all headers of the response
|
/// Get all headers of the response
|
||||||
const SafeStringMap<std::string> &getHeaders() const
|
const std::
|
||||||
|
unordered_map<std::string, std::string, utils::internal::SafeStringHash>
|
||||||
|
&getHeaders() const
|
||||||
{
|
{
|
||||||
return headers();
|
return headers();
|
||||||
}
|
}
|
||||||
@ -271,14 +230,18 @@ class DROGON_EXPORT HttpResponse
|
|||||||
virtual void addCookie(Cookie &&cookie) = 0;
|
virtual void addCookie(Cookie &&cookie) = 0;
|
||||||
|
|
||||||
/// Get the cookie identified by the key parameter.
|
/// Get the cookie identified by the key parameter.
|
||||||
/// If there is no the cookie, the empty cookie is returned.
|
/// If there is no the cookie, the empty cookie is retured.
|
||||||
virtual const Cookie &getCookie(const std::string &key) const = 0;
|
virtual const Cookie &getCookie(const std::string &key) const = 0;
|
||||||
|
|
||||||
/// Get all cookies.
|
/// Get all cookies.
|
||||||
virtual const SafeStringMap<Cookie> &cookies() const = 0;
|
virtual const std::
|
||||||
|
unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
|
||||||
|
&cookies() const = 0;
|
||||||
|
|
||||||
/// Get all cookies.
|
/// Get all cookies.
|
||||||
const SafeStringMap<Cookie> &getCookies() const
|
const std::
|
||||||
|
unordered_map<std::string, Cookie, utils::internal::SafeStringHash>
|
||||||
|
&getCookies() const
|
||||||
{
|
{
|
||||||
return cookies();
|
return cookies();
|
||||||
}
|
}
|
||||||
@ -327,7 +290,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
/// Return the enum type version of the response.
|
/// Return the enum type version of the response.
|
||||||
/**
|
/**
|
||||||
* kHttp10 means Http version is 1.0
|
* kHttp10 means Http version is 1.0
|
||||||
* kHttp11 means Http version is 1.1
|
* kHttp11 means Http verison is 1.1
|
||||||
*/
|
*/
|
||||||
virtual Version version() const = 0;
|
virtual Version version() const = 0;
|
||||||
|
|
||||||
@ -337,7 +300,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
return version();
|
return version();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the response object to its initial state
|
/// Reset the reponse object to its initial state
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
/// Set the expiration time of the response cache in memory.
|
/// Set the expiration time of the response cache in memory.
|
||||||
@ -355,7 +318,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
|
|
||||||
/// Get the json object from the server response.
|
/// Get the json object from the server response.
|
||||||
/// If the response is not in json format, then a empty shared_ptr is
|
/// If the response is not in json format, then a empty shared_ptr is
|
||||||
/// returned.
|
/// retured.
|
||||||
virtual const std::shared_ptr<Json::Value> &jsonObject() const = 0;
|
virtual const std::shared_ptr<Json::Value> &jsonObject() const = 0;
|
||||||
|
|
||||||
const std::shared_ptr<Json::Value> &getJsonObject() const
|
const std::shared_ptr<Json::Value> &getJsonObject() const
|
||||||
@ -374,9 +337,9 @@ class DROGON_EXPORT HttpResponse
|
|||||||
virtual const std::string &getJsonError() const = 0;
|
virtual const std::string &getJsonError() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the response object to the pass-through mode or not. It's not
|
* @brief Set the reponse object to the pass-through mode or not. It's not
|
||||||
* by default when a new response object is created.
|
* by default when a new response object is created.
|
||||||
* In pass-through mode, no additional headers (including server, date,
|
* In pass-through mode, no addtional headers (including server, date,
|
||||||
* content-type and content-length, etc.) are added to the response. This
|
* content-type and content-length, etc.) are added to the response. This
|
||||||
* mode is useful for some applications such as a proxy.
|
* mode is useful for some applications such as a proxy.
|
||||||
*
|
*
|
||||||
@ -405,8 +368,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
static HttpResponsePtr newHttpResponse(HttpStatusCode code,
|
static HttpResponsePtr newHttpResponse(HttpStatusCode code,
|
||||||
ContentType type);
|
ContentType type);
|
||||||
/// Create a response which returns a 404 page.
|
/// Create a response which returns a 404 page.
|
||||||
static HttpResponsePtr newNotFoundResponse(
|
static HttpResponsePtr newNotFoundResponse();
|
||||||
const HttpRequestPtr &req = HttpRequestPtr());
|
|
||||||
/// Create a response which returns a json object. Its content-type is set
|
/// Create a response which returns a json object. Its content-type is set
|
||||||
/// to application/json.
|
/// to application/json.
|
||||||
static HttpResponsePtr newHttpJsonResponse(const Json::Value &data);
|
static HttpResponsePtr newHttpJsonResponse(const Json::Value &data);
|
||||||
@ -422,8 +384,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
*/
|
*/
|
||||||
static HttpResponsePtr newHttpViewResponse(
|
static HttpResponsePtr newHttpViewResponse(
|
||||||
const std::string &viewName,
|
const std::string &viewName,
|
||||||
const HttpViewData &data = HttpViewData(),
|
const HttpViewData &data = HttpViewData());
|
||||||
const HttpRequestPtr &req = HttpRequestPtr());
|
|
||||||
|
|
||||||
/// Create a response that returns a redirection page, redirecting to
|
/// Create a response that returns a redirection page, redirecting to
|
||||||
/// another page located in the location parameter.
|
/// another page located in the location parameter.
|
||||||
@ -450,8 +411,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
const std::string &fullPath,
|
const std::string &fullPath,
|
||||||
const std::string &attachmentFileName = "",
|
const std::string &attachmentFileName = "",
|
||||||
ContentType type = CT_NONE,
|
ContentType type = CT_NONE,
|
||||||
const std::string &typeString = "",
|
const std::string &typeString = "");
|
||||||
const HttpRequestPtr &req = HttpRequestPtr());
|
|
||||||
|
|
||||||
/// Create a response that returns part of a file to the client.
|
/// Create a response that returns part of a file to the client.
|
||||||
/**
|
/**
|
||||||
@ -477,8 +437,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
bool setContentRange = true,
|
bool setContentRange = true,
|
||||||
const std::string &attachmentFileName = "",
|
const std::string &attachmentFileName = "",
|
||||||
ContentType type = CT_NONE,
|
ContentType type = CT_NONE,
|
||||||
const std::string &typeString = "",
|
const std::string &typeString = "");
|
||||||
const HttpRequestPtr &req = HttpRequestPtr());
|
|
||||||
|
|
||||||
/// Create a response that returns a file to the client from buffer in
|
/// Create a response that returns a file to the client from buffer in
|
||||||
/// memory/stack
|
/// memory/stack
|
||||||
@ -504,43 +463,23 @@ class DROGON_EXPORT HttpResponse
|
|||||||
/**
|
/**
|
||||||
* @note if the Connection is keep-alive and the Content-Length header is
|
* @note if the Connection is keep-alive and the Content-Length header is
|
||||||
* not set, the stream data is sent with Transfer-Encoding: chunked.
|
* not set, the stream data is sent with Transfer-Encoding: chunked.
|
||||||
* @param callback function to retrieve the stream data (stream ends when a
|
* @param function to retrieve the stream data (stream ends when a zero size
|
||||||
* zero size is returned) the callback will be called with
|
* is returned) the callback will be called with nullptr when the send is
|
||||||
* nullptr when the send is finished/interrupted so that it
|
* finished/interruped so that it cleans up its internals.
|
||||||
* cleans up its internals.
|
|
||||||
* @param attachmentFileName if the parameter is not empty, the browser
|
* @param attachmentFileName if the parameter is not empty, the browser
|
||||||
* does not open the file, but saves it as an
|
* does not open the file, but saves it as an
|
||||||
* attachment.
|
* attachment.
|
||||||
* @param type the content type code. If the parameter is CT_NONE, the
|
* @param type the content type code. If the parameter is CT_NONE, the
|
||||||
* content type is set by drogon based on the file extension and
|
* content type is set by drogon based on the file extension and
|
||||||
* typeString. Set it to CT_CUSTOM when no drogon internal
|
* typeString. Set it to CT_CUSTOM when no drogon internal content type
|
||||||
* content type matches.
|
* matches.
|
||||||
* @param typeString the MIME string of the content type.
|
* @param typeString the MIME string of the content type.
|
||||||
*/
|
*/
|
||||||
static HttpResponsePtr newStreamResponse(
|
static HttpResponsePtr newStreamResponse(
|
||||||
const std::function<std::size_t(char *, std::size_t)> &callback,
|
const std::function<std::size_t(char *, std::size_t)> &callback,
|
||||||
const std::string &attachmentFileName = "",
|
const std::string &attachmentFileName = "",
|
||||||
ContentType type = CT_NONE,
|
ContentType type = CT_NONE,
|
||||||
const std::string &typeString = "",
|
const std::string &typeString = "");
|
||||||
const HttpRequestPtr &req = HttpRequestPtr());
|
|
||||||
|
|
||||||
/// Create a response that allows sending asynchronous data from a callback
|
|
||||||
/// function
|
|
||||||
/**
|
|
||||||
* @note Async streams are always sent with Transfer-Encoding: chunked.
|
|
||||||
* @param callback function that receives the asynchronous HTTP stream. You
|
|
||||||
* may call the stream->send() method to transmit new data.
|
|
||||||
* The send method will return true as long as the stream is
|
|
||||||
* still open. Once you have finished sending data, or the
|
|
||||||
* stream->send() function returned false, you should call
|
|
||||||
* stream->close() to gracefully close the chunked transfer.
|
|
||||||
* @param disableKickoffTimeout set this to true to disable trantors default
|
|
||||||
* kickoff timeout. This is useful if you need
|
|
||||||
* long running asynchronous streams.
|
|
||||||
*/
|
|
||||||
static HttpResponsePtr newAsyncStreamResponse(
|
|
||||||
const std::function<void(ResponseStreamPtr)> &callback,
|
|
||||||
bool disableKickoffTimeout = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a custom HTTP response object. For using this template,
|
* @brief Create a custom HTTP response object. For using this template,
|
||||||
@ -561,7 +500,7 @@ class DROGON_EXPORT HttpResponse
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the range of the file response as a pair ot size_t
|
* @brief Returns the range of the file response as a pair ot size_t
|
||||||
* (offset, length). Length of 0 means the entire file is sent. Behavior of
|
* (offset, length). Length of 0 means the entire file is sent. Behaivor of
|
||||||
* this function is undefined if the response if not a file response
|
* this function is undefined if the response if not a file response
|
||||||
*/
|
*/
|
||||||
using SendfileRange = std::pair<size_t, size_t>; // { offset, length }
|
using SendfileRange = std::pair<size_t, size_t>; // { offset, length }
|
||||||
@ -572,15 +511,8 @@ class DROGON_EXPORT HttpResponse
|
|||||||
* newStreamResponse) returns the callback function. Otherwise a
|
* newStreamResponse) returns the callback function. Otherwise a
|
||||||
* null function.
|
* null function.
|
||||||
*/
|
*/
|
||||||
virtual const std::function<std::size_t(char *, std::size_t)> &
|
virtual const std::function<std::size_t(char *, std::size_t)>
|
||||||
streamCallback() const = 0;
|
&streamCallback() const = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief If the response is a async stream response (i.e. created by
|
|
||||||
* asyncStreamCallback) returns the stream ptr.
|
|
||||||
*/
|
|
||||||
virtual const std::function<void(ResponseStreamPtr)> &asyncStreamCallback()
|
|
||||||
const = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the content type associated with the response
|
* @brief Returns the content type associated with the response
|
||||||
|
@ -76,7 +76,7 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
|
|||||||
|
|
||||||
static void registerSelf__(
|
static void registerSelf__(
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
const std::vector<internal::HttpConstraint> &constraints)
|
const std::vector<internal::HttpConstraint> &filtersAndMethods)
|
||||||
{
|
{
|
||||||
LOG_TRACE << "register simple controller("
|
LOG_TRACE << "register simple controller("
|
||||||
<< HttpSimpleController<T, AutoCreation>::classTypeName()
|
<< HttpSimpleController<T, AutoCreation>::classTypeName()
|
||||||
@ -84,7 +84,7 @@ class HttpSimpleController : public DrObject<T>, public HttpSimpleControllerBase
|
|||||||
app().registerHttpSimpleController(
|
app().registerHttpSimpleController(
|
||||||
path,
|
path,
|
||||||
HttpSimpleController<T, AutoCreation>::classTypeName(),
|
HttpSimpleController<T, AutoCreation>::classTypeName(),
|
||||||
constraints);
|
filtersAndMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -106,71 +106,26 @@ enum ContentType
|
|||||||
CT_APPLICATION_X_JAVASCRIPT [[deprecated("use CT_TEXT_JAVASCRIPT")]],
|
CT_APPLICATION_X_JAVASCRIPT [[deprecated("use CT_TEXT_JAVASCRIPT")]],
|
||||||
CT_TEXT_JAVASCRIPT,
|
CT_TEXT_JAVASCRIPT,
|
||||||
CT_TEXT_CSS,
|
CT_TEXT_CSS,
|
||||||
CT_TEXT_CSV,
|
CT_TEXT_XML,
|
||||||
CT_TEXT_XML, // suggests human readable xml
|
CT_APPLICATION_XML,
|
||||||
CT_APPLICATION_XML, // suggest machine-to-machine xml
|
|
||||||
CT_TEXT_XSL,
|
CT_TEXT_XSL,
|
||||||
CT_APPLICATION_WASM,
|
CT_APPLICATION_WASM,
|
||||||
CT_APPLICATION_OCTET_STREAM,
|
CT_APPLICATION_OCTET_STREAM,
|
||||||
CT_APPLICATION_FONT_WOFF,
|
|
||||||
CT_APPLICATION_FONT_WOFF2,
|
|
||||||
CT_APPLICATION_GZIP,
|
|
||||||
CT_APPLICATION_JAVA_ARCHIVE,
|
|
||||||
CT_APPLICATION_PDF,
|
|
||||||
CT_APPLICATION_MSWORD,
|
|
||||||
CT_APPLICATION_MSWORDX,
|
|
||||||
CT_APPLICATION_VND_MS_FONTOBJ,
|
|
||||||
CT_APPLICATION_VND_RAR,
|
|
||||||
CT_APPLICATION_XHTML,
|
|
||||||
CT_APPLICATION_X_7Z,
|
|
||||||
CT_APPLICATION_X_BZIP,
|
|
||||||
CT_APPLICATION_X_BZIP2,
|
|
||||||
CT_APPLICATION_X_HTTPD_PHP,
|
|
||||||
CT_APPLICATION_X_FONT_TRUETYPE,
|
CT_APPLICATION_X_FONT_TRUETYPE,
|
||||||
CT_APPLICATION_X_FONT_OPENTYPE,
|
CT_APPLICATION_X_FONT_OPENTYPE,
|
||||||
CT_APPLICATION_X_TAR,
|
CT_APPLICATION_FONT_WOFF,
|
||||||
CT_APPLICATION_X_TGZ,
|
CT_APPLICATION_FONT_WOFF2,
|
||||||
CT_APPLICATION_X_XZ,
|
CT_APPLICATION_VND_MS_FONTOBJ,
|
||||||
CT_APPLICATION_ZIP,
|
CT_APPLICATION_PDF,
|
||||||
CT_AUDIO_AAC,
|
|
||||||
CT_AUDIO_AC3,
|
|
||||||
CT_AUDIO_AIFF,
|
|
||||||
CT_AUDIO_FLAC,
|
|
||||||
CT_AUDIO_MATROSKA,
|
|
||||||
CT_AUDIO_MPEG,
|
|
||||||
CT_AUDIO_MPEG4,
|
|
||||||
CT_AUDIO_OGG,
|
|
||||||
CT_AUDIO_WAVE,
|
|
||||||
CT_AUDIO_WEBM,
|
|
||||||
CT_AUDIO_X_APE,
|
|
||||||
CT_AUDIO_X_MS_WMA,
|
|
||||||
CT_AUDIO_X_TTA,
|
|
||||||
CT_AUDIO_X_WAVPACK,
|
|
||||||
CT_IMAGE_APNG,
|
|
||||||
CT_IMAGE_AVIF,
|
|
||||||
CT_IMAGE_BMP,
|
|
||||||
CT_IMAGE_GIF,
|
|
||||||
CT_IMAGE_ICNS,
|
|
||||||
CT_IMAGE_JPG,
|
|
||||||
CT_IMAGE_JP2,
|
|
||||||
CT_IMAGE_PNG,
|
|
||||||
CT_IMAGE_SVG_XML,
|
CT_IMAGE_SVG_XML,
|
||||||
CT_IMAGE_TIFF,
|
CT_IMAGE_PNG,
|
||||||
CT_IMAGE_WEBP,
|
CT_IMAGE_WEBP,
|
||||||
CT_IMAGE_X_MNG,
|
CT_IMAGE_AVIF,
|
||||||
CT_IMAGE_X_TGA,
|
CT_IMAGE_JPG,
|
||||||
|
CT_IMAGE_GIF,
|
||||||
CT_IMAGE_XICON,
|
CT_IMAGE_XICON,
|
||||||
CT_VIDEO_APG,
|
CT_IMAGE_ICNS,
|
||||||
CT_VIDEO_AV1,
|
CT_IMAGE_BMP,
|
||||||
CT_VIDEO_QUICKTIME,
|
|
||||||
CT_VIDEO_MATROSKA,
|
|
||||||
CT_VIDEO_MP4,
|
|
||||||
CT_VIDEO_MPEG,
|
|
||||||
CT_VIDEO_MPEG2TS,
|
|
||||||
CT_VIDEO_OGG,
|
|
||||||
CT_VIDEO_WEBM,
|
|
||||||
CT_VIDEO_X_M4V,
|
|
||||||
CT_VIDEO_X_MSVIDEO,
|
|
||||||
CT_MULTIPART_FORM_DATA,
|
CT_MULTIPART_FORM_DATA,
|
||||||
CT_CUSTOM
|
CT_CUSTOM
|
||||||
};
|
};
|
||||||
@ -261,34 +216,4 @@ inline trantor::LogStream &operator<<(trantor::LogStream &out,
|
|||||||
{
|
{
|
||||||
return out << to_string_view(result);
|
return out << to_string_view(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string_view to_string_view(drogon::HttpMethod method)
|
|
||||||
{
|
|
||||||
switch (method)
|
|
||||||
{
|
|
||||||
case drogon::HttpMethod::Get:
|
|
||||||
return "GET";
|
|
||||||
case drogon::HttpMethod::Post:
|
|
||||||
return "POST";
|
|
||||||
case drogon::HttpMethod::Head:
|
|
||||||
return "HEAD";
|
|
||||||
case drogon::HttpMethod::Put:
|
|
||||||
return "PUT";
|
|
||||||
case drogon::HttpMethod::Delete:
|
|
||||||
return "DELETE";
|
|
||||||
case drogon::HttpMethod::Options:
|
|
||||||
return "OPTIONS";
|
|
||||||
case drogon::HttpMethod::Patch:
|
|
||||||
return "PATCH";
|
|
||||||
default:
|
|
||||||
return "INVALID";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string to_string(drogon::HttpMethod method)
|
|
||||||
{
|
|
||||||
auto sv = to_string_view(method);
|
|
||||||
return std::string(sv.data(), sv.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -37,7 +37,7 @@ class DROGON_EXPORT HttpViewData
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
const T &get(const std::string &key) const
|
const T &get(const std::string &key) const
|
||||||
{
|
{
|
||||||
static const T nullVal = T();
|
const static T nullVal = T();
|
||||||
auto it = viewData_.find(key);
|
auto it = viewData_.find(key);
|
||||||
if (it != viewData_.end())
|
if (it != viewData_.end())
|
||||||
{
|
{
|
||||||
@ -74,7 +74,7 @@ class DROGON_EXPORT HttpViewData
|
|||||||
viewData_[key] = ss.str();
|
viewData_[key] = ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a formatted string identified by the key parameter.
|
/// Insert a formated string identified by the key parameter.
|
||||||
void insertFormattedString(const std::string &key, const char *format, ...)
|
void insertFormattedString(const std::string &key, const char *format, ...)
|
||||||
{
|
{
|
||||||
std::string strBuffer;
|
std::string strBuffer;
|
||||||
|
@ -90,7 +90,7 @@ class IOThreadStorage : public trantor::NonCopyable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the thread storage associate with the current thread
|
* @brief Get the thread storage asociate with the current thread
|
||||||
*
|
*
|
||||||
* This function may only be called in a request handler
|
* This function may only be called in a request handler
|
||||||
*/
|
*/
|
||||||
|
@ -29,7 +29,7 @@ class DROGON_EXPORT IntranetIpFilter : public HttpFilter<IntranetIpFilter>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void doFilter(const HttpRequestPtr &req,
|
virtual void doFilter(const HttpRequestPtr &req,
|
||||||
FilterCallback &&fcb,
|
FilterCallback &&fcb,
|
||||||
FilterChainCallback &&fccb) override;
|
FilterChainCallback &&fccb) override;
|
||||||
};
|
};
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "drogon/utils/Utilities.h"
|
|
||||||
#include <drogon/exports.h>
|
#include <drogon/exports.h>
|
||||||
#include <drogon/HttpRequest.h>
|
#include <drogon/HttpRequest.h>
|
||||||
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -63,7 +63,7 @@ class DROGON_EXPORT HttpFile
|
|||||||
*/
|
*/
|
||||||
int save() const noexcept;
|
int save() const noexcept;
|
||||||
|
|
||||||
/// Save the file to @p path
|
/// Save the file to @param path
|
||||||
/**
|
/**
|
||||||
* @param path if the parameter is prefixed with "/", "./" or "../", or is
|
* @param path if the parameter is prefixed with "/", "./" or "../", or is
|
||||||
* "." or "..", the full path is path+"/"+this->getFileName(),
|
* "." or "..", the full path is path+"/"+this->getFileName(),
|
||||||
@ -123,8 +123,6 @@ class DROGON_EXPORT MultiPartParser
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MultiPartParser(){};
|
MultiPartParser(){};
|
||||||
MultiPartParser(const MultiPartParser &other) = default; // Copyable
|
|
||||||
MultiPartParser(MultiPartParser &&other) = default; // Movable
|
|
||||||
~MultiPartParser(){};
|
~MultiPartParser(){};
|
||||||
/// Get files, This method should be called after calling the parse()
|
/// Get files, This method should be called after calling the parse()
|
||||||
/// method.
|
/// method.
|
||||||
@ -135,54 +133,19 @@ class DROGON_EXPORT MultiPartParser
|
|||||||
|
|
||||||
/// Get parameters, This method should be called after calling the parse ()
|
/// Get parameters, This method should be called after calling the parse ()
|
||||||
/// method.
|
/// method.
|
||||||
const SafeStringMap<std::string> &getParameters() const;
|
const std::map<std::string, std::string> &getParameters() const;
|
||||||
|
|
||||||
/// Get the value of an optional parameter
|
|
||||||
/// This method should be called after calling the parse() method.
|
|
||||||
template <typename T>
|
|
||||||
std::optional<T> getOptionalParameter(const std::string &key)
|
|
||||||
{
|
|
||||||
auto ¶ms = getParameters();
|
|
||||||
auto it = params.find(key);
|
|
||||||
if (it != params.end())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return std::optional<T>(utils::fromString<T>(it->second));
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
LOG_ERROR << e.what();
|
|
||||||
return std::optional<T>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return std::optional<T>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the value of a parameter
|
|
||||||
/// This method should be called after calling the parse() method.
|
|
||||||
/// Note: returns a default T object if the parameter is missing
|
|
||||||
template <typename T>
|
|
||||||
T getParameter(const std::string &key)
|
|
||||||
{
|
|
||||||
return getOptionalParameter<T>(key).value_or(T{});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse the http request stream to get files and parameters.
|
/// Parse the http request stream to get files and parameters.
|
||||||
int parse(const HttpRequestPtr &req);
|
int parse(const HttpRequestPtr &req);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<HttpFile> files_;
|
std::vector<HttpFile> files_;
|
||||||
SafeStringMap<std::string> parameters_;
|
std::map<std::string, std::string> parameters_;
|
||||||
int parse(const HttpRequestPtr &req,
|
int parse(const HttpRequestPtr &req,
|
||||||
const char *boundaryData,
|
const char *boundaryData,
|
||||||
size_t boundaryLen);
|
size_t boundaryLen);
|
||||||
int parseEntity(const HttpRequestPtr &req,
|
int parseEntity(const char *begin, const char *end);
|
||||||
const char *begin,
|
HttpRequestPtr requestPtr_;
|
||||||
const char *end);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// In order to be compatible with old interfaces
|
/// In order to be compatible with old interfaces
|
||||||
|
@ -57,7 +57,7 @@ class Topic : public trantor::NonCopyable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Subscribe to the topic.
|
* @brief Subcribe to the topic.
|
||||||
*
|
*
|
||||||
* @param handler is invoked when a message arrives.
|
* @param handler is invoked when a message arrives.
|
||||||
* @return SubscriberID
|
* @return SubscriberID
|
||||||
@ -70,7 +70,7 @@ class Topic : public trantor::NonCopyable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Subscribe to the topic.
|
* @brief Subcribe to the topic.
|
||||||
*
|
*
|
||||||
* @param handler is invoked when a message arrives.
|
* @param handler is invoked when a message arrives.
|
||||||
* @return SubscriberID
|
* @return SubscriberID
|
||||||
@ -175,9 +175,6 @@ class PubSubService : public trantor::NonCopyable
|
|||||||
/**
|
/**
|
||||||
* @brief Subscribe to a topic. When a message is published to the topic,
|
* @brief Subscribe to a topic. When a message is published to the topic,
|
||||||
* the handler is invoked by passing the topic and message as parameters.
|
* the handler is invoked by passing the topic and message as parameters.
|
||||||
* @param topicName Topic name.
|
|
||||||
* @param handler The message handler.
|
|
||||||
* @return The subscriber ID.
|
|
||||||
*/
|
*/
|
||||||
SubscriberID subscribe(const std::string &topicName,
|
SubscriberID subscribe(const std::string &topicName,
|
||||||
MessageHandler &&handler)
|
MessageHandler &&handler)
|
||||||
@ -192,7 +189,7 @@ class PubSubService : public trantor::NonCopyable
|
|||||||
/**
|
/**
|
||||||
* @brief Unsubscribe from a topic.
|
* @brief Unsubscribe from a topic.
|
||||||
*
|
*
|
||||||
* @param topicName Topic name.
|
* @param topic
|
||||||
* @param id The subscriber ID returned from the subscribe method.
|
* @param id The subscriber ID returned from the subscribe method.
|
||||||
*/
|
*/
|
||||||
void unsubscribe(const std::string &topicName, SubscriberID id)
|
void unsubscribe(const std::string &topicName, SubscriberID id)
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* @file RequestStream.h
|
|
||||||
* @author Nitromelon
|
|
||||||
*
|
|
||||||
* Copyright 2024, Nitromelon. All rights reserved.
|
|
||||||
* https://github.com/drogonframework/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/exports.h>
|
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
class HttpRequest;
|
|
||||||
using HttpRequestPtr = std::shared_ptr<HttpRequest>;
|
|
||||||
|
|
||||||
class RequestStreamReader;
|
|
||||||
using RequestStreamReaderPtr = std::shared_ptr<RequestStreamReader>;
|
|
||||||
|
|
||||||
struct MultipartHeader
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string filename;
|
|
||||||
std::string contentType;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DROGON_EXPORT RequestStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RequestStream() = default;
|
|
||||||
virtual void setStreamReader(RequestStreamReaderPtr reader) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using RequestStreamPtr = std::shared_ptr<RequestStream>;
|
|
||||||
|
|
||||||
namespace internal
|
|
||||||
{
|
|
||||||
DROGON_EXPORT RequestStreamPtr createRequestStream(const HttpRequestPtr &req);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class StreamErrorCode
|
|
||||||
{
|
|
||||||
kNone = 0,
|
|
||||||
kBadRequest,
|
|
||||||
kConnectionBroken
|
|
||||||
};
|
|
||||||
|
|
||||||
class StreamError final : public std::exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const char *what() const noexcept override
|
|
||||||
{
|
|
||||||
return message_.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamErrorCode code() const
|
|
||||||
{
|
|
||||||
return code_;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamError(StreamErrorCode code, const std::string &message)
|
|
||||||
: message_(message), code_(code)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamError(StreamErrorCode code, std::string &&message)
|
|
||||||
: message_(std::move(message)), code_(code)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamError() = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string message_;
|
|
||||||
StreamErrorCode code_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for stream request reading.
|
|
||||||
* User should create an implementation class, or use built-in handlers
|
|
||||||
*/
|
|
||||||
class DROGON_EXPORT RequestStreamReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RequestStreamReader() = default;
|
|
||||||
virtual void onStreamData(const char *, size_t) = 0;
|
|
||||||
virtual void onStreamFinish(std::exception_ptr) = 0;
|
|
||||||
|
|
||||||
using StreamDataCallback = std::function<void(const char *, size_t)>;
|
|
||||||
using StreamFinishCallback = std::function<void(std::exception_ptr)>;
|
|
||||||
|
|
||||||
// Create a handler with default implementation
|
|
||||||
static RequestStreamReaderPtr newReader(StreamDataCallback dataCb,
|
|
||||||
StreamFinishCallback finishCb);
|
|
||||||
|
|
||||||
// A handler that drops all data
|
|
||||||
static RequestStreamReaderPtr newNullReader();
|
|
||||||
|
|
||||||
using MultipartHeaderCallback = std::function<void(MultipartHeader header)>;
|
|
||||||
|
|
||||||
static RequestStreamReaderPtr newMultipartReader(
|
|
||||||
const HttpRequestPtr &req,
|
|
||||||
MultipartHeaderCallback headerCb,
|
|
||||||
StreamDataCallback dataCb,
|
|
||||||
StreamFinishCallback finishCb);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace drogon
|
|
@ -182,7 +182,7 @@ class Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return true if the data identified by the key exists.
|
* @brief Retrun true if the data identified by the key exists.
|
||||||
*/
|
*/
|
||||||
bool find(const std::string &key)
|
bool find(const std::string &key)
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,8 @@ class UploadFile
|
|||||||
/**
|
/**
|
||||||
* @param filePath The file location on local host, including file name.
|
* @param filePath The file location on local host, including file name.
|
||||||
* @param fileName The file name provided to the server. If it is empty by
|
* @param fileName The file name provided to the server. If it is empty by
|
||||||
* default, the file name in the @p filePath is provided to the server.
|
* default, the file name in the @param filePath
|
||||||
|
* is provided to the server.
|
||||||
* @param itemName The item name on the browser form.
|
* @param itemName The item name on the browser form.
|
||||||
* @param contentType The Mime content type for the part
|
* @param contentType The Mime content type for the part
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +65,7 @@ class DROGON_EXPORT WebSocketClient
|
|||||||
virtual WebSocketConnectionPtr getConnection() = 0;
|
virtual WebSocketConnectionPtr getConnection() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set messages handler. When a message is received from the server,
|
* @brief Set messages handler. When a message is recieved from the server,
|
||||||
* the callback is called.
|
* the callback is called.
|
||||||
*
|
*
|
||||||
* @param callback The function to call when a message is received.
|
* @param callback The function to call when a message is received.
|
||||||
@ -76,7 +76,8 @@ class DROGON_EXPORT WebSocketClient
|
|||||||
const WebSocketMessageType &)> &callback) = 0;
|
const WebSocketMessageType &)> &callback) = 0;
|
||||||
|
|
||||||
/// Set the connection closing handler. When the connection is established
|
/// Set the connection closing handler. When the connection is established
|
||||||
/// or closed, the @p callback is called with a bool parameter.
|
/// or closed, the @param callback is called with a bool parameter.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the connection closing handler. When the websocket connection
|
* @brief Set the connection closing handler. When the websocket connection
|
||||||
* is closed, the callback is called
|
* is closed, the callback is called
|
||||||
@ -90,34 +91,9 @@ class DROGON_EXPORT WebSocketClient
|
|||||||
virtual void connectToServer(const HttpRequestPtr &request,
|
virtual void connectToServer(const HttpRequestPtr &request,
|
||||||
const WebSocketRequestCallback &callback) = 0;
|
const WebSocketRequestCallback &callback) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the client certificate used by the HTTP connection
|
|
||||||
*
|
|
||||||
* @param cert Path to the certificate
|
|
||||||
* @param key Path to the certificate's private key
|
|
||||||
* @note this method has no effect if the HTTP client is communicating via
|
|
||||||
* unencrypted HTTP
|
|
||||||
*/
|
|
||||||
virtual void setCertPath(const std::string &cert,
|
|
||||||
const std::string &key) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Supplies command style options for `SSL_CONF_cmd`
|
|
||||||
*
|
|
||||||
* @param sslConfCmds options for SSL_CONF_cmd
|
|
||||||
* @note this method has no effect if the HTTP client is communicating via
|
|
||||||
* unencrypted HTTP
|
|
||||||
* @code
|
|
||||||
addSSLConfigs({{"-dhparam", "/path/to/dhparam"}, {"-strict", ""}});
|
|
||||||
* @endcode
|
|
||||||
*/
|
|
||||||
virtual void addSSLConfigs(
|
|
||||||
const std::vector<std::pair<std::string, std::string>>
|
|
||||||
&sslConfCmds) = 0;
|
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
/**
|
/**
|
||||||
* @brief Set messages handler. When a message is received from the server,
|
* @brief Set messages handler. When a message is recieved from the server,
|
||||||
* the callback is called.
|
* the callback is called.
|
||||||
*
|
*
|
||||||
* @param callback The function to call when a message is received.
|
* @param callback The function to call when a message is received.
|
||||||
|
@ -14,11 +14,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json/value.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <drogon/HttpTypes.h>
|
#include <drogon/HttpTypes.h>
|
||||||
#include <string_view>
|
|
||||||
#include <trantor/net/InetAddress.h>
|
#include <trantor/net/InetAddress.h>
|
||||||
#include <trantor/utils/NonCopyable.h>
|
#include <trantor/utils/NonCopyable.h>
|
||||||
|
|
||||||
@ -114,17 +112,7 @@ class WebSocketConnection
|
|||||||
* @param type The message type.
|
* @param type The message type.
|
||||||
*/
|
*/
|
||||||
virtual void send(
|
virtual void send(
|
||||||
std::string_view msg,
|
const std::string &msg,
|
||||||
const WebSocketMessageType type = WebSocketMessageType::Text) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Send a message to the peer
|
|
||||||
*
|
|
||||||
* @param json The JSON message to be sent.
|
|
||||||
* @param type The message type.
|
|
||||||
*/
|
|
||||||
virtual void sendJson(
|
|
||||||
const Json::Value &json,
|
|
||||||
const WebSocketMessageType type = WebSocketMessageType::Text) = 0;
|
const WebSocketMessageType type = WebSocketMessageType::Text) = 0;
|
||||||
|
|
||||||
/// Return the local IP address and port number of the connection
|
/// Return the local IP address and port number of the connection
|
||||||
|
@ -28,8 +28,6 @@
|
|||||||
static void initPathRouting() \
|
static void initPathRouting() \
|
||||||
{
|
{
|
||||||
#define WS_PATH_ADD(path, ...) registerSelf__(path, {__VA_ARGS__})
|
#define WS_PATH_ADD(path, ...) registerSelf__(path, {__VA_ARGS__})
|
||||||
#define WS_ADD_PATH_VIA_REGEX(regExp, ...) \
|
|
||||||
registerSelfRegex__(regExp, {__VA_ARGS__})
|
|
||||||
#define WS_PATH_LIST_END }
|
#define WS_PATH_LIST_END }
|
||||||
|
|
||||||
namespace drogon
|
namespace drogon
|
||||||
@ -85,7 +83,7 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
|||||||
|
|
||||||
static void registerSelf__(
|
static void registerSelf__(
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
const std::vector<internal::HttpConstraint> &constraints)
|
const std::vector<internal::HttpConstraint> &filtersAndMethods)
|
||||||
{
|
{
|
||||||
LOG_TRACE << "register websocket controller("
|
LOG_TRACE << "register websocket controller("
|
||||||
<< WebSocketController<T, AutoCreation>::classTypeName()
|
<< WebSocketController<T, AutoCreation>::classTypeName()
|
||||||
@ -93,20 +91,7 @@ class WebSocketController : public DrObject<T>, public WebSocketControllerBase
|
|||||||
app().registerWebSocketController(
|
app().registerWebSocketController(
|
||||||
path,
|
path,
|
||||||
WebSocketController<T, AutoCreation>::classTypeName(),
|
WebSocketController<T, AutoCreation>::classTypeName(),
|
||||||
constraints);
|
filtersAndMethods);
|
||||||
}
|
|
||||||
|
|
||||||
static void registerSelfRegex__(
|
|
||||||
const std::string ®Exp,
|
|
||||||
const std::vector<internal::HttpConstraint> &constraints)
|
|
||||||
{
|
|
||||||
LOG_TRACE << "register websocket controller("
|
|
||||||
<< WebSocketController<T, AutoCreation>::classTypeName()
|
|
||||||
<< ") on regExp:" << regExp;
|
|
||||||
app().registerWebSocketControllerRegex(
|
|
||||||
regExp,
|
|
||||||
WebSocketController<T, AutoCreation>::classTypeName(),
|
|
||||||
constraints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -31,9 +31,4 @@ using AdviceDestroySessionCallback = std::function<void(const std::string &)>;
|
|||||||
using FilterCallback = std::function<void(const HttpResponsePtr &)>;
|
using FilterCallback = std::function<void(const HttpResponsePtr &)>;
|
||||||
using FilterChainCallback = std::function<void()>;
|
using FilterChainCallback = std::function<void()>;
|
||||||
using HttpReqCallback = std::function<void(ReqResult, const HttpResponsePtr &)>;
|
using HttpReqCallback = std::function<void(ReqResult, const HttpResponsePtr &)>;
|
||||||
|
|
||||||
using MiddlewareCallback = std::function<void(const HttpResponsePtr &)>;
|
|
||||||
using MiddlewareNextCallback =
|
|
||||||
std::function<void(std::function<void(const HttpResponsePtr &)> &&)>;
|
|
||||||
|
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -69,10 +69,11 @@ struct is_printable : std::false_type
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename _Tp>
|
template <typename _Tp>
|
||||||
struct is_printable<
|
struct is_printable<_Tp,
|
||||||
_Tp,
|
typename std::enable_if<
|
||||||
std::enable_if_t<std::is_same_v<decltype(std::cout << std::declval<_Tp>()),
|
std::is_same<decltype(std::cout << std::declval<_Tp>()),
|
||||||
std::ostream &>>> : std::true_type
|
std::ostream &>::value>::type>
|
||||||
|
: std::true_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,29 +108,82 @@ inline std::string escapeString(const std::string_view sv)
|
|||||||
DROGON_EXPORT std::string prettifyString(const std::string_view sv,
|
DROGON_EXPORT std::string prettifyString(const std::string_view sv,
|
||||||
size_t maxLength = 120);
|
size_t maxLength = 120);
|
||||||
|
|
||||||
|
#ifdef __cpp_fold_expressions
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void outputReason(Args &&...args)
|
inline void outputReason(Args &&...args)
|
||||||
{
|
{
|
||||||
(std::cout << ... << std::forward<Args>(args));
|
(std::cout << ... << std::forward<Args>(args));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
template <typename T>
|
template <typename Head>
|
||||||
inline std::string attemptPrint(T &&v)
|
inline void outputReason(Head &&head)
|
||||||
{
|
{
|
||||||
using Type = std::remove_cv_t<std::remove_reference_t<T>>;
|
std::cout << std::forward<Head>(head);
|
||||||
if constexpr (std::is_same_v<Type, std::nullptr_t>)
|
}
|
||||||
return "nullptr";
|
|
||||||
else if constexpr (std::is_same_v<Type, char>)
|
template <typename Head, typename... Tail>
|
||||||
return "'" + std::string(1, v) + "'";
|
inline void outputReason(Head &&head, Tail &&...tail)
|
||||||
else if constexpr (std::is_convertible_v<Type, std::string_view>)
|
{
|
||||||
return prettifyString(v);
|
std::cout << std::forward<Head>(head);
|
||||||
else if constexpr (internal::is_printable<Type>::value)
|
outputReason(std::forward<Tail>(tail)...);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <bool P>
|
||||||
|
struct AttemptPrintViaStream
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
std::string operator()(const T &v)
|
||||||
|
{
|
||||||
|
return "{un-printable}";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct AttemptPrintViaStream<true>
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
std::string operator()(const T &v)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << v;
|
ss << v;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
return "{un-printable}";
|
};
|
||||||
|
|
||||||
|
struct StringPrinter
|
||||||
|
{
|
||||||
|
std::string operator()(const std::string_view &v)
|
||||||
|
{
|
||||||
|
return prettifyString(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline std::string attemptPrint(T &&v)
|
||||||
|
{
|
||||||
|
using DefaultPrinter =
|
||||||
|
internal::AttemptPrintViaStream<is_printable<T>::value>;
|
||||||
|
|
||||||
|
// Poor man's if constexpr because SFINAE don't disambiguate between
|
||||||
|
// possible resolutions
|
||||||
|
return typename std::conditional<
|
||||||
|
std::is_convertible<T, std::string_view>::value,
|
||||||
|
internal::StringPrinter,
|
||||||
|
DefaultPrinter>::type()(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specializations to reduce template construction
|
||||||
|
template <>
|
||||||
|
inline std::string attemptPrint(const std::nullptr_t &v)
|
||||||
|
{
|
||||||
|
return "nullptr";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline std::string attemptPrint(const char &v)
|
||||||
|
{
|
||||||
|
return "'" + std::string(1, v) + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string stringifyFuncCall(const std::string &funcName)
|
inline std::string stringifyFuncCall(const std::string &funcName)
|
||||||
@ -227,7 +281,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator&&(const RhsType &rhs)
|
ComparsionResult operator&&(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same_v<RhsType, void>,
|
static_assert(!std::is_same<RhsType, void>::value,
|
||||||
" && is not supported in expression decomposition");
|
" && is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -235,7 +289,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator||(const RhsType &rhs)
|
ComparsionResult operator||(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same_v<RhsType, void>,
|
static_assert(!std::is_same<RhsType, void>::value,
|
||||||
" || is not supported in expression decomposition");
|
" || is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -243,7 +297,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator|(const RhsType &rhs)
|
ComparsionResult operator|(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same_v<RhsType, void>,
|
static_assert(!std::is_same<RhsType, void>::value,
|
||||||
" | is not supported in expression decomposition");
|
" | is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -251,7 +305,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator&(const RhsType &rhs)
|
ComparsionResult operator&(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same_v<RhsType, void>,
|
static_assert(!std::is_same<RhsType, void>::value,
|
||||||
" & is not supported in expression decomposition");
|
" & is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ namespace plugin
|
|||||||
"name": "drogon::plugin::AccessLogger",
|
"name": "drogon::plugin::AccessLogger",
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"config": {
|
"config": {
|
||||||
"use_spdlog": false,
|
|
||||||
"log_path": "./",
|
"log_path": "./",
|
||||||
"log_format": "",
|
"log_format": "",
|
||||||
"log_file": "access.log",
|
"log_file": "access.log",
|
||||||
@ -36,7 +35,6 @@ namespace plugin
|
|||||||
// "show_microseconds": true,
|
// "show_microseconds": true,
|
||||||
// "custom_time_format": "",
|
// "custom_time_format": "",
|
||||||
// "use_real_ip": false
|
// "use_real_ip": false
|
||||||
// "path_exempt": ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
@ -70,8 +68,6 @@ namespace plugin
|
|||||||
* "$request_date $method $url [$body_bytes_received] ($remote_addr -
|
* "$request_date $method $url [$body_bytes_received] ($remote_addr -
|
||||||
* $local_addr) $status $body_bytes_sent $processing_time" is applied.
|
* $local_addr) $status $body_bytes_sent $processing_time" is applied.
|
||||||
*
|
*
|
||||||
* use_spdlog: log using spdlog, disabled by default.
|
|
||||||
*
|
|
||||||
* log_path: Log file path, empty by default,in which case,logs are output to
|
* log_path: Log file path, empty by default,in which case,logs are output to
|
||||||
* the regular log file (or stdout based on the log configuration).
|
* the regular log file (or stdout based on the log configuration).
|
||||||
*
|
*
|
||||||
@ -89,7 +85,7 @@ namespace plugin
|
|||||||
* show_microseconds: Whether print microsecond in time. True by default.
|
* show_microseconds: Whether print microsecond in time. True by default.
|
||||||
*
|
*
|
||||||
* custom_time_format: Provide a custom format for time. If not provided or
|
* custom_time_format: Provide a custom format for time. If not provided or
|
||||||
* empty, the default format is "%Y%m%d %H:%M:%S", with microseconds followed if
|
* empty, the default format is "%Y%m%d %H:%M:%S", with microseonds followed if
|
||||||
* show_microseconds is true. For detailed information about formats, please
|
* show_microseconds is true. For detailed information about formats, please
|
||||||
* refer to cpp reference about strftime().
|
* refer to cpp reference about strftime().
|
||||||
*
|
*
|
||||||
@ -99,10 +95,6 @@ namespace plugin
|
|||||||
* Enable the plugin by adding the configuration to the list of plugins in the
|
* Enable the plugin by adding the configuration to the list of plugins in the
|
||||||
* configuration file.
|
* configuration file.
|
||||||
*
|
*
|
||||||
* path_exempt: must be a string or a string array, present a regular expression
|
|
||||||
* (for matching the path of a request) or a regular expression list for URLs
|
|
||||||
* that don't have to be logged.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
class DROGON_EXPORT AccessLogger : public drogon::Plugin<AccessLogger>
|
class DROGON_EXPORT AccessLogger : public drogon::Plugin<AccessLogger>
|
||||||
{
|
{
|
||||||
@ -122,8 +114,6 @@ class DROGON_EXPORT AccessLogger : public drogon::Plugin<AccessLogger>
|
|||||||
bool useCustomTimeFormat_{false};
|
bool useCustomTimeFormat_{false};
|
||||||
std::string timeFormat_;
|
std::string timeFormat_;
|
||||||
static bool useRealIp_;
|
static bool useRealIp_;
|
||||||
std::regex exemptRegex_;
|
|
||||||
bool regexFlag_{false};
|
|
||||||
|
|
||||||
using LogFunction = std::function<void(trantor::LogStream &,
|
using LogFunction = std::function<void(trantor::LogStream &,
|
||||||
const drogon::HttpRequestPtr &,
|
const drogon::HttpRequestPtr &,
|
||||||
|
@ -11,7 +11,7 @@ namespace drogon
|
|||||||
namespace plugin
|
namespace plugin
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief This plugin is used to add global filters to all HTTP requests.
|
* @brif This plugin is used to add global filters to all HTTP requests.
|
||||||
* The json configuration is as follows:
|
* The json configuration is as follows:
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
|
@ -71,9 +71,7 @@ IPs or users. the default value is 600.
|
|||||||
"ip_capacity": 0,
|
"ip_capacity": 0,
|
||||||
"user_capacity": 0
|
"user_capacity": 0
|
||||||
},...
|
},...
|
||||||
],
|
]
|
||||||
// Trusted proxy ip or cidr
|
|
||||||
"trust_ips": ["127.0.0.1", "172.16.0.0/12"],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
@ -139,14 +137,12 @@ class DROGON_EXPORT Hodor : public drogon::Plugin<Hodor>
|
|||||||
std::function<HttpResponsePtr(const drogon::HttpRequestPtr &)>
|
std::function<HttpResponsePtr(const drogon::HttpRequestPtr &)>
|
||||||
rejectResponseFactory_;
|
rejectResponseFactory_;
|
||||||
|
|
||||||
RealIpResolver::CIDRs trustCIDRs_;
|
|
||||||
|
|
||||||
void onHttpRequest(const drogon::HttpRequestPtr &,
|
void onHttpRequest(const drogon::HttpRequestPtr &,
|
||||||
AdviceCallback &&,
|
AdviceCallback &&,
|
||||||
AdviceChainCallback &&);
|
AdviceChainCallback &&);
|
||||||
bool checkLimit(const drogon::HttpRequestPtr &req,
|
bool checkLimit(const drogon::HttpRequestPtr &req,
|
||||||
const LimitStrategy &strategy,
|
const LimitStrategy &strategy,
|
||||||
const trantor::InetAddress &ip,
|
const std::string &ip,
|
||||||
const std::optional<std::string> &userId);
|
const std::optional<std::string> &userId);
|
||||||
HttpResponsePtr rejectResponse_;
|
HttpResponsePtr rejectResponse_;
|
||||||
};
|
};
|
||||||
|
@ -106,7 +106,8 @@ class DROGON_EXPORT PluginBase : public virtual DrObjectBase,
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsPlugin
|
struct IsPlugin
|
||||||
{
|
{
|
||||||
using TYPE = std::remove_cv_t<typename std::remove_reference_t<T>>;
|
using TYPE =
|
||||||
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||||
|
|
||||||
static int test(void *)
|
static int test(void *)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +57,7 @@ class DROGON_EXPORT RealIpResolver : public drogon::Plugin<RealIpResolver>
|
|||||||
private:
|
private:
|
||||||
const trantor::InetAddress &getRealAddr(
|
const trantor::InetAddress &getRealAddr(
|
||||||
const drogon::HttpRequestPtr &req) const;
|
const drogon::HttpRequestPtr &req) const;
|
||||||
|
bool matchCidr(const trantor::InetAddress &addr) const;
|
||||||
|
|
||||||
struct CIDR
|
struct CIDR
|
||||||
{
|
{
|
||||||
@ -65,12 +66,7 @@ class DROGON_EXPORT RealIpResolver : public drogon::Plugin<RealIpResolver>
|
|||||||
in_addr_t mask_{32};
|
in_addr_t mask_{32};
|
||||||
};
|
};
|
||||||
|
|
||||||
using CIDRs = std::vector<CIDR>;
|
std::vector<CIDR> trustCIDRs_;
|
||||||
static bool matchCidr(const trantor::InetAddress &addr,
|
|
||||||
const CIDRs &trustCIDRs);
|
|
||||||
|
|
||||||
friend class Hodor;
|
|
||||||
CIDRs trustCIDRs_;
|
|
||||||
std::string fromHeader_;
|
std::string fromHeader_;
|
||||||
std::string attributeKey_;
|
std::string attributeKey_;
|
||||||
bool useXForwardedFor_{false};
|
bool useXForwardedFor_{false};
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <drogon/DrObject.h>
|
#include <drogon/DrObject.h>
|
||||||
#include <drogon/RequestStream.h>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@ -47,88 +46,11 @@ struct resumable_type : std::false_type
|
|||||||
template <typename>
|
template <typename>
|
||||||
struct FunctionTraits;
|
struct FunctionTraits;
|
||||||
|
|
||||||
//
|
// functor,lambda,std::function...
|
||||||
// Basic match, inherited by all other matches
|
|
||||||
//
|
|
||||||
template <typename ReturnType, typename... Arguments>
|
|
||||||
struct FunctionTraits<ReturnType (*)(Arguments...)>
|
|
||||||
{
|
|
||||||
using result_type = ReturnType;
|
|
||||||
|
|
||||||
template <std::size_t Index>
|
|
||||||
using argument =
|
|
||||||
typename std::tuple_element_t<Index, std::tuple<Arguments...>>;
|
|
||||||
|
|
||||||
static const std::size_t arity = sizeof...(Arguments);
|
|
||||||
using class_type = void;
|
|
||||||
using return_type = ReturnType;
|
|
||||||
static const bool isHTTPFunction = false;
|
|
||||||
static const bool isClassFunction = false;
|
|
||||||
static const bool isStreamHandler = false;
|
|
||||||
static const bool isDrObjectClass = false;
|
|
||||||
static const bool isCoroutine = false;
|
|
||||||
|
|
||||||
static const std::string name()
|
|
||||||
{
|
|
||||||
return std::string("Normal or Static Function");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Match normal functions
|
|
||||||
//
|
|
||||||
|
|
||||||
// normal function for HTTP handling
|
|
||||||
template <typename ReturnType, typename... Arguments>
|
|
||||||
struct FunctionTraits<
|
|
||||||
ReturnType (*)(const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
|
||||||
{
|
|
||||||
static const bool isHTTPFunction = !resumable_type<ReturnType>::value;
|
|
||||||
static const bool isCoroutine = false;
|
|
||||||
using class_type = void;
|
|
||||||
using first_param_type = HttpRequestPtr;
|
|
||||||
using return_type = ReturnType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// normal function with custom request object
|
|
||||||
template <typename T, typename ReturnType, typename... Arguments>
|
|
||||||
struct FunctionTraits<
|
|
||||||
ReturnType (*)(T &&customReq,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
|
||||||
{
|
|
||||||
static const bool isHTTPFunction = !resumable_type<ReturnType>::value;
|
|
||||||
static const bool isCoroutine = false;
|
|
||||||
using class_type = void;
|
|
||||||
using first_param_type = T;
|
|
||||||
using return_type = ReturnType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// normal function with stream handler
|
|
||||||
template <typename ReturnType, typename... Arguments>
|
|
||||||
struct FunctionTraits<
|
|
||||||
ReturnType (*)(const HttpRequestPtr &req,
|
|
||||||
RequestStreamPtr &&streamCtx,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
|
||||||
{
|
|
||||||
static const bool isHTTPFunction = !resumable_type<ReturnType>::value;
|
|
||||||
static const bool isCoroutine = false;
|
|
||||||
static const bool isStreamHandler = true;
|
|
||||||
using class_type = void;
|
|
||||||
using first_param_type = HttpRequestPtr;
|
|
||||||
using return_type = ReturnType;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Match functor,lambda,std::function... inherits normal function matches
|
|
||||||
//
|
|
||||||
template <typename Function>
|
template <typename Function>
|
||||||
struct FunctionTraits
|
struct FunctionTraits
|
||||||
: public FunctionTraits<
|
: public FunctionTraits<
|
||||||
decltype(&std::remove_reference_t<Function>::operator())>
|
decltype(&std::remove_reference<Function>::type::operator())>
|
||||||
{
|
{
|
||||||
static const bool isClassFunction = false;
|
static const bool isClassFunction = false;
|
||||||
static const bool isDrObjectClass = false;
|
static const bool isDrObjectClass = false;
|
||||||
@ -140,11 +62,7 @@ struct FunctionTraits
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
// class instance method of const object
|
||||||
// Match class functions, inherits normal function matches
|
|
||||||
//
|
|
||||||
|
|
||||||
// class const method
|
|
||||||
template <typename ClassType, typename ReturnType, typename... Arguments>
|
template <typename ClassType, typename ReturnType, typename... Arguments>
|
||||||
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const>
|
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const>
|
||||||
: FunctionTraits<ReturnType (*)(Arguments...)>
|
: FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
@ -160,7 +78,7 @@ struct FunctionTraits<ReturnType (ClassType::*)(Arguments...) const>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// class non-const method
|
// class instance method of non-const object
|
||||||
template <typename ClassType, typename ReturnType, typename... Arguments>
|
template <typename ClassType, typename ReturnType, typename... Arguments>
|
||||||
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)>
|
struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)>
|
||||||
: FunctionTraits<ReturnType (*)(Arguments...)>
|
: FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
@ -176,9 +94,30 @@ struct FunctionTraits<ReturnType (ClassType::*)(Arguments...)>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
// normal function for HTTP handling
|
||||||
// Match coroutine functions
|
template <typename ReturnType, typename... Arguments>
|
||||||
//
|
struct FunctionTraits<
|
||||||
|
ReturnType (*)(const HttpRequestPtr &req,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
|
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
|
{
|
||||||
|
static const bool isHTTPFunction = !resumable_type<ReturnType>::value;
|
||||||
|
static const bool isCoroutine = false;
|
||||||
|
using class_type = void;
|
||||||
|
using first_param_type = HttpRequestPtr;
|
||||||
|
using return_type = ReturnType;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ReturnType, typename... Arguments>
|
||||||
|
struct FunctionTraits<
|
||||||
|
ReturnType (*)(HttpRequestPtr &req,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
|
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
|
{
|
||||||
|
static const bool isHTTPFunction = false;
|
||||||
|
using class_type = void;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cpp_impl_coroutine
|
#ifdef __cpp_impl_coroutine
|
||||||
template <typename... Arguments>
|
template <typename... Arguments>
|
||||||
struct FunctionTraits<
|
struct FunctionTraits<
|
||||||
@ -219,20 +158,6 @@ struct FunctionTraits<Task<HttpResponsePtr> (*)(HttpRequestPtr req,
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
|
||||||
// Bad matches
|
|
||||||
//
|
|
||||||
|
|
||||||
template <typename ReturnType, typename... Arguments>
|
|
||||||
struct FunctionTraits<
|
|
||||||
ReturnType (*)(HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
|
||||||
{
|
|
||||||
static const bool isHTTPFunction = false;
|
|
||||||
using class_type = void;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename ReturnType, typename... Arguments>
|
template <typename ReturnType, typename... Arguments>
|
||||||
struct FunctionTraits<
|
struct FunctionTraits<
|
||||||
ReturnType (*)(HttpRequestPtr &&req,
|
ReturnType (*)(HttpRequestPtr &&req,
|
||||||
@ -243,5 +168,43 @@ struct FunctionTraits<
|
|||||||
using class_type = void;
|
using class_type = void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// normal function for HTTP handling
|
||||||
|
template <typename T, typename ReturnType, typename... Arguments>
|
||||||
|
struct FunctionTraits<
|
||||||
|
ReturnType (*)(T &&customReq,
|
||||||
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
|
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
|
{
|
||||||
|
static const bool isHTTPFunction = !resumable_type<ReturnType>::value;
|
||||||
|
static const bool isCoroutine = false;
|
||||||
|
using class_type = void;
|
||||||
|
using first_param_type = T;
|
||||||
|
using return_type = ReturnType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal function
|
||||||
|
template <typename ReturnType, typename... Arguments>
|
||||||
|
struct FunctionTraits<ReturnType (*)(Arguments...)>
|
||||||
|
{
|
||||||
|
using result_type = ReturnType;
|
||||||
|
|
||||||
|
template <std::size_t Index>
|
||||||
|
using argument =
|
||||||
|
typename std::tuple_element<Index, std::tuple<Arguments...>>::type;
|
||||||
|
|
||||||
|
static const std::size_t arity = sizeof...(Arguments);
|
||||||
|
using class_type = void;
|
||||||
|
using return_type = ReturnType;
|
||||||
|
static const bool isHTTPFunction = false;
|
||||||
|
static const bool isClassFunction = false;
|
||||||
|
static const bool isDrObjectClass = false;
|
||||||
|
static const bool isCoroutine = false;
|
||||||
|
|
||||||
|
static const std::string name()
|
||||||
|
{
|
||||||
|
return std::string("Normal or Static Function");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -25,7 +25,7 @@ enum class ConstraintType
|
|||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
HttpMethod,
|
HttpMethod,
|
||||||
HttpMiddleware
|
HttpFilter
|
||||||
};
|
};
|
||||||
|
|
||||||
class HttpConstraint
|
class HttpConstraint
|
||||||
@ -36,14 +36,13 @@ class HttpConstraint
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpConstraint(std::string middlewareName)
|
HttpConstraint(const std::string &filterName)
|
||||||
: type_(ConstraintType::HttpMiddleware),
|
: type_(ConstraintType::HttpFilter), filterName_(filterName)
|
||||||
middlewareName_(std::move(middlewareName))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpConstraint(const char *middlewareName)
|
HttpConstraint(const char *filterName)
|
||||||
: type_(ConstraintType::HttpMiddleware), middlewareName_(middlewareName)
|
: type_(ConstraintType::HttpFilter), filterName_(filterName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,15 +56,15 @@ class HttpConstraint
|
|||||||
return method_;
|
return method_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &getMiddlewareName() const
|
const std::string &getFilterName() const
|
||||||
{
|
{
|
||||||
return middlewareName_;
|
return filterName_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstraintType type_{ConstraintType::None};
|
ConstraintType type_{ConstraintType::None};
|
||||||
HttpMethod method_{HttpMethod::Invalid};
|
HttpMethod method_{HttpMethod::Invalid};
|
||||||
std::string middlewareName_;
|
std::string filterName_;
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -21,16 +21,24 @@ namespace drogon
|
|||||||
{
|
{
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
template <typename T, typename = void>
|
|
||||||
struct CanConvertToString : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct CanConvertToString<
|
struct CanConvertToString
|
||||||
T,
|
|
||||||
std::void_t<decltype(std::to_string(std::declval<T>()))>> : std::true_type
|
|
||||||
{
|
{
|
||||||
|
using Type = std::remove_reference_t<std::remove_cv_t<T>>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using yes = std::true_type;
|
||||||
|
using no = std::false_type;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static auto test(int) -> decltype(std::to_string(U{}), yes());
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
static no test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same<decltype(test<Type>(0)), yes>::value;
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -45,20 +53,21 @@ class OStringStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
OStringStream &operator<<(T &&value)
|
std::enable_if_t<!internal::CanConvertToString<T>::value, OStringStream &>
|
||||||
{
|
operator<<(T &&value)
|
||||||
if constexpr (internal::CanConvertToString<T>::value)
|
|
||||||
{
|
|
||||||
buffer_.append(std::to_string(std::forward<T>(value)));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::forward<T>(value);
|
ss << std::forward<T>(value);
|
||||||
buffer_.append(ss.str());
|
buffer_.append(ss.str());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::enable_if_t<internal::CanConvertToString<T>::value, OStringStream &>
|
||||||
|
operator<<(T &&value)
|
||||||
|
{
|
||||||
|
buffer_.append(std::to_string(std::forward<T>(value)));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
|
@ -28,8 +28,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
|
||||||
#include <type_traits>
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
DROGON_EXPORT char *strptime(const char *s, const char *f, struct tm *tm);
|
DROGON_EXPORT char *strptime(const char *s, const char *f, struct tm *tm);
|
||||||
@ -39,45 +37,36 @@ namespace drogon
|
|||||||
{
|
{
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
template <typename T, typename = void>
|
|
||||||
struct CanConvertFromStringStream : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct CanConvertFromStringStream<
|
struct CanConvertFromStringStream
|
||||||
T,
|
|
||||||
std::void_t<decltype(std::declval<std::stringstream &>() >>
|
|
||||||
std::declval<T &>())>> : std::true_type
|
|
||||||
{
|
{
|
||||||
};
|
private:
|
||||||
|
using yes = std::true_type;
|
||||||
|
using no = std::false_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename U>
|
||||||
struct CanConstructFromString : std::is_constructible<T, std::string>
|
static auto test(U *p, std::stringstream &&ss)
|
||||||
{
|
-> decltype((ss >> *p), yes());
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename>
|
||||||
struct CanConvertFromString : std::is_assignable<T &, std::string>
|
static no test(...);
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same<decltype(test<T>(nullptr, std::stringstream())),
|
||||||
|
yes>::value;
|
||||||
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the HTTP messages corresponding to the HTTP status codes
|
|
||||||
*
|
|
||||||
* @param code HTTP status code
|
|
||||||
*
|
|
||||||
* @return the corresponding message
|
|
||||||
*/
|
|
||||||
DROGON_EXPORT const std::string_view &statusCodeToString(int code);
|
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
/// Determine if the string is an integer
|
/// Determine if the string is an integer
|
||||||
|
DROGON_EXPORT bool isInteger(const std::string &str);
|
||||||
|
/// Determine if the string is an integer
|
||||||
DROGON_EXPORT bool isInteger(std::string_view str);
|
DROGON_EXPORT bool isInteger(std::string_view str);
|
||||||
|
|
||||||
|
/// Determine if the string is base64 encoded
|
||||||
|
DROGON_EXPORT bool isBase64(const std::string &str);
|
||||||
/// Determine if the string is base64 encoded
|
/// Determine if the string is base64 encoded
|
||||||
DROGON_EXPORT bool isBase64(std::string_view str);
|
DROGON_EXPORT bool isBase64(std::string_view str);
|
||||||
|
|
||||||
@ -90,8 +79,7 @@ DROGON_EXPORT std::string genRandomString(int length);
|
|||||||
|
|
||||||
/// Convert a binary string to hex format
|
/// Convert a binary string to hex format
|
||||||
DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr,
|
DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr,
|
||||||
size_t length,
|
size_t length);
|
||||||
bool lowerCase = false);
|
|
||||||
|
|
||||||
/// Get a binary string from hexadecimal format
|
/// Get a binary string from hexadecimal format
|
||||||
DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
||||||
@ -100,15 +88,8 @@ DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
|||||||
DROGON_EXPORT std::vector<char> hexToBinaryVector(const char *ptr,
|
DROGON_EXPORT std::vector<char> hexToBinaryVector(const char *ptr,
|
||||||
size_t length);
|
size_t length);
|
||||||
|
|
||||||
DROGON_EXPORT void binaryStringToHex(const char *ptr,
|
|
||||||
size_t length,
|
|
||||||
char *out,
|
|
||||||
bool lowerCase = false);
|
|
||||||
|
|
||||||
/// Split the string into multiple separated strings.
|
/// Split the string into multiple separated strings.
|
||||||
/**
|
/**
|
||||||
* @param str string to split
|
|
||||||
* @param separator element separator
|
|
||||||
* @param acceptEmptyString if true, empty strings are accepted in the
|
* @param acceptEmptyString if true, empty strings are accepted in the
|
||||||
* result, for example, splitting the ",1,2,,3," by "," produces
|
* result, for example, splitting the ",1,2,,3," by "," produces
|
||||||
* ["","1","2","","3",""]
|
* ["","1","2","","3",""]
|
||||||
@ -125,7 +106,7 @@ DROGON_EXPORT std::set<std::string> splitStringToSet(
|
|||||||
const std::string &separator);
|
const std::string &separator);
|
||||||
|
|
||||||
/// Get UUID string.
|
/// Get UUID string.
|
||||||
DROGON_EXPORT std::string getUuid(bool lowercase = true);
|
DROGON_EXPORT std::string getUuid();
|
||||||
|
|
||||||
/// Get the encoded length of base64.
|
/// Get the encoded length of base64.
|
||||||
constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
|
constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
|
||||||
@ -134,85 +115,47 @@ constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encode the string to base64 format.
|
/// Encode the string to base64 format.
|
||||||
DROGON_EXPORT void base64Encode(const unsigned char *bytesToEncode,
|
DROGON_EXPORT std::string base64Encode(const unsigned char *bytes_to_encode,
|
||||||
size_t inLen,
|
size_t in_len,
|
||||||
unsigned char *outputBuffer,
|
bool url_safe = false,
|
||||||
bool urlSafe = false,
|
|
||||||
bool padded = true);
|
bool padded = true);
|
||||||
|
|
||||||
/// Encode the string to base64 format.
|
|
||||||
inline std::string base64Encode(const unsigned char *bytesToEncode,
|
|
||||||
size_t inLen,
|
|
||||||
bool urlSafe = false,
|
|
||||||
bool padded = true)
|
|
||||||
{
|
|
||||||
std::string ret;
|
|
||||||
ret.resize(base64EncodedLength(inLen, padded));
|
|
||||||
base64Encode(
|
|
||||||
bytesToEncode, inLen, (unsigned char *)ret.data(), urlSafe, padded);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode the string to base64 format.
|
/// Encode the string to base64 format.
|
||||||
inline std::string base64Encode(std::string_view data,
|
inline std::string base64Encode(std::string_view data,
|
||||||
bool urlSafe = false,
|
bool url_safe = false,
|
||||||
bool padded = true)
|
bool padded = true)
|
||||||
{
|
{
|
||||||
return base64Encode((unsigned char *)data.data(),
|
return base64Encode((unsigned char *)data.data(),
|
||||||
data.size(),
|
data.size(),
|
||||||
urlSafe,
|
url_safe,
|
||||||
padded);
|
padded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode the string to base64 format with no padding.
|
/// Encode the string to base64 format with no padding.
|
||||||
inline void base64EncodeUnpadded(const unsigned char *bytesToEncode,
|
inline std::string base64EncodeUnpadded(const unsigned char *bytes_to_encode,
|
||||||
size_t inLen,
|
size_t in_len,
|
||||||
unsigned char *outputBuffer,
|
bool url_safe = false)
|
||||||
bool urlSafe = false)
|
|
||||||
{
|
{
|
||||||
base64Encode(bytesToEncode, inLen, outputBuffer, urlSafe, false);
|
return base64Encode(bytes_to_encode, in_len, url_safe, false);
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode the string to base64 format with no padding.
|
|
||||||
inline std::string base64EncodeUnpadded(const unsigned char *bytesToEncode,
|
|
||||||
size_t inLen,
|
|
||||||
bool urlSafe = false)
|
|
||||||
{
|
|
||||||
return base64Encode(bytesToEncode, inLen, urlSafe, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode the string to base64 format with no padding.
|
/// Encode the string to base64 format with no padding.
|
||||||
inline std::string base64EncodeUnpadded(std::string_view data,
|
inline std::string base64EncodeUnpadded(std::string_view data,
|
||||||
bool urlSafe = false)
|
bool url_safe = false)
|
||||||
{
|
{
|
||||||
return base64Encode(data, urlSafe, false);
|
return base64Encode(data, url_safe, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the decoded length of base64.
|
/// Get the decoded length of base64.
|
||||||
constexpr size_t base64DecodedLength(size_t inLen)
|
constexpr size_t base64DecodedLength(size_t in_len)
|
||||||
{
|
{
|
||||||
return (inLen * 3) / 4;
|
return (in_len * 3) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode the base64 format string.
|
/// Decode the base64 format string.
|
||||||
/// Return the number of bytes written.
|
DROGON_EXPORT std::string base64Decode(std::string_view encoded_string);
|
||||||
DROGON_EXPORT size_t base64Decode(const char *encodedString,
|
|
||||||
size_t inLen,
|
|
||||||
unsigned char *outputBuffer);
|
|
||||||
|
|
||||||
/// Decode the base64 format string.
|
|
||||||
inline std::string base64Decode(std::string_view encodedString)
|
|
||||||
{
|
|
||||||
auto inLen = encodedString.size();
|
|
||||||
std::string ret;
|
|
||||||
ret.resize(base64DecodedLength(inLen));
|
|
||||||
ret.resize(
|
|
||||||
base64Decode(encodedString.data(), inLen, (unsigned char *)ret.data()));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DROGON_EXPORT std::vector<char> base64DecodeToVector(
|
DROGON_EXPORT std::vector<char> base64DecodeToVector(
|
||||||
std::string_view encodedString);
|
std::string_view encoded_string);
|
||||||
|
|
||||||
/// Check if the string need decoding
|
/// Check if the string need decoding
|
||||||
DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end);
|
DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end);
|
||||||
@ -271,7 +214,7 @@ inline std::string getBlake2b(const std::string &originalString)
|
|||||||
return getBlake2b(originalString.data(), originalString.length());
|
return getBlake2b(originalString.data(), originalString.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compress or decompress data using gzip lib.
|
/// Commpress or decompress data using gzip lib.
|
||||||
/**
|
/**
|
||||||
* @param data the input data
|
* @param data the input data
|
||||||
* @param ndata the input data length
|
* @param ndata the input data length
|
||||||
@ -279,7 +222,7 @@ inline std::string getBlake2b(const std::string &originalString)
|
|||||||
DROGON_EXPORT std::string gzipCompress(const char *data, const size_t ndata);
|
DROGON_EXPORT std::string gzipCompress(const char *data, const size_t ndata);
|
||||||
DROGON_EXPORT std::string gzipDecompress(const char *data, const size_t ndata);
|
DROGON_EXPORT std::string gzipDecompress(const char *data, const size_t ndata);
|
||||||
|
|
||||||
/// Compress or decompress data using brotli lib.
|
/// Commpress or decompress data using brotli lib.
|
||||||
/**
|
/**
|
||||||
* @param data the input data
|
* @param data the input data
|
||||||
* @param ndata the input data length
|
* @param ndata the input data length
|
||||||
@ -301,12 +244,6 @@ DROGON_EXPORT std::string brotliDecompress(const char *data,
|
|||||||
DROGON_EXPORT char *getHttpFullDate(
|
DROGON_EXPORT char *getHttpFullDate(
|
||||||
const trantor::Date &date = trantor::Date::now());
|
const trantor::Date &date = trantor::Date::now());
|
||||||
|
|
||||||
DROGON_EXPORT const std::string &getHttpFullDateStr(
|
|
||||||
const trantor::Date &date = trantor::Date::now());
|
|
||||||
|
|
||||||
DROGON_EXPORT void dateToCustomFormattedString(const std::string &fmtStr,
|
|
||||||
std::string &str,
|
|
||||||
const trantor::Date &date);
|
|
||||||
/// Get the trantor::Date object according to the http full date string
|
/// Get the trantor::Date object according to the http full date string
|
||||||
/**
|
/**
|
||||||
* Returns trantor::Date(std::numeric_limits<int64_t>::max()) upon failure.
|
* Returns trantor::Date(std::numeric_limits<int64_t>::max()) upon failure.
|
||||||
@ -430,9 +367,8 @@ inline std::string fromNativePath(const std::wstring &strPath)
|
|||||||
return trantor::utils::fromNativePath(strPath);
|
return trantor::utils::fromNativePath(strPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace all occurrences of from to to inplace
|
/// Replace all occurances of from to to inplace
|
||||||
/**
|
/**
|
||||||
* @param s string to alter
|
|
||||||
* @param from string to replace
|
* @param from string to replace
|
||||||
* @param to string to replace with
|
* @param to string to replace with
|
||||||
*/
|
*/
|
||||||
@ -446,7 +382,7 @@ DROGON_EXPORT void replaceAll(std::string &s,
|
|||||||
* @param ptr the pointer which the random bytes are stored to
|
* @param ptr the pointer which the random bytes are stored to
|
||||||
* @param size number of bytes to generate
|
* @param size number of bytes to generate
|
||||||
*
|
*
|
||||||
* @return true if generation is successful. False otherwise
|
* @return true if generation is successfull. False otherwise
|
||||||
*/
|
*/
|
||||||
DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
|
DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
|
||||||
|
|
||||||
@ -460,70 +396,24 @@ DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
|
|||||||
DROGON_EXPORT std::string secureRandomString(size_t size);
|
DROGON_EXPORT std::string secureRandomString(size_t size);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T fromString(const std::string &p) noexcept(false)
|
typename std::enable_if<internal::CanConvertFromStringStream<T>::value, T>::type
|
||||||
|
fromString(const std::string &p) noexcept(false)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_integral<T>::value && std::is_signed<T>::value)
|
|
||||||
{
|
|
||||||
std::size_t pos;
|
|
||||||
auto v = std::stoll(p, &pos);
|
|
||||||
// throw if the whole string could not be parsed
|
|
||||||
// ("1a" should not return 1)
|
|
||||||
if (pos != p.size())
|
|
||||||
throw std::invalid_argument("Invalid value");
|
|
||||||
if ((v < static_cast<long long>((std::numeric_limits<T>::min)())) ||
|
|
||||||
(v > static_cast<long long>((std::numeric_limits<T>::max)())))
|
|
||||||
throw std::out_of_range("Value out of range");
|
|
||||||
return static_cast<T>(v);
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_integral<T>::value &&
|
|
||||||
(!std::is_signed<T>::value))
|
|
||||||
{
|
|
||||||
std::size_t pos;
|
|
||||||
auto v = std::stoull(p, &pos);
|
|
||||||
// throw if the whole string could not be parsed
|
|
||||||
// ("1a" should not return 1)
|
|
||||||
if (pos != p.size())
|
|
||||||
throw std::invalid_argument("Invalid value");
|
|
||||||
if (v >
|
|
||||||
static_cast<unsigned long long>((std::numeric_limits<T>::max)()))
|
|
||||||
throw std::out_of_range("Value out of range");
|
|
||||||
return static_cast<T>(v);
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_floating_point<T>::value)
|
|
||||||
{
|
|
||||||
std::size_t pos;
|
|
||||||
auto v = std::stold(p, &pos);
|
|
||||||
// throw if the whole string could not be parsed
|
|
||||||
// ("1a" should not return 1)
|
|
||||||
if (pos != p.size())
|
|
||||||
throw std::invalid_argument("Invalid value");
|
|
||||||
if ((v < static_cast<long double>((std::numeric_limits<T>::min)())) ||
|
|
||||||
(v > static_cast<long double>((std::numeric_limits<T>::max)())))
|
|
||||||
throw std::out_of_range("Value out of range");
|
|
||||||
return static_cast<T>(v);
|
|
||||||
}
|
|
||||||
else if constexpr (internal::CanConvertFromStringStream<T>::value)
|
|
||||||
{
|
|
||||||
T value{};
|
T value{};
|
||||||
if (!p.empty())
|
if (!p.empty())
|
||||||
{
|
{
|
||||||
std::stringstream ss(p);
|
std::stringstream ss(p);
|
||||||
// must except in case of invalid value, not return a default value
|
|
||||||
// (else it returns 0 for integers if the string is empty or
|
|
||||||
// non-numeric)
|
|
||||||
ss.exceptions(std::ios_base::failbit);
|
|
||||||
ss >> value;
|
ss >> value;
|
||||||
// throw if the whole string could not be parsed
|
|
||||||
// ("1a" should not return 1)
|
|
||||||
if (!ss.eof())
|
|
||||||
std::runtime_error("Bad type conversion");
|
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
template <typename T>
|
||||||
|
typename std::enable_if<!(internal::CanConvertFromStringStream<T>::value),
|
||||||
|
T>::type
|
||||||
|
fromString(const std::string &) noexcept(false)
|
||||||
|
{
|
||||||
throw std::runtime_error("Bad type conversion");
|
throw std::runtime_error("Bad type conversion");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -532,13 +422,67 @@ inline std::string fromString<std::string>(const std::string &p) noexcept(false)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline int fromString<int>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stoi(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long fromString<long>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stol(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long long fromString<long long>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stoll(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long fromString<unsigned long>(const std::string &p) noexcept(
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
return std::stoul(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long long fromString<unsigned long long>(
|
||||||
|
const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stoull(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline float fromString<float>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stof(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline double fromString<double>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stod(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long double fromString<long double>(const std::string &p) noexcept(false)
|
||||||
|
{
|
||||||
|
return std::stold(p);
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline bool fromString<bool>(const std::string &p) noexcept(false)
|
inline bool fromString<bool>(const std::string &p) noexcept(false)
|
||||||
{
|
{
|
||||||
if (!p.empty() && std::all_of(p.begin(), p.end(), [](unsigned char c) {
|
if (p == "1")
|
||||||
return std::isdigit(c);
|
{
|
||||||
}))
|
return true;
|
||||||
return (std::stoll(p) != 0);
|
}
|
||||||
|
if (p == "0")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::string l{p};
|
std::string l{p};
|
||||||
std::transform(p.begin(), p.end(), l.begin(), [](unsigned char c) {
|
std::transform(p.begin(), p.end(), l.begin(), [](unsigned char c) {
|
||||||
return (char)tolower(c);
|
return (char)tolower(c);
|
||||||
@ -574,17 +518,12 @@ struct SafeStringHash
|
|||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using SafeStringMap =
|
|
||||||
std::unordered_map<std::string, T, utils::internal::SafeStringHash>;
|
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
|
||||||
namespace trantor
|
namespace trantor
|
||||||
{
|
{
|
||||||
inline LogStream &operator<<(LogStream &ls, const std::string_view &v)
|
inline LogStream &operator<<(LogStream &ls, const std::string_view &v)
|
||||||
{
|
{
|
||||||
if (!v.empty())
|
|
||||||
ls.append(v.data(), v.length());
|
ls.append(v.data(), v.length());
|
||||||
return ls;
|
return ls;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ struct [[nodiscard]] Task
|
|||||||
|
|
||||||
std::optional<T> value;
|
std::optional<T> value;
|
||||||
std::exception_ptr exception_;
|
std::exception_ptr exception_;
|
||||||
std::coroutine_handle<> continuation_{std::noop_coroutine()};
|
std::coroutine_handle<> continuation_;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto operator co_await() const noexcept
|
auto operator co_await() const noexcept
|
||||||
@ -332,7 +332,7 @@ struct [[nodiscard]] Task<void>
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::exception_ptr exception_;
|
std::exception_ptr exception_;
|
||||||
std::coroutine_handle<> continuation_{std::noop_coroutine()};
|
std::coroutine_handle<> continuation_;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto operator co_await() const noexcept
|
auto operator co_await() const noexcept
|
||||||
@ -749,7 +749,7 @@ void async_run(Coro &&coro)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief returns a function that calls a coroutine
|
* @brief returns a function that calls a coroutine
|
||||||
* @param coro A coroutine that is awaitable
|
* @param Coro A coroutine that is awaitable
|
||||||
*/
|
*/
|
||||||
template <typename Coro>
|
template <typename Coro>
|
||||||
std::function<void()> async_func(Coro &&coro)
|
std::function<void()> async_func(Coro &&coro)
|
||||||
@ -811,180 +811,4 @@ inline internal::EventLoopAwaiter<T> queueInLoopCoro(trantor::EventLoop *loop,
|
|||||||
return internal::EventLoopAwaiter<T>(std::move(task), loop);
|
return internal::EventLoopAwaiter<T>(std::move(task), loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutex final
|
|
||||||
{
|
|
||||||
class ScopedCoroMutexAwaiter;
|
|
||||||
class CoroMutexAwaiter;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Mutex() noexcept : state_(unlockedValue()), waiters_(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Mutex(const Mutex &) = delete;
|
|
||||||
Mutex(Mutex &&) = delete;
|
|
||||||
Mutex &operator=(const Mutex &) = delete;
|
|
||||||
Mutex &operator=(Mutex &&) = delete;
|
|
||||||
|
|
||||||
~Mutex()
|
|
||||||
{
|
|
||||||
[[maybe_unused]] auto state = state_.load(std::memory_order_relaxed);
|
|
||||||
assert(state == unlockedValue() || state == nullptr);
|
|
||||||
assert(waiters_ == nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool try_lock() noexcept
|
|
||||||
{
|
|
||||||
void *oldValue = unlockedValue();
|
|
||||||
return state_.compare_exchange_strong(oldValue,
|
|
||||||
nullptr,
|
|
||||||
std::memory_order_acquire,
|
|
||||||
std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] ScopedCoroMutexAwaiter scoped_lock(
|
|
||||||
trantor::EventLoop *loop =
|
|
||||||
trantor::EventLoop::getEventLoopOfCurrentThread()) noexcept
|
|
||||||
{
|
|
||||||
return ScopedCoroMutexAwaiter(*this, loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] CoroMutexAwaiter lock(
|
|
||||||
trantor::EventLoop *loop =
|
|
||||||
trantor::EventLoop::getEventLoopOfCurrentThread()) noexcept
|
|
||||||
{
|
|
||||||
return CoroMutexAwaiter(*this, loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() noexcept
|
|
||||||
{
|
|
||||||
assert(state_.load(std::memory_order_relaxed) != unlockedValue());
|
|
||||||
auto *waitersHead = waiters_;
|
|
||||||
if (waitersHead == nullptr)
|
|
||||||
{
|
|
||||||
void *currentState = state_.load(std::memory_order_relaxed);
|
|
||||||
if (currentState == nullptr)
|
|
||||||
{
|
|
||||||
const bool releasedLock =
|
|
||||||
state_.compare_exchange_strong(currentState,
|
|
||||||
unlockedValue(),
|
|
||||||
std::memory_order_release,
|
|
||||||
std::memory_order_relaxed);
|
|
||||||
if (releasedLock)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentState = state_.exchange(nullptr, std::memory_order_acquire);
|
|
||||||
assert(currentState != unlockedValue());
|
|
||||||
assert(currentState != nullptr);
|
|
||||||
auto *waiter = static_cast<CoroMutexAwaiter *>(currentState);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto *temp = waiter->next_;
|
|
||||||
waiter->next_ = waitersHead;
|
|
||||||
waitersHead = waiter;
|
|
||||||
waiter = temp;
|
|
||||||
} while (waiter != nullptr);
|
|
||||||
}
|
|
||||||
assert(waitersHead != nullptr);
|
|
||||||
waiters_ = waitersHead->next_;
|
|
||||||
if (waitersHead->loop_)
|
|
||||||
{
|
|
||||||
auto handle = waitersHead->handle_;
|
|
||||||
waitersHead->loop_->runInLoop([handle] { handle.resume(); });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
waitersHead->handle_.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
class CoroMutexAwaiter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CoroMutexAwaiter(Mutex &mutex, trantor::EventLoop *loop) noexcept
|
|
||||||
: mutex_(mutex), loop_(loop)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool await_ready() noexcept
|
|
||||||
{
|
|
||||||
return mutex_.try_lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool await_suspend(std::coroutine_handle<> handle) noexcept
|
|
||||||
{
|
|
||||||
handle_ = handle;
|
|
||||||
return mutex_.asynclockImpl(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void await_resume() noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class Mutex;
|
|
||||||
|
|
||||||
Mutex &mutex_;
|
|
||||||
trantor::EventLoop *loop_;
|
|
||||||
std::coroutine_handle<> handle_;
|
|
||||||
CoroMutexAwaiter *next_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScopedCoroMutexAwaiter : public CoroMutexAwaiter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ScopedCoroMutexAwaiter(Mutex &mutex, trantor::EventLoop *loop)
|
|
||||||
: CoroMutexAwaiter(mutex, loop)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto await_resume() noexcept
|
|
||||||
{
|
|
||||||
return std::unique_lock<Mutex>{mutex_, std::adopt_lock};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool asynclockImpl(CoroMutexAwaiter *awaiter)
|
|
||||||
{
|
|
||||||
void *oldValue = state_.load(std::memory_order_relaxed);
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (oldValue == unlockedValue())
|
|
||||||
{
|
|
||||||
void *newValue = nullptr;
|
|
||||||
if (state_.compare_exchange_weak(oldValue,
|
|
||||||
newValue,
|
|
||||||
std::memory_order_acquire,
|
|
||||||
std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
void *newValue = awaiter;
|
|
||||||
awaiter->next_ = static_cast<CoroMutexAwaiter *>(oldValue);
|
|
||||||
if (state_.compare_exchange_weak(oldValue,
|
|
||||||
newValue,
|
|
||||||
std::memory_order_release,
|
|
||||||
std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *unlockedValue() noexcept
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic<void *> state_;
|
|
||||||
CoroMutexAwaiter *waiters_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace drogon
|
} // namespace drogon
|
||||||
|
@ -60,10 +60,8 @@ class Collector : public CollectorBase
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Arguments>
|
|
||||||
const std::shared_ptr<T> &metric(
|
const std::shared_ptr<T> &metric(
|
||||||
const std::vector<std::string> &labelValues,
|
const std::vector<std::string> &labelValues) noexcept(false)
|
||||||
Arguments... args) noexcept(false)
|
|
||||||
{
|
{
|
||||||
if (labelValues.size() != labelsNames_.size())
|
if (labelValues.size() != labelsNames_.size())
|
||||||
{
|
{
|
||||||
@ -77,8 +75,7 @@ class Collector : public CollectorBase
|
|||||||
{
|
{
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
auto metric =
|
auto metric = std::make_shared<T>(name_, labelsNames_, labelValues);
|
||||||
std::make_shared<T>(name_, labelsNames_, labelValues, args...);
|
|
||||||
metrics_[labelValues] = metric;
|
metrics_[labelValues] = metric;
|
||||||
return metrics_[labelValues];
|
return metrics_[labelValues];
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user