Removed lots of unneeded files.

This commit is contained in:
Relintai 2021-06-20 15:06:21 +02:00
parent d2b0ff2e22
commit 13b2863908
71 changed files with 0 additions and 10877 deletions

View File

@ -1,4 +0,0 @@
[submodule "trantor"]
path = trantor
url = https://github.com/an-tao/trantor.git

View File

@ -1,80 +0,0 @@
matrix:
include:
- os: linux
dist: xenial
- os: osx
osx_image: xcode12.2
sudo: required
language: cpp
addons:
apt:
sources:
- xenial
- sourceline: 'deb http://archive.ubuntu.com/ubuntu xenial main'
- sourceline: 'ppa:mhier/libboost-latest'
packages:
- gcc
- g++
- libjsoncpp-dev
- uuid-dev
- zlib1g-dev
- postgresql-server-dev-10
- openssl
- libssl-dev
- libsqlite3-dev
- mariadb-client
- mariadb-server
- build-essential
- cmake
- boost1.67
- libbrotli-dev
homebrew:
packages:
- jsoncpp
- ossp-uuid
- openssl
- cmake
- libtool
- lz4
- mariadb
- sqlite3
update: true
mariadb: '10.0'
before_install:
- wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz
- tar xf release-1.10.0.tar.gz
- cd googletest-release-1.10.0
- cmake .
- make
- sudo make install
- cd -
before_script:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew tap homebrew/services;
brew services restart postgresql;
brew services start mariadb;
sleep 4;
mariadb -e "CREATE USER 'root'@'localhost' IDENTIFIED BY ''";
mariadb -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('')";
mariadb -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost'";
mariadb -e "FLUSH PRIVILEGES";
brew services restart mariadb;
sleep 4;
psql -c 'create user postgres superuser;' postgres;
fi
services:
- postgresql
- mysql
script:
- ./build.sh -t
- ./test.sh -t
- sudo rm /usr/local/lib/libtrantor.a && sudo rm /usr/local/lib/libdrogon.a
- ./build.sh -tshared
- ./test.sh -t

View File

@ -1,574 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(drogon)
message(STATUS "compiler: " ${CMAKE_CXX_COMPILER_ID})
# If your cross compile is failing, you should set
# CMAKE_SYSTEM_NAME in your toolchain file
if (NOT CMAKE_CROSSCOMPILING)
set(BUILD_PROGRAMS ON)
else ()
set(BUILD_PROGRAMS OFF)
endif ()
option(BUILD_CTL "Build drogon_ctl" ${BUILD_PROGRAMS})
option(BUILD_EXAMPLES "Build examples" ${BUILD_PROGRAMS})
option(BUILD_ORM "Build orm" ON)
option(COZ_PROFILING "Use coz for profiling" OFF)
option(BUILD_DROGON_SHARED "Build drogon as a shared lib" OFF)
include(CMakeDependentOption)
CMAKE_DEPENDENT_OPTION(BUILD_POSTGRESQL "Build with postgresql support" ON "BUILD_ORM" OFF)
CMAKE_DEPENDENT_OPTION(LIBPQ_BATCH_MODE "Use batch mode for libpq" ON "BUILD_POSTGRESQL" OFF)
CMAKE_DEPENDENT_OPTION(BUILD_MYSQL "Build with mysql support" ON "BUILD_ORM" OFF)
CMAKE_DEPENDENT_OPTION(BUILD_SQLITE "Build with sqlite3 support" ON "BUILD_ORM" OFF)
CMAKE_DEPENDENT_OPTION(BUILD_REDIS "Build with redis support" ON "BUILD_ORM" OFF)
set(DROGON_MAJOR_VERSION 1)
set(DROGON_MINOR_VERSION 6)
set(DROGON_PATCH_VERSION 0)
set(DROGON_VERSION
${DROGON_MAJOR_VERSION}.${DROGON_MINOR_VERSION}.${DROGON_PATCH_VERSION})
set(DROGON_VERSION_STRING "${DROGON_VERSION}")
# Offer the user the choice of overriding the installation directories
set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
set(DEF_INSTALL_DROGON_CMAKE_DIR lib/cmake/Drogon)
set(INSTALL_DROGON_CMAKE_DIR ${DEF_INSTALL_DROGON_CMAKE_DIR}
CACHE PATH "Installation directory for cmake files")
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# Force MSVC to use UTF-8 because that's what we use. Otherwise it uses
# the default of whatever Windows sets and causes encoding issues.
message(STATUS "You are using MSVC. Forceing to use UTF-8")
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif ()
if (BUILD_DROGON_SHARED)
set(BUILD_TRANTOR_SHARED TRUE)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
find_package(Threads)
# set(BUILD_EXAMPLES FALSE)
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
"${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}" isSystemDir)
if ("${isSystemDir}" STREQUAL "-1")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}")
endif ("${isSystemDir}" STREQUAL "-1")
add_library(${PROJECT_NAME} SHARED)
set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${DROGON_VERSION}
SOVERSION ${DROGON_MAJOR_VERSION})
target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads)
if (WIN32)
target_link_libraries(${PROJECT_NAME} PUBLIC Rpcrt4 ws2_32 crypt32 Advapi32)
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
# Ignore MSVC C4251 and C4275 warning of exporting std objects with no dll export
# We export class to facilitate maintenance, thus if you compile
# drogon on windows as a shared library, you will need to use
# exact same compiler for drogon and your app.
target_compile_options(${PROJECT_NAME} PUBLIC /wd4251 /wd4275)
endif ()
endif ()
else (BUILD_DROGON_SHARED)
add_library(${PROJECT_NAME} STATIC)
endif (BUILD_DROGON_SHARED)
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror)
endif ()
include(GenerateExportHeader)
generate_export_header(${PROJECT_NAME} EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
include(cmake/DrogonUtilities.cmake)
include(cmake/ParseAndAddDrogonTests.cmake)
include(CheckIncludeFileCXX)
check_include_file_cxx(any HAS_ANY)
check_include_file_cxx(string_view HAS_STRING_VIEW)
check_include_file_cxx(coroutine HAS_COROUTINE)
if (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
set(DROGON_CXX_STANDARD 20)
elseif (HAS_ANY AND HAS_STRING_VIEW)
set(DROGON_CXX_STANDARD 17)
else ()
set(DROGON_CXX_STANDARD 14)
endif ()
target_include_directories(
${PROJECT_NAME}
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib/inc>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/orm_lib/inc>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/nosql_lib/redis/inc>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/trantor>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/exports>
$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>)
if (WIN32)
target_include_directories(
${PROJECT_NAME}
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/third_party/mman-win32>)
endif (WIN32)
add_subdirectory(trantor)
target_link_libraries(${PROJECT_NAME} PUBLIC trantor)
if (NOT WIN32)
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
target_link_libraries(${PROJECT_NAME} PRIVATE dl)
endif (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
else (NOT WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi)
endif (NOT WIN32)
if (DROGON_CXX_STANDARD EQUAL 14)
# With C++14, use boost to support any and string_view
message(STATUS "use c++14")
find_package(Boost 1.61.0 REQUIRED)
message(STATUS "boost include dir:" ${Boost_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::boost)
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${Boost_INCLUDE_DIR})
elseif (DROGON_CXX_STANDARD EQUAL 17)
message(STATUS "use c++17")
else ()
message(STATUS "use c++20")
endif ()
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules/)
# jsoncpp
find_package(Jsoncpp REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_lib)
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW ${JSONCPP_INCLUDE_DIRS})
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD"
AND NOT WIN32)
find_package(UUID REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE UUID_lib)
try_compile(normal_uuid ${CMAKE_BINARY_DIR}/cmaketest
${PROJECT_SOURCE_DIR}/cmake/tests/normal_uuid_lib_test.cc
LINK_LIBRARIES UUID_lib)
try_compile(ossp_uuid ${CMAKE_BINARY_DIR}/cmaketest
${PROJECT_SOURCE_DIR}/cmake/tests/ossp_uuid_lib_test.cc
LINK_LIBRARIES UUID_lib)
if (normal_uuid)
add_definitions(-DUSE_OSSP_UUID=0)
elseif (ossp_uuid)
add_definitions(-DUSE_OSSP_UUID=1)
else ()
message(FATAL_ERROR "uuid lib error")
endif ()
endif (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"
AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD"
AND NOT WIN32)
find_package(Brotli)
if (Brotli_FOUND)
message(STATUS "Brotli found")
add_definitions(-DUSE_BROTLI)
target_link_libraries(${PROJECT_NAME} PRIVATE Brotli_lib)
endif (Brotli_FOUND)
set(DROGON_SOURCES
lib/src/AOPAdvice.cc
lib/src/CacheFile.cc
lib/src/ConfigLoader.cc
lib/src/Cookie.cc
lib/src/DrClassMap.cc
lib/src/DrTemplateBase.cc
lib/src/FiltersFunction.cc
lib/src/HttpAppFrameworkImpl.cc
lib/src/HttpBinder.cc
lib/src/HttpClientImpl.cc
lib/src/HttpControllersRouter.cc
lib/src/HttpFileImpl.cc
lib/src/HttpFileUploadRequest.cc
lib/src/HttpRequestImpl.cc
lib/src/HttpRequestParser.cc
lib/src/HttpResponseImpl.cc
lib/src/HttpResponseParser.cc
lib/src/HttpServer.cc
lib/src/HttpSimpleControllersRouter.cc
lib/src/HttpUtils.cc
lib/src/HttpViewData.cc
lib/src/IntranetIpFilter.cc
lib/src/ListenerManager.cc
lib/src/LocalHostFilter.cc
lib/src/MultiPart.cc
lib/src/NotFound.cc
lib/src/PluginsManager.cc
lib/src/SecureSSLRedirector.cc
lib/src/AccessLogger.cc
lib/src/SessionManager.cc
lib/src/StaticFileRouter.cc
lib/src/TaskTimeoutFlag.cc
lib/src/Utilities.cc
lib/src/WebSocketClientImpl.cc
lib/src/WebSocketConnectionImpl.cc
lib/src/WebsocketControllersRouter.cc)
if (NOT WIN32)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/SharedLibManager.cc)
else (NOT WIN32)
set(DROGON_SOURCES ${DROGON_SOURCES} third_party/mman-win32/mman.c)
endif (NOT WIN32)
if (BUILD_POSTGRESQL)
# find postgres
find_package(pg)
if (pg_FOUND)
message(STATUS "libpq inc path:" ${PG_INCLUDE_DIRS})
message(STATUS "libpq lib:" ${PG_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PRIVATE pg_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PostgreSQLResultImpl.cc)
if (LIBPQ_BATCH_MODE)
try_compile(libpq_supports_batch ${CMAKE_BINARY_DIR}/cmaketest
${PROJECT_SOURCE_DIR}/cmake/tests/test_libpq_batch_mode.cc
LINK_LIBRARIES ${PostgreSQL_LIBRARIES}
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PostgreSQL_INCLUDE_DIR}")
endif (LIBPQ_BATCH_MODE)
if (libpq_supports_batch)
message(STATUS "The libpq supports batch mode")
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" ON)
set(DROGON_SOURCES ${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PgBatchConnection.cc)
else (libpq_supports_batch)
option(LIBPQ_SUPPORTS_BATCH_MODE "libpq batch mode" OFF)
set(DROGON_SOURCES ${DROGON_SOURCES}
orm_lib/src/postgresql_impl/PgConnection.cc)
endif (libpq_supports_batch)
endif (pg_FOUND)
endif (BUILD_POSTGRESQL)
if (BUILD_MYSQL)
# Find mysql, only mariadb client liberary is supported
find_package(MySQL)
if (MySQL_FOUND)
message(STATUS "Ok! We find the mariadb!")
target_link_libraries(${PROJECT_NAME} PRIVATE MySQL_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
orm_lib/src/mysql_impl/MysqlConnection.cc
orm_lib/src/mysql_impl/MysqlResultImpl.cc)
endif (MySQL_FOUND)
endif (BUILD_MYSQL)
if (BUILD_SQLITE)
# Find sqlite3.
find_package(SQLite3)
if (SQLite3_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite3_lib)
set(DROGON_SOURCES ${DROGON_SOURCES}
orm_lib/src/sqlite3_impl/Sqlite3Connection.cc
orm_lib/src/sqlite3_impl/Sqlite3ResultImpl.cc)
endif (SQLite3_FOUND)
endif (BUILD_SQLITE)
if (BUILD_REDIS)
find_package(Hiredis)
if (Hiredis_FOUND)
add_definitions(-DUSE_REDIS)
target_link_libraries(${PROJECT_NAME} PRIVATE Hiredis_lib)
set(DROGON_SOURCES
${DROGON_SOURCES}
nosql_lib/redis/src/RedisClientImpl.cc
nosql_lib/redis/src/RedisConnection.cc
nosql_lib/redis/src/RedisResult.cc
nosql_lib/redis/src/RedisClientLockFree.cc
nosql_lib/redis/src/RedisClientManager.cc
nosql_lib/redis/src/RedisTransactionImpl.cc)
endif (Hiredis_FOUND)
endif (BUILD_REDIS)
if (NOT Hiredis_FOUND)
set(DROGON_SOURCES
${DROGON_SOURCES}
lib/src/RedisClientSkipped.cc
lib/src/RedisResultSkipped.cc
lib/src/RedisClientManagerSkipped.cc)
endif (NOT Hiredis_FOUND)
if (BUILD_TESTING)
add_subdirectory(nosql_lib/redis/tests)
endif (BUILD_TESTING)
find_package(ZLIB REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE ZLIB::ZLIB)
find_package(OpenSSL)
if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
else (OpenSSL_FOUND)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/ssl_funcs/Md5.cc
lib/src/ssl_funcs/Sha1.cc)
endif (OpenSSL_FOUND)
execute_process(COMMAND "git" rev-parse HEAD
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE GIT_SHA1
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/version.h.in"
"${PROJECT_SOURCE_DIR}/lib/inc/drogon/version.h" @ONLY)
if (DROGON_CXX_STANDARD EQUAL 20)
option(USE_COROUTINE "Enable C++20 coroutine support" ON)
else (DROGON_CXX_STANDARD EQUAL 20)
option(USE_COROUTINE "Enable C++20 coroutine support" OFF)
endif (DROGON_CXX_STANDARD EQUAL 20)
if (BUILD_EXAMPLES)
add_subdirectory(examples)
endif (BUILD_EXAMPLES)
if (BUILD_CTL)
add_subdirectory(drogon_ctl)
endif (BUILD_CTL)
if (COZ_PROFILING)
find_package(coz-profiler REQUIRED)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DCOZ_PROFILING=1)
# If linked will not need to be ran with `coz run --- [executable]` to run the
# profiler, but drogon_ctl currently won't build because it doesn't find debug
# information while trying to generate it's own sources
# target_link_libraries(${PROJECT_NAME} PUBLIC coz::coz)
target_include_directories(${PROJECT_NAME} PUBLIC ${COZ_INCLUDE_DIRS})
endif (COZ_PROFILING)
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/ArrayParser.cc
orm_lib/src/Criteria.cc
orm_lib/src/DbClient.cc
orm_lib/src/DbClientImpl.cc
orm_lib/src/DbClientLockFree.cc
orm_lib/src/DbConnection.cc
orm_lib/src/Exception.cc
orm_lib/src/Field.cc
orm_lib/src/Result.cc
orm_lib/src/Row.cc
orm_lib/src/SqlBinder.cc
orm_lib/src/TransactionImpl.cc
orm_lib/src/RestfulController.cc)
if (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
set(DROGON_SOURCES
${DROGON_SOURCES}
orm_lib/src/DbClientManager.cc)
else (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
set(DROGON_SOURCES ${DROGON_SOURCES} lib/src/DbClientManagerSkipped.cc)
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
target_sources(${PROJECT_NAME} PRIVATE ${DROGON_SOURCES})
set_target_properties(${PROJECT_NAME}
PROPERTIES CXX_STANDARD ${DROGON_CXX_STANDARD})
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD_REQUIRED ON)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF)
set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME Drogon)
if (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
if (pg_FOUND)
option(USE_POSTGRESQL "Enable PostgreSQL" ON)
else (pg_FOUND)
option(USE_POSTGRESQL "Disable PostgreSQL" OFF)
endif (pg_FOUND)
if (MySQL_FOUND)
option(USE_MYSQL "Enable Mysql" ON)
else (MySQL_FOUND)
option(USE_MYSQL "DisableMysql" OFF)
endif (MySQL_FOUND)
if (SQLite3_FOUND)
option(USE_SQLITE3 "Enable Sqlite3" ON)
else (SQLite3_FOUND)
option(USE_SQLITE3 "Disable Sqlite3" OFF)
endif (SQLite3_FOUND)
endif (pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
set(COMPILER_COMMAND ${CMAKE_CXX_COMPILER})
set(COMPILER_ID ${CMAKE_CXX_COMPILER_ID})
if (CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
if (_type STREQUAL release)
set(COMPILATION_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -std=c++")
elseif (_type STREQUAL debug)
set(COMPILATION_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} -std=c++")
else ()
set(COMPILATION_FLAGS "-std=c++")
endif ()
else (CMAKE_BUILD_TYPE)
set(COMPILATION_FLAGS "-std=c++")
endif (CMAKE_BUILD_TYPE)
list(APPEND INCLUDE_DIRS_FOR_DYNAMIC_VIEW
"${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}")
list(REMOVE_DUPLICATES INCLUDE_DIRS_FOR_DYNAMIC_VIEW)
set(INS_STRING "")
foreach (loop_var ${INCLUDE_DIRS_FOR_DYNAMIC_VIEW})
set(INS_STRING "${INS_STRING} -I${loop_var}")
endforeach (loop_var)
set(INCLUDING_DIRS ${INS_STRING})
configure_file(${PROJECT_SOURCE_DIR}/cmake/templates/config.h.in
${PROJECT_BINARY_DIR}/drogon/config.h @ONLY)
if (BUILD_TESTING)
message(STATUS "Building tests")
enable_testing()
add_subdirectory(lib/tests)
if (pg_FOUND)
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/postgresql_impl/test)
endif (pg_FOUND)
if (MySQL_FOUND)
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/mysql_impl/test)
endif (MySQL_FOUND)
if (SQLite3_FOUND)
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/src/sqlite3_impl/test)
endif (SQLite3_FOUND)
add_subdirectory(${PROJECT_SOURCE_DIR}/orm_lib/tests)
endif (BUILD_TESTING)
# Installation
install(TARGETS ${PROJECT_NAME}
EXPORT DrogonTargets
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib)
set(DROGON_HEADERS
lib/inc/drogon/Attribute.h
lib/inc/drogon/CacheMap.h
lib/inc/drogon/Cookie.h
lib/inc/drogon/DrClassMap.h
lib/inc/drogon/DrObject.h
lib/inc/drogon/DrTemplate.h
lib/inc/drogon/DrTemplateBase.h
lib/inc/drogon/HttpAppFramework.h
lib/inc/drogon/HttpBinder.h
lib/inc/drogon/HttpClient.h
lib/inc/drogon/HttpController.h
lib/inc/drogon/HttpFilter.h
lib/inc/drogon/HttpRequest.h
lib/inc/drogon/HttpResponse.h
lib/inc/drogon/HttpSimpleController.h
lib/inc/drogon/HttpTypes.h
lib/inc/drogon/HttpViewData.h
lib/inc/drogon/IntranetIpFilter.h
lib/inc/drogon/IOThreadStorage.h
lib/inc/drogon/LocalHostFilter.h
lib/inc/drogon/MultiPart.h
lib/inc/drogon/NotFound.h
lib/inc/drogon/Session.h
lib/inc/drogon/UploadFile.h
lib/inc/drogon/WebSocketClient.h
lib/inc/drogon/WebSocketConnection.h
lib/inc/drogon/WebSocketController.h
lib/inc/drogon/drogon.h
lib/inc/drogon/version.h
lib/inc/drogon/drogon_callbacks.h
lib/inc/drogon/PubSubService.h
lib/inc/drogon/drogon_test.h
${CMAKE_CURRENT_BINARY_DIR}/exports/drogon/exports.h)
install(FILES ${DROGON_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon)
set(ORM_HEADERS
orm_lib/inc/drogon/orm/ArrayParser.h
orm_lib/inc/drogon/orm/Criteria.h
orm_lib/inc/drogon/orm/DbClient.h
orm_lib/inc/drogon/orm/DbTypes.h
orm_lib/inc/drogon/orm/Exception.h
orm_lib/inc/drogon/orm/Field.h
orm_lib/inc/drogon/orm/FunctionTraits.h
orm_lib/inc/drogon/orm/Mapper.h
orm_lib/inc/drogon/orm/CoroMapper.h
orm_lib/inc/drogon/orm/Result.h
orm_lib/inc/drogon/orm/ResultIterator.h
orm_lib/inc/drogon/orm/Row.h
orm_lib/inc/drogon/orm/RowIterator.h
orm_lib/inc/drogon/orm/SqlBinder.h
orm_lib/inc/drogon/orm/RestfulController.h)
install(FILES ${ORM_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/orm)
set(NOSQL_HEADERS nosql_lib/redis/inc/drogon/nosql/RedisClient.h
nosql_lib/redis/inc/drogon/nosql/RedisResult.h
nosql_lib/redis/inc/drogon/nosql/RedisException.h)
install(FILES ${NOSQL_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/nosql)
set(DROGON_UTIL_HEADERS
lib/inc/drogon/utils/FunctionTraits.h
lib/inc/drogon/utils/Utilities.h
lib/inc/drogon/utils/any.h
lib/inc/drogon/utils/string_view.h
lib/inc/drogon/utils/optional.h
lib/inc/drogon/utils/coroutine.h
lib/inc/drogon/utils/HttpConstraint.h
lib/inc/drogon/utils/OStringStream.h)
install(FILES ${DROGON_UTIL_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
set(DROGON_PLUGIN_HEADERS lib/inc/drogon/plugins/Plugin.h
lib/inc/drogon/plugins/SecureSSLRedirector.h
lib/inc/drogon/plugins/AccessLogger.h)
install(FILES ${DROGON_PLUGIN_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
source_group("Public API"
FILES
${DROGON_HEADERS}
${ORM_HEADERS}
${DROGON_UTIL_HEADERS}
${DROGON_PLUGIN_HEADERS}
${NOSQL_HEADERS})
# Export the package for use from the build-tree (this registers the build-tree
# with a global cmake-registry) export(PACKAGE Drogon)
include(CMakePackageConfigHelpers)
# ... for the install tree
configure_package_config_file(
cmake/templates/DrogonConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DrogonConfig.cmake
INSTALL_DESTINATION
${INSTALL_DROGON_CMAKE_DIR})
# version
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/DrogonConfigVersion.cmake
VERSION ${DROGON_VERSION}
COMPATIBILITY SameMajorVersion)
# Install the DrogonConfig.cmake and DrogonConfigVersion.cmake
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DrogonConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/DrogonConfigVersion.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindUUID.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindJsoncpp.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindSQLite3.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindMySQL.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findpg.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindBrotli.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findcoz-profiler.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindHiredis.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/DrogonUtilities.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/ParseAndAddDrogonTests.cmake"
DESTINATION "${INSTALL_DROGON_CMAKE_DIR}"
COMPONENT dev)
# Install the export set for use with the install-tree
install(EXPORT DrogonTargets
DESTINATION "${INSTALL_DROGON_CMAKE_DIR}"
NAMESPACE Drogon::
COMPONENT dev)

View File

@ -1,78 +0,0 @@
# Contributing
**Drogon** is an open source project at its heart and every contribution is
welcome. By participating in this project you agree to stick to common sense and
contribute in an overall positive way.
## Getting Started
1. Fork, then clone the repository: `git clone
git@github.com:your-username/drogon.git`
1. Follow the [official installation steps on
DocsForge](https://drogon.docsforge.com/master/installation/). Its best to
make sure to have the `drogon_ctl` executable in your shells `PATH`
environment variable in case you use a terminal.
Now you can create branches, start adding features & bugfixes to the code, and
[create pull requests](https://github.com/an-tao/drogon/compare).
## Pull Requests
Feel free to [create a pull request](https://github.com/an-tao/drogon/compare)
if you think you can contribute to the project. You will be listed as a
[contributor](https://github.com/an-tao/drogon/graphs/contributors), agree to
this document, and the
[LICENSE](https://github.com/an-tao/drogon/blob/master/LICENSE).
There are also some recommendations you can follow. These arent requirements,
but they will make the development more straightforward:
1. If you are unsure about a specific change, have questions, or want to get
feedback about a feature you want to introduce, [open a new
issue](https://github.com/an-tao/drogon/issues) (please make sure that there
is no previous issue about a similar topic).
1. You should branch off the current state of the `master` branch, and also
merge it into your local branch before creating a pull request if there were
other changes introduced in the meantime.
1. You can use the following branch names to make your intent clearer:
* `bugfix/123-fix-template-parser` when you want to fix a bug in the
template parser.
* `feature/123-add-l10n-and-i18n` if you want to add localization (l10n) and
internationalization (i18n) as a new feature to the project.
* If theres no open issue and no need to open one you can skip the number,
and just use the descriptive part: `bugfix/fix-typo-in-docs`.
1. Write a brief, but good, and descriptive commit message / pull request title in English,
e. g. “Added Internationalization and Localization”.
If you follow these recommendations your pull request will have more success:
1. Keep the style consistent to the project, when in doubt refer to the [Google
C++ Style Guide](https://google.github.io/styleguide/cppguide.html#C++_Version).
1. Please write all comments in English. Comments for new public API introduced by
your pull request must be added and written in [Doxygen](http://www.doxygen.nl/) format.
1. Format the code with `clang-format` (>= 8.0.0). The configuration is already
provided in the `.clang-format` file, just run the `./format.sh` script
before submitting your pull request.
1. Install [Google Test](https://github.com/google/googletest), and write a test
case.
1. In case it is a bugfix, its best to write a test that breaks in the old
version, but works in the new one. This way regressions can be tracked
over time.
1. If you add a feature, it is best to write the test as if it would be an
example how to use the newly introduced feature and to test all major,
newly introduced code.
## Project Maintainers & Collaborators
In addition to the guidelines mentioned above, collaborators with write access
to the repository should also follow these guidelines:
1. If there are new tests as part of the pull request, you should make sure that
they succeed.
1. When merging **Pull Requests** you should use the option *Squash & Merge* and
chose a descriptive commit message for the bugfix / feature (if not already
done by the individual contributor).
This way the history in the `master` branch will be free of small
corrections and easier to follow for people who arent engaged in the
project on a day-to-day basis.

View File

@ -1,837 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
## [Unreleased]
## [1.6.0] - 2021-05-15
### API changes list
- Add option to set default handler.
- Add the setTimeout() method to the DbClient class and the RedisClient class.
- Add the validateCert parameter to the newWebSocketClient method.
### Changed
- A few mini changes to drogon_ctl command.
- Improve the MultiPartParser class.
- Add GNU -Werror & fix warnings.
- Enhancements on files part.
- Add version/soversion to shared library.
- Disallow coroutines to be resolved as plain subroutine handlers.
- Send the content-length header even if the body(POST,PUT,OPTIONS,PATCH) is empty.
- Use make_exception_ptr instead of throw/catch when possible.
- Remove duplicated inclusion.
- Print error before terminating in AsyncTask.
- Allow users to override drogon Find modules.
- Use two-phase construction for the DbClientImpl and the RedisClientImpl.
- Add support 'select <db>' for redis.
### Fixed
- Fix a bug of the Transaction class.
- Copy CoroMapper.h to installation location.
- Remove the related request from the buffer if it's not sent after the timeout.
- Fix ORM with SQLite3 not compiling on Arch Linux.
- Fix an error when constructing RedisClientImpl objects.
- Fix coroutine frame leak upon assigning to awaitable.
- Set running flag to true before installing plugins.
- Fix double free in coroutine exception handling.
## [1.5.1] - 2021-04-10
### Fixed
- Fix a bug of reflection failure.
## [1.5.0] - 2021-04-10
### API changes list
- Add option to disable signal handling.
- Added newFileResponse Support for buffers in memory.
- Add a method to HttpRequest to set the user_agent header.
- Catch exceptions thrown by handlers.
### Changed
- Add convert method to models.
- Add Arch Dockerfile.
- Add Redis support.
- Print error and exit when IP parsing failed in server startup.
- Use a canonical way of calling max() function on Windows.
- Remove an assertion statement in the HttpClientImpl class.
- Send ping messages by default for WebSockets.
- Use canonical cmake logic for cross-compilation.
- set make job count to the number of threads in GitHub Actions workflow.
- Use lambda instead of std::bind in HttpServer.
- Add exports macro to allow Shared Library with hidden symbols by default.
- Remove repeated class names on relationships from the model generator.
### Fixed
- Fix compile warnings in SQL client.
- Fix compilation errors for the TimeFilter example.
- Fix build.sh missing nproc error in build for macOS.
- Fix a bug when creating sqlite3 models.
- Fix two building corner cases, CMake quality of life improvements.
- Add CoroMapper to models' friends.
## [1.4.1] - 2021-03-07
### Fixed
- Fix a bug of DbClientImpl class that can lead to a crash when database connections are breaking.
## [1.4.0] - 2021-03-05
### API changes list
- Add coroutine support.
- Add default value interface to SqlBinder for MySQL and PostgreSQL.
- Support SNI in the HttpClient class.
- Validate certificate in HttpClient.
- HttpRequest: add a feature to avoid URL encoding of the path.
### Changed
- Handle cross-compiling properly.
- Lowercase all HTTP headers, add webp and avif types.
- Modify FindMySQL.cmake
### Fixed
- Fix an error in the HttpClient class when a response has no content-length.
- Return 404 or 405 responses correctly.
- Fix compilation errors on vs2019.
- Fix stack use after scope error in client_example.
- Fix the error when the SSL handshake fails.
## [1.3.0] - 2021-01-16
### API changes list
- Add an option for setting float precision in Json string.
### Fixed
- Fix brotli link order.
- Fix cmake with drogonctl cross-compilation.
- sqlite3: Insert into stmtsMap_ as string_view.
- Fix some bugs when creating models via drogon_ctl.
- Fix an error in sqlite3 ORM generator.
- Fix an error with missing composite key to sqlite3 ORM generator.
### Changed
- Remove the use of std::filesystem to adapt to old compilers.
- Add github actions.
- Serve wasm files with the correct MIME type.
## [1.2.0] - 2020-12-12
### Fixed
- Fix error when receiving response without content-length header.
- Fix a stack-overflow error when high concurrency happening on sqlite3.
- Fix MinGW ORM building by enabling htonll and ntohll.
### Changed
- Modify the WebSocketTest controller to create a simple chat room.
- Add support for OpenBSD.
- Return 400 if the content-length is invalid.
- Don't send content type in a 304 response.
- Add the reuse_port option to app() interface.
- Add the 'std::optional' support in the SqlBinder class and the Session class.
- Add implicit page resolving capability.
## [1.1.0] - 2020-10-31
### Fixed
- Fix failing to connect to DB if parameters contains spaces.
- Fix a CMAKE bug when SHARED and EXAMPLES are on.
- Fix the HttpServer::isWebSocket method.
- Find MariaDB client library correctly on Ubuntu 20.04.
- Fix a bug when creating sqlite3 database models.
- Fix a bug in the Mapper::insertFuture method.
### Changed
- Disable TLS1.0/1.1 on HTTPS by default.
- Use explicit lambda capture lists.
- Modify the procedure of the app().run() method.
- Support namespaces when creating view source files.
- Add --path-to-namespace option to drogon_ctl for creating views.
- Add the Host and Sec-WebSocket-Version headers when connecting to a websocket server.
## [1.0.0] - 2020-09-27
### Fixed
- Fix an issue of simple_reverse_proxy when handling chunked transfer-encoding.
- Fix a bug when losting connection to MySQL server during query.
- Remove the expired std::iterator template.
- Fix a bug when creating models in some special cases.
### API changes list
- Modify methods related to headers.
- Remove the expired std::iterator template.
- Add getListeners() method to the HttpAppFramework class.
- Remove the useless method stat() from the PluginBase class.
- Add ConfigLoader::ConfigLoader(const Json::Value &data).
### Changed
- Add support for status code 418.
- Modify session handling.
- Modify the FileUpload.csp in simple_example to avoid CORS.
- remove execution permission on /tmp/drogon.lock.
## [1.0.0-beta21] - 2020-08-19
### Changed
- Modify the Result class in ORM.
### Fixed
- Fix zlib link error on Windows for the latest vcpkg.
## [1.0.0-beta20] - 2020-08-15
### API changes list
- Provide users with a method to change the session ID of a session.
### Changed
- Modify parseContentType function.
- Modify the docker file to build release version in docker.
- Set session to requests for websockets.
- Modify parseContentType function.
- Change the return value type of the mktime() function in models.
- Fix compilation warning of sprintf function.
### Fixed
- Fix a bug when saving uploaded files on Windows.
- Fix a MySQL issue when connections are lost.
- Resolve an issue when sending big files (>=2GB) on Windows.
- Fix boost::string_view compilation error of MysqlConnection class.
- Set the response Access-Control-Allow-Headers header correctly for CORS.
- Fix a bug in drogon_ctl when creating a model, that causes to write source files multiple times.
## [1.0.0-beta19] - 2020-07-16
### API changes list
- Add a method to disable unicode escaping in json string.
- Add a timeout parameter when sending HTTP requests.
- Add the getJsonError method.
### Changed
- Remove the restriction on the location of layout tags in views.
- Add a way to set the character set when creating DbClient objects.
- Make `GET` as the only method for accessing static files.
- Modify the 404 pages generator.
- Modify the DbClient class.
- Optimize the HttpResponse class.
### Fixed
- Properly handle chunked encoding requests.
- Destroy DNS resolver of HttpClient in the correct thread.
- Add the header <cctype> to resolve build errors in VS2017.
## [1.0.0-beta18] - 2020-06-14
### API changes list
- Add a new joinpoint of AOP for modification on each HTTP response.
- Add a method for the TERM signal handling.
- Add getContextRef method to the WebSocketConnection class.
### Changed
- Create a class template for publish subscribe pattern.
- Add contribution recommendations.
- Send a close message when closing a web socket connection.
- Add additional formats for getHttpDate function.
- Make app().run() method callable on a non-main thread.
- Add digest filter in examples.
- Use string_view to parse multipart/form-data requests.
### Fixed
- Fix building of ORM on FreeBSD.
- Fix a Mysql connection error on Windows.
- Fix a bug in ListenerManager::getIOLoop().
- Fix the count() method of Mysql ORM.
- Fix a compilation issue on windows.
- Fix model generation for PostgreSQL primary keys.
- Fix a bug with quoted column names in sqlite3 databases.
## [1.0.0-beta17] - 2020-05-22
### API changes list
- Add methods to get DbClient connection status
### Changed
- Add causal profiling with coz
- Add filters on static file locations
- Pass data from view to its layout container
- Add additional HttpStatusCodes and implement a custom error handler
- Modify drogon_ctl to show more compilation information
### Fixed
- Fix a bug in drogon_ctl (when size of a line is larger than buffer size)
- Fix a connection bug of MariaDB clients
## [1.0.0-beta16] - 2020-04-27
### API changes list
- Standardize Row and Result api in ORM
### Changed
- Add support for brotli compression
- Parse content-type of HTTP requests
- Remove non standard macros
- Support url safe base64 codec
## [1.0.0-beta15] - 2020-03-28
### API changes list
- Modify the Attributes interface of the HttpRequest class
- Add the getHomePage() method to HttpAppFramework
### Changed
- Support br compression files
- Update Content-Type support for PDF
- Add support for MSVC 2015
- Optimize the rendering of HTTP responses
- Update the Dynamic Views Loading, add the `layout` tag
- Graceful shutdown
### Fixed
- Fix error when finding the jsoncpp library
- Fix the 'many to many' relationship in ORM
- Fix a bug when creating json responses
- Fix a bug on filters with WebSocketControllers
- Fix a fatal bug in the MysqlConnection class
- Fix crash with partial matched url
- Fix null jsonObject from newHttpJsonRequest
## [1.0.0-beta14] - 2020-02-17
### API changes list
- None
### Added
- Add IOLoop access function
### Changed
- Add support for regular expressions when routing
- Add location configuration for static resources
- Port drogon to Windows
- Support 'password' keyword in configuration files
- Remove get_version.sh
- Modify dynamic view loading algorithm, add 'layout' tag for view generation.
### Fixed
- Fix an issue of out-of-range (#334)
- Fix a bug in views generation (#341)
## [1.0.0-beta13] - 2020-01-04
### API changes list
- None
### Changed
- Add some unit tests (based on gtest)
- Add a reverse proxy example
- Make a patch to support the ossp UUID library
- Make shared linking possible
- Add the drogon::OStringStream class
- Optimize ORM
- Modify singleton logic of DrClassMap
### Fixed
- Fix an error in the batch mode of libpq
- Fix an error when clients use HTTP1.0
## [1.0.0-beta12] - 2019-11-30
### Changed
- Make dg_ctl a symlink
- Modify some code styles
- Explicitly set path to '/' for JSESSIONID cookie
- Handle gzip errors safely
- Add the SecureSSLRedirector plugin
### Fixed
- Fix a bug in dg_ctl for creating models of sqlite3
- Reset the flag used to parse json to false before recycling HttpRequest objects
## [1.0.0-beta11] - 2019-11-06
### Changed
- Delete useless log output
## [1.0.0-beta10] - 2019-11-04
### API changes list
- None
### Changed
- Add the headers configuration option for static files
### Fixed
- Fix(compilation on alpine): Replace u_short alias.
## [1.0.0-beta9] - 2019-10-28
### API changes list
- Add interfaces for accessing content of attachments.
- Add option to disable setting the 404 status code of the custom 404 page.
- Make user can use any string as a placeholder's name in routing patterns.
- Add type conversion methods to the HttpRequest and HttpResponse classes.
### Changed
- Modify cmake configuration.
- Modify the quit() method.
- Implement relationships in ORM.
### Fixed
- Fix size_t underflow of drogon_ctl.
- Fix some race conditions.
- Fix a busy loop bug when connections to MySQL server are timeout.
## [1.0.0-beta8] - 2019-10-03
### API changes list
- Add length() method to the Field class.
- Add `as<bool>()` function template specialization to the Field class.
- Add add attribute store methods to the HttpRequest class.
- Add the setCustomContentTypeString() method to the HttpRequest class.
- Add thread storage.
### Changed
- Use .find('x') instead of .find("x") in a string search.
- Add the ability to create restful API controllers.
### Fixed
- Fix a bug of creating models for MySQL.
- Fix a bug when HTTP method is PUT.
- Fix a bug when using 'is null' substatement in ORM.
- Fix a sqlite3 bug when some SQL errors occur.
- Fix bug with parsing json.
- Fix url decode.
- Fix a error in HttpClient.
- Fix a error in setThreadNum method.
- Fix some race conditions.
## [1.0.0-beta7] - 2019-08-31
### API changes list
- Remove the default value parameter of some methods (#220)
### Changed
- Optimize DNS in HttpClient and WebSocketClient (support c-ares library).
- Reduce dependencies between declarations.
- Add database tests in the travis CI and add test cases to database tests.
- Reduce size of docker image.
- Make the framework API support chained calls.
- Add a synchronous join point for AOP.
- Modify the CMakeLists to modern cmake style.
### Fixed
- Fix bugs in default return values of functions(#220),
- Fix a bug in the cmake configuration file when there's '+' in the building path.
- Fix a bug in drogon_ctl (when creating orm models)
## [1.0.0-beta6] - 2019-08-08
### API changes list
- None
### Changed
- Modify the 'create view' sub-command of drogon_ctl
- Optimize the transmission of pipelining responses.
- Add the DrogonConfig.cmake file so that users can use drogon with the `find_package(Drogon)` command.
## [1.0.0-beta5] - 2019-08-01
### API changes list
- None
### Added
- Add two methods to control if the Server header or the Date header is sent to clients with HTTP responses.
* void HttpAppFramework::enableServerHeader(bool);
* void HttpAppFramework::enableDateHeader(bool);
### Changed
- Support high performance batch mode of libpq.
### Fixed
- None
## [1.0.0-beta4] - 2019-07-30
### API changes list
- HttpRequest::query() returns a const reference of std::string instead of a string_view
- WebSocketConnection::setContext(), WebSocketConnection::getContext(), etc.
- Remove the config.h from public API.
### Added
- None
### Changed
- Modify the CMakeLists.txt
- Modify the get_version.sh
### Fixed
- None
## [1.0.0-beta3] - 2019-07-28
### API changes list
- None
### Added
- Add a README file for examples.
- Add some managers to reduce the size of the HttpAppFrameworkImpl code.
- Add missing wasm ContentType.
### Changed
- Update the submodule - trantor.
- Optimize processing of HTTP pipelining.
### Fixed
- Fix an error in the HttpClient class when sending a request using the HEAD method.
## [1.0.0-beta2] - 2019-07-10
### API changes list
- Add setBody methods to the HttpRequest class.
- Add the setContentTypeCodeAndCustomString method to the HttpResponse class.
### Added
- Add stress testing command to drogon_ctl.
- Add -v, -h parameters to drogon_ctl.
### Changed
- Update the submodule - trantor.
- Modify the handling of CORS.
- Optimize the htmlTranslate method and the Field class.
- Make all listeners share IO threads in the MacOS/Unix system.
### Fixed
- Fix a bug of the IsPlugin class.
- Use default constructor of string_view to reset _statusMessage to fix a warning on GCC 9.1 on Arch Linux.
## [1.0.0-beta1] - 2019-06-11
[Unreleased]: https://github.com/an-tao/drogon/compare/v1.6.0...HEAD
[1.6.0]: https://github.com/an-tao/drogon/compare/v1.5.1...v1.6.0
[1.5.1]: https://github.com/an-tao/drogon/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/an-tao/drogon/compare/v1.4.1...v1.5.0
[1.4.1]: https://github.com/an-tao/drogon/compare/v1.4.0...v1.4.1
[1.4.0]: https://github.com/an-tao/drogon/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/an-tao/drogon/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/an-tao/drogon/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/an-tao/drogon/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/an-tao/drogon/compare/v1.0.0-beta21...v1.0.0
[1.0.0-beta21]: https://github.com/an-tao/drogon/compare/v1.0.0-beta20...v1.0.0-beta21
[1.0.0-beta20]: https://github.com/an-tao/drogon/compare/v1.0.0-beta19...v1.0.0-beta20
[1.0.0-beta19]: https://github.com/an-tao/drogon/compare/v1.0.0-beta18...v1.0.0-beta19
[1.0.0-beta18]: https://github.com/an-tao/drogon/compare/v1.0.0-beta17...v1.0.0-beta18
[1.0.0-beta17]: https://github.com/an-tao/drogon/compare/v1.0.0-beta16...v1.0.0-beta17
[1.0.0-beta16]: https://github.com/an-tao/drogon/compare/v1.0.0-beta15...v1.0.0-beta16
[1.0.0-beta15]: https://github.com/an-tao/drogon/compare/v1.0.0-beta14...v1.0.0-beta15
[1.0.0-beta14]: https://github.com/an-tao/drogon/compare/v1.0.0-beta13...v1.0.0-beta14
[1.0.0-beta13]: https://github.com/an-tao/drogon/compare/v1.0.0-beta12...v1.0.0-beta13
[1.0.0-beta12]: https://github.com/an-tao/drogon/compare/v1.0.0-beta11...v1.0.0-beta12
[1.0.0-beta11]: https://github.com/an-tao/drogon/compare/v1.0.0-beta10...v1.0.0-beta11
[1.0.0-beta10]: https://github.com/an-tao/drogon/compare/v1.0.0-beta9...v1.0.0-beta10
[1.0.0-beta9]: https://github.com/an-tao/drogon/compare/v1.0.0-beta8...v1.0.0-beta9
[1.0.0-beta8]: https://github.com/an-tao/drogon/compare/v1.0.0-beta7...v1.0.0-beta8
[1.0.0-beta7]: https://github.com/an-tao/drogon/compare/v1.0.0-beta6...v1.0.0-beta7
[1.0.0-beta6]: https://github.com/an-tao/drogon/compare/v1.0.0-beta5...v1.0.0-beta6
[1.0.0-beta5]: https://github.com/an-tao/drogon/compare/v1.0.0-beta4...v1.0.0-beta5
[1.0.0-beta4]: https://github.com/an-tao/drogon/compare/v1.0.0-beta3...v1.0.0-beta4
[1.0.0-beta3]: https://github.com/an-tao/drogon/compare/v1.0.0-beta2...v1.0.0-beta3
[1.0.0-beta2]: https://github.com/an-tao/drogon/compare/v1.0.0-beta1...v1.0.0-beta2
[1.0.0-beta1]: https://github.com/an-tao/drogon/releases/tag/v1.0.0-beta1

View File

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

View File

@ -1,199 +0,0 @@
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
![Build Status](https://github.com/an-tao/drogon/workflows/Build%20Drogon/badge.svg?branch=master)
[![Build status](https://ci.appveyor.com/api/projects/status/12ffuf6j5vankgyb/branch/master?svg=true)](https://ci.appveyor.com/project/an-tao/drogon/branch/master)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/alerts/)
[![Join the chat at https://gitter.im/drogon-web/community](https://badges.gitter.im/drogon-web/community.svg)](https://gitter.im/drogon-web/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the telegram group at https://t.me/joinchat/_mMNGv0748ZkMDAx](https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/joinchat/_mMNGv0748ZkMDAx)
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
[English](./README.md) | [简体中文](./README.zh-CN.md) | 繁體中文
**Drogon**是一個基於C++14/17的Http應用框架使用Drogon可以方便的使用C++構建各種類型的Web App伺服器程式。
本版本庫是github上[Drogon](https://github.com/an-tao/drogon)的鏡像庫。 **Drogon**是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(漢譯作卓耿)和龍有關但並不是dragon的誤寫為了不至於引起不必要的誤會這裡說明一下。
Drogon是一個跨平台框架它支援Linux也支援macOS、FreeBSD/OpenBSD和Windows。它的主要特點如下
* 網路層使用基於epoll(macOS/FreeBSD下是kqueue)的非阻塞IO框架提供高並發、高性能的網路IO。詳細請見[TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite)
* 全異步程式設計;
* 支援Http1.0/1.1(server端和client端)
* 基於模板(template)實現了簡單的反射機制,使主程式框架、控制器(controller)和視圖(view)完全去耦;
* 支援cookies和內建的session
* 支援後端渲染把控制器生成的數據交給視圖生成Html頁面視圖由CSP模板文件描述通過CSP標籤把C++程式碼嵌入到Html頁面由drogon的指令列工具在編譯階段自動生成C++程式碼並編譯;
* 支援運行期的視圖頁面動態加載(動態編譯和載入so文件)
* 非常方便靈活的路徑(path)到控制器處理函數(handler)的映射方案;
* 支援過濾器(filter)鏈,方便在控制器之前執行統一的邏輯(如登錄驗證、Http Method約束驗證等)
* 支援https(基於OpenSSL);
* 支援websocket(server端和client端);
* 支援Json格式的請求和回應, 方便開發Restful API;
* 支援文件下載和上傳,支援sendfile系統呼叫
* 支援gzip/brotli壓縮傳輸
* 支援pipelining
* 提供一個輕量的指令列工具drogon_ctl幫助簡化各種類的創造和視圖程式碼的生成過程
* 非同步的讀寫資料庫目前支援PostgreSQL和MySQL(MariaDB)資料庫;
* 支援異步讀寫Redis;
* 基於執行序池實現sqlite3資料庫的異步讀寫提供與上文資料庫相同的接口
* 支援ARM架構
* 方便的輕量級ORM實現一般物件到資料庫的雙向映射
* 支援外掛,可通過設定文件在載入時動態載入;
* 支援內建插入點的AOP
* 支援C++ coroutine
## 一個非常簡單的例子
不像大多數C++框架那樣drogon的主程式可以非常簡單。 Drogon使用了一些小技巧使主程式和控制器去耦. 控制器的路由設定可以在控制器類別中定義或者設定文件中完成.
下面是一個典型的主程式的樣子:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().setLogPath("./")
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 80)
.setThreadNum(16)
.enableRunAsDaemon()
.run();
}
```
如果使用設定文件,可以進一步簡化成這樣:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().loadConfigFile("./config.json").run();
}
```
當然Drogon也提供了一些函數使使用者可以在main()函數中直接添加控制器邏輯比如使用者可以註冊一個lambda處理器到drogon框架中如下所示
```c++
app().registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
{
Json::Value json;
json["result"]="ok";
json["message"]=std::string("hello,")+name;
auto resp=HttpResponse::newHttpJsonResponse(json);
callback(resp);
},
{Get,"LoginFilter"});
```
這看起來是很方便但是這並不適用於復雜的場景試想假如有數十個或者數百個處理函數要註冊進框架main()函數將膨脹到不可讀的程度。顯然讓每個包含處理函數的類在自己的定義中完成註冊是更好的選擇。所以除非你的應用邏輯非常簡單我們不推薦使用上述接口更好的實踐是我們可以創造一個HttpSimpleController類別如下
```c++
/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
virtual void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
PATH_ADD("/test",Get);
PATH_LIST_END
};
/// The TestCtrl.cc file
#include "TestCtrl.h"
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
//write your application logic here
auto resp = HttpResponse::newHttpResponse();
resp->setBody("<p>Hello, world!</p>");
resp->setExpiredTime(0);
callback(resp);
}
```
**上面程式的大部分程式碼都可以由`drogon_ctl`指令創造**(這個指令是`drogon_ctl create controller TestCtr`。使用者所需做的就是添加自己的業務邏輯。在這個例子中當客戶端訪問URL`http://ip/test`時,控制器簡單的回傳了一個`Hello, world!`頁面。
對於JSON格式的回應我們可以像下面這樣創造控制器
```c++
/// The header file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
virtual void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
//list path definitions here;
PATH_ADD("/json", Get);
PATH_LIST_END
};
/// The source file
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["message"] = "Hello, World!";
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
```
讓我們更進一步通過HttpController類別創造一個RESTful API的例子如下所示忽略了實做文件
```c++
/// The header file
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api
{
namespace v1
{
class User : public drogon::HttpController<User>
{
public:
METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here;
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
METHOD_LIST_END
//your declaration of processing function maybe like this:
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
public:
User()
{
LOG_DEBUG << "User constructor!";
}
};
} // namespace v1
} // namespace api
```
如你所見,通過`HttpController`類別使用者可以同時映射路徑和路徑參數這對RESTful API應用來說非常方便。
另外,你可以發現前面所有的處理函數接口都是異步的,處理器的回應是通過回調對象回傳的。這種設計是出於對高性能的考慮,因為在異步模式下,可以使用少量的執行序(比如和處理器核心數相等的執行序)處理大量的並發請求。
編譯上述的所有源文件後我們得到了一個非常簡單的web應用程式這是一個不錯的開始。 **請瀏覽[wiki](https://github.com/an-tao/drogon/wiki/CHN-01-概述)或者[doxiz](https://doxiz.com/drogon/master/overview/)以獲取更多的信息**
## 貢獻方式
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以獲取更多的信息。
## QQ交流群1137909452
歡迎交流探討。

View File

@ -1,101 +0,0 @@
#!/usr/bin/env bash
#build drogon
function build_drogon() {
#Update the submodule and initialize
git submodule update --init
#Remove the config.h generated by the old version of drogon.
rm -f lib/inc/drogon/config.h
#Save current directory
current_dir="${PWD}"
#The folder in which we will build drogon
build_dir='./build'
if [ -d $build_dir ]; then
echo "Deleted folder: ${build_dir}"
rm -rf $build_dir
fi
#Create building folder
echo "Created building folder: ${build_dir}"
mkdir $build_dir
echo "Entering folder: ${build_dir}"
cd $build_dir
echo "Start building drogon ..."
if [ $1 -eq 1 ]; then
cmake .. -DBUILD_TESTING=YES $cmake_gen
elif [ $1 -eq 2 ]; then
cmake .. -DBUILD_TESTING=YES -DBUILD_DROGON_SHARED=ON -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=1 $cmake_gen
else
cmake .. -DCMAKE_BUILD_TYPE=release $cmake_gen
fi
#If errors then exit
if [ "$?" != "0" ]; then
exit -1
fi
$make_program $make_flags
#If errors then exit
if [ "$?" != "0" ]; then
exit -1
fi
echo "Installing ..."
sudo $make_program install
#Go back to the current directory
cd $current_dir
#Ok!
}
make_program=make
make_flags=''
cmake_gen=''
parallel=1
case $(uname) in
FreeBSD)
nproc=$(sysctl -n hw.ncpu)
;;
Darwin)
nproc=$(sysctl -n hw.ncpu) # sysctl -n hw.ncpu is the equivalent to nproc on macOS.
;;
*)
nproc=$(nproc)
;;
esac
# simulate ninja's parallelism
case nproc in
1)
parallel=$(( nproc + 1 ))
;;
2)
parallel=$(( nproc + 1 ))
;;
*)
parallel=$(( nproc + 2 ))
;;
esac
if [ -f /bin/ninja ]; then
make_program=ninja
cmake_gen='-GNinja'
else
make_flags="$make_flags -j$parallel"
fi
if [ "$1" = "-t" ]; then
build_drogon 1
elif [ "$1" = "-tshared" ]; then
build_drogon 2
else
build_drogon 0
fi

View File

@ -1,60 +0,0 @@
# ##############################################################################
# function drogon_create_views(target source_path output_path
# [use_path_as_namespace])
# ##############################################################################
function(drogon_create_views arg)
if(ARGC LESS 3)
message(STATUS "arguments error when calling drogon_create_views")
return()
endif()
file(MAKE_DIRECTORY ${ARGV2})
file(GLOB_RECURSE SCP_LIST ${ARGV1}/*.csp)
foreach(cspFile ${SCP_LIST})
file(RELATIVE_PATH
inFile
${CMAKE_CURRENT_SOURCE_DIR}
${cspFile})
if(ARGC GREATER 3 AND ARGV3)
string(REPLACE "/"
"_"
f1
${inFile})
string(REPLACE "\\"
"_"
f2
${f1})
string(REPLACE ".csp"
""
outputFile
${f2})
add_custom_command(OUTPUT ${ARGV2}/${outputFile}.h ${ARGV2}/${outputFile}.cc
COMMAND drogon_ctl
ARGS
create
view
${inFile}
--path-to-namespace
-o
${ARGV2}
DEPENDS ${cspFile}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM)
set(VIEWSRC ${VIEWSRC} ${ARGV2}/${outputFile}.cc)
else()
get_filename_component(classname ${cspFile} NAME_WE)
add_custom_command(OUTPUT ${ARGV2}/${classname}.h ${ARGV2}/${classname}.cc
COMMAND drogon_ctl
ARGS
create
view
${inFile}
-o
${ARGV2}
DEPENDS ${cspFile}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM)
set(VIEWSRC ${VIEWSRC} ${ARGV2}/${classname}.cc)
endif()
endforeach()
target_sources(${ARGV0} PRIVATE ${VIEWSRC})
endfunction(drogon_create_views)

View File

@ -1,79 +0,0 @@
#==================================================================================================#
# Adapted and re-written from Catch2 to work with Drogon Test #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# enable_testing() #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddDrogonTests) #
# ParseAndAddDrogonTests(${PROJECT_NAME}) #
#==================================================================================================#
cmake_minimum_required(VERSION 3.5)
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
set(FullSourcePath ${CMAKE_CURRENT_SOURCE_DIR}/${SourceFile})
if(NOT EXISTS ${FullSourcePath})
return()
endif()
file(STRINGS ${FullSourcePath} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*DROGON_TEST[ \t]*\\\([a-zA-Z0-9_]+\\\)" Tests "${Contents}")
foreach(TestLine ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestLine "${TestLine}")
# Get the name of the test
string(REGEX REPLACE "[ \t]*DROGON_TEST[ \t]*" "" TestLine "${TestLine}")
string(REGEX MATCHALL "[a-zA-Z0-9_]+" TestName "${TestLine}")
# Validate that a test name and tags have been provided
list(LENGTH TestName TestNameLength)
if(NOT TestNameLength EQUAL 1)
message(FATAL_ERROR "${TestName} in ${SourceFile} is not a valid test name."
" Either a bug in the Drogon Test CMake parser or a bug in the test itself")
endif()
# Add the test and set its properties
add_test(NAME "${TestName}" COMMAND ${TestTarget} -r ${TestName} ${AdditionalCatchParameters})
endforeach()
endfunction()
# entry point
function(ParseAndAddDrogonTests TestTarget)
get_target_property(SourceFiles ${TestTarget} SOURCES)
foreach(SourceFile ${SourceFiles})
ParseFile(${SourceFile} ${TestTarget})
endforeach()
endfunction()

View File

@ -1,56 +0,0 @@
# - Config file for the Drogon package
# It defines the following variables
# DROGON_INCLUDE_DIRS - include directories for Drogon
# DROGON_LIBRARIES - libraries to link against
# DROGON_EXECUTABLE - the drogon_ctl executable
# Drogon_FOUND
# This module defines the following IMPORTED target:
# Drogon::Drogon
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
find_dependency(Jsoncpp REQUIRED)
find_dependency(Trantor REQUIRED)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
find_dependency(UUID REQUIRED)
endif(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
find_dependency(ZLIB REQUIRED)
if(@pg_FOUND@)
find_dependency(pg)
endif()
if(@SQLite3_FOUND@)
find_dependency(SQLite3)
endif()
if(@MySQL_FOUND@)
find_dependency(MySQL)
endif()
if(@Boost_FOUND@)
find_dependency(Boost)
endif()
if(@Brotli_FOUND@)
find_dependency(Brotli)
endif()
if(@COZ-PROFILER_FOUND@)
find_dependency(coz-profiler)
endif()
if(@Hiredis_FOUND@)
find_dependency(Hiredis)
endif()
if(@BUILD_DROGON_SHARED@)
find_dependency(Threads)
endif()
# Our library dependencies (contains definitions for IMPORTED targets)
get_filename_component(DROGON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(NOT TARGET Drogon::Drogon)
include("${DROGON_CMAKE_DIR}/DrogonTargets.cmake")
include("${DROGON_CMAKE_DIR}/DrogonUtilities.cmake")
endif()
get_target_property(DROGON_INCLUDE_DIRS Drogon::Drogon INTERFACE_INCLUDE_DIRECTORIES)
set(DROGON_LIBRARIES Drogon::Drogon)
set(DROGON_EXECUTABLE drogon_ctl)

View File

@ -1,14 +0,0 @@
#pragma once
#cmakedefine01 USE_POSTGRESQL
#cmakedefine01 LIBPQ_SUPPORTS_BATCH_MODE
#cmakedefine01 USE_MYSQL
#cmakedefine01 USE_SQLITE3
#cmakedefine OpenSSL_FOUND
#cmakedefine Boost_FOUND
#cmakedefine COMPILATION_FLAGS "@COMPILATION_FLAGS@@DROGON_CXX_STANDARD@"
#cmakedefine COMPILER_COMMAND "@COMPILER_COMMAND@"
#cmakedefine COMPILER_ID "@COMPILER_ID@"
#cmakedefine INCLUDING_DIRS "@INCLUDING_DIRS@"

View File

@ -1,5 +0,0 @@
#define MAJOR @DROGON_MAJOR_VERSION@
#define MINOR @DROGON_MINOR_VERSION@
#define PATCH @DROGON_PATCH_VERSION@
#define DROGON_VERSION "@DROGON_VERSION_STRING@"
#define DROGON_VERSION_SHA1 "@GIT_SHA1@"

View File

@ -1,7 +0,0 @@
#include <uuid.h>
int main()
{
uuid_t uu;
uuid_generate(uu);
return 0;
}

View File

@ -1,8 +0,0 @@
#include <uuid.h>
int main()
{
uuid_t *uuid;
uuid_create(&uuid);
uuid_make(uuid, UUID_MAKE_V1);
return 0;
}

View File

@ -1,12 +0,0 @@
#include <libpq-fe.h>
int main()
{
PQisInBatchMode(NULL);
PQbatchIsAborted(NULL);
PQqueriesInBatch(NULL);
PQbeginBatchMode(NULL);
PQendBatchMode(NULL);
PQsendEndBatch(NULL);
PQgetNextQuery(NULL);
}

View File

@ -1,50 +0,0 @@
# ***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which you should
# have received as part of this distribution. The terms are also available at
# https://curl.haxx.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is furnished
# to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# ##############################################################################
include(FindPackageHandleStandardArgs)
find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
find_library(BROTLIENC_LIBRARY NAMES brotlienc)
find_package_handle_standard_args(Brotli
REQUIRED_VARS
BROTLIDEC_LIBRARY
BROTLIENC_LIBRARY
BROTLICOMMON_LIBRARY
BROTLI_INCLUDE_DIR
FAIL_MESSAGE
"Could NOT find BROTLI")
set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY}
${BROTLIENC_LIBRARY} ${BROTLICOMMON_LIBRARY})
if(Brotli_FOUND)
add_library(Brotli_lib INTERFACE IMPORTED)
set_target_properties(Brotli_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${BROTLI_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${BROTLI_LIBRARIES}")
endif(Brotli_FOUND)

View File

@ -1,40 +0,0 @@
# Try to find hiredis
# Once done, this will define
#
# HIREDIS_FOUND - system has hiredis
# HIREDIS_INCLUDE_DIRS - hiredis include directories
# HIREDIS_LIBRARIES - libraries need to use hiredis
if (HIREDIS_INCLUDE_DIRS AND HIREDIS_LIBRARIES)
set(HIREDIS_FIND_QUIETLY TRUE)
else ()
find_path(
HIREDIS_INCLUDE_DIR
NAMES hiredis/hiredis.h
HINTS ${HIREDIS_ROOT_DIR}
PATH_SUFFIXES include)
find_library(
HIREDIS_LIBRARY
NAMES hiredis
HINTS ${HIREDIS_ROOT_DIR}
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR})
set(HIREDIS_INCLUDE_DIRS ${HIREDIS_INCLUDE_DIR})
set(HIREDIS_LIBRARIES ${HIREDIS_LIBRARY})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
Hiredis DEFAULT_MSG HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
mark_as_advanced(HIREDIS_LIBRARY HIREDIS_INCLUDE_DIR)
endif ()
if(Hiredis_FOUND)
add_library(Hiredis_lib INTERFACE IMPORTED)
set_target_properties(Hiredis_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${HIREDIS_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${HIREDIS_LIBRARIES}")
endif(Hiredis_FOUND)

View File

@ -1,68 +0,0 @@
# Find jsoncpp
#
# Find the jsoncpp includes and library
#
# if you nee to add a custom library search path, do it via via
# CMAKE_PREFIX_PATH
#
# This module defines JSONCPP_INCLUDE_DIRS, where to find header, etc.
# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. JSONCPP_FOUND, If
# false, do not try to use jsoncpp.
# Jsoncpp_lib - The imported target library.
# only look in default directories
find_path(JSONCPP_INCLUDE_DIRS
NAMES json/json.h
DOC "jsoncpp include dir"
PATH_SUFFIXES jsoncpp)
find_library(JSONCPP_LIBRARIES NAMES jsoncpp DOC "jsoncpp library")
# debug library on windows same naming convention as in qt (appending debug
# library with d) boost is using the same "hack" as us with "optimized" and
# "debug" if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# find_library(JSONCPP_LIBRARIES_DEBUG NAMES jsoncppd DOC "jsoncpp debug
# library") if("${JSONCPP_LIBRARIES_DEBUG}" STREQUAL "JSONCPP_LIBRARIES_DEBUG-
# NOTFOUND") set(JSONCPP_LIBRARIES_DEBUG ${JSONCPP_LIBRARIES}) endif()
# set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug
# ${JSONCPP_LIBRARIES_DEBUG})
# endif()
# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE if all
# listed variables are TRUE, hide their existence from configuration view
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Jsoncpp
DEFAULT_MSG
JSONCPP_INCLUDE_DIRS
JSONCPP_LIBRARIES)
mark_as_advanced(JSONCPP_INCLUDE_DIRS JSONCPP_LIBRARIES)
if(Jsoncpp_FOUND)
if(NOT EXISTS ${JSONCPP_INCLUDE_DIRS}/json/version.h)
message(FATAL_ERROR "Error: jsoncpp lib is too old.....stop")
endif()
if(NOT WIN32)
exec_program(
cat
ARGS
"${JSONCPP_INCLUDE_DIRS}/json/version.h |grep JSONCPP_VERSION_STRING|sed s'/.*define/define/'|awk '{printf $3}'|sed s'/\"//g'"
OUTPUT_VARIABLE
jsoncpp_ver)
message(STATUS "jsoncpp verson:" ${jsoncpp_ver})
if(jsoncpp_ver LESS 1.7)
message(
FATAL_ERROR
"jsoncpp lib is too old, please get new version from https://github.com/open-source-parsers/jsoncpp"
)
endif(jsoncpp_ver LESS 1.7)
endif()
add_library(Jsoncpp_lib INTERFACE IMPORTED)
set_target_properties(Jsoncpp_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${JSONCPP_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${JSONCPP_LIBRARIES}")
endif(Jsoncpp_FOUND)

View File

@ -1,122 +0,0 @@
# --------------------------------------------------------
# Copyright (C) 1995-2007 MySQL AB
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# There are special exceptions to the terms and conditions of the GPL as it is
# applied to this software. View the full text of the exception in file
# LICENSE.exceptions in the top-level directory of this software distribution.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301, USA
#
# The MySQL Connector/ODBC is licensed under the terms of the GPL, like most
# MySQL Connectors. There are special exceptions to the terms and conditions of
# the GPL as it is applied to this software, see the FLOSS License Exception
# available on mysql.com.
# MySQL_lib - The imported target library.
# ##############################################################################
# -------------- FIND MYSQL_INCLUDE_DIRS ------------------
find_path(MYSQL_INCLUDE_DIRS
NAMES mysql.h
PATH_SUFFIXES mysql
PATHS /usr/include/mysql
/usr/local/include/mysql
/usr/include/mariadb
/usr/local/include/mariadb
/opt/mysql/mysql/include
/opt/mysql/mysql/include/mysql
/opt/mysql/include
/opt/local/include/mysql5
/usr/local/mysql/include
/usr/local/mysql/include/mysql
/usr/local/mariadb/include
/usr/local/mariadb/include/mariadb
/opt/rh/rh-mariadb105/root/usr/include
/opt/rh/rh-mariadb105/root/usr/include/mysql
$ENV{ProgramFiles}/MySQL/*/include
$ENV{SystemDrive}/MySQL/*/include)
if(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql.h")
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql/mysql.h")
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIRS}/mysql)
endif()
# ----------------- FIND MYSQL_LIBRARIES_DIR -------------------
if(WIN32)
# Set lib path suffixes dist = for mysql binary distributions build = for
# custom built tree
if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(libsuffixDist debug)
set(libsuffixBuild Debug)
else(CMAKE_BUILD_TYPE STREQUAL Debug)
set(libsuffixDist opt)
set(libsuffixBuild Release)
add_definitions(-DDBUG_OFF)
endif(CMAKE_BUILD_TYPE STREQUAL Debug)
find_library(MYSQL_LIBRARIES
NAMES mariadbclient
PATHS $ENV{MYSQL_DIR}/lib/${libsuffixDist}
$ENV{MYSQL_DIR}/libmysql
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
$ENV{MYSQL_DIR}/client/${libsuffixBuild}
$ENV{MYSQL_DIR}/libmysql/${libsuffixBuild}
$ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist}
$ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist})
else(WIN32)
find_library(MYSQL_LIBRARIES
NAMES mysqlclient_r mariadbclient
PATHS /usr/lib/mysql
/usr/lib/mariadb
/usr/local/lib/mysql
/usr/local/lib/mariadb
/usr/local/mysql/lib
/usr/local/mysql/lib/mysql
/opt/local/mysql5/lib
/opt/local/lib/mysql5/mysql
/opt/mysql/mysql/lib/mysql
/opt/mysql/lib/mysql
/opt/rh/rh-mariadb105/root/usr/lib64)
endif(WIN32)
if(MYSQL_INCLUDE_DIRS AND MYSQL_LIBRARIES)
message(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIRS}")
message(STATUS "MySQL client libraries: ${MYSQL_LIBRARIES}")
elseif(MySQL_FIND_REQUIRED)
message(
FATAL_ERROR
"Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIRS} library dir: ${MYSQL_LIBRARIES_DIR}"
)
endif(MYSQL_INCLUDE_DIRS AND MYSQL_LIBRARIES)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MySQL
DEFAULT_MSG
MYSQL_LIBRARIES
MYSQL_INCLUDE_DIRS)
# Copy the results to the output variables.
if(MySQL_FOUND)
add_library(MySQL_lib INTERFACE IMPORTED)
set_target_properties(MySQL_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${MYSQL_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${MYSQL_LIBRARIES}")
else(MySQL_FOUND)
set(MYSQL_LIBRARIES)
set(MYSQL_INCLUDE_DIRS)
endif(MySQL_FOUND)
mark_as_advanced(MYSQL_INCLUDE_DIRS MYSQL_LIBRARIES)

View File

@ -1,43 +0,0 @@
# Copyright (C) 2007-2009 LuaDist. Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the
# MIT license. For details see the COPYRIGHT file distributed with LuaDist.
# Note: Searching headers and libraries is very simple and is NOT as powerful as
# scripts distributed with CMake, because LuaDist defines directories to search
# for. Everyone is encouraged to contact the author with improvements. Maybe
# this file becomes part of CMake distribution sometimes.
# * Find sqlite3 Find the native SQLITE3 headers and libraries.
#
# SQLITE3_INCLUDE_DIRS - where to find sqlite3.h, etc.
# SQLITE3_LIBRARIES - List of libraries when using sqlite.
# SQLite3_FOUND - True if sqlite3 found.
# SQLite3_lib - The imported target library.
# Look for the header file.
find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
# Look for the library.
find_library(SQLITE3_LIBRARIES NAMES sqlite3)
# Handle the QUIETLY and REQUIRED arguments and set SQLite3_FOUND to TRUE if all
# listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SQLite3
DEFAULT_MSG
SQLITE3_LIBRARIES
SQLITE3_INCLUDE_DIRS)
# Copy the results to the output variables.
if(SQLite3_FOUND)
add_library(SQLite3_lib INTERFACE IMPORTED)
set_target_properties(SQLite3_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${SQLITE3_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${SQLITE3_LIBRARIES}")
else(SQLite3_FOUND)
set(SQLITE3_LIBRARIES)
set(SQLITE3_INCLUDE_DIRS)
endif(SQLite3_FOUND)
mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES)

View File

@ -1,118 +0,0 @@
# * Try to find UUID Once done this will define
#
# UUID_FOUND - system has UUID
# UUID_INCLUDE_DIRS - the UUID include directory
# UUID_LIBRARIES - Link these to use UUID UUID_DEFINITIONS - Compiler switches
# required for using UUID
#
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the New BSD
# license. For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
# in cache already
set(UUID_FOUND TRUE)
else(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
find_path(
UUID_INCLUDE_DIR
NAMES uuid.h
PATH_SUFFIXES uuid
HINTS ${UUID_DIR}/include
$ENV{UUID_DIR}/include
$ENV{UUID_DIR}
${DELTA3D_EXT_DIR}/inc
$ENV{DELTA_ROOT}/ext/inc
$ENV{DELTA_ROOT}
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include
/usr/include
/usr/include/gdal
/sw/include # Fink
/opt/local/include # DarwinPorts
/opt/csw/include # Blastwave
/opt/include
[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
/usr/freeware/include)
find_library(UUID_LIBRARY
NAMES uuid ossp-uuid
HINTS ${UUID_DIR}/lib
$ENV{UUID_DIR}/lib
$ENV{UUID_DIR}
${DELTA3D_EXT_DIR}/lib
$ENV{DELTA_ROOT}/ext/lib
$ENV{DELTA_ROOT}
$ENV{OSG_ROOT}/lib
PATHS ~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/lib
/sw/lib
/opt/local/lib
/opt/csw/lib
/opt/lib
/usr/freeware/lib64)
find_library(UUID_LIBRARY_DEBUG
NAMES uuidd
HINTS ${UUID_DIR}/lib
$ENV{UUID_DIR}/lib
$ENV{UUID_DIR}
${DELTA3D_EXT_DIR}/lib
$ENV{DELTA_ROOT}/ext/lib
$ENV{DELTA_ROOT}
$ENV{OSG_ROOT}/lib
PATHS ~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/lib
/sw/lib
/opt/local/lib
/opt/csw/lib
/opt/lib
/usr/freeware/lib64)
if(NOT UUID_LIBRARY AND BSD)
set(UUID_LIBRARY "")
endif(NOT UUID_LIBRARY AND BSD)
set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR})
set(UUID_LIBRARIES ${UUID_LIBRARY})
if(UUID_INCLUDE_DIRS)
if(BSD OR UUID_LIBRARIES)
set(UUID_FOUND TRUE)
endif(BSD OR UUID_LIBRARIES)
endif(UUID_INCLUDE_DIRS)
if(UUID_FOUND)
if(NOT UUID_FIND_QUIETLY)
message(STATUS "Found UUID: ${UUID_LIBRARIES}")
endif(NOT UUID_FIND_QUIETLY)
else(UUID_FOUND)
if(UUID_FIND_REQUIRED)
message(FATAL_ERROR "Could not find UUID")
endif(UUID_FIND_REQUIRED)
endif(UUID_FOUND)
# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced
# view
mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
endif(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
if(UUID_FOUND)
add_library(UUID_lib INTERFACE IMPORTED)
set_target_properties(UUID_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${UUID_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${UUID_LIBRARIES}")
else(UUID_FOUND)
set(UUID_LIBRARIES)
set(UUID_INCLUDE_DIRS)
endif(UUID_FOUND)

View File

@ -1,23 +0,0 @@
find_path(COZ_INCLUDE_DIRS NAMES coz.h)
find_library(COZ_LIBRARIES NAMES coz PATH_SUFFIXES coz-profiler)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(coz-profiler
DEFAULT_MSG
COZ_LIBRARIES
COZ_INCLUDE_DIRS)
if(COZ-PROFILER_FOUND)
add_library(coz::coz INTERFACE IMPORTED)
set_target_properties(coz::coz
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
${COZ_INCLUDE_DIRS}
INTERFACE_LINK_LIBRARIES
${COZ_LIBRARIES})
else(COZ-PROFILER_FOUND)
set(COZ_LIBRARIES)
set(COZ_INCLUDE_DIRS)
endif(COZ-PROFILER_FOUND)
mark_as_advanced(COZ_INCLUDE_DIRS COZ_LIBRARIES)

View File

@ -1,27 +0,0 @@
# Find PostgreSQL
#
# Find the PostgreSQL includes and library
#
# This module defines PG_INCLUDE_DIRS, where to find header, etc. PG_LIBRARIES,
# the libraries needed to use PostgreSQL. pg_FOUND, If false, do not try to use
# PostgreSQL.
# pg_lib - The imported target library.
find_package(PostgreSQL)
if(PostgreSQL_FOUND)
set(PG_LIBRARIES ${PostgreSQL_LIBRARIES})
set(PG_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIRS})
message(STATUS "pg inc: " ${PostgreSQL_INCLUDE_DIRS})
add_library(pg_lib INTERFACE IMPORTED)
set_target_properties(pg_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${PostgreSQL_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${PostgreSQL_LIBRARIES}")
mark_as_advanced(PG_INCLUDE_DIRS PG_LIBRARIES)
endif(PostgreSQL_FOUND)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pg
DEFAULT_MSG
PG_LIBRARIES
PG_INCLUDE_DIRS)

View File

@ -1,16 +0,0 @@
[requires]
jsoncpp/1.9.4
zlib/1.2.11
gtest/1.10.0
sqlite3/3.34.1
#libpq/13.2
openssl/1.1.1j
hiredis/1.0.0
brotli/1.0.9
[generators]
cmake_paths
[options]
[imports]

View File

@ -1,21 +0,0 @@
FROM archlinux:base-20210307.0.16708
RUN pacman -Syu --noconfirm && pacman -S wget sudo cmake make git gcc jsoncpp postgresql mariadb-clients --noconfirm
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
CC=gcc \
CXX=g++ \
AR=gcc-ar \
RANLIB=gcc-ranlib \
IROOT=/install
ENV DROGON_ROOT="$IROOT/drogon"
ADD https://api.github.com/repos/an-tao/drogon/git/refs/heads/master $IROOT/version.json
RUN git clone https://github.com/an-tao/drogon $DROGON_ROOT
WORKDIR $DROGON_ROOT
RUN ./build.sh

View File

@ -1,27 +0,0 @@
FROM ubuntu:18.04
RUN apt-get update -yqq \
&& apt-get install -yqq --no-install-recommends software-properties-common \
sudo curl wget cmake pkg-config locales git gcc-8 g++-8 \
openssl libssl-dev libjsoncpp-dev uuid-dev zlib1g-dev libc-ares-dev\
postgresql-server-dev-all libmariadbclient-dev libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
CC=gcc-8 \
CXX=g++-8 \
AR=gcc-ar-8 \
RANLIB=gcc-ranlib-8 \
IROOT=/install
ENV DROGON_ROOT="$IROOT/drogon"
ADD https://api.github.com/repos/an-tao/drogon/git/refs/heads/master $IROOT/version.json
RUN git clone https://github.com/an-tao/drogon $DROGON_ROOT
WORKDIR $DROGON_ROOT
RUN ./build.sh

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,81 +0,0 @@
set(ctl_sources
cmd.cc
create.cc
create_controller.cc
create_filter.cc
create_model.cc
create_plugin.cc
create_project.cc
create_view.cc
help.cc
main.cc
press.cc
version.cc)
add_executable(_drogon_ctl
main.cc
cmd.cc
create.cc
create_view.cc)
target_link_libraries(_drogon_ctl ${PROJECT_NAME})
if (WIN32 AND BUILD_DROGON_SHARED)
set(DROGON_FILE $<TARGET_FILE:drogon>)
set(TRANTOR_FILE $<TARGET_FILE:trantor>)
add_custom_command(TARGET _drogon_ctl POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DCTL_FILE=${DROGON_FILE}
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
-P
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
add_custom_command(TARGET _drogon_ctl POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DCTL_FILE=${TRANTOR_FILE}
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
-P
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
endif()
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/templates/*.csp)
foreach(cspFile ${SCP_LIST})
message(STATUS "cspFile:" ${cspFile})
get_filename_component(classname ${cspFile} NAME_WE)
message(STATUS "view classname:" ${classname})
add_custom_command(OUTPUT ${classname}.h ${classname}.cc
COMMAND $<TARGET_FILE:_drogon_ctl>
ARGS
create
view
${cspFile}
DEPENDS ${cspFile}
VERBATIM)
set(TEMPL_SRC ${TEMPL_SRC} ${classname}.cc)
endforeach()
add_executable(drogon_ctl ${ctl_sources} ${TEMPL_SRC})
target_link_libraries(drogon_ctl PRIVATE ${PROJECT_NAME})
target_include_directories(drogon_ctl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(drogon_ctl _drogon_ctl)
if(WIN32)
target_link_libraries(drogon_ctl PRIVATE ws2_32 Rpcrt4)
endif(WIN32)
message(STATUS "bin:" ${INSTALL_BIN_DIR})
install(TARGETS drogon_ctl RUNTIME DESTINATION ${INSTALL_BIN_DIR})
if(WIN32)
set(CTL_FILE $<TARGET_FILE:drogon_ctl>)
add_custom_command(TARGET drogon_ctl POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DCTL_FILE=${CTL_FILE}
-DINSTALL_BIN_DIR=${INSTALL_BIN_DIR}
-DRENAME_EXE=ON
-P
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
else(WIN32)
install(CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \
./drogon_ctl \
./dg_ctl \
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dg_ctl"
DESTINATION ${INSTALL_BIN_DIR})
endif(WIN32)
set(ctl_targets _drogon_ctl drogon_ctl)
set_property(TARGET ${ctl_targets} PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD})
set_property(TARGET ${ctl_targets} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${ctl_targets} PROPERTY CXX_EXTENSIONS OFF)

View File

@ -1,35 +0,0 @@
/**
*
* CommandHandler.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <drogon/DrObject.h>
#include <string>
#include <vector>
class CommandHandler : public virtual drogon::DrObjectBase {
public:
virtual void handleCommand(std::vector<std::string> &parameters) = 0;
virtual bool isTopCommand() {
return false;
}
virtual std::string script() {
return "";
}
virtual std::string detail() {
return "";
}
virtual ~CommandHandler() {
}
};

View File

@ -1,8 +0,0 @@
make_directory("${INSTALL_BIN_DIR}")
get_filename_component(CTL_PATH ${CTL_FILE} DIRECTORY)
file(GLOB DLL_FILES ${CTL_PATH}/*.dll)
file(COPY ${DLL_FILES} DESTINATION ${INSTALL_BIN_DIR})
file(COPY ${CTL_FILE} DESTINATION ${INSTALL_BIN_DIR})
if (RENAME_EXE)
file(RENAME ${INSTALL_BIN_DIR}/drogon_ctl.exe ${INSTALL_BIN_DIR}/dg_ctl.exe)
endif()

View File

@ -1,48 +0,0 @@
/**
*
* cmd.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "cmd.h"
#include "CommandHandler.h"
#include <drogon/DrClassMap.h>
#include <memory>
using namespace drogon;
void exeCommand(std::vector<std::string> &parameters) {
if (parameters.empty()) {
std::cout << "incomplete command!use help command to get usage!"
<< std::endl;
return;
}
std::string command = parameters[0];
std::string handlerName = std::string("drogon_ctl::").append(command);
parameters.erase(parameters.begin());
// new command handler to do cmd
auto obj = std::shared_ptr<DrObjectBase>(
drogon::DrClassMap::newObject(handlerName));
if (obj) {
auto ctl = std::dynamic_pointer_cast<CommandHandler>(obj);
if (ctl) {
ctl->handleCommand(parameters);
} else {
std::cout << "command not found!use help command to get usage!"
<< std::endl;
}
} else {
std::cout << "command error!use help command to get usage!"
<< std::endl;
}
}

View File

@ -1,21 +0,0 @@
/**
*
* cmd.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <iostream>
#include <string>
#include <vector>
#define ARGS_ERROR_STR "args error!use help command to get usage!"
void exeCommand(std::vector<std::string> &parameters);

View File

@ -1,53 +0,0 @@
/**
*
* @file create.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create.h"
#include "cmd.h"
#include <drogon/DrClassMap.h>
#include <iostream>
#include <memory>
using namespace drogon_ctl;
std::string create::detail() {
return "Use create command to create some source files of drogon webapp\n\n"
"Usage:drogon_ctl create <view|controller|filter|project|model> "
"[-options] <object name>\n\n"
"drogon_ctl create view <csp file name> [-o <output path>] [-n "
"<namespace>]|[--path-to-namespace]//create HttpView source files "
"from csp files\n\n"
"drogon_ctl create controller [-s] <[namespace::]class_name> //"
"create HttpSimpleController source files\n\n"
"drogon_ctl create controller -h <[namespace::]class_name> //"
"create HttpController source files\n\n"
"drogon_ctl create controller -w <[namespace::]class_name> //"
"create WebSocketController source files\n\n"
"drogon_ctl create controller -r <[namespace::]class_name> "
"[--resource=...]//"
"create restful controller source files\n\n"
"drogon_ctl create filter <[namespace::]class_name> //"
"create a filter named class_name\n\n"
"drogon_ctl create plugin <[namespace::]class_name> //"
"create a plugin named class_name\n\n"
"drogon_ctl create project <project_name> //"
"create a project named project_name\n\n"
"drogon_ctl create model <model_path> [--table=<table_name>] [-f]//"
"create model classes in model_path\n";
}
void create::handleCommand(std::vector<std::string> &parameters) {
// std::cout<<"create!"<<std::endl;
auto createObjName = parameters[0];
createObjName = std::string("create_") + createObjName;
parameters[0] = createObjName;
exeCommand(parameters);
}

View File

@ -1,33 +0,0 @@
/**
*
* create.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class create : public DrObject<create>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create some source files(Use 'drogon_ctl help create' for more "
"information)";
}
virtual bool isTopCommand() override {
return true;
}
virtual std::string detail() override;
};
} // namespace drogon_ctl

View File

@ -1,396 +0,0 @@
/**
*
* create_controller.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create_controller.h"
#include "cmd.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <fstream>
#include <iostream>
#include <regex>
using namespace drogon_ctl;
void create_controller::handleCommand(std::vector<std::string> &parameters) {
// std::cout<<"create!"<<std::endl;
ControllerType type = Simple;
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) {
if ((*iter)[0] == '-') {
if (*iter == "-s" || (*iter == "--simple")) {
parameters.erase(iter);
break;
} else if (*iter == "-a" || *iter == "-h" || *iter == "--http") {
type = Http;
parameters.erase(iter);
break;
} else if (*iter == "-w" || *iter == "--websocket") {
type = WebSocket;
parameters.erase(iter);
break;
} else if (*iter == "-r" || *iter == "--restful") {
type = Restful;
parameters.erase(iter);
break;
} else {
std::cout << ARGS_ERROR_STR << std::endl;
return;
}
}
}
if (type != Restful)
createController(parameters, type);
else {
std::string resource;
for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) {
if ((*iter).find("--resource=") == 0) {
resource = (*iter).substr(strlen("--resource="));
parameters.erase(iter);
break;
}
if ((*iter)[0] == '-') {
std::cerr << "Error parameter for '" << (*iter) << "'"
<< std::endl;
exit(1);
}
}
if (parameters.size() > 1) {
std::cerr << "Too many parameters" << std::endl;
exit(1);
}
auto className = parameters[0];
createARestfulController(className, resource);
}
}
void create_controller::newSimpleControllerHeaderFile(
std::ofstream &file,
const std::string &className) {
file << "#pragma once\n";
file << "#include <drogon/HttpSimpleController.h>\n";
file << "using namespace drogon;\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
size_t namespaceCount = 0;
while (pos != std::string::npos) {
++namespaceCount;
auto namespaceName = class_name.substr(0, pos);
class_name = class_name.substr(pos + 2);
file << "namespace " << namespaceName << "\n";
namepace_path.append(namespaceName).append("/");
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::HttpSimpleController<"
<< class_name << ">\n";
file << "{\n";
file << " public:\n";
file << " virtual void asyncHandleHttpRequest(const HttpRequestPtr& "
"req, std::function<void (const HttpResponsePtr &)> &&callback) "
"override;\n";
file << " PATH_LIST_BEGIN\n";
file << " //list path definitions here;\n";
file << " "
"//PATH_ADD(\"/"
"path\",\"filter1\",\"filter2\",HttpMethod1,HttpMethod2...);\n";
file << " PATH_LIST_END\n";
file << "};\n";
while (namespaceCount > 0) {
--namespaceCount;
file << "}\n";
}
}
void create_controller::newSimpleControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename) {
file << "#include \"" << filename << ".h\"\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos) {
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
class_name = className.substr(pos + 2);
}
file << "void " << class_name
<< "::asyncHandleHttpRequest(const HttpRequestPtr& req, "
"std::function<void (const HttpResponsePtr &)> &&callback)\n";
file << "{\n";
file << " //write your application logic here\n";
file << "}";
}
void create_controller::newWebsockControllerHeaderFile(
std::ofstream &file,
const std::string &className) {
file << "#pragma once\n";
file << "#include <drogon/WebSocketController.h>\n";
file << "using namespace drogon;\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
size_t namespaceCount = 0;
while (pos != std::string::npos) {
++namespaceCount;
auto namespaceName = class_name.substr(0, pos);
class_name = class_name.substr(pos + 2);
file << "namespace " << namespaceName << "\n";
namepace_path.append(namespaceName).append("/");
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::WebSocketController<"
<< class_name << ">\n";
file << "{\n";
file << " public:\n";
file
<< " virtual void handleNewMessage(const WebSocketConnectionPtr&,\n";
file << " std::string &&,\n";
file << " const WebSocketMessageType &) "
"override;\n";
file << " virtual void handleNewConnection(const HttpRequestPtr &,\n";
file << " const "
"WebSocketConnectionPtr&)override;\n";
file << " virtual void handleConnectionClosed(const "
"WebSocketConnectionPtr&)override;\n";
file << " WS_PATH_LIST_BEGIN\n";
file << " //list path definitions here;\n";
file << " //WS_PATH_ADD(\"/path\",\"filter1\",\"filter2\",...);\n";
file << " WS_PATH_LIST_END\n";
file << "};\n";
while (namespaceCount > 0) {
--namespaceCount;
file << "}\n";
}
}
void create_controller::newWebsockControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename) {
file << "#include \"" << filename << ".h\"\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos) {
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
class_name = className.substr(pos + 2);
}
file << "void " << class_name
<< "::handleNewMessage(const WebSocketConnectionPtr& wsConnPtr, "
"std::string &&message, const WebSocketMessageType &type)\n";
file << "{\n";
file << " //write your application logic here\n";
file << "}\n";
file << "void " << class_name
<< "::handleNewConnection(const HttpRequestPtr &req,const "
"WebSocketConnectionPtr& wsConnPtr)\n";
file << "{\n";
file << " //write your application logic here\n";
file << "}\n";
file << "void " << class_name
<< "::handleConnectionClosed(const WebSocketConnectionPtr& "
"wsConnPtr)\n";
file << "{\n";
file << " //write your application logic here\n";
file << "}\n";
}
void create_controller::newHttpControllerHeaderFile(
std::ofstream &file,
const std::string &className) {
file << "#pragma once\n";
file << "#include <drogon/HttpController.h>\n";
file << "using namespace drogon;\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
size_t namespaceCount = 0;
while (pos != std::string::npos) {
++namespaceCount;
auto namespaceName = class_name.substr(0, pos);
class_name = class_name.substr(pos + 2);
file << "namespace " << namespaceName << "\n";
namepace_path.append(namespaceName).append("/");
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::HttpController<"
<< class_name << ">\n";
file << "{\n";
file << " public:\n";
file << " METHOD_LIST_BEGIN\n";
file << " //use METHOD_ADD to add your custom processing function "
"here;\n";
file << " //METHOD_ADD(" << class_name
<< "::get,\"/{2}/{1}\",Get);"
"//path is "
<< namepace_path << class_name << "/{arg2}/{arg1}\n";
file << " //METHOD_ADD(" << class_name
<< "::your_method_name,\"/{1}/{2}/list\",Get);"
"//path is "
<< namepace_path << class_name << "/{arg1}/{arg2}/list\n";
file << " //ADD_METHOD_TO(" << class_name
<< "::your_method_name,\"/absolute/path/{1}/{2}/list\",Get);"
"//path is /absolute/path/{arg1}/{arg2}/list\n";
file << "\n";
file << " METHOD_LIST_END\n";
file << " // your declaration of processing function maybe like this:\n";
file << " // void get(const HttpRequestPtr& req,"
"std::function<void (const HttpResponsePtr &)> &&callback,int "
"p1,std::string p2);\n";
file << " // void your_method_name(const HttpRequestPtr& req,"
"std::function<void (const HttpResponsePtr &)> &&callback,double "
"p1,int p2) const;\n";
file << "};\n";
while (namespaceCount > 0) {
--namespaceCount;
file << "}\n";
}
}
void create_controller::newHttpControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename) {
file << "#include \"" << filename << ".h\"\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos) {
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
class_name = className.substr(pos + 2);
}
file << "//add definition of your processing function here\n";
}
void create_controller::createController(std::vector<std::string> &httpClasses,
ControllerType type) {
for (auto iter = httpClasses.begin(); iter != httpClasses.end(); ++iter) {
if ((*iter)[0] == '-') {
std::cout << ARGS_ERROR_STR << std::endl;
return;
}
}
for (auto const &className : httpClasses) {
createController(className, type);
}
}
void create_controller::createController(const std::string &className,
ControllerType type) {
std::regex regex("::");
std::string ctlName =
std::regex_replace(className, regex, std::string("_"));
std::string headFileName = ctlName + ".h";
std::string sourceFilename = ctlName + ".cc";
{
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
if (iHeadFile || iSourceFile) {
std::cout << "The file you want to create already exists, "
"overwrite it(y/n)?"
<< std::endl;
auto in = getchar();
(void)getchar(); // get the return key
if (in != 'Y' && in != 'y') {
std::cout << "Abort!" << std::endl;
exit(0);
}
}
}
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
if (!oHeadFile || !oSourceFile) {
perror("");
exit(1);
}
if (type == Http) {
std::cout << "create a http controller:" << className << std::endl;
newHttpControllerHeaderFile(oHeadFile, className);
newHttpControllerSourceFile(oSourceFile, className, ctlName);
} else if (type == Simple) {
std::cout << "create a http simple controller:" << className
<< std::endl;
newSimpleControllerHeaderFile(oHeadFile, className);
newSimpleControllerSourceFile(oSourceFile, className, ctlName);
} else if (type == WebSocket) {
std::cout << "create a websocket controller:" << className << std::endl;
newWebsockControllerHeaderFile(oHeadFile, className);
newWebsockControllerSourceFile(oSourceFile, className, ctlName);
}
}
void create_controller::createARestfulController(const std::string &className,
const std::string &resource) {
std::regex regex("::");
std::string ctlName =
std::regex_replace(className, regex, std::string("_"));
std::string headFileName = ctlName + ".h";
std::string sourceFilename = ctlName + ".cc";
{
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
std::ifstream iSourceFile(sourceFilename.c_str(), std::ifstream::in);
if (iHeadFile || iSourceFile) {
std::cout << "The file you want to create already exists, "
"overwrite it(y/n)?"
<< std::endl;
auto in = getchar();
(void)getchar(); // get the return key
if (in != 'Y' && in != 'y') {
std::cout << "Abort!" << std::endl;
exit(0);
}
}
}
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
if (!oHeadFile || !oSourceFile) {
perror("");
exit(1);
}
auto v = utils::splitString(className, "::");
drogon::DrTemplateData data;
data.insert("className", v[v.size() - 1]);
v.pop_back();
data.insert("namespaceVector", v);
data.insert("resource", resource);
data.insert("fileName", ctlName);
if (resource.empty()) {
data.insert("ctlCommand",
std::string("drogon_ctl create controller -r ") +
className);
} else {
data.insert("ctlCommand",
std::string("drogon_ctl create controller -r ") +
className + " --resource=" + resource);
}
try {
auto templ = DrTemplateBase::newTemplate("restful_controller_h.csp");
oHeadFile << templ->genText(data);
templ = DrTemplateBase::newTemplate("restful_controller_cc.csp");
oSourceFile << templ->genText(data);
} catch (const std::exception &err) {
std::cerr << err.what() << std::endl;
exit(1);
}
std::cout << "create a http restful API controller:" << className
<< std::endl;
std::cout << "file name: " << ctlName << ".h and " << ctlName << ".cc"
<< std::endl;
}

View File

@ -1,62 +0,0 @@
/**
*
* create_controller.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
#include <drogon/DrTemplateBase.h>
using namespace drogon;
namespace drogon_ctl {
class create_controller : public DrObject<create_controller>,
public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create controller files";
}
protected:
enum ControllerType {
Simple = 0,
Http,
WebSocket,
Restful
};
void createController(std::vector<std::string> &httpClasses,
ControllerType type);
void createController(const std::string &className, ControllerType type);
void createARestfulController(const std::string &className,
const std::string &resource);
void newSimpleControllerHeaderFile(std::ofstream &file,
const std::string &className);
void newSimpleControllerSourceFile(std::ofstream &file,
const std::string &className,
const std::string &filename);
void newWebsockControllerHeaderFile(std::ofstream &file,
const std::string &className);
void newWebsockControllerSourceFile(std::ofstream &file,
const std::string &className,
const std::string &filename);
void newHttpControllerHeaderFile(std::ofstream &file,
const std::string &className);
void newHttpControllerSourceFile(std::ofstream &file,
const std::string &className,
const std::string &filename);
};
} // namespace drogon_ctl

View File

@ -1,103 +0,0 @@
/**
*
* create_filter.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create_filter.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <iostream>
#include <string>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fstream>
#include <regex>
#include <sys/stat.h>
#include <sys/types.h>
using namespace drogon_ctl;
static void createFilterHeaderFile(std::ofstream &file,
const std::string &className,
const std::string &fileName) {
auto templ = drogon::DrTemplateBase::newTemplate("filter_h");
HttpViewData data;
if (className.find("::") != std::string::npos) {
auto namespaceVector = utils::splitString(className, "::");
data.insert("className", namespaceVector.back());
namespaceVector.pop_back();
data.insert("namespaceVector", namespaceVector);
} else {
data.insert("className", className);
}
data.insert("filename", fileName);
file << templ->genText(data);
}
static void createFilterSourceFile(std::ofstream &file,
const std::string &className,
const std::string &fileName) {
auto templ = drogon::DrTemplateBase::newTemplate("filter_cc");
HttpViewData data;
if (className.find("::") != std::string::npos) {
auto pos = className.rfind("::");
data.insert("namespaceString", className.substr(0, pos));
data.insert("className", className.substr(pos + 2));
} else {
data.insert("className", className);
}
data.insert("filename", fileName);
file << templ->genText(data);
}
void create_filter::handleCommand(std::vector<std::string> &parameters) {
if (parameters.size() < 1) {
std::cout << "Invalid parameters!" << std::endl;
}
for (auto className : parameters) {
std::regex regex("::");
std::string fileName =
std::regex_replace(className, regex, std::string("_"));
std::string headFileName = fileName + ".h";
std::string sourceFilename = fileName + ".cc";
{
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
std::ifstream iSourceFile(sourceFilename.c_str(),
std::ifstream::in);
if (iHeadFile || iSourceFile) {
std::cout << "The file you want to create already exists, "
"overwrite it(y/n)?"
<< std::endl;
auto in = getchar();
(void)getchar(); // get the return key
if (in != 'Y' && in != 'y') {
std::cout << "Abort!" << std::endl;
exit(0);
}
}
}
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
if (!oHeadFile || !oSourceFile) {
perror("");
exit(1);
}
std::cout << "create a http filter:" << className << std::endl;
createFilterHeaderFile(oHeadFile, className, fileName);
createFilterSourceFile(oSourceFile, className, fileName);
}
}

View File

@ -1,31 +0,0 @@
/**
*
* create_filter.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class create_filter : public DrObject<create_filter>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create filter class files";
}
protected:
std::string outputPath_{ "." };
};
} // namespace drogon_ctl

File diff suppressed because it is too large Load Diff

View File

@ -1,345 +0,0 @@
/**
*
* create_model.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <drogon/DrTemplateBase.h>
#include <drogon/config.h>
#include <drogon/orm/DbClient.h>
#include <json/json.h>
using namespace drogon::orm;
#include "CommandHandler.h"
#include <drogon/DrObject.h>
#include <algorithm>
#include <string>
using namespace drogon;
namespace drogon_ctl {
struct ColumnInfo {
std::string colName_;
std::string colValName_;
std::string colTypeName_;
std::string colType_;
std::string colDatabaseType_;
std::string dbType_;
ssize_t colLength_{ 0 };
size_t index_{ 0 };
bool isAutoVal_{ false };
bool isPrimaryKey_{ false };
bool notNull_{ false };
bool hasDefaultVal_{ false };
};
inline std::string nameTransform(const std::string &origName, bool isType) {
auto str = origName;
std::transform(str.begin(), str.end(), str.begin(), tolower);
std::string::size_type startPos = 0;
std::string::size_type pos;
std::string ret;
do {
pos = str.find("_", startPos);
if (pos == std::string::npos) {
pos = str.find(".", startPos);
}
if (pos != std::string::npos)
ret += str.substr(startPos, pos - startPos);
else {
ret += str.substr(startPos);
break;
}
while (str[pos] == '_' || str[pos] == '.')
++pos;
if (str[pos] >= 'a' && str[pos] <= 'z')
str[pos] += ('A' - 'a');
startPos = pos;
} while (1);
if (isType && ret[0] >= 'a' && ret[0] <= 'z')
ret[0] += ('A' - 'a');
return ret;
}
class PivotTable {
public:
PivotTable() = default;
PivotTable(const Json::Value &json) :
tableName_(json.get("table_name", "").asString()) {
if (tableName_.empty()) {
throw std::runtime_error("table_name can't be empty");
}
originalKey_ = json.get("original_key", "").asString();
if (originalKey_.empty()) {
throw std::runtime_error("original_key can't be empty");
}
targetKey_ = json.get("target_key", "").asString();
if (targetKey_.empty()) {
throw std::runtime_error("target_key can't be empty");
}
}
PivotTable reverse() const {
PivotTable pivot;
pivot.tableName_ = tableName_;
pivot.originalKey_ = targetKey_;
pivot.targetKey_ = originalKey_;
return pivot;
}
const std::string &tableName() const {
return tableName_;
}
const std::string &originalKey() const {
return originalKey_;
}
const std::string &targetKey() const {
return targetKey_;
}
private:
std::string tableName_;
std::string originalKey_;
std::string targetKey_;
};
class ConvertMethod {
public:
ConvertMethod(const Json::Value &convert) {
tableName_ = convert.get("table", "*").asString();
colName_ = convert.get("column", "*").asString();
auto method = convert["method"];
if (method.isNull()) {
throw std::runtime_error("method - object is missing.");
} // endif
if (!method.isObject()) {
throw std::runtime_error("method is not an object.");
} // endif
methodBeforeDbWrite_ = method.get("before_db_write", "").asString();
methodAfterDbRead_ = method.get("after_db_read", "").asString();
auto includeFiles = convert["includes"];
if (includeFiles.isNull()) {
return;
} // endif
if (!includeFiles.isArray()) {
throw std::runtime_error("includes must be an array");
} // endif
for (auto &i : includeFiles) {
includeFiles_.push_back(i.asString());
} // for
}
ConvertMethod() = default;
bool shouldConvert(const std::string &tableName,
const std::string &colName) const;
const std::string &tableName() const {
return tableName_;
}
const std::string &colName() const {
return colName_;
}
const std::string &methodBeforeDbWrite() const {
return methodBeforeDbWrite_;
}
const std::string &methodAfterDbRead() const {
return methodAfterDbRead_;
}
const std::vector<std::string> &includeFiles() const {
return includeFiles_;
}
private:
std::string tableName_{ "*" };
std::string colName_{ "*" };
std::string methodBeforeDbWrite_;
std::string methodAfterDbRead_;
std::vector<std::string> includeFiles_;
};
class Relationship {
public:
enum class Type {
HasOne,
HasMany,
ManyToMany
};
Relationship(const Json::Value &relationship) {
auto type = relationship.get("type", "has one").asString();
if (type == "has one") {
type_ = Relationship::Type::HasOne;
} else if (type == "has many") {
type_ = Relationship::Type::HasMany;
} else if (type == "many to many") {
type_ = Relationship::Type::ManyToMany;
} else {
char message[128];
snprintf(message,
sizeof(message),
"Invalid relationship type: %s",
type.data());
throw std::runtime_error(message);
}
originalTableName_ =
relationship.get("original_table_name", "").asString();
if (originalTableName_.empty()) {
throw std::runtime_error("original_table_name can't be empty");
}
originalKey_ = relationship.get("original_key", "").asString();
if (originalKey_.empty()) {
throw std::runtime_error("original_key can't be empty");
}
originalTableAlias_ =
relationship.get("original_table_alias", "").asString();
targetTableName_ = relationship.get("target_table_name", "").asString();
if (targetTableName_.empty()) {
throw std::runtime_error("target_table_name can't be empty");
}
targetKey_ = relationship.get("target_key", "").asString();
if (targetKey_.empty()) {
throw std::runtime_error("target_key can't be empty");
}
targetTableAlias_ =
relationship.get("target_table_alias", "").asString();
enableReverse_ = relationship.get("enable_reverse", false).asBool();
if (type_ == Type::ManyToMany) {
auto &pivot = relationship["pivot_table"];
if (pivot.isNull()) {
throw std::runtime_error(
"ManyToMany relationship needs a pivot table");
}
pivotTable_ = PivotTable(pivot);
}
}
Relationship() = default;
Relationship reverse() const {
Relationship r;
if (type_ == Type::HasMany) {
r.type_ = Type::HasOne;
} else {
r.type_ = type_;
}
r.originalTableName_ = targetTableName_;
r.originalTableAlias_ = targetTableAlias_;
r.originalKey_ = targetKey_;
r.targetTableName_ = originalTableName_;
r.targetTableAlias_ = originalTableAlias_;
r.targetKey_ = originalKey_;
r.enableReverse_ = enableReverse_;
r.pivotTable_ = pivotTable_.reverse();
return r;
}
Type type() const {
return type_;
}
bool enableReverse() const {
return enableReverse_;
}
const std::string &originalTableName() const {
return originalTableName_;
}
const std::string &originalTableAlias() const {
return originalTableAlias_;
}
const std::string &originalKey() const {
return originalKey_;
}
const std::string &targetTableName() const {
return targetTableName_;
}
const std::string &targetTableAlias() const {
return targetTableAlias_;
}
const std::string &targetKey() const {
return targetKey_;
}
const PivotTable &pivotTable() const {
return pivotTable_;
}
private:
Type type_{ Type::HasOne };
std::string originalTableName_;
std::string originalTableAlias_;
std::string targetTableName_;
std::string targetTableAlias_;
std::string originalKey_;
std::string targetKey_;
bool enableReverse_{ false };
PivotTable pivotTable_;
};
class create_model : public DrObject<create_model>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create Model classes files";
}
protected:
void createModel(const std::string &path,
const std::string &singleModelName);
void createModel(const std::string &path,
const Json::Value &config,
const std::string &singleModelName);
#if USE_POSTGRESQL
void createModelClassFromPG(
const std::string &path,
const DbClientPtr &client,
const std::string &tableName,
const std::string &schema,
const Json::Value &restfulApiConfig,
const std::vector<Relationship> &relationships,
const std::vector<ConvertMethod> &convertMethods);
void createModelFromPG(
const std::string &path,
const DbClientPtr &client,
const std::string &schema,
const Json::Value &restfulApiConfig,
std::map<std::string, std::vector<Relationship> > &relationships,
std::map<std::string, std::vector<ConvertMethod> > &convertMethods);
#endif
#if USE_MYSQL
void createModelClassFromMysql(
const std::string &path,
const DbClientPtr &client,
const std::string &tableName,
const Json::Value &restfulApiConfig,
const std::vector<Relationship> &relationships,
const std::vector<ConvertMethod> &convertMethods);
void createModelFromMysql(
const std::string &path,
const DbClientPtr &client,
const Json::Value &restfulApiConfig,
std::map<std::string, std::vector<Relationship> > &relationships,
std::map<std::string, std::vector<ConvertMethod> > &convertMethods);
#endif
#if USE_SQLITE3
void createModelClassFromSqlite3(
const std::string &path,
const DbClientPtr &client,
const std::string &tableName,
const Json::Value &restfulApiConfig,
const std::vector<Relationship> &relationships,
const std::vector<ConvertMethod> &convertMethod);
void createModelFromSqlite3(
const std::string &path,
const DbClientPtr &client,
const Json::Value &restfulApiConfig,
std::map<std::string, std::vector<Relationship> > &relationships,
std::map<std::string, std::vector<ConvertMethod> > &convertMethod);
#endif
void createRestfulAPIController(const DrTemplateData &tableInfo,
const Json::Value &restfulApiConfig);
std::string dbname_;
bool forceOverwrite_{ false };
};
} // namespace drogon_ctl

View File

@ -1,103 +0,0 @@
/**
*
* create_plugin.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create_plugin.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <iostream>
#include <string>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fstream>
#include <regex>
#include <sys/stat.h>
#include <sys/types.h>
using namespace drogon_ctl;
static void createPluginHeaderFile(std::ofstream &file,
const std::string &className,
const std::string &fileName) {
auto templ = drogon::DrTemplateBase::newTemplate("plugin_h");
HttpViewData data;
if (className.find("::") != std::string::npos) {
auto namespaceVector = utils::splitString(className, "::");
data.insert("className", namespaceVector.back());
namespaceVector.pop_back();
data.insert("namespaceVector", namespaceVector);
} else {
data.insert("className", className);
}
data.insert("filename", fileName);
file << templ->genText(data);
}
static void createPluginSourceFile(std::ofstream &file,
const std::string &className,
const std::string &fileName) {
auto templ = drogon::DrTemplateBase::newTemplate("plugin_cc");
HttpViewData data;
if (className.find("::") != std::string::npos) {
auto pos = className.rfind("::");
data.insert("namespaceString", className.substr(0, pos));
data.insert("className", className.substr(pos + 2));
} else {
data.insert("className", className);
}
data.insert("filename", fileName);
file << templ->genText(data);
}
void create_plugin::handleCommand(std::vector<std::string> &parameters) {
if (parameters.size() < 1) {
std::cout << "Invalid parameters!" << std::endl;
}
for (auto className : parameters) {
std::regex regex("::");
std::string fileName =
std::regex_replace(className, regex, std::string("_"));
std::string headFileName = fileName + ".h";
std::string sourceFilename = fileName + ".cc";
{
std::ifstream iHeadFile(headFileName.c_str(), std::ifstream::in);
std::ifstream iSourceFile(sourceFilename.c_str(),
std::ifstream::in);
if (iHeadFile || iSourceFile) {
std::cout << "The file you want to create already exists, "
"overwrite it(y/n)?"
<< std::endl;
auto in = getchar();
(void)getchar(); // get the return key
if (in != 'Y' && in != 'y') {
std::cout << "Abort!" << std::endl;
exit(0);
}
}
}
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out);
if (!oHeadFile || !oSourceFile) {
perror("");
exit(1);
}
std::cout << "create a plugin:" << className << std::endl;
createPluginHeaderFile(oHeadFile, className, fileName);
createPluginSourceFile(oSourceFile, className, fileName);
}
}

View File

@ -1,31 +0,0 @@
/**
*
* create_plugin.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class create_plugin : public DrObject<create_plugin>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create plugin class files";
}
protected:
std::string outputPath_{ "." };
};
} // namespace drogon_ctl

View File

@ -1,102 +0,0 @@
/**
*
* create_project.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create_project.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#else
#include <direct.h>
#include <io.h>
#endif
#include <fstream>
using namespace drogon_ctl;
void create_project::handleCommand(std::vector<std::string> &parameters) {
if (parameters.size() < 1) {
std::cout << "please input project name" << std::endl;
exit(1);
}
auto pName = parameters[0];
createProject(pName);
}
static void newCmakeFile(std::ofstream &cmakeFile,
const std::string &projectName) {
HttpViewData data;
data.insert("ProjectName", projectName);
auto templ = DrTemplateBase::newTemplate("cmake.csp");
cmakeFile << templ->genText(data);
}
static void newMainFile(std::ofstream &mainFile) {
auto templ = DrTemplateBase::newTemplate("demoMain");
mainFile << templ->genText();
}
static void newGitIgFile(std::ofstream &gitFile) {
auto templ = DrTemplateBase::newTemplate("gitignore.csp");
gitFile << templ->genText();
}
static void newConfigFile(std::ofstream &configFile) {
auto templ = DrTemplateBase::newTemplate("config");
configFile << templ->genText();
}
static void newModelConfigFile(std::ofstream &configFile) {
auto templ = DrTemplateBase::newTemplate("model_json");
configFile << templ->genText();
}
void create_project::createProject(const std::string &projectName) {
#ifdef _WIN32
if (_access(projectName.data(), 0) == 0)
#else
if (access(projectName.data(), 0) == 0)
#endif
{
std::cerr
<< "The directory already exists, please use another project name!"
<< std::endl;
exit(1);
}
std::cout << "create a project named " << projectName << std::endl;
drogon::utils::createPath(projectName);
// 1.create CMakeLists.txt
#ifdef _WIN32
auto r = _chdir(projectName.data());
#else
auto r = chdir(projectName.data());
#endif
(void)(r);
std::ofstream cmakeFile("CMakeLists.txt", std::ofstream::out);
newCmakeFile(cmakeFile, projectName);
std::ofstream mainFile("main.cc", std::ofstream::out);
newMainFile(mainFile);
drogon::utils::createPath("views");
drogon::utils::createPath("controllers");
drogon::utils::createPath("filters");
drogon::utils::createPath("plugins");
drogon::utils::createPath("build");
drogon::utils::createPath("models");
std::ofstream gitFile(".gitignore", std::ofstream::out);
newGitIgFile(gitFile);
std::ofstream configFile("config.json", std::ofstream::out);
newConfigFile(configFile);
std::ofstream modelConfigFile("models/model.json", std::ofstream::out);
newModelConfigFile(modelConfigFile);
}

View File

@ -1,31 +0,0 @@
/**
*
* create_project.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class create_project : public DrObject<create_project>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create a project";
}
protected:
std::string outputPath_{ "." };
void createProject(const std::string &projectName);
};
} // namespace drogon_ctl

View File

@ -1,456 +0,0 @@
/**
*
* @file create_view.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "create_view.h"
#include "cmd.h"
#include <drogon/utils/Utilities.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <regex>
#include <string>
static const std::string cxx_include = "<%inc";
static const std::string cxx_end = "%>";
static const std::string cxx_lang = "<%c++";
static const std::string cxx_view_data = "@@";
static const std::string cxx_output = "$$";
static const std::string cxx_val_start = "[[";
static const std::string cxx_val_end = "]]";
static const std::string sub_view_start = "<%view";
static const std::string sub_view_end = "%>";
using namespace drogon_ctl;
static std::string &replace_all(std::string &str,
const std::string &old_value,
const std::string &new_value) {
std::string::size_type pos(0);
while (true) {
// std::cout<<str<<endl;
// std::cout<<"pos="<<pos<<endl;
if ((pos = str.find(old_value, pos)) != std::string::npos) {
str = str.replace(pos, old_value.length(), new_value);
pos += new_value.length() - old_value.length();
++pos;
} else
break;
}
return str;
}
static void parseCxxLine(std::ofstream &oSrcFile,
const std::string &line,
const std::string &streamName,
const std::string &viewDataName) {
if (line.length() > 0) {
std::string tmp = line;
replace_all(tmp, cxx_output, streamName);
replace_all(tmp, cxx_view_data, viewDataName);
oSrcFile << tmp << "\n";
}
}
static void outputVal(std::ofstream &oSrcFile,
const std::string &streamName,
const std::string &viewDataName,
const std::string &keyName) {
oSrcFile << "{\n";
oSrcFile << " auto & val=" << viewDataName << "[\"" << keyName
<< "\"];\n";
oSrcFile << " if(val.type()==typeid(const char *)){\n";
oSrcFile << " " << streamName
<< "<<*any_cast<const char *>(&val);\n";
oSrcFile << " }else "
"if(val.type()==typeid(std::string)||val.type()==typeid(const "
"std::string)){\n";
oSrcFile << " " << streamName
<< "<<*any_cast<const std::string>(&val);\n";
oSrcFile << " }\n";
oSrcFile << "}\n";
}
static void outputSubView(std::ofstream &oSrcFile,
const std::string &streamName,
const std::string &viewDataName,
const std::string &keyName) {
oSrcFile << "{\n";
oSrcFile << " auto templ=DrTemplateBase::newTemplate(\"" << keyName
<< "\");\n";
oSrcFile << " if(templ){\n";
oSrcFile << " " << streamName << "<< templ->genText(" << viewDataName
<< ");\n";
oSrcFile << " }\n";
oSrcFile << "}\n";
}
static void parseLine(std::ofstream &oSrcFile,
std::string &line,
const std::string &streamName,
const std::string &viewDataName,
int &cxx_flag,
int returnFlag = 1) {
std::string::size_type pos(0);
// std::cout<<line<<"("<<line.length()<<")\n";
if (line.length() > 0 && line[line.length() - 1] == '\r') {
line.resize(line.length() - 1);
}
if (line.length() == 0) {
// std::cout<<"blank line!"<<std::endl;
// std::cout<<streamName<<"<<\"\\n\";\n";
if (returnFlag)
oSrcFile << streamName << "<<\"\\n\";\n";
return;
}
if (cxx_flag == 0) {
// find cxx lang begin
if ((pos = line.find(cxx_lang)) != std::string::npos) {
std::string oldLine = line.substr(0, pos);
if (oldLine.length() > 0)
parseLine(
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
std::string newLine = line.substr(pos + cxx_lang.length());
cxx_flag = 1;
if (newLine.length() > 0)
parseLine(oSrcFile,
newLine,
streamName,
viewDataName,
cxx_flag,
returnFlag);
} else {
if ((pos = line.find(cxx_val_start)) != std::string::npos) {
std::string oldLine = line.substr(0, pos);
parseLine(
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
std::string newLine = line.substr(pos + cxx_val_start.length());
if ((pos = newLine.find(cxx_val_end)) != std::string::npos) {
std::string keyName = newLine.substr(0, pos);
auto iter = keyName.begin();
while (iter != keyName.end() && *iter == ' ')
++iter;
auto iterEnd = iter;
while (iterEnd != keyName.end() && *iterEnd != ' ')
++iterEnd;
keyName = std::string(iter, iterEnd);
outputVal(oSrcFile, streamName, viewDataName, keyName);
std::string tailLine =
newLine.substr(pos + cxx_val_end.length());
parseLine(oSrcFile,
tailLine,
streamName,
viewDataName,
cxx_flag,
returnFlag);
} else {
std::cerr << "format err!" << std::endl;
exit(1);
}
} else if ((pos = line.find(sub_view_start)) != std::string::npos) {
std::string oldLine = line.substr(0, pos);
parseLine(
oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0);
std::string newLine =
line.substr(pos + sub_view_start.length());
if ((pos = newLine.find(sub_view_end)) != std::string::npos) {
std::string keyName = newLine.substr(0, pos);
auto iter = keyName.begin();
while (iter != keyName.end() && *iter == ' ')
++iter;
auto iterEnd = iter;
while (iterEnd != keyName.end() && *iterEnd != ' ')
++iterEnd;
keyName = std::string(iter, iterEnd);
outputSubView(oSrcFile, streamName, viewDataName, keyName);
std::string tailLine =
newLine.substr(pos + sub_view_end.length());
parseLine(oSrcFile,
tailLine,
streamName,
viewDataName,
cxx_flag,
returnFlag);
} else {
std::cerr << "format err!" << std::endl;
exit(1);
}
} else {
if (line.length() > 0) {
replace_all(line, "\\", "\\\\");
replace_all(line, "\"", "\\\"");
oSrcFile << "\t" << streamName << " << \"" << line;
}
if (returnFlag)
oSrcFile << "\\n\";\n";
else
oSrcFile << "\";\n";
}
}
} else {
if ((pos = line.find(cxx_end)) != std::string::npos) {
std::string newLine = line.substr(0, pos);
parseCxxLine(oSrcFile, newLine, streamName, viewDataName);
std::string oldLine = line.substr(pos + cxx_end.length());
cxx_flag = 0;
if (oldLine.length() > 0)
parseLine(oSrcFile,
oldLine,
streamName,
viewDataName,
cxx_flag,
returnFlag);
} else {
parseCxxLine(oSrcFile, line, streamName, viewDataName);
}
}
}
void create_view::handleCommand(std::vector<std::string> &parameters) {
for (auto iter = parameters.begin(); iter != parameters.end();) {
auto &file = *iter;
if (file == "-o" || file == "--output") {
iter = parameters.erase(iter);
if (iter != parameters.end()) {
outputPath_ = *iter;
iter = parameters.erase(iter);
}
continue;
} else if (file == "-n" || file == "--namespace") {
iter = parameters.erase(iter);
if (iter != parameters.end()) {
namespaces_ = utils::splitString(*iter, "::");
iter = parameters.erase(iter);
}
continue;
} else if (file == "--path-to-namespace") {
iter = parameters.erase(iter);
pathToNamespaceFlag_ = true;
continue;
} else if (file[0] == '-') {
std::cout << ARGS_ERROR_STR << std::endl;
return;
}
++iter;
}
createViewFiles(parameters);
}
void create_view::createViewFiles(std::vector<std::string> &cspFileNames) {
for (auto const &file : cspFileNames) {
std::cout << "create view:" << file << std::endl;
createViewFile(file);
}
}
int create_view::createViewFile(const std::string &script_filename) {
std::cout << "create HttpView Class file by " << script_filename
<< std::endl;
if (pathToNamespaceFlag_) {
std::string::size_type pos1 = 0, pos2 = 0;
if (script_filename.length() >= 2 && script_filename[0] == '.' &&
(script_filename[1] == '/' || script_filename[1] == '\\')) {
pos1 = pos2 = 2;
} else if (script_filename.length() >= 1 &&
(script_filename[0] == '/' || script_filename[0] == '\\')) {
pos1 = pos2 = 1;
}
while (pos2 < script_filename.length() - 1) {
if (script_filename[pos2] == '/' || script_filename[pos2] == '\\') {
if (pos2 > pos1) {
namespaces_.push_back(
script_filename.substr(pos1, pos2 - pos1));
}
pos1 = ++pos2;
} else {
++pos2;
}
}
}
std::string npPrefix;
for (auto &np : namespaces_) {
npPrefix += np;
npPrefix += "_";
}
std::ifstream infile(script_filename.c_str(), std::ifstream::in);
if (infile) {
std::string::size_type pos = script_filename.rfind('.');
if (pos != std::string::npos) {
std::string className = script_filename.substr(0, pos);
if ((pos = className.rfind('/')) != std::string::npos) {
className = className.substr(pos + 1);
}
std::cout << "className=" << className << std::endl;
std::string headFileName =
outputPath_ + "/" + npPrefix + className + ".h";
std::string sourceFilename =
outputPath_ + "/" + npPrefix + className + ".cc";
std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(),
std::ofstream::out);
if (!oHeadFile || !oSourceFile) {
std::cerr << "Can't open " << headFileName << " or "
<< sourceFilename << "\n";
return -1;
}
newViewHeaderFile(oHeadFile, className);
newViewSourceFile(oSourceFile, className, npPrefix, infile);
} else
return -1;
} else {
std::cerr << "can't open file " << script_filename << std::endl;
return -1;
}
return 0;
}
void create_view::newViewHeaderFile(std::ofstream &file,
const std::string &className) {
file << "//this file is generated by program automatically,don't modify "
"it!\n";
file << "#include <drogon/DrTemplate.h>\n";
for (auto &np : namespaces_) {
file << "namespace " << np << "\n";
file << "{\n";
}
file << "class " << className << ":public drogon::DrTemplate<" << className
<< ">\n";
file << "{\npublic:\n\t" << className << "(){};\n\tvirtual ~" << className
<< "(){};\n\t"
"virtual std::string genText(const drogon::DrTemplateData &) "
"override;\n};\n";
for (std::size_t i = 0; i < namespaces_.size(); ++i) {
file << "}\n";
}
}
void create_view::newViewSourceFile(std::ofstream &file,
const std::string &className,
const std::string &namespacePrefix,
std::ifstream &infile) {
file << "//this file is generated by program(drogon_ctl) "
"automatically,don't modify it!\n";
file << "#include \"" << namespacePrefix << className << ".h\"\n";
file << "#include <drogon/utils/OStringStream.h>\n";
file << "#include <string>\n";
file << "#include <map>\n";
file << "#include <vector>\n";
file << "#include <set>\n";
file << "#include <iostream>\n";
file << "#include <unordered_map>\n";
file << "#include <unordered_set>\n";
file << "#include <algorithm>\n";
file << "#include <list>\n";
file << "#include <deque>\n";
file << "#include <queue>\n";
// Find layout tag
std::string layoutName;
std::regex layoutReg("<%layout[ \\t]+(((?!%\\}).)*[^ \\t])[ \\t]*%>");
for (std::string buffer; std::getline(infile, buffer);) {
std::smatch results;
if (std::regex_search(buffer, results, layoutReg)) {
if (results.size() > 1) {
layoutName = results[1].str();
break;
}
}
}
infile.clear();
infile.seekg(0, std::ifstream::beg);
bool import_flag{ false };
for (std::string buffer; std::getline(infile, buffer);) {
std::string::size_type pos(0);
if (!import_flag) {
std::string lowerBuffer = buffer;
std::transform(lowerBuffer.begin(),
lowerBuffer.end(),
lowerBuffer.begin(),
::tolower);
if ((pos = lowerBuffer.find(cxx_include)) != std::string::npos) {
// std::cout<<"haha find it!"<<endl;
std::string newLine = buffer.substr(pos + cxx_include.length());
import_flag = true;
if ((pos = newLine.find(cxx_end)) != std::string::npos) {
newLine = newLine.substr(0, pos);
file << newLine << "\n";
break;
} else {
file << newLine << "\n";
}
}
} else {
// std::cout<<buffer<<endl;
if ((pos = buffer.find(cxx_end)) != std::string::npos) {
std::string newLine = buffer.substr(0, pos);
file << newLine << "\n";
break;
} else {
// std::cout<<"to source file"<<buffer<<endl;
file << buffer << "\n";
}
}
}
// std::cout<<"import_flag="<<import_flag<<std::endl;
if (!import_flag) {
infile.clear();
infile.seekg(0, std::ifstream::beg);
}
if (!namespaces_.empty()) {
file << "using namespace ";
for (std::size_t i = 0; i < namespaces_.size(); ++i) {
if (i != namespaces_.size() - 1) {
file << namespaces_[i] << "::";
} else {
file << namespaces_[i] << ";";
}
}
file << "\n";
}
file << "using namespace drogon;\n";
std::string viewDataName = className + "_view_data";
// virtual std::string genText(const DrTemplateData &)
file << "std::string " << className << "::genText(const DrTemplateData& "
<< viewDataName << ")\n{\n";
// std::string bodyName=className+"_bodystr";
std::string streamName = className + "_tmp_stream";
// oSrcFile <<"\tstd::string "<<bodyName<<";\n";
file << "\tdrogon::OStringStream " << streamName << ";\n";
file << "\tstd::string layoutName{\"" << layoutName << "\"};\n";
int cxx_flag = 0;
for (std::string buffer; std::getline(infile, buffer);) {
if (buffer.length() > 0) {
std::smatch results;
if (std::regex_search(buffer, results, layoutReg)) {
if (results.size() > 1) {
continue;
}
}
std::regex re("\\{%[ \\t]*(((?!%\\}).)*[^ \\t])[ \\t]*%\\}");
buffer = std::regex_replace(buffer, re, "<%c++$$$$<<$1;%>");
}
parseLine(file, buffer, streamName, viewDataName, cxx_flag);
}
file << "if(layoutName.empty())\n{\n";
file << "std::string ret{std::move(" << streamName << ".str())};\n";
file << "return ret;\n}else\n{\n";
file << "auto templ = DrTemplateBase::newTemplate(layoutName);\n";
file << "if(!templ) return \"\";\n";
file << "HttpViewData data = " << viewDataName << ";\n";
file << "auto str = std::move(" << streamName << ".str());\n";
file << "if(!str.empty() && str[str.length()-1] == '\\n') "
"str.resize(str.length()-1);\n";
file << "data[\"\"] = std::move(str);\n";
file << "return templ->genText(data);\n";
file << "}\n}\n";
}

View File

@ -1,40 +0,0 @@
/**
*
* @file create_view.h
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class create_view : public DrObject<create_view>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "create view class files";
}
protected:
std::string outputPath_{ "." };
std::vector<std::string> namespaces_;
bool pathToNamespaceFlag_{ false };
void createViewFiles(std::vector<std::string> &cspFileNames);
int createViewFile(const std::string &script_filename);
void newViewHeaderFile(std::ofstream &file, const std::string &className);
void newViewSourceFile(std::ofstream &file,
const std::string &className,
const std::string &namespacePrefix,
std::ifstream &infile);
};
} // namespace drogon_ctl

View File

@ -1,59 +0,0 @@
/**
*
* help.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "help.h"
#include <drogon/DrClassMap.h>
#include <iostream>
#include <memory>
using namespace drogon_ctl;
void help::handleCommand(std::vector<std::string> &parameters) {
if (parameters.size() == 0) {
std::cout << "usage: drogon_ctl [-v | --version] [-h | --help] "
"<command> [<args>]"
<< std::endl;
std::cout << "commands list:" << std::endl;
for (auto &className : drogon::DrClassMap::getAllClassName()) {
auto classPtr = std::shared_ptr<DrObjectBase>(
drogon::DrClassMap::newObject(className));
if (classPtr) {
auto cmdHdlPtr =
std::dynamic_pointer_cast<CommandHandler>(classPtr);
if (cmdHdlPtr) {
if (!cmdHdlPtr->isTopCommand())
continue;
auto pos = className.rfind("::");
if (pos != std::string::npos) {
className = className.substr(pos + 2);
}
while (className.length() < 24)
className.append(" ");
std::cout << className << cmdHdlPtr->script() << std::endl;
}
}
}
} else {
auto cmd = std::string("drogon_ctl::") + parameters[0];
auto classPtr =
std::shared_ptr<DrObjectBase>(drogon::DrClassMap::newObject(cmd));
if (classPtr) {
auto cmdHdlPtr =
std::dynamic_pointer_cast<CommandHandler>(classPtr);
if (cmdHdlPtr) {
if (cmdHdlPtr->isTopCommand())
std::cout << cmdHdlPtr->detail() << std::endl;
}
}
}
}

View File

@ -1,31 +0,0 @@
/**
*
* help.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class help : public DrObject<help>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "display this message";
}
virtual bool isTopCommand() override {
return true;
}
};
} // namespace drogon_ctl

View File

@ -1,42 +0,0 @@
/**
*
* @file main.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "cmd.h"
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
std::vector<std::string> args;
if (argc < 2) {
args = { "help" };
exeCommand(args);
return 0;
}
for (int i = 1; i < argc; ++i) {
args.push_back(argv[i]);
}
if (args.size() > 0) {
auto &arg = args[0];
if (arg == "-h" || arg == "--help") {
arg = "help";
} else if (arg == "-v" || arg == "--version") {
arg = "version";
}
}
exeCommand(args);
return 0;
}

View File

@ -1,259 +0,0 @@
/**
*
* press.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by the MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "press.h"
#include "cmd.h"
#include <drogon/DrClassMap.h>
#include <stdlib.h>
#include <iomanip>
#include <iostream>
#include <memory>
#ifndef _WIN32
#include <unistd.h>
#endif
using namespace drogon_ctl;
std::string press::detail() {
return "Use press command to do stress testing\n"
"Usage:drogon_ctl press <options> <url>\n"
" -n num number of requests(default : 1)\n"
" -t num number of threads(default : 1)\n"
" -c num concurrent connections(default : 1)\n"
// " -k keep alive(default: no)\n"
" -q no progress indication(default: no)\n\n"
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
"http://localhost:8080/index.html\n";
}
void outputErrorAndExit(const string_view &err) {
std::cout << err << std::endl;
exit(1);
}
void press::handleCommand(std::vector<std::string> &parameters) {
for (auto iter = parameters.begin(); iter != parameters.end(); iter++) {
auto &param = *iter;
if (param.find("-n") == 0) {
if (param == "-n") {
++iter;
if (iter == parameters.end()) {
outputErrorAndExit("No number of requests!");
}
auto &num = *iter;
try {
numOfRequests_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of requests!");
}
continue;
} else {
auto num = param.substr(2);
try {
numOfRequests_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of requests!");
}
continue;
}
} else if (param.find("-t") == 0) {
if (param == "-t") {
++iter;
if (iter == parameters.end()) {
outputErrorAndExit("No number of threads!");
}
auto &num = *iter;
try {
numOfThreads_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of threads!");
}
continue;
} else {
auto num = param.substr(2);
try {
numOfThreads_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of threads!");
}
continue;
}
} else if (param.find("-c") == 0) {
if (param == "-c") {
++iter;
if (iter == parameters.end()) {
outputErrorAndExit("No number of connections!");
}
auto &num = *iter;
try {
numOfConnections_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of connections!");
}
continue;
} else {
auto num = param.substr(2);
try {
numOfConnections_ = std::stoll(num);
} catch (...) {
outputErrorAndExit("Invalid number of connections!");
}
continue;
}
}
// else if (param == "-k")
// {
// keepAlive_ = true;
// continue;
// }
else if (param == "-q") {
processIndication_ = false;
} else if (param[0] != '-') {
url_ = param;
}
}
// std::cout << "n=" << numOfRequests_ << std::endl;
// std::cout << "t=" << numOfThreads_ << std::endl;
// std::cout << "c=" << numOfConnections_ << std::endl;
// std::cout << "q=" << processIndication_ << std::endl;
// std::cout << "url=" << url_ << std::endl;
if (url_.empty() || url_.compare(0, 4, "http") != 0 ||
(url_.compare(4, 3, "://") != 0 && url_.compare(4, 4, "s://") != 0)) {
outputErrorAndExit("Invalid URL");
} else {
auto pos = url_.find("://");
auto posOfPath = url_.find("/", pos + 3);
if (posOfPath == std::string::npos) {
host_ = url_;
path_ = "/";
} else {
host_ = url_.substr(0, posOfPath);
path_ = url_.substr(posOfPath);
}
}
// std::cout << "host=" << host_ << std::endl;
// std::cout << "path=" << path_ << std::endl;
doTesting();
}
void press::doTesting() {
createRequestAndClients();
if (clients_.empty()) {
outputErrorAndExit("No connection!");
}
statistics_.startDate_ = trantor::Date::now();
for (auto &client : clients_) {
sendRequest(client);
}
loopPool_->wait();
}
void press::createRequestAndClients() {
loopPool_ = std::make_unique<trantor::EventLoopThreadPool>(numOfThreads_);
loopPool_->start();
for (size_t i = 0; i < numOfConnections_; ++i) {
auto client =
HttpClient::newHttpClient(host_, loopPool_->getNextLoop());
client->enableCookies();
clients_.push_back(client);
}
}
void press::sendRequest(const HttpClientPtr &client) {
auto numOfRequest = statistics_.numOfRequestsSent_++;
if (numOfRequest >= numOfRequests_) {
return;
}
auto request = HttpRequest::newHttpRequest();
request->setPath(path_);
request->setMethod(Get);
// std::cout << "send!" << std::endl;
client->sendRequest(
request,
[this, client, request](ReqResult r, const HttpResponsePtr &resp) {
size_t goodNum, badNum;
if (r == ReqResult::Ok) {
// std::cout << "OK" << std::endl;
goodNum = ++statistics_.numOfGoodResponse_;
badNum = statistics_.numOfBadResponse_;
statistics_.bytesRecieved_ += resp->body().length();
auto delay = trantor::Date::now().microSecondsSinceEpoch() -
request->creationDate().microSecondsSinceEpoch();
statistics_.totalDelay_ += delay;
} else {
goodNum = statistics_.numOfGoodResponse_;
badNum = ++statistics_.numOfBadResponse_;
if (badNum > numOfRequests_ / 10) {
outputErrorAndExit("Too many errors");
}
}
if (goodNum + badNum >= numOfRequests_) {
outputResults();
}
if (r == ReqResult::Ok)
sendRequest(client);
else {
client->getLoop()->runAfter(1, [this, client]() {
sendRequest(client);
});
}
if (processIndication_) {
auto rec = goodNum + badNum;
if (rec % 100000 == 0) {
std::cout << rec << " responses are received" << std::endl
<< std::endl;
}
}
});
}
void press::outputResults() {
static std::mutex mtx;
size_t totalSent = 0;
size_t totalRecv = 0;
for (auto &client : clients_) {
totalSent += client->bytesSent();
totalRecv += client->bytesReceived();
}
auto now = trantor::Date::now();
auto microSecs = now.microSecondsSinceEpoch() -
statistics_.startDate_.microSecondsSinceEpoch();
double seconds = (double)microSecs / 1000000.0;
size_t rps = static_cast<size_t>(statistics_.numOfGoodResponse_ / seconds);
std::cout << std::endl;
std::cout << "TOTALS: " << numOfConnections_ << " connect, "
<< numOfRequests_ << " requests, "
<< statistics_.numOfGoodResponse_ << " success, "
<< statistics_.numOfBadResponse_ << " fail" << std::endl;
std::cout << "TRAFFIC: "
<< statistics_.bytesRecieved_ / statistics_.numOfGoodResponse_
<< " avg bytes, "
<< (totalRecv - statistics_.bytesRecieved_) /
statistics_.numOfGoodResponse_
<< " avg overhead, " << statistics_.bytesRecieved_ << " bytes, "
<< totalRecv - statistics_.bytesRecieved_ << " overhead"
<< std::endl;
std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(3)
<< "TIMING: " << seconds << " seconds, " << rps << " rps, "
<< (double)(statistics_.totalDelay_) /
statistics_.numOfGoodResponse_ / 1000
<< " ms avg req time" << std::endl;
std::cout << "SPEED: download " << totalRecv / seconds / 1000
<< " kBps, upload " << totalSent / seconds / 1000 << " kBps"
<< std::endl
<< std::endl;
exit(0);
}

View File

@ -1,69 +0,0 @@
/**
*
* press.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by the MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpClient.h>
#include <trantor/net/EventLoopThreadPool.h>
#include <trantor/utils/Date.h>
#include <atomic>
#include <memory>
#include <string>
#include <vector>
using namespace drogon;
namespace drogon_ctl {
struct Statistics {
std::atomic_size_t numOfRequestsSent_{ 0 };
std::atomic_size_t bytesRecieved_{ 0 };
std::atomic_size_t numOfGoodResponse_{ 0 };
std::atomic_size_t numOfBadResponse_{ 0 };
std::atomic_size_t totalDelay_{ 0 };
trantor::Date startDate_;
trantor::Date endDate_;
};
class press : public DrObject<press>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "Do stress testing(Use 'drogon_ctl help press' for more "
"information)";
}
virtual bool isTopCommand() override {
return true;
}
virtual std::string detail() override;
private:
size_t numOfThreads_{ 1 };
size_t numOfRequests_{ 1 };
size_t numOfConnections_{ 1 };
// bool keepAlive_ = false;
bool processIndication_{ true };
std::string url_;
std::string host_;
std::string path_;
void doTesting();
void createRequestAndClients();
void sendRequest(const HttpClientPtr &client);
void outputResults();
std::unique_ptr<trantor::EventLoopThreadPool> loopPool_;
std::vector<HttpClientPtr> clients_;
Statistics statistics_;
};
} // namespace drogon_ctl

View File

@ -1,68 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project([[ProjectName]] CXX)
include(CheckIncludeFileCXX)
check_include_file_cxx(any HAS_ANY)
check_include_file_cxx(string_view HAS_STRING_VIEW)
check_include_file_cxx(coroutine HAS_COROUTINE)
if (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
set(CMAKE_CXX_STANDARD 20)
elseif (HAS_ANY AND HAS_STRING_VIEW)
set(CMAKE_CXX_STANDARD 17)
else ()
set(CMAKE_CXX_STANDARD 14)
endif ()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(${PROJECT_NAME} main.cc)
# ##############################################################################
# If you include the drogon source code locally in your project, use this method
# to add drogon
# add_subdirectory(drogon)
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
#
# and comment out the following lines
find_package(Drogon CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
# ##############################################################################
if (CMAKE_CXX_STANDARD LESS 17)
# With C++14, use boost to support any and string_view
message(STATUS "use c++14")
find_package(Boost 1.61.0 REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
elseif (CMAKE_CXX_STANDARD LESS 20)
message(STATUS "use c++17")
else ()
message(STATUS "use c++20")
endif ()
aux_source_directory(controllers CTL_SRC)
aux_source_directory(filters FILTER_SRC)
aux_source_directory(plugins PLUGIN_SRC)
aux_source_directory(models MODEL_SRC)
drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
${CMAKE_CURRENT_BINARY_DIR})
# use the following line to create views with namespaces.
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
# ${CMAKE_CURRENT_BINARY_DIR} TRUE)
target_include_directories(${PROJECT_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/models)
target_sources(${PROJECT_NAME}
PRIVATE
${SRC_DIR}
${CTL_SRC}
${FILTER_SRC}
${PLUGIN_SRC}
${MODEL_SRC})
# ##############################################################################
# uncomment the following line for dynamically loading views
# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON)

View File

@ -1,297 +0,0 @@
/* This is a JSON format configuration file
*/
{
/*
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
"ssl": {
"cert": "../../trantor/trantor/tests/server.pem",
"key": "../../trantor/trantor/tests/server.pem",
"conf": [
//["Options", "-SessionTicket"],
//["Options", "Compression"]
]
},
"listeners": [
{
//address: Ip address,0.0.0.0 by default
"address": "0.0.0.0",
//port: Port number
"port": 80,
//https: If true, use https for security,false by default
"https": false
},
{
"address": "0.0.0.0",
"port": 443,
"https": true,
//cert,key: Cert file path and key file path, empty by default,
//if empty, use the global setting
"cert": "",
"key": "",
//use_old_tls: enable the TLS1.0/1.1, false by default
"use_old_tls": false,
"ssl_conf": [
//["MinProtocol", "TLSv1.3"]
]
}
],
"db_clients": [
{
//name: Name of the client,'default' by default
//"name":"",
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
"rdbms": "postgresql",
//filename: Sqlite3 db file name
//"filename":"",
//host: Server address,localhost by default
"host": "127.0.0.1",
//port: Server port, 5432 by default
"port": 5432,
//dbname: Database name
"dbname": "test",
//user: 'postgres' by default
"user": "",
//passwd: '' by default
"passwd": "",
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//client_encoding: The character set used by the client. it is empty string by default which
//means use the default character set.
//"client_encoding": "",
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
//zero or negative value means no timeout.
"timeout": -1.0
}
],
"redis_clients": [
{
//name: Name of the client,'default' by default
//"name":"",
//host: Server IP, 127.0.0.1 by default
"host": "127.0.0.1",
//port: Server port, 6379 by default
"port": 6379,
//passwd: '' by default
"passwd": "",
//db index: 0 by default
"db": 0,
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a command.
//zero or negative value means no timeout.
"timeout": -1.0
}
],*/
"app": {
//number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
//is the number of CPU cores
"number_of_threads": 1,
//enable_session: False by default
"enable_session": false,
"session_timeout": 0,
//document_root: Root path of HTTP document, defaut path is ./
"document_root": "./",
//home_page: Set the HTML file of the home page, the default value is "index.html"
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
//to the request for "/".
"home_page": "index.html",
//use_implicit_page: enable implicit pages if true, true by default
"use_implicit_page": true,
//implicit_page: Set the file which would the server access in a directory that a user accessed.
//For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
"implicit_page": "index.html",
//static_file_headers: Headers for static files
/*"static_file_headers": [
{
"name": "field-name",
"value": "field-value"
}
],*/
//upload_path: The path to save the uploaded file. "uploads" by default.
//If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"upload_path": "uploads",
/* file_types:
* HTTP download file types,The file types supported by drogon
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
* "gif", "bmp", "ico", "icns", etc. */
"file_types": [
"gif",
"png",
"jpg",
"js",
"css",
"html",
"ico",
"swf",
"xap",
"apk",
"cur",
"xml"
],
//locations: An array of locations of static files for GET requests.
"locations": [
{
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
//"uri_prefix": "/.well-known/acme-challenge/",
//default_content_type: The default content type of the static files without
//an extension. empty string by default.
"default_content_type": "text/plain",
//alias: The location in file system, if it is prefixed with "/", it
//presents an absolute path, otherwise it presents a relative path to
//the document_root path.
//The default value is "" which means use the document root path as the location base path.
"alias": "",
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
"is_case_sensitive": false,
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
"allow_all": true,
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
"is_recursive": true,
//filters: string array, the filters applied to the location.
"filters": []
}
],
//max_connections: maximum number of connections, 100000 by default
"max_connections": 100000,
//max_connections_per_ip: maximum number of connections per clinet, 0 by default which means no limit
"max_connections_per_ip": 0,
//Load_dynamic_views: False by default, when set to true, drogon
//compiles and loads dynamically "CSP View Files" in directories defined
//by "dynamic_views_path"
"load_dynamic_views": false,
//dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
"enable_unicode_escaping_in_json": true,
//float_precision_in_json: set precision of float number in json.
"float_precision_in_json": {
//precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
"precision": 0,
//precision_type: must be "significant" or "decimal", defaults to "significant" that means
//setting max number of significant digits in string, "decimal" means setting max number of
//digits after "." in string
"precision_type": "significant"
},
//log: Set log output, drogon output logs to stdout by default
"log": {
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
//"log_path": "./",
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
//drogon.log ...
"logfile_base_name": "",
//log_size_limit: 100000000 bytes by default,
//When the log file size reaches "log_size_limit", the log file is switched.
"log_size_limit": 100000000,
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
//The TRACE level is only valid when built in DEBUG mode.
"log_level": "DEBUG"
},
//run_as_daemon: False by default
"run_as_daemon": false,
//handle_sig_term: True by default
"handle_sig_term": true,
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
"relaunch_on_error": false,
//use_sendfile: True by default, if true, the program
//uses sendfile() system-call to send static files to clients;
"use_sendfile": true,
//use_gzip: True by default, use gzip to compress the response body's content;
"use_gzip": true,
//use_brotli: False by default, use brotli to compress the response body's content;
"use_brotli": false,
//static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
//0 means cache forever, the negative value means no cache
"static_files_cache_time": 5,
//simple_controllers_map: Used to configure mapping from path to simple controller
"simple_controllers_map": [
{
"path": "/path/name",
"controller": "controllerClassName",
"http_methods": [
"get",
"post"
],
"filters": [
"FilterClassName"
]
}
],
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
//of the connection without read or write
"idle_connection_timeout": 60,
//server_header_field: Set the 'Server' header field in each response sent by drogon,
//empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
"server_header_field": "",
//enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
//value is true.
"enable_server_header": true,
//enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
//value is true.
"enable_date_header": true,
//keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"keepalive_requests": 0,
//pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"pipelining_requests": 0,
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".gz" in the same path and send the compressed file to the client.
//The default value of gzip_static is true.
"gzip_static": true,
//br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".br" in the same path and send the compressed file to the client.
//The default value of br_static is true.
"br_static": true,
//client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_body_size": "1M",
//max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
//If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
//Setting it to "" means no limit.
"client_max_memory_body_size": "64K",
//client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_websocket_message_size": "128K",
//reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
"reuse_port": false
},
//plugins: Define all plugins running in the application
"plugins": [
{
//name: The class name of the plugin
//"name": "drogon::plugin::SecureSSLRedirector",
//dependencies: Plugins that the plugin depends on. It can be commented out
"dependencies": [],
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
//It can be commented out
"config": {
"ssl_redirect_exempt": [
".*\\.jpg"
],
"secure_ssl_host": "localhost:8849"
}
}
],
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
"custom_config": {}
}

View File

@ -1,10 +0,0 @@
#include <drogon/drogon.h>
int main() {
//Set HTTP listener address and port
drogon::app().addListener("0.0.0.0",80);
//Load config file
//drogon::app().loadConfigFile("../config.json");
//Run HTTP framework,the method will block in the internal event loop
drogon::app().run();
return 0;
}

View File

@ -1,30 +0,0 @@
/**
*
* [[filename]].cc
*
*/
#include "[[filename]].h"
using namespace drogon;
<%c++auto namespaceStr=@@.get<std::string>("namespaceString");
if(!namespaceStr.empty())
$$<<"using namespace "<<namespaceStr<<";\n";
%>
void [[className]]::doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb)
{
//Edit your logic here
if (1)
{
//Passed
fccb();
return;
}
//Check failed
auto res = drogon::HttpResponse::newHttpResponse();
res->setStatusCode(k500InternalServerError);
fcb(res);
}

View File

@ -1,32 +0,0 @@
/**
*
* [[filename]].h
*
*/
#pragma once
#include <drogon/HttpFilter.h>
using namespace drogon;
<%c++
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
if(namespaceVector.empty())
$$<<"\n";
for(auto &namespaceName:namespaceVector){%>
namespace {%namespaceName%}
{
<%c++}
$$<<"\n";%>
class [[className]] : public HttpFilter<[[className]]>
{
public:
[[className]]() {}
virtual void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) override;
};
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
}
<%c++}%>

View File

@ -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++

File diff suppressed because it is too large Load Diff

View File

@ -1,558 +0,0 @@
<%inc#include "create_model.h"
using namespace drogon_ctl;
%>
/**
*
* [[className]].h
* DO NOT EDIT. This file is generated by drogon_ctl
*
*/
#pragma once
#include <drogon/orm/Result.h>
#include <drogon/orm/Row.h>
#include <drogon/orm/Field.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/orm/Mapper.h>
#ifdef __cpp_impl_coroutine
#include <drogon/orm/CoroMapper.h>
#endif
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#include <json/json.h>
#include <string>
#include <memory>
#include <vector>
#include <tuple>
#include <stdint.h>
#include <iostream>
using namespace drogon::orm;
namespace drogon
{
namespace orm
{
class DbClient;
using DbClientPtr = std::shared_ptr<DbClient>;
}
}
namespace drogon_model
{
namespace [[dbName]]
{
<%c++
auto &schema=@@.get<std::string>("schema");
if(!schema.empty())
{
$$<<"namespace "<<schema<<"\n";
$$<<"{\n";
}
std::vector<std::string> relationshipClassNames;
auto &relationships=@@.get<std::vector<Relationship>>("relationships");
for(auto &relationship : relationships)
{
auto &name = relationship.targetTableName();
auto relationshipClassName = nameTransform(name, true);
relationshipClassNames.push_back(relationshipClassName);
if(relationship.type() == Relationship::Type::ManyToMany)
{
auto &pivotTableName = relationship.pivotTable().tableName();
auto pivotTableClassName = nameTransform(pivotTableName, true);
relationshipClassNames.push_back(pivotTableClassName);
}
}
std::sort(relationshipClassNames.begin(), relationshipClassNames.end());
relationshipClassNames.erase(std::unique(relationshipClassNames.begin(), relationshipClassNames.end()), relationshipClassNames.end());
for(std::string &relationshipClassName : relationshipClassNames)
{
%>
class {%relationshipClassName%};
<%c++
}
%>
class [[className]]
{
public:
struct Cols
{
<%c++
auto cols=@@.get<std::vector<ColumnInfo>>("columns");
for(size_t i=0;i<cols.size();i++)
{
$$<<" static const std::string _"<<cols[i].colName_<<";\n";
}
%>
};
const static int primaryKeyNumber;
const static std::string tableName;
const static bool hasPrimaryKey;
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
const static std::string primaryKeyName;
<%c++if(!@@.get<std::string>("primaryKeyType").empty()){%>
using PrimaryKeyType = [[primaryKeyType]];
const PrimaryKeyType &getPrimaryKey() const;
<%c++}else{%>
using PrimaryKeyType = void;
int getPrimaryKey() const { assert(false); return 0; }
<%c++}%>
<%c++}else{
auto pkTypes=@@.get<std::vector<std::string>>("primaryKeyType");
std::string typelist;
for(size_t i=0;i<pkTypes.size();i++)
{
typelist += pkTypes[i];
if(i<(pkTypes.size()-1))
typelist += ",";
}
%>
const static std::vector<std::string> primaryKeyName;
using PrimaryKeyType = std::tuple<{%typelist%}>;//<%c++
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
for(size_t i=0;i<pkName.size();i++)
{
$$<<pkName[i];
if(i<(pkName.size()-1))
$$<<",";
}
%>
PrimaryKeyType getPrimaryKey() const;
<%c++}%>
/**
* @brief constructor
* @param r One row of records in the SQL query result.
* @param indexOffset Set the offset to -1 to access all columns by column names,
* otherwise access all columns by offsets.
* @note If the SQL is not a style of 'select * from table_name ...' (select all
* columns by an asterisk), please set the offset to -1.
*/
explicit [[className]](const Row &r, const ssize_t indexOffset = 0) noexcept;
/**
* @brief constructor
* @param pJson The json object to construct a new instance.
*/
explicit [[className]](const Json::Value &pJson) noexcept(false);
/**
* @brief constructor
* @param pJson The json object to construct a new instance.
* @param pMasqueradingVector The aliases of table columns.
*/
[[className]](const Json::Value &pJson, const std::vector<std::string> &pMasqueradingVector) noexcept(false);
[[className]]() = default;
void updateByJson(const Json::Value &pJson) noexcept(false);
void updateByMasqueradedJson(const Json::Value &pJson,
const std::vector<std::string> &pMasqueradingVector) noexcept(false);
static bool validateJsonForCreation(const Json::Value &pJson, std::string &err);
static bool validateMasqueradedJsonForCreation(const Json::Value &,
const std::vector<std::string> &pMasqueradingVector,
std::string &err);
static bool validateJsonForUpdate(const Json::Value &pJson, std::string &err);
static bool validateMasqueradedJsonForUpdate(const Json::Value &,
const std::vector<std::string> &pMasqueradingVector,
std::string &err);
static bool validJsonOfField(size_t index,
const std::string &fieldName,
const Json::Value &pJson,
std::string &err,
bool isForCreation);
<%c++
for(const auto &col:cols)
{
$$<<" /** For column "<<col.colName_<<" */\n";
if(!col.colType_.empty())
{
$$<<" ///Get the value of the column "<<col.colName_<<", returns the default value if the column is null\n";
$$<<" const "<<col.colType_<<" &getValueOf"<<col.colTypeName_<<"() const noexcept;\n";
if(col.colType_=="std::vector<char>")
{
$$<<" ///Return the column value by std::string with binary data\n";
$$<<" std::string getValueOf"<<col.colTypeName_<<"AsString() const noexcept;\n";
}
$$<<" ///Return a shared_ptr object pointing to the column const value, or an empty shared_ptr object if the column is null\n";
$$<<" const std::shared_ptr<"<<col.colType_<<"> &get"<<col.colTypeName_<<"() const noexcept;\n";
$$<<" ///Set the value of the column "<<col.colName_<<"\n";
$$<<" void set"<<col.colTypeName_<<"(const "<<col.colType_<<" &p"<<col.colTypeName_<<") noexcept;\n";
if(col.colType_=="std::string")
$$<<" void set"<<col.colTypeName_<<"("<<col.colType_<<" &&p"<<col.colTypeName_<<") noexcept;\n";
if(col.colType_=="std::vector<char>")
{
$$<<" void set"<<col.colTypeName_<<"(const std::string &p"<<col.colTypeName_<<") noexcept;\n";
}
if(!col.notNull_)
{
$$<<" void set"<<col.colTypeName_<<"ToNull() noexcept;\n";
}
}
else
$$<<" //FIXME!!"<<" getValueOf"<<col.colTypeName_<<"() const noexcept;\n";
$$<<"\n";
}
%>
static size_t getColumnNumber() noexcept { return {% cols.size() %}; }
static const std::string &getColumnName(size_t index) noexcept(false);
Json::Value toJson() const;
Json::Value toMasqueradedJson(const std::vector<std::string> &pMasqueradingVector) const;
/// Relationship interfaces
<%c++
for(auto &relationship : relationships)
{
if(relationship.targetKey().empty() || relationship.originalKey().empty())
{
continue;
}
auto &name=relationship.targetTableName();
auto relationshipClassName=nameTransform(name, true);
auto relationshipValName=nameTransform(name, false);
auto alias=relationship.targetTableAlias();
auto aliasValName=nameTransform(alias, false);
if(relationship.type() == Relationship::Type::HasOne)
{
if(!alias.empty())
{
if(alias[0] <= 'z' && alias[0] >= 'a')
{
alias[0] += ('A' - 'a');
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
{%alind%} const std::function<void({%relationshipClassName%})> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void({%relationshipClassName%})> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
<%c++
}
}
else if(relationship.type() == Relationship::Type::HasMany)
{
if(!alias.empty())
{
if(alias[0] <= 'z' && alias[0] >= 'a')
{
alias[0] += ('A' - 'a');
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
{%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
<%c++
}
}
else if(relationship.type() == Relationship::Type::ManyToMany)
{
auto &pivotTableName=relationship.pivotTable().tableName();
auto pivotTableClassName=nameTransform(pivotTableName, true);
if(!alias.empty())
{
if(alias[0] <= 'z' && alias[0] >= 'a')
{
alias[0] += ('A' - 'a');
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
{%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
<%c++
}
}
}
%>
private:
friend Mapper<[[className]]>;
#ifdef __cpp_impl_coroutine
friend CoroMapper<[[className]]>;
#endif
static const std::vector<std::string> &insertColumns() noexcept;
void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
const std::vector<std::string> updateColumns() const;
void updateArgs(drogon::orm::internal::SqlBinder &binder) const;
///For mysql or sqlite3
void updateId(const uint64_t id);
<%c++
for(auto col:cols)
{
if(!col.colType_.empty())
$$<<" std::shared_ptr<"<<col.colType_<<"> "<<col.colValName_<<"_;\n";
}
%>
struct MetaData
{
const std::string colName_;
const std::string colType_;
const std::string colDatabaseType_;
const ssize_t colLength_;
const bool isAutoVal_;
const bool isPrimaryKey_;
const bool notNull_;
};
static const std::vector<MetaData> metaData_;
bool dirtyFlag_[{%cols.size()%}]={ false };
public:
static const std::string &sqlForFindingByPrimaryKey()
{
<%c++
auto rdbms=@@.get<std::string>("rdbms");
if(@@.get<int>("hasPrimaryKey")<=1){
if(!@@.get<std::string>("primaryKeyType").empty()){%>
static const std::string sql="select * from " + tableName + " where [[primaryKeyName]] = {%(rdbms=="postgresql"?"$1":"?")%}";
<%c++}else{%>
static const std::string sql="";
<%c++}%>
<%c++}else{
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
%>
static const std::string sql="select * from " + tableName + " where <%c++
for(size_t i=0;i<pkName.size();i++)
{
if(rdbms=="postgresql")
{
$$<<pkName[i]<<" = $"<<i+1;
}
else
{
$$<<pkName[i]<<" = ?";
}
if(i<(pkName.size()-1))
$$<<" and ";
}
$$<<"\";\n";
}
%>
return sql;
}
static const std::string &sqlForDeletingByPrimaryKey()
{
<%c++
if(@@.get<int>("hasPrimaryKey")<=1){
if(!@@.get<std::string>("primaryKeyType").empty()){%>
static const std::string sql="delete from " + tableName + " where [[primaryKeyName]] = {%(rdbms=="postgresql"?"$1":"?")%}";
<%c++}else{%>
static const std::string sql="";
<%c++}%>
<%c++}else{
auto pkName=@@.get<std::vector<std::string>>("primaryKeyName");
%>
static const std::string sql="delete from " + tableName + " where <%c++
for(size_t i=0;i<pkName.size();i++)
{
if(rdbms=="postgresql")
{
$$<<pkName[i]<<" = $"<<i+1;
}
else
{
$$<<pkName[i]<<" = ?";
}
if(i<(pkName.size()-1))
$$<<" and ";
}
$$<<"\";\n";
}
%>
return sql;
}
std::string sqlForInserting(bool &needSelection) const
{
std::string sql="insert into " + tableName + " (";
size_t parametersCount = 0;
needSelection = false;
<%c++
bool selFlag=false;
for(size_t i=0;i<cols.size();i++)
{
if(cols[i].isAutoVal_)
{
if(@@.get<std::string>("rdbms")=="sqlite3")
{
continue;
}
if(@@.get<int>("hasPrimaryKey")>0)
{
selFlag = true;
}
$$<<" sql += \""<<cols[i].colName_<<",\";\n";
$$<<" ++parametersCount;\n";
continue;
}
if(cols[i].colType_.empty())
continue;
if(cols[i].hasDefaultVal_)
{
if(@@.get<std::string>("rdbms")!="sqlite3")
{
$$<<" sql += \""<<cols[i].colName_<<",\";\n";
$$<<" ++parametersCount;\n";
}
else
{
%>
if(dirtyFlag_[{%i%}])
{
sql += "{%cols[i].colName_%},";
++parametersCount;
}
<%c++
}
if(@@.get<int>("hasPrimaryKey")>0||@@.get<std::string>("rdbms")=="postgresql")
{
%>
if(!dirtyFlag_[{%i%}])
{
needSelection=true;
}
<%c++
}
}
else
{
%>
if(dirtyFlag_[{%i%}])
{
sql += "{%cols[i].colName_%},";
++parametersCount;
}
<%c++
}
}
if(selFlag)
{
$$<<" needSelection=true;\n";
}
%>
if(parametersCount > 0)
{
sql[sql.length()-1]=')';
sql += " values (";
}
else
sql += ") values (";
<%c++
if(@@.get<std::string>("rdbms")=="postgresql")
{
%>
int placeholder=1;
char placeholderStr[64];
size_t n=0;
<%c++
}
for(size_t i=0;i<cols.size();i++)
{
if(cols[i].isAutoVal_)
{
if(@@.get<std::string>("rdbms")!="sqlite3")
{
%>
sql +="default,";
<%c++
}
continue;
}
if(cols[i].colType_.empty())
continue;
%>
if(dirtyFlag_[{%i%}])
{
<%c++
if(@@.get<std::string>("rdbms")=="postgresql")
{
%>
n = sprintf(placeholderStr,"$%d,",placeholder++);
sql.append(placeholderStr, n);
<%c++
}else
{
%>
sql.append("?,");
<%c++
}
%>
}
<%c++
if(cols[i].hasDefaultVal_&&@@.get<std::string>("rdbms")!="sqlite3")
{
%>
else
{
sql +="default,";
}
<%c++
}
}
%>
if(parametersCount > 0)
{
sql.resize(sql.length() - 1);
}
<%c++
if(rdbms=="postgresql")
{
%>
if(needSelection)
{
sql.append(") returning *");
}
else
{
sql.append(1, ')');
}
<%c++
}
else
{
$$<<" sql.append(1, ')');\n";
}
%>
LOG_TRACE << sql;
return sql;
}
};
<%c++
if(!schema.empty())
{
$$<<"} // namespace "<<schema<<"\n";
}
%>
} // namespace [[dbName]]
} // namespace drogon_model

View File

@ -1,104 +0,0 @@
{
//rdbms: server type, postgresql,mysql or sqlite3
"rdbms": "postgresql",
//filename: sqlite3 db file name
//"filename":"",
//host: server address,localhost by default;
"host": "127.0.0.1",
//port: server port, 5432 by default;
"port": 5432,
//dbname: Database name;
"dbname": "",
//schema: valid for postgreSQL, "public" by default;
"schema": "public",
//user: User name
"user": "",
//password or passwd: Password
"password": "",
//client_encoding: The character set used by drogon_ctl. it is empty string by default which
//means use the default character set.
//"client_encoding": "",
//table: An array of tables to be modelized. if the array is empty, all revealed tables are modelized.
"tables": [],
//convert: the value can be changed by a function call before it is stored into database or
//after it is read from database
"convert": {
"enabled": false,
"items":[{
"table": "user",
"column": "password",
"method": {
//after_db_read: name of the method which is called after reading from database, signature: void([const] std::shared_ptr [&])
"after_db_read": "decrypt_password",
//before_db_write: name of the method which is called before writing to database, signature: void([const] std::shared_ptr [&])
"before_db_write": "encrypt_password"
},
"includes": [
"\"file_local_search_path.h\"","<file_in_global_search_path.h>"
]
}]
},
"relationships": {
"enabled": false,
"items": [{
"type": "has one",
"original_table_name": "products",
"original_table_alias": "product",
"original_key": "id",
"target_table_name": "skus",
"target_table_alias": "SKU",
"target_key": "product_id",
"enable_reverse": true
},
{
"type": "has many",
"original_table_name": "products",
"original_table_alias": "product",
"original_key": "id",
"target_table_name": "reviews",
"target_table_alias": "",
"target_key": "product_id",
"enable_reverse": true
},
{
"type": "many to many",
"original_table_name": "products",
"original_table_alias": "",
"original_key": "id",
"pivot_table": {
"table_name": "carts_products",
"original_key": "product_id",
"target_key": "cart_id"
},
"target_table_name": "carts",
"target_table_alias": "",
"target_key": "id",
"enable_reverse": true
}
]
},
"restful_api_controllers": {
"enabled": false,
// resource_uri: The URI to access the resource, the default value
// is '/*' in which the asterisk represents the table name.
// If this option is set to a empty string, the URI is composed of the namespaces and the class name.
"resource_uri": "/*",
// class_name: "Restful*Ctrl" by default, the asterisk represents the table name.
// This option can contain namespaces.
"class_name": "Restful*Ctrl",
// filters: an array of filter names.
"filters": [],
// db_client: the database client used by the controller. this option must be consistent with
// the configuration of the application.
"db_client": {
//name: Name of the client,'default' by default
"name": "default",
//is_fast:
"is_fast": false
},
// directory: The directory where the controller source files are stored.
"directory": "controllers",
// generate_base_only: false by default. Set to true to avoid overwriting custom subclasses.
"generate_base_only": false
}
}

View File

@ -1,23 +0,0 @@
/**
*
* [[filename]].cc
*
*/
#include "[[filename]].h"
using namespace drogon;
<%c++auto namespaceStr=@@.get<std::string>("namespaceString");
if(!namespaceStr.empty())
$$<<"using namespace "<<namespaceStr<<";\n";
%>
void [[className]]::initAndStart(const Json::Value &config)
{
/// Initialize and start the plugin
}
void [[className]]::shutdown()
{
/// Shutdown the plugin
}

View File

@ -1,35 +0,0 @@
/**
*
* [[filename]].h
*
*/
#pragma once
#include <drogon/plugins/Plugin.h>
<%c++
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
if(namespaceVector.empty())
$$<<"\n";
for(auto &namespaceName:namespaceVector){%>
namespace {%namespaceName%}
{
<%c++}
$$<<"\n";%>
class [[className]] : public drogon::Plugin<[[className]]>
{
public:
[[className]]() {}
/// This method must be called by drogon to initialize and start the plugin.
/// It must be implemented by the user.
virtual void initAndStart(const Json::Value &config) override;
/// This method must be called by drogon to shutdown the plugin.
/// It must be implemented by the user.
virtual void shutdown() override;
};
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>
}
<%c++}%>

View File

@ -1,494 +0,0 @@
<%inc#include "create_model.h"
using namespace drogon_ctl;
%>
/**
*
* [[fileName]]Base.cc
* DO NOT EDIT. This file is generated by drogon_ctl automatically.
* Users should implement business logic in the derived class.
*/
#include "[[fileName]]Base.h"
#include <string>
<%c++
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
auto modelName = tableInfo.get<std::string>("className");
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
std::string namespaceStr;
for(auto &name:namespaceVector)
{
namespaceStr.append(name);
namespaceStr.append("::");
}
if(!namespaceStr.empty())
{
namespaceStr.resize(namespaceStr.length()-2);
$$<<"using namespace "<<namespaceStr<<";\n";
}
std::string indentStr(@@.get<std::string>("className").length(), ' ');
%>
<%c++
if(hasPrimaryKey)
{%>
void [[className]]Base::getOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
auto dbClientPtr = getDbClient();
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(callback));
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
mapper.findByPrimaryKey(
id,
[req, callbackPtr, this]({%modelName%} r) {
(*callbackPtr)(HttpResponse::newHttpJsonResponse(makeJson(req, r)));
},
[callbackPtr](const DrogonDbException &e) {
const drogon::orm::UnexpectedRows *s=dynamic_cast<const drogon::orm::UnexpectedRows *>(&e.base());
if(s)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k404NotFound);
(*callbackPtr)(resp);
return;
}
LOG_ERROR<<e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
void [[className]]Base::updateOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
auto jsonPtr=req->jsonObject();
if(!jsonPtr)
{
Json::Value ret;
ret["error"]="No json object is found in the request";
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
{%modelName%} object;
std::string err;
if(!doCustomValidations(*jsonPtr, err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
try
{
if(isMasquerading())
{
if(!{%modelName%}::validateMasqueradedJsonForUpdate(*jsonPtr, masqueradingVector(), err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
object.updateByMasqueradedJson(*jsonPtr, masqueradingVector());
}
else
{
if(!{%modelName%}::validateJsonForUpdate(*jsonPtr, err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
object.updateByJson(*jsonPtr);
}
}
catch(const Json::Exception &e)
{
LOG_ERROR << e.what();
Json::Value ret;
ret["error"]="Field type error";
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
if(object.getPrimaryKey() != id)
{
Json::Value ret;
ret["error"]="Bad primary key";
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
auto dbClientPtr = getDbClient();
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(callback));
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
mapper.update(
object,
[callbackPtr](const size_t count)
{
if(count == 1)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k202Accepted);
(*callbackPtr)(resp);
}
else if(count == 0)
{
Json::Value ret;
ret["error"]="No resources are updated";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k404NotFound);
(*callbackPtr)(resp);
}
else
{
LOG_FATAL << "More than one resource is updated: " << count;
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
}
},
[callbackPtr](const DrogonDbException &e) {
LOG_ERROR << e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
void [[className]]Base::deleteOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
auto dbClientPtr = getDbClient();
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(callback));
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
mapper.deleteByPrimaryKey(
id,
[callbackPtr](const size_t count) {
if(count == 1)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k204NoContent);
(*callbackPtr)(resp);
}
else if(count == 0)
{
Json::Value ret;
ret["error"] = "No resources deleted";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k404NotFound);
(*callbackPtr)(resp);
}
else
{
LOG_FATAL << "Delete more than one records: " << count;
Json::Value ret;
ret["error"] = "Database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
}
},
[callbackPtr](const DrogonDbException &e) {
LOG_ERROR << e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
<%c++}%>
void [[className]]Base::get(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
auto dbClientPtr = getDbClient();
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
auto &parameters = req->parameters();
auto iter = parameters.find("sort");
if(iter != parameters.end())
{
auto sortFields = drogon::utils::splitString(iter->second, ",");
for(auto &field : sortFields)
{
if(field.empty())
continue;
if(field[0] == '+')
{
field = field.substr(1);
mapper.orderBy(field, SortOrder::ASC);
}
else if(field[0] == '-')
{
field = field.substr(1);
mapper.orderBy(field, SortOrder::DESC);
}
else
{
mapper.orderBy(field, SortOrder::ASC);
}
}
}
iter = parameters.find("offset");
if(iter != parameters.end())
{
try{
auto offset = std::stoll(iter->second);
mapper.offset(offset);
}
catch(...)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
}
iter = parameters.find("limit");
if(iter != parameters.end())
{
try{
auto limit = std::stoll(iter->second);
mapper.limit(limit);
}
catch(...)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
}
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(callback));
auto jsonPtr = req->jsonObject();
if(jsonPtr && jsonPtr->isMember("filter"))
{
try{
auto criteria = makeCriteria((*jsonPtr)["filter"]);
mapper.findBy(criteria,
[req, callbackPtr, this](const std::vector<{%modelName%}> &v) {
Json::Value ret;
ret.resize(0);
for (auto &obj : v)
{
ret.append(makeJson(req, obj));
}
(*callbackPtr)(HttpResponse::newHttpJsonResponse(ret));
},
[callbackPtr](const DrogonDbException &e) {
LOG_ERROR << e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
catch(const std::exception &e)
{
LOG_ERROR << e.what();
Json::Value ret;
ret["error"] = e.what();
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
(*callbackPtr)(resp);
return;
}
}
else
{
mapper.findAll([req, callbackPtr, this](const std::vector<{%modelName%}> &v) {
Json::Value ret;
ret.resize(0);
for (auto &obj : v)
{
ret.append(makeJson(req, obj));
}
(*callbackPtr)(HttpResponse::newHttpJsonResponse(ret));
},
[callbackPtr](const DrogonDbException &e) {
LOG_ERROR << e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
}
void [[className]]Base::create(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
auto jsonPtr=req->jsonObject();
if(!jsonPtr)
{
Json::Value ret;
ret["error"]="No json object is found in the request";
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
std::string err;
if(!doCustomValidations(*jsonPtr, err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
if(isMasquerading())
{
if(!{%modelName%}::validateMasqueradedJsonForCreation(*jsonPtr, masqueradingVector(), err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
}
else
{
if(!{%modelName%}::validateJsonForCreation(*jsonPtr, err))
{
Json::Value ret;
ret["error"] = err;
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
}
try
{
{%modelName%} object =
(isMasquerading()?
{%modelName%}(*jsonPtr, masqueradingVector()) :
{%modelName%}(*jsonPtr));
auto dbClientPtr = getDbClient();
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(callback));
drogon::orm::Mapper<{%modelName%}> mapper(dbClientPtr);
mapper.insert(
object,
[req, callbackPtr, this]({%modelName%} newObject){
(*callbackPtr)(HttpResponse::newHttpJsonResponse(
makeJson(req, newObject)));
},
[callbackPtr](const DrogonDbException &e){
LOG_ERROR << e.base().what();
Json::Value ret;
ret["error"] = "database error";
auto resp = HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k500InternalServerError);
(*callbackPtr)(resp);
});
}
catch(const Json::Exception &e)
{
LOG_ERROR << e.what();
Json::Value ret;
ret["error"]="Field type error";
auto resp= HttpResponse::newHttpJsonResponse(ret);
resp->setStatusCode(k400BadRequest);
callback(resp);
return;
}
}
/*
void [[className]]Base::update(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
}*/
[[className]]Base::[[className]]Base()
: RestfulController({
<%c++
tableInfo = @@.get<DrTemplateData>("tableInfo");
const auto &cols=tableInfo.get<std::vector<ColumnInfo>>("columns");
for(size_t i=0; i<cols.size(); ++i)
{
auto &col = cols[i];
if(i < (cols.size()-1))
{
%>
"{%col.colName_%}",
<%c++
}else{
%>
"{%col.colName_%}"
<%c++
}
}
%>
})
{
/**
* The items in the vector are aliases of column names in the table.
* if one item is set to an empty string, the related column is not sent
* to clients.
*/
enableMasquerading({
<%c++
for(size_t i=0; i<cols.size(); ++i)
{
auto &col = cols[i];
if(i < (cols.size()-1))
{
%>
"{%col.colName_%}", // the alias for the {%col.colName_%} column.
<%c++
}else{
%>
"{%col.colName_%}" // the alias for the {%col.colName_%} column.
<%c++
}
}
%>
});
}

View File

@ -1,86 +0,0 @@
<%inc#include "create_model.h"
using namespace drogon_ctl;
%>
/**
*
* [[fileName]]Base.h
* DO NOT EDIT. This file is generated by drogon_ctl automatically.
* Users should implement business logic in the derived class.
*/
#pragma once
#include <drogon/HttpController.h>
#include <drogon/orm/RestfulController.h>
<%c++
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
auto modelName = tableInfo.get<std::string>("className");
$$<<"#include \""<<modelName<<".h\"\n";
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
$$<<"using namespace drogon;\n";
$$<<"using namespace drogon_model::"<<tableInfo.get<std::string>("dbName");
auto &schema=tableInfo.get<std::string>("schema");
if(!schema.empty())
{
$$<<"::"<<schema<<";\n";
}
else
{
$$<<";\n";
}
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
for(auto &name:namespaceVector)
{
%>
namespace {%name%}
{
<%c++}%>
/**
* @brief this class is created by the drogon_ctl command.
* this class is a restful API controller for reading and writing the [[tableName]] table.
*/
class [[className]]Base : public RestfulController
{
public:
<%c++if(hasPrimaryKey)
{
%>
void getOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
void updateOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
void deleteOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
<%c++}
%>
void get(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void create(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
// void update(const HttpRequestPtr &req,
// std::function<void(const HttpResponsePtr &)> &&callback);
orm::DbClientPtr getDbClient()
{
return drogon::app().get{%(@@.get<bool>("isFastDbClient")?"Fast":"")%}DbClient(dbClientName_);
}
protected:
/// Ensure that subclasses inherited from this class are instantiated.
[[className]]Base();
const std::string dbClientName_{"[[dbClientName]]"};
};
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
{
$$<<"}\n";
}
%>

View File

@ -1,58 +0,0 @@
/**
*
* [[fileName]].cc
* This file is generated by drogon_ctl
*
*/
#include "[[fileName]].h"
#include <string>
<%c++
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
std::string namespaceStr;
for(auto &name:namespaceVector)
{
namespaceStr.append(name);
namespaceStr.append("::");
}
if(!namespaceStr.empty())
{
namespaceStr.resize(namespaceStr.length()-2);
$$<<"using namespace "<<namespaceStr<<";\n";
}
std::string indentStr(@@.get<std::string>("className").length(), ' ');
%>
void [[className]]::getOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} std::string &&id)
{
}
void [[className]]::get(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
}
void [[className]]::create(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
}
void [[className]]::updateOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} std::string &&id)
{
}
/*
void [[className]]::update(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
}*/
void [[className]]::deleteOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} std::string &&id)
{
}

View File

@ -1,70 +0,0 @@
/**
*
* [[fileName]].cc
* This file is generated by drogon_ctl
*
*/
#include "[[fileName]].h"
#include <string>
<%c++
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
auto modelName = tableInfo.get<std::string>("className");
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
std::string namespaceStr;
for(auto &name:namespaceVector)
{
namespaceStr.append(name);
namespaceStr.append("::");
}
if(!namespaceStr.empty())
{
namespaceStr.resize(namespaceStr.length()-2);
$$<<"using namespace "<<namespaceStr<<";\n";
}
std::string indentStr(@@.get<std::string>("className").length(), ' ');
%>
<%c++
if(hasPrimaryKey)
{%>
void [[className]]::getOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
[[className]]Base::getOne(req, std::move(callback), std::move(id));
}
void [[className]]::updateOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
[[className]]Base::updateOne(req, std::move(callback), std::move(id));
}
void [[className]]::deleteOne(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback,
{%indentStr%} {%modelName%}::PrimaryKeyType &&id)
{
[[className]]Base::deleteOne(req, std::move(callback), std::move(id));
}
<%c++}%>
void [[className]]::get(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
[[className]]Base::get(req, std::move(callback));
}
void [[className]]::create(const HttpRequestPtr &req,
{%indentStr%} std::function<void(const HttpResponsePtr &)> &&callback)
{
[[className]]Base::create(req, std::move(callback));
}

View File

@ -1,104 +0,0 @@
<%inc#include "create_model.h"
using namespace drogon_ctl;
%>
/**
*
* [[fileName]].h
* This file is generated by drogon_ctl
*
*/
#pragma once
#include <drogon/HttpController.h>
#include "[[className]]Base.h"
<%c++
auto tableInfo = @@.get<DrTemplateData>("tableInfo");
auto modelName = tableInfo.get<std::string>("className");
$$<<"#include \""<<modelName<<".h\"\n";
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
$$<<"using namespace drogon;\n";
$$<<"using namespace drogon_model::"<<tableInfo.get<std::string>("dbName");
auto &schema=tableInfo.get<std::string>("schema");
if(!schema.empty())
{
$$<<"::"<<schema<<";\n";
}
else
{
$$<<";\n";
}
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
for(auto &name:namespaceVector)
{
%>
namespace {%name%}
{
<%c++}%>
/**
* @brief this class is created by the drogon_ctl command.
* this class is a restful API controller for reading and writing the [[tableName]] table.
*/
class [[className]]: public drogon::HttpController<[[className]]>, public [[className]]Base
{
public:
METHOD_LIST_BEGIN
<%c++
auto resource=@@.get<std::string>("resource");
if(resource.empty())
{
if(hasPrimaryKey)
{
%>
METHOD_ADD([[className]]::getOne,"/{1}",Get,Options[[filters]]);
METHOD_ADD([[className]]::updateOne,"/{1}",Put,Options[[filters]]);
METHOD_ADD([[className]]::deleteOne,"/{1}",Delete,Options[[filters]]);
<%c++}%>
METHOD_ADD([[className]]::get,"",Get,Options[[filters]]);
METHOD_ADD([[className]]::create,"",Post,Options[[filters]]);
//METHOD_ADD([[className]]::update,"",Put,Options[[filters]]);
<%c++
}else
{
if(hasPrimaryKey)
{
%>
ADD_METHOD_TO([[className]]::getOne,"{%resource%}/{1}",Get,Options[[filters]]);
ADD_METHOD_TO([[className]]::updateOne,"{%resource%}/{1}",Put,Options[[filters]]);
ADD_METHOD_TO([[className]]::deleteOne,"{%resource%}/{1}",Delete,Options[[filters]]);
<%c++}%>
ADD_METHOD_TO([[className]]::get,"{%resource%}",Get,Options[[filters]]);
ADD_METHOD_TO([[className]]::create,"{%resource%}",Post,Options[[filters]]);
//ADD_METHOD_TO([[className]]::update,"{%resource%}",Put,Options[[filters]]);
<%c++}%>
METHOD_LIST_END
<%c++if(hasPrimaryKey)
{
%>
void getOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
void updateOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
void deleteOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
{%modelName%}::PrimaryKeyType &&id);
<%c++}
%>
void get(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void create(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
};
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
{
$$<<"}\n";
}
%>

View File

@ -1,80 +0,0 @@
<%inc#include "create_model.h"
using namespace drogon_ctl;
%>
/**
*
* [[fileName]].h
* This file is generated by drogon_ctl
*
*/
#pragma once
#include <drogon/HttpController.h>
<%c++
$$<<"using namespace drogon;\n";
auto namespaceVector=@@.get<std::vector<std::string>>("namespaceVector");
for(auto &name:namespaceVector)
{
%>
namespace {%name%}
{
<%c++
}
%>
/**
* @brief this class is created by the drogon_ctl command ([[ctlCommand]]).
* this class is a restful API controller.
*/
class [[className]]: public drogon::HttpController<[[className]]>
{
public:
METHOD_LIST_BEGIN
// use METHOD_ADD to add your custom processing function here;
<%c++
auto resource=@@.get<std::string>("resource");
if(resource.empty())
{
%>
METHOD_ADD([[className]]::getOne,"/{1}",Get,Options[[filters]]);
METHOD_ADD([[className]]::get,"",Get,Options[[filters]]);
METHOD_ADD([[className]]::create,"",Post,Options[[filters]]);
METHOD_ADD([[className]]::updateOne,"/{1}",Put,Options[[filters]]);
//METHOD_ADD([[className]]::update,"",Put,Options[[filters]]);
METHOD_ADD([[className]]::deleteOne,"/{1}",Delete,Options[[filters]]);
<%c++
}else
{
%>
ADD_METHOD_TO([[className]]::getOne,"{%resource%}/{1}",Get,Options[[filters]]);
ADD_METHOD_TO([[className]]::updateOne,"{%resource%}/{1}",Put,Options[[filters]]);
ADD_METHOD_TO([[className]]::deleteOne,"{%resource%}/{1}",Delete,Options[[filters]]);
ADD_METHOD_TO([[className]]::get,"{%resource%}",Get,Options[[filters]]);
ADD_METHOD_TO([[className]]::create,"{%resource%}",Post,Options[[filters]]);
//ADD_METHOD_TO([[className]]::update,"{%resource%}",Put,Options[[filters]]);
<%c++}%>
METHOD_LIST_END
void getOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::string &&id);
void updateOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::string &&id);
void deleteOne(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::string &&id);
void get(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void create(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
// void update(const HttpRequestPtr &req,
// std::function<void(const HttpResponsePtr &)> &&callback);
};
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
{
$$<<"}\n";
}
%>

View File

@ -1,66 +0,0 @@
/**
*
* version.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "version.h"
#include <drogon/config.h>
#include <drogon/version.h>
#include <trantor/net/Resolver.h>
#include <iostream>
using namespace drogon_ctl;
static const char banner[] =
" _ \n"
" __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n"
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
" |___/ \n";
void version::handleCommand(std::vector<std::string> &parameters) {
std::cout << banner << std::endl;
std::cout << "A utility for drogon" << std::endl;
std::cout << "Version: " << DROGON_VERSION << std::endl;
std::cout << "Git commit: " << DROGON_VERSION_SHA1 << std::endl;
std::cout << "Compilation: \n Compiler: " << COMPILER_COMMAND
<< "\n Compiler ID: " << COMPILER_ID
<< "\n Compilation flags: " << COMPILATION_FLAGS
<< INCLUDING_DIRS << std::endl;
std::cout << "Libraries: \n postgresql: "
<< (USE_POSTGRESQL ? "yes" : "no") << " (batch mode: "
<< (LIBPQ_SUPPORTS_BATCH_MODE ? "yes)\n" : "no)\n")
<< " mariadb: " << (USE_MYSQL ? "yes\n" : "no\n")
<< " sqlite3: " << (USE_SQLITE3 ? "yes\n" : "no\n");
#ifdef OpenSSL_FOUND
std::cout << " openssl: yes\n";
#else
std::cout << " openssl: no\n";
#endif
#ifdef USE_BROTLI
std::cout << " brotli: yes\n";
#else
std::cout << " brotli: no\n";
#endif
#ifdef Boost_FOUND
std::cout << " boost: yes\n";
#else
std::cout << " boost: no\n";
#endif
#ifdef USE_REDIS
std::cout << " hiredis: yes\n";
#else
std::cout << " hiredis: no\n";
#endif
std::cout << " c-ares: "
<< (trantor::Resolver::isCAresUsed() ? "yes\n" : "no\n");
}

View File

@ -1,33 +0,0 @@
/**
*
* version.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include "CommandHandler.h"
#include <drogon/DrObject.h>
using namespace drogon;
namespace drogon_ctl {
class version : public DrObject<version>, public CommandHandler {
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override {
return "display version of this tool";
}
virtual bool isTopCommand() override {
return true;
}
version() {
}
};
} // namespace drogon_ctl