Compare commits

...

856 Commits

Author SHA1 Message Date
an-tao
a22956b82b Bump version to 1.9.11 2025-06-20 16:51:27 +08:00
Heran Yang
3c5749bbc2
Fix compile warning (#2337) 2025-06-18 17:43:25 +08:00
Heran Yang
7cd1ae8940
chore(workflow): upgrade Windows image and re-enable tests on Windows (#2336)
* chore(workflow): upgrade Windows image to 2022

* chore(test): re-enable tests on Windows
2025-06-18 15:47:28 +08:00
LordMZTE
c3f9192541
Add RawParameter API to pass raw SQL parameters to the database directly (#2335) 2025-06-17 23:15:47 +08:00
KEBE Mouhamad
e46e05e94a
dg_ctl: fix segfault when using --output option (#2330) 2025-06-05 13:52:33 +08:00
dm
26e7c6913c
Add support for continuation frame in WebSocketMessageParser (#2320)
Co-authored-by: antao <antao2002@gmail.com>
2025-06-04 10:02:07 +08:00
曹梦轩
8d640bafb4
Add cors example to demonstrate cross-origin support in drogon (#2323) 2025-05-26 10:10:39 +08:00
Leonardo Monteiro
f6b5404dbb
Add a new overload for execSqlCoro (#2314) 2025-05-22 18:16:11 +08:00
程憨憨
46b5c9044d
Fix issue with precision loss of double-type parameters in ORM inputs (#2310) 2025-05-19 19:07:37 +08:00
an-tao
ac0d4d0f89 Update trantor 2025-05-16 11:10:24 +08:00
cjserio
5c4057331e
Support for iOS compiling (#2307) 2025-05-15 17:25:56 +08:00
an-tao
95a518e7f2 Add qrcode for WeChat official account​ to the README file 2025-05-13 11:15:48 +08:00
KEBE Mouhamad
c03a3df106
added -o|--output option to drogon_ctl create models (#2304)
Co-authored-by: Mouhamad Kebe <mouhamad.kebe@ses.com>
2025-05-10 21:20:52 +08:00
Alexey Gerasimchuck
d6a33f93c9
Added handleFatalError in handleClosed (#2291) 2025-04-21 11:15:00 +08:00
An Tao
59cd4366c7
Fix CI on MacOS (#2289) 2025-04-08 14:11:03 +08:00
Alexey Gerasimchuck
c92d146374
Improved Postgres connection stability (#2286) 2025-04-08 11:03:02 +08:00
Axel Svensson
3c7c66e310
fix: Do not write to source directory during build (#2288)
Fixes #2287
2025-04-08 10:23:43 +08:00
Tanglong3bf
1fb67d68be
fix: Fix a bug in isAutoCreationClass<T>. (#2277) 2025-03-22 15:46:41 +08:00
antao
cbf63f8fc4 Bump version to 1.9.10 2025-02-20 21:19:18 +08:00
an-tao
d68e8aa554 Fix the CI status badge 2025-02-20 14:16:30 +08:00
An Tao
41537a6e86
Fix ci: codespell (#2259) 2025-02-18 22:29:47 +08:00
TheEnigmist
a32dc67867
Added path_exempt in AccessLogger plugin config to exclude desired path from logging (#2258) 2025-02-18 10:28:57 +08:00
ereynalabs
e155df9f66
Fix the issue in view generation by including the missing header file drogon/utils/Utilities.h (#2248)
Co-authored-by: dlinten <david.linten@gmail.com>
2025-02-06 15:19:44 +08:00
Alexey Gerasimchuck
f5de41f5d7
Make quit function thread safe (#2247) 2025-02-02 22:22:17 +08:00
pan93412
a3b4779540
Improve the zh-TW README translation (#2239)
* Improve the zh-TW README translation

* Unify the "View" term in the zh-TW README
2025-01-14 20:08:30 +08:00
fantasy-peak
686f68a12f
Add setConnectionCallback (#2204) 2025-01-08 20:00:44 +08:00
An Tao
152a69f1e9
ORM:Avoid unnecessary copies when returning search results (#2237) 2025-01-02 22:44:09 +08:00
antao
38dd5fea31 Bump version to 1.9.9 2025-01-01 11:26:30 +08:00
Alexey Gerasimchuck
3a6268f7e9
Added emptiness check to the LogStream &operator<< with std::string_view (#2234) 2024-12-19 10:36:20 +08:00
antao
47f8af7ca1 Update README 2024-12-14 01:17:49 +08:00
Heran Yang
44f796b796
Chore(workflow/cmake.yml): upgrade macos runner (#2228) 2024-12-10 12:56:24 +08:00
Antonio Nesic
df7e83ae74
Added Partitioned flag for cookies (#2230)
Co-authored-by: Antonio Nesic <anesic@collectivemind.dev>
2024-12-10 12:55:16 +08:00
EasyMoney322
99e816283d
Fix: Removed dependency on locales being installed (#2227) 2024-12-09 10:53:15 +08:00
EasyMoney322
3e944d28d8
Fixed issues created by the date string being localized (#2217) 2024-12-05 18:08:24 +08:00
Eyal Niv
1765223755
Fix CMAKE issues mentioned in #2144 and a linking problem which manifest with gcc12.3 when building with shared libs (#2208) (#2213)
* Respect find_package QUIET

* Add policy_max to cmake_minimum_required
Avoid deprecation warning introduced by cmake 3.31

* Add missing DROGON_EXPORT
2024-11-26 22:53:09 +08:00
hanhuayin
71b6d57cae
Update FindFilesystem.cmake to check for GNU instead of GCC for CMAKE_CXX_COMPILER_ID (#2211)
This patch fixes a build issue encountered in our Amazon Linux 2 environment when integrating Drogon alongside other dependencies. The issue occurred because the filesystem check failed to compile when the compiler ID was set to "GNU", due to missing -std=c++17 flag. The existing CXX_FILESYSTEM_HAVE_FS check was looking for "GCC" instead of "GNU". "GNU" is the correct identifier for gcc according to CMake documentation (see https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html).

Interestingly, this issue only manifested when Drogon was integrated alongside other dependencies. When Drogon was the sole project added to our build, compilation proceeded without error.
2024-11-25 16:15:21 +08:00
Tanglong3bf
882c1d9ecd
fix a bug in plugin Redirector. (#2198) 2024-11-16 15:04:57 +08:00
dependabot[bot]
8541e67143
Bump docker/login-action from 1 to 3 (#2197)
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-02 09:48:46 +08:00
antao
6d9ecb8d8d Bump version to 1.9.8 2024-10-27 14:31:56 +08:00
fantasy-peak
23c561f072
Add check the client connection status (#2191) 2024-10-25 16:08:03 +08:00
Tanglong3bf
284d14b8ca
Fix some bugs in plugin PromExporter. (#2189) 2024-10-21 09:51:34 +08:00
fantasy-peak
ca2210331d
Add sending customized http requests to drogon_ctl (#2186) 2024-10-17 10:47:04 +08:00
Martin Chang
3fce70b535
Replace rejection sampling and remove use of rand() (#2180) 2024-10-10 13:45:46 +08:00
An Tao
bf1fc03bff
Fix lint (#2181) 2024-10-09 18:20:29 +08:00
an-tao
5225bb3295 Update trantor and add docker actions 2024-10-09 16:45:19 +08:00
An Tao
ac0a1b873e
Fix a bug after removing content-length header in some responses (#2176) 2024-10-02 16:42:40 +08:00
Muhammad
912f1d803c
Optimize query params and allow for empty values (#2171) 2024-09-26 15:47:58 +08:00
An Tao
13d7148764
Remove websocketResponseTest from windows shared library env (#2170) 2024-09-25 20:16:40 +08:00
Chad Barth
b0c5331bc1
Remove content-length header from 101 Switching Protocols response (#2164) 2024-09-25 17:52:41 +08:00
Christopher T
c9f5754423
Add support for escaped identifiers in Postgresql (#2167) 2024-09-23 16:00:50 +08:00
an-tao
31fb18fb46 Update trantor 2024-09-20 16:22:09 +08:00
toge
f918ead0ae
include exception header for std::exception_ptr (#2159) 2024-09-19 10:11:04 +08:00
Muhammad
fee34095a2
Add Hodor whitelists (#2154) 2024-09-19 09:56:11 +08:00
Omar Mohamed Khallaf
2911a7c08a
Fix coroutine continuation handle (#2163)
Using coroutines directly by the user e.g. declaring a function with
drogon::Task<> return type, will have it's continuation set to nullptr.

Returning nullptr causes a segfault and it must be checked before
returning e.g. the snippet form https://en.cppreference.com/w/cpp/coroutine/noop_coroutine

```cpp
struct final_awaiter
{
    std::coroutine_handle<>
        await_suspend(std::coroutine_handle<promise_type> h) noexcept
    {
        // final_awaiter::await_suspend is called when the execution of the
        // current coroutine (referred to by 'h') is about to finish.
        // If the current coroutine was resumed by another coroutine via
        // co_await get_task(), a handle to that coroutine has been stored
        // as h.promise().previous. In that case, return the handle to resume
        // the previous coroutine.
        // Otherwise, return noop_coroutine(), whose resumption does nothing.

        if (auto previous = h.promise().previous; previous)
            return previous;
        else
            return std::noop_coroutine();
    }
};
```

This commit default initializes the continuation handle to no op coroutine and
avoids the check.

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>
2024-09-19 09:52:51 +08:00
Muhammad
1b4653577f
Revert original path to its initial behavior (#2157) 2024-09-17 11:54:33 +08:00
Muhammad
bbcad71458
Add in-place base64 encode and decode (#2153) 2024-09-14 09:57:07 +08:00
Muhammad
beec858eba
Partially revert commit 93d8fb425d7e95939d398afd51b9d5adc4392c43 (#2156) 2024-09-13 17:34:23 +08:00
Muhammad
93d8fb425d
Fix forwarding with space in url by encoding (#2155) 2024-09-13 09:46:06 +08:00
antao
73406d1225 Bump version to 1.9.7 2024-09-10 23:12:02 +08:00
Ponder
6bafdf30fd
Feature: TcpServer hot reload SSL file (#2150) 2024-09-10 11:38:56 +08:00
元路
59919f33ef
Refine SQLite3 error types with new exception handling (#2145)
Signed-off-by: yuanlu <2573580691@qq.com>
2024-09-06 15:37:09 +08:00
an-tao
1326205483 Change a log level 2024-08-23 11:34:50 +08:00
Omar Mohamed Khallaf
80ec7d9211
Use correct libraries when compiling statically (#2136)
When compiling statically, cmake pulls shared libraries as dependencies
for drogon e.g. libpq.so instead of libpq.a. This causes linkage errors
when compiling the whole program.

The flag USE_STATIC_LIBS_ONLY should set the CMAKE_FIND_LIBRARY_SUFFIXES
to the appropriate suffix on different platforms, thus find_* commands
find the right library.
2024-08-22 15:46:47 +08:00
fantasy-peak
5b5d1906bf
Add requestsBufferSize function (#2124) 2024-08-14 11:15:33 +08:00
Muhammad
206ef0d881
Modernize cookies (#2112) 2024-08-08 22:23:28 +08:00
fantasy-peak
c46f149c2c
Add coroutine mutex (#2095) 2024-08-08 15:17:06 +08:00
Bohdan Tsehelnyk
0546032edc
change stoi to stoul (#2115) 2024-08-06 17:16:06 +08:00
Bohdan Tsehelnyk
f743cfd4d1
add quotes (#2116) 2024-08-06 17:15:01 +08:00
Muhammad
500d44faac
Allow MultiPartParser to be movable (#2107) 2024-07-23 11:52:52 +03:00
antao
e786907478 Bump version to 1.9.6 2024-07-20 23:35:17 +08:00
Nitromelon
5d4523a3a6
Support request stream (#2055) 2024-07-03 11:31:39 +08:00
fantasy-peak
dfacd1b454
Add setsockopt to HttpServer (#2086) 2024-07-02 10:04:56 +08:00
Chuck
85b918f9e9
Update README.md (#2080)
A few minor typos.
2024-06-21 10:04:11 +08:00
fantasy-peak
7b8d0085b1
Delay parsing json for HttpClient (#2077) 2024-06-20 00:09:08 +08:00
An Tao
f6913f6328 Add an example of prometheus (#2076) 2024-06-19 14:13:15 +08:00
Martin Chang
a2f759e4cd
Update trantor (#2074) 2024-06-17 18:59:57 +08:00
Nitromelon
ad2b7e13e1
Fix typo in yaml config. (#2069) 2024-06-15 10:27:51 +08:00
An Tao
b04dfd7f96
Fix some compilation warnings (#2066) 2024-06-13 17:11:03 +08:00
Muhammad
de5a4a5f57
Allow MultiPartParser to parse PATCH requests (#2062) 2024-06-09 18:46:57 +03:00
An Tao
8bdb9b2fa6
Bump version to 1.9.5 (#2057) 2024-06-08 20:31:23 +08:00
fantasy-peak
0a889e921d
Add registerMiddleware (#2052) 2024-06-04 17:05:52 +08:00
TYUTthelastone
9a96a20c6e
Add regex support for websocket controller (#1779) 2024-06-04 11:27:00 +08:00
Nitromelon
f37a1d036f
Fix pg client name; Add testcase. (#2043) 2024-05-29 00:23:43 +08:00
Nitromelon
c4c95918bf
Fix wrong parameter order. (#2040) 2024-05-27 19:10:05 +08:00
Martin Chang
6726df139d
fix codespell error (#2038) 2024-05-26 14:08:18 +08:00
Jonathan S. Fonseca
150735848d
Intention to present an alternative to improve the aforementioned method (#2034) 2024-05-25 21:30:01 +08:00
Nitromelon
155ae9ad65
Support postgresql connection options (#1972) 2024-05-23 14:03:28 +08:00
Nitromelon
306df8a8fb
Install gcc in ci. (#2028) 2024-05-22 14:48:12 +08:00
Nitromelon
82c46f13f8
Fix CI on windows (#2025) 2024-05-10 14:11:28 +08:00
an-tao
5f75222243 Add the conan badge to readme files 2024-05-10 10:59:32 +08:00
Nitromelon
5b7cefd32c Support per-method middlewares. (#2015) 2024-05-10 10:59:32 +08:00
Tanglong3bf
abbcf6023d
Fix an error in the yaml format config file (#2020)
There is an error in the `app.log.use_spdlog` item in the default
config file in the yaml format.
While fixing this error, other minor problems in the config files were
fixed.
For example, some spelling errors and missing items in yaml format.
At the same time, different config files are modified to store the same
content.
2024-05-07 14:00:15 +08:00
antao
b5cd748a12 Bump version to 1.9.4 2024-05-04 22:42:15 +08:00
Nitromelon
439ddd8dbe
Bypass clang thread_local error. (#2016) 2024-04-29 11:32:30 +08:00
Alexey Gerasimchuck
e79d5170b4
Implemented database reconnection loop (#2003) 2024-04-24 10:09:05 +08:00
Muhammad
519398c159
Avoid string copy and lowercasing on every request (#2008) 2024-04-22 17:52:36 +08:00
lirunjie
96919df488
Fix typo in HttpAppFrameworkImpl.cc (#1992) 2024-04-09 10:15:47 +08:00
Martin Chang
294035beb9
update trantor (#1988) 2024-04-04 18:24:18 +08:00
Muhammad
46ac53adb3
Add JSON send overloads for WebSocket connections (#1970) 2024-04-02 15:41:47 +08:00
An Tao
9f2872639a
Remove the request shared_ptr from the multipart parser (#1984) 2024-03-27 16:02:37 +08:00
I-LOVE-C2H5OH
4cbac301fb
add client cert support for websocket (#1967) 2024-03-04 16:50:33 +08:00
itrofimow
88d06684f2
Minor enhancement: move some smart pointers around instead of copying them (#1954) 2024-02-15 14:52:10 +08:00
an-tao
da7f065a6f Bump version to 1.9.3 2024-02-09 16:06:33 +08:00
Greisberger Christophe
aa04d33e02
Enhancement: extend drogon::ContentType for file handling (#1921) 2024-02-09 15:30:50 +08:00
Muhammad
1a9ad1a2c9
Use std::string_view for WebSockets (#1949) 2024-02-08 13:44:08 +08:00
Ken Matsui
22f4b4fad6
Simplify traits in utils (#1952) 2024-02-08 00:25:31 +08:00
An Tao
99d97df25f
Alias the safe hashmap template (#1947) 2024-02-04 23:13:01 +08:00
Muhammad
6aed658fab
Change drogon::MultiPartParser's parameters data type from std::map to std::unordered_map (#1946) 2024-02-04 21:32:12 +08:00
Ken Matsui
3d469112ca
Enable readability/multiline_string for cpplint (#1940) 2024-01-31 20:17:59 +08:00
Ken Matsui
f63480674f
Enable build/storage_class for cpplint (#1937) 2024-01-31 19:21:46 +08:00
Ken Matsui
0d178877f0
Enable build/header_guard for cpplint (#1936) 2024-01-31 19:05:20 +08:00
Ken Matsui
5f273d8744
Enable build/include_order for cpplint (#1938) 2024-01-31 14:00:56 +08:00
Ken Matsui
3c8c273582
Enable build/explicit_make_pair for cpplint (#1935) 2024-01-31 11:21:39 +08:00
Ken Matsui
c2b8e7c624
Enable readability/inheritance for cpplint (#1934) 2024-01-31 11:21:18 +08:00
Ken Matsui
56a53165b6
Add newline at EOF (#1932) 2024-01-31 10:43:30 +08:00
Ken Matsui
674137e89d
Use clang-format-17 (#1931) 2024-01-30 09:57:58 +08:00
Ken Matsui
ffc6e74f27
Enable readability/alt_tokens for cpplint (#1930)
* Enable readability/alt_tokens for cpplint

* Format drogon_ctl/create_model.cc
2024-01-30 09:55:47 +08:00
Ken Matsui
359b63fa77
Introduce cpplint (#1929) 2024-01-30 00:47:28 +08:00
Greisberger Christophe
baea2dce47
Added getParameter() and getOptionalParameter() (#1923) 2024-01-27 13:37:58 +08:00
Greisberger Christophe
cca1c8f262
Fix drogon::util::fromString() (#1925) 2024-01-26 08:27:14 +08:00
Nitromelon
aeed963915
Fix a wrong place of return. (#1922) 2024-01-25 19:13:28 +08:00
Hazimi Md Nazri
e640cc092d
Add support for gentoo linux, dev-db/mariadb contains mysql (#1914) 2024-01-19 22:11:53 +08:00
an-tao
93c568bb95 Bump version to 1.9.2 2024-01-18 21:46:10 +08:00
MWX
af29e25b03
Fix name issue when cross-compiling (#1906) 2024-01-18 13:38:27 +08:00
An Tao
d745cfe765
Move the RealIpResolver plugin to the PreRouting join point (#1904) 2024-01-16 11:18:13 +08:00
tripleslash
6b36b3a4f9
Support asynchronous sending of chunked responses (trantors new API) (#1886)
Co-authored-by: fantasy-peak <1356346239@qq.com>
Co-authored-by: Michael Bleis <michael.bleis@aracom.de>
2024-01-15 23:26:27 +08:00
antores
8e4ffa71e2
Fix building with MSYS2 (#1902)
Co-authored-by: antores <antores@users.noreply.github.com>
2024-01-15 10:14:05 +08:00
an-tao
25f874a278 Update trantor 2024-01-12 13:56:14 +08:00
antores
5ecbd1f184
Fix htonll/ntohll redefinition (#1899)
Co-authored-by: antores <antores@users.noreply.github.com>
2024-01-09 09:47:07 +08:00
dependabot[bot]
34d32a1ef0
Bump github/codeql-action from 2 to 3 (#1894)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-01 21:09:34 +08:00
Ken Matsui
1fd5c7ea5e
Remove macos-11 CI; not supported by Homebrew (#1891) 2023-12-28 22:29:45 +08:00
An Tao
2a0da80d5f
Avoid a race condition in database listener tests (#1890) 2023-12-28 19:23:42 +08:00
Ken Matsui
01ad18d2d5
Add CI tests with more compilers (#1889) 2023-12-28 15:59:29 +08:00
Nitromelon
f4443dce44
Refine request routing process (#1871)
Code structure changes:
* Combine HttpSimpleControllersRouter, HttpControllersRouter and WebsocketControllersRouter, saving a lot of repetitive codes.
* Extract ControllerBinder classes from three Router classes.
* Extract aop advices and logics into AopAdvice class. Flatten the callback hells of AOPs. Prevent aop vectors from being passed into every router.
* Extract request handling process out of Router class. Let router class do its own work (routing only). Put them in HttpServer class. Now all http process logic stays in HttpServer class, no need to jump around to follow the code flow.
* Adjust doFilters() and doAdviceChain(), save a few lambda construction.
Fixed logic bugs (behavior changing):
* Fix inconsistent session handling (callCallback() vs. callback directly)
* Fix inconsistent aop path between SimpleController and HttpController
* Remove router if simple controller class not found.
2023-12-28 11:53:10 +08:00
An Tao
021c89ec78
Add -k option to the drogon_ctl when running the press command (#1887)
* Add -k option to the drogon_ctl when running the press command

* Fix some warnings

* Fix a bug of bytes statistics in HttpClient
2023-12-25 09:39:16 +08:00
an-tao
125dd0e69e Set the url of trantor to the official repository 2023-12-19 10:02:42 +08:00
an-tao
38bde80aaa Update trantor 2023-12-18 18:25:36 +08:00
An Tao
4eec56c49f
Remove the default ctor of the Row class in ORM (#1885) 2023-12-17 08:28:35 +08:00
Tanglong3bf
ba9e9731d2
Fix ORM: The original way did not handle exceptions correctly. (#1872) 2023-12-16 14:07:27 +08:00
Martin Chang
41b740f649
add discord link to readme (#1879) 2023-12-11 14:10:33 +08:00
Christian Clauss
e76bf08eb2
GitHub Action to find typos in the codebase using codespell (#1876)
GitHub Action to find typos in the codebase using codespell
https://github.com/codespell-project/codespell
2023-12-09 13:48:24 +08:00
An Tao
c35e62ccd2
Use execute_process instead of exec_program in FindJsoncpp.cmake (#1875) 2023-12-08 17:33:06 +08:00
antao
358de6e66f Modify the configuration file templates in drogon_ctl 2023-12-05 22:05:19 +08:00
Greisberger Christophe
8026790e1a
Feature: Integrate spdlog as logging backend (#1771) 2023-12-04 23:42:35 +08:00
An Tao
4e890f52d6
Fix a error of coroutines on Windows (#1870) 2023-12-04 15:13:09 +08:00
Minha, Jeong
27f1a3d812
Fix: typo on Mapper method (#1867) 2023-11-28 17:52:25 +08:00
an-tao
6370461896 Bump version to 1.9.1 2023-11-27 18:55:54 +08:00
Muhammad
6b20a9fa8d
Return HttpAppFramework by setExceptionHandler (#1866) 2023-11-27 17:43:56 +08:00
Muhammad
830ced8c5b
Remove unused and undefined overloads of isBase64 (#1865) 2023-11-27 17:08:01 +08:00
Tanglong3bf
6f6a03b14b
Provide some functions for incrementing the value of given columns. (#1831) 2023-11-25 02:23:37 +08:00
Martin Chang
f21b899e63
Simplify drogon test with c++17 (#1862) 2023-11-24 18:17:30 +08:00
Vinicius
26840aa056
Fix: uuid formatting (#1854)
Co-authored-by: root <vinicts@protonmail.com>
Co-authored-by: an-tao <antao2002@gmail.com>
2023-11-18 16:23:13 +08:00
George Constantinides
01385f4f33
Update test_cmake.csp (#1856)
_test not needed for submodule target_link_libraries since it was added in project
2023-11-18 16:13:30 +08:00
Muhammad
2000a4279e
Make id generator consistent (#1851) 2023-11-18 15:46:59 +08:00
An Tao
1ec3c96cbb
Use the constexpr if instead of std::enable_if (#1843) 2023-11-15 11:22:14 +08:00
Muhammad
56f0102cfe
Custom sessions (#1841) 2023-11-09 21:38:41 +08:00
antores
a76c11cc34
Pass HttpRequestPtr to custom error handlers (#1830) 2023-11-09 12:49:11 +08:00
An Tao
e5daba6bf5
Fix a bug of the GlobalFilters plugin (#1842) 2023-11-09 12:47:02 +08:00
Vincent Le Quang
8586874c87
Fix build due to trantor commit out of date and address warnings. (#1839) 2023-11-08 15:10:50 +08:00
antao
f215cb15a0 Bump version to 1.9.0 2023-10-29 11:44:42 +08:00
An Tao
7599ae98a0
Change logs in the AccessLogger plugin to TRACE level (#1829) 2023-10-29 11:30:44 +08:00
Viktor Mukha
4323e7b6ef
FIX int mapping to int64_t instead of uint64_t (#1825)
Negative numbers were not passing json validation
2023-10-28 22:13:57 +08:00
An Tao
9ffe1b267b
Fix an error in the secureRandomString function (#1816) 2023-10-19 19:38:17 +08:00
Muhammad
645c2d8aaf
Use wss://echo.websocket.events/.ws in WebSocket client example (#1809) 2023-10-12 11:27:49 +08:00
An Tao
ab76e80089
Make & and * directly adjacent to variable names (#1810) 2023-10-12 11:27:25 +08:00
TheEnigmist
d9afdf279a
Added isTopicEmpty function (#1808)
Co-authored-by: TheEnigmist <lthenigmistl@gmail.com>
2023-10-10 11:03:27 +08:00
dependabot[bot]
1efe89a719
Bump actions/checkout from 3 to 4 (#1801)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-01 20:37:09 +08:00
OrbitZore
fd7af8110f
Add optional Criteria && || operator support (#1797) 2023-09-26 13:58:02 +08:00
an-tao
63b7f5eb13 Update the ubuntu Dockerfile 2023-09-25 18:06:08 +08:00
An Tao
94ca651cbd
Bump version to 1.9.0-rc.1 (#1789) 2023-09-24 10:52:52 +08:00
Muhammad
6cb8ac6f52
SlashRemover optimization (#1781) 2023-09-19 22:28:06 +08:00
Muhammad
078f60ca03
Add override keyword to setSockOptCallback (#1785) 2023-09-19 09:23:33 +03:00
Muhammad
cfa0de4389
Optimize regex generator (#1782) 2023-09-18 09:50:28 +08:00
An Tao
112d19ff12
Optimize plugins with redirection functions (#1776)
Note: after this submission, users who use the SecureSSLRedirector plugin and the SlashRemover plugin should add the following line to the configuration file:
   {
      "name": "drogon::plugin::Redirector",
      "dependencies": [],
      "config": {
      }
   }
 and add the plugin name "drogon::plugin::Redirector" to the dependencies list of the SecureSSLRedirector plugin and the SlashRemover plugin.
2023-09-16 17:33:38 +08:00
An Tao
cedeeb59f4
Add a plugin for prometheus (#1632) 2023-09-04 10:16:44 +08:00
An Tao
4e5638fdcd
Add a method to HttpRequest to access the matched routing parameters (#1765) 2023-09-04 10:13:14 +08:00
Nitromelon
e2e5d6d57f
Allow omitting template paremeter in execCommandSync. (#1764) 2023-08-31 19:19:58 +08:00
Nitromelon
53c84305b2
Simplify coroutine implementation (#1762) 2023-08-31 10:08:44 +08:00
an-tao
85d7c068e4 Update trantor (fix botan) 2023-08-30 19:57:51 +08:00
Ken Matsui
5d0c70278e
Delete apply.h (#1763) 2023-08-29 13:55:04 +08:00
Ken Matsui
366311c196
Avoid using well-known ports for demoMain (#1761) 2023-08-28 19:31:17 +08:00
Ken Matsui
5df9b48998
main -> master in C++ CI 2023-08-28 02:59:39 -07:00
Ken Matsui
8d4c17702a
Use ninja to build faster (#1755) 2023-08-28 17:59:14 +08:00
dependabot[bot]
9337571e1a
Bump actions/checkout from 2 to 3 (#1760)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-28 02:58:11 -07:00
frank10gm
816684e15d
Replace sprintf with snprintf (#1758)
Co-authored-by: francesco.laplaca <francesco.laplaca@enhancers.it>
Co-authored-by: Ken Matsui <26405363+ken-matsui@users.noreply.github.com>
2023-08-28 17:18:12 +08:00
Ken Matsui
40aa034595
Add dependabot.yml for GH actions (#1756) 2023-08-28 17:17:08 +08:00
Ken Matsui
de4c811772
Set concurrency for CodeQL (#1759) 2023-08-28 02:12:34 -07:00
Ken Matsui
3ecb8b4917
Split macOS and Ubuntu CIs for readability (#1754) 2023-08-28 17:07:52 +08:00
Ken Matsui
f761c54aa8
Extract format action into distinct job (#1751) 2023-08-28 13:50:22 +08:00
Ken Matsui
58055ae39c
Validate clang-format version & Customize clang-format path (#1752) 2023-08-27 20:54:22 +08:00
Ken Matsui
bc4d740b0c
Set concurrency to prevent blocking CI queue (#1753) 2023-08-27 20:53:36 +08:00
Muhammad
f8f5283dff
Allow sync advice to be callable on websocket requests (#1733)
Co-authored-by: Nitromelon <hwc14@qq.com>
2023-08-24 15:09:31 +08:00
an-tao
54b137d64f Update readme files 2023-08-24 14:41:47 +08:00
Greisberger Christophe
40579ae308
Added isHead() method to HttpRequest, to preserve information about the original method for use in the controller (#1743) 2023-08-24 12:41:48 +08:00
an-tao
81bf767d89 Update trantor: fix tls reading 2023-08-24 10:42:37 +08:00
Martin Chang
f1426c6e9a
fix race condition when setting the secure flag during test (#1742) 2023-08-23 23:58:29 +08:00
Nikolay Mitev
17c80508c0 Drop cpp14 build (#1740)
* Drop C++14 Support

* Update README.md

* Remove drogon::optional in favor of std::optional

* Remove drogon::filesystem in favor of std::filesystem

* Remove boost::string_view and pre-c++17 hacks

* Remove boost::any

* Remove the string_view.h and the any.h

* Remove boost lib

* Update .clang-format and ci

Co-authored-by: Omar Mohamed <omar@omar-laptop.lan>
Co-authored-by: Ken Matsui <26405363+ken-matsui@users.noreply.github.com>
Co-authored-by: An Tao <antao2002@gmail.com>
Co-authored-by: albaropereyra22 <141711575+albaropereyra22@users.noreply.github.com>
Co-authored-by: Yoshihiro Hokazono <47231909+hokacci@users.noreply.github.com>
Co-authored-by: Omar Mohamed Khallaf <51155980+omarmohamedkh@users.noreply.github.com>
2023-08-23 11:49:55 +08:00
an-tao
f361995035 Bump version to 1.8.6 2023-08-23 10:02:08 +08:00
Ken Matsui
3723ed5e0c
Show outputs of try_compile for UUID libs (#1738) 2023-08-22 21:24:42 +08:00
antao
83e08f4b27 Bump version to 1.8.5 2023-08-20 13:17:52 +08:00
An Tao
3aa93e62e7
Add getConnectionCount method (#1731) 2023-08-18 15:31:11 +08:00
antao
5c43b82dc2 Update trantor (fix tls) 2023-08-16 21:06:18 +08:00
antao
4c44322221 Update trantor 2023-08-15 22:52:12 +08:00
albaropereyra22
47e700c77f
Fixed broken link. (#1727) 2023-08-15 22:14:06 +08:00
albaropereyra22
a122725c3b
Update LICENSE (#1725)
Updated copyright year.
2023-08-15 09:58:18 +08:00
Omar Mohamed Khallaf
5509091ab8
Perform insensitive string compare of cookie SameSite attribute (#1706)
Co-authored-by: Omar Mohamed <omar@omar-laptop.lan>
2023-08-14 09:41:34 +08:00
an-tao
43b014cc24 Update trantor 2023-08-12 17:11:51 +08:00
Ken Matsui
4ad68db5e2
Address warnings on macOS CI (#1722) 2023-08-12 13:08:32 +08:00
Yoshihiro Hokazono
d3dbaed60a
Recognize URI in request lines (#1720) 2023-08-11 15:20:00 +08:00
albaropereyra22
d7ae3a21b3
Update build.sh appended prefix "X" to string variable comparisons (#1710)
It is recommended to use the letter 'X' when comparing strings because if the string is a - it causes issues according to the book with the turtle.
2023-08-10 23:45:12 -07:00
albaropereyra22
3fa480dd87
Update test.sh appended prefix "X" to string variable comparisons (#1711)
Added the prefix "X" to string variable comparisons because it is the convention mentioned in the book with the turtle. This is done because comparing a variable to a - causes issues.
2023-08-11 12:00:23 +08:00
An Tao
56f620717e
Fix CI in MacOS (#1719) 2023-08-11 00:32:57 +08:00
An Tao
ad99cf724d
Ensure that all filters, AOP advices, and handlers are executed within the IO threads. (#1717) 2023-08-10 23:53:56 +08:00
Ken Matsui
a91014a982
Remove unused Jekyll config (#1714) 2023-08-10 15:24:13 +08:00
Ken Matsui
9b2716ec24
Remove unused CI files (#1713) 2023-08-09 19:25:15 +08:00
an-tao
d00222883f Update trantor 2023-08-03 10:18:59 +08:00
luk1337
0fb887cb07
Fix build error on win32/mingw (#1668) 2023-08-01 00:30:55 +08:00
Bensuperpc
f16017ee6e
Change options BUILD_CTL and BUILD_EXAMPLES and update readme with Building options (#1672)
Signed-off-by: Bensuperpc <bensuperpc@gmail.com>
2023-07-31 23:16:15 +08:00
VladlenPopolitov
ec5dfdd9f7
Use unsigned char to call the std::isspace function (#1703) 2023-07-30 23:03:06 +08:00
Hayden Zhou
8f37e526cc
Fix target link libraries of yaml-cpp to comaptiable with vcpkg. (#1698) 2023-07-29 23:23:05 +08:00
Muhammad
c1da9922eb
Removed const string& (#1693) 2023-07-25 22:22:22 -07:00
Tanglong3bf
ca92e32d55
Add an example of yaml config file. (#1690) 2023-07-22 22:04:28 +08:00
AR Dabbour
cca5e5badd
chore: add package.xml (#1681)
the package.xml file allows for the integration of drogon in ROS applications.
2023-07-14 14:21:49 +08:00
An Tao
92e036874a
Fix issues in the ListParaView and content types (#1678) 2023-07-12 15:59:13 +08:00
Muhammad
cb2ae14bdf
Make isBase64() and isInteger() take string_view (#1662) 2023-07-05 17:47:49 +08:00
Muhammad
34a5c37974
constexpr base64 length calculators (#1652) 2023-07-05 15:25:33 +08:00
Jorge
3c82dcb491
Add CodeQL workflow (#1664) 2023-07-03 17:19:25 +08:00
Umar Sharief
6dbe650c74
Fix typo in newHttpJsonResponse documentation (#1658) 2023-07-01 11:44:22 +08:00
Umar Sharief
74bb47c690
Add CT_TEXT_JAVASCRIPT (#1654) 2023-07-01 11:43:39 +08:00
Muhammad
61073b4f74
Base64 improvements (#1635) 2023-06-24 18:09:08 +08:00
Nitromelon
eea916315e
Throw custom exception in HttpClient (#1641) 2023-06-24 18:05:39 +08:00
fantasy-peak
8e4474bf4c
Add overload function of newHttpResponse (#1646) 2023-06-24 18:04:38 +08:00
Muhammad
269399b701
Minor improvements for SlashRemover plugin (#1634) 2023-06-14 13:46:15 +08:00
An Tao
586fd6d67a
Use shared_ptr to store plugins (#1640) 2023-06-14 10:13:12 +08:00
Nitromelon
44b6916d7e
Support setting max_files in loggers. (#1628) 2023-06-09 13:14:03 +08:00
Nitromelon
7f04e63f25
Coroutine handle should be captured by value. (#1631) 2023-06-06 22:29:48 +08:00
fantasy-peak
5e245d08dc
Add setsockopt to HttpClient (#1625) 2023-05-31 16:44:12 +08:00
An Tao
b9a699f866
Update trantor (#1623) 2023-05-30 22:39:19 +08:00
fantasy-peak
3263b78ec3
Add getOriginalPath function (#1620) 2023-05-28 15:12:09 +08:00
Muhammad
07726dfcab
Add SlashRemover plugin (#1614) 2023-05-26 11:08:57 +08:00
435qb
415b34e06d
Fix Missing Header BaseBuilder.h in CMakeLists (#1617) 2023-05-23 19:39:08 +08:00
Ken Matsui
75b106599d
Implement QueryBuilder (#1331) 2023-05-22 09:52:19 +08:00
Muhammad
7fce0f1ff5
Hodor plugin - Use IP bytes for user IP identification (#1606) 2023-05-19 23:34:15 +08:00
Muhammad
87a3132fd1
Fixed logic error of limiterExpireTime_ (#1605) 2023-05-13 23:26:13 +08:00
An Tao
abf6f6cc86
Fix a hanging bug when writing large string to text field (postgresql) (#1599) 2023-05-11 09:55:40 +08:00
Ken Matsui
bd66fa4f55
Remove path from COMPILER_COMMAND (#1590) 2023-05-09 19:24:00 +08:00
Nitromelon
5baca75359
Bugfix: PgBatchConnection did not report error message. (#1588) 2023-05-09 19:20:23 +08:00
An Tao
29984f26e0
Revert modifications to the type of clientMaxBodySize (#1596) 2023-05-09 19:18:10 +08:00
Sqeaky
fddbc0abb7
Update SqlBinder.h (#1595)
On a fully updated Rasperry Pi OS using Raspberry Pi OS 2023-05-03 Drogon built fine, but a project linking to/including drogon would fail to build with `/usr/local/include/drogon/orm/SqlBinder.h:70:1: error: body of ‘constexpr’ function ‘constexpr T htonT(T) [with T = long unsigned int]’ not a return-statement 70 | }`.

Compiler details:
    $ gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/aarch64-linux-gnu/10/lto-wrapper
    Target: aarch64-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Debian 10.2.1-6' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=aarch64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-mutex
    Thread model: posix
    Supported LTO compression algorithms: zlib zstd
    gcc version 10.2.1 20210110 (Debian 10.2.1-6)

This is a proposed fix for this issue that adjusts this function to be a pair of IFDEFed return statements based on network byte order as the original function appeared to intend. This makes it so the function body is entirely a single return statement on each platform. 

The error message from the C++17 compiler (which is the latest version supported on Raspberry Pi OS currently) indicates that constexpr functions must be entirely single return statements.
2023-05-09 17:23:47 +08:00
Omar Mohamed Khallaf
bf4ff759ad
Fix typo in config (#1593)
change 'enabled_compresed_request' to 'enabled_compressed_request'
2023-05-08 23:37:52 +08:00
Kumar Arnav
42bbc185e1
Fix #1497 (#1592) 2023-05-08 09:46:34 +08:00
an-tao
8b250f8638 Update trantor 2023-05-04 10:34:35 +08:00
Martin Chang
178fb22b49
update trantor (#1579) 2023-04-29 16:41:49 +08:00
Charles
2caa8c4a34
Add webp and svg to the default file_types (#1575) 2023-04-27 15:19:33 +08:00
Horribile
4ec75e03e0
Possibility to add plugins without config file (#1572) 2023-04-24 19:42:52 +08:00
monoliths
22c7567da3
Fix error: conversion from ‘long int’ to ‘Json::Value’ is ambiguous (#1573) 2023-04-23 14:48:47 +08:00
An Tao
f615d5e8df
Add the forwardCoro method to HttpAppFramework (#1570) 2023-04-19 13:29:11 +08:00
An Tao
f14ba8de28
Update the README.md (#1567) 2023-04-18 17:17:56 +08:00
timulations
7c96c7fbf5
Fix bug on Mac M1 with redis chat example code (#1566) 2023-04-17 23:08:17 +08:00
An Tao
65b1715539
Add the DROGON_EXPORT macro to the GlobalFilters plugin (#1565) 2023-04-16 13:42:46 +08:00
an-tao
4358b71f55 Add filters and plugins to the drogon.h header file 2023-04-16 12:15:27 +08:00
An Tao
c7912f246b
Add the GlobalFilters plugin (#1555) 2023-04-16 11:55:00 +08:00
An Tao
d133b21804
Modify the HttpMessageBody class (#1564) 2023-04-16 11:54:11 +08:00
An Tao
ad2798e4aa
Adapt to gcc13 (#1563) 2023-04-16 09:30:37 +08:00
Martin Chang
abee656699
remove docsforge from readme (#1560)
Co-authored-by: marty1885 <marty1885@gmail.com>
2023-04-08 16:39:48 +08:00
an-tao
292d677446 Update trantor 2023-04-03 09:33:33 +08:00
An Tao
0715a94a06
Add avatars of all contributors to the readme file (#1553) 2023-04-01 18:52:42 +08:00
Justen Di Ruscio
5df4db96a5
Fix generation of JSON field validation for short type. (#1549) 2023-03-31 10:49:48 +08:00
Martin Chang
122a42cd4f
Adapt Drogon to take advitange of Trantor TLS refactor (#1505)
Co-authored-by: marty1885 <marty1885@gmail.com>
2023-03-30 23:14:53 +08:00
An Tao
120aaf249d
Remove the deprecated Json::Reader (#1546) 2023-03-26 17:03:19 +08:00
Nitromelon
f0a011b14d
Use syncAdvices.empty() to check. (#1545) 2023-03-25 17:37:33 +08:00
Tanglong3bf
e25a162887
Add synchronization interface to model's associated query (#1531) 2023-03-25 16:27:08 +08:00
An Tao
02742e4518
Fix a configuration error when building drogon_ctl (#1544) 2023-03-24 10:20:25 +08:00
Nitromelon
4f066258f2
Temporary fix dead HttpClient. (#1542) 2023-03-21 14:51:37 +08:00
An Tao
ceab5f3037
Bump version to 1.8.4 (#1539) 2023-03-20 23:31:07 +08:00
An Tao
21e207abe5
Add a cmake option to use yaml-cpp or not (#1538) 2023-03-20 19:02:13 +08:00
Martin Chang
c63b021e7d
Hold shared pointer from the very beginning (#1537) 2023-03-18 18:38:55 +08:00
Martin Chang
2af8e47278
Trigger error message in drogon test when faced with bad parameter (#1495) 2023-03-14 22:43:50 +08:00
Nitin Anand
00debb056b
Changes to free http client if no request is pending (#1529) 2023-03-14 22:41:52 +08:00
Hayden Zhou
af551bf2fb
fix missing symbol '@' (#1532) 2023-03-13 22:23:32 +08:00
Ostropik
b229f74743
Fix namespaces (#1528)
Co-authored-by: Ostropik <Dmytro.OSTROPITSKYI@ingenico.com>
2023-03-13 17:44:00 +08:00
An Tao
a039157587
Fix loading configuration on windows (#1530) 2023-03-12 18:47:21 +08:00
An Tao
97a5496fa4
Add queueInLoopCoro function (#1526) 2023-03-09 16:44:34 +08:00
Nitromelon
314bab0b4c
Add switchThreadCoro(). (#1501) 2023-03-09 12:13:51 +08:00
Martin Chang
ab5259b290
Add coroutine to wait until event loop ends (#1500) 2023-03-09 10:13:18 +08:00
Hayden Zhou
d4c0e063f1
Add support to yaml config file. (#1521)
Co-authored-by: an-tao <antao2002@gmail.com>
2023-03-09 00:17:11 +08:00
An Tao
57ec87d38d
Add an option in CMakeLists.txt to set how to use trantor (#1520) 2023-03-09 00:16:21 +08:00
An Tao
b739a7fab8
Update ConfigLoader.cc (#1524) 2023-03-07 17:01:23 +08:00
An Tao
394f9bd0d4
Add the stackLimit option for jsoncpp (#1518) 2023-03-01 10:49:25 +08:00
Nitromelon
bc028776f7
Refactor HttpServer codes. (#1508) 2023-02-28 10:19:26 +08:00
An Tao
d321bd4fc1
Fix a conan issue in github actions (#1517) 2023-02-27 14:30:38 +08:00
An Tao
313392a9b6
Add a configuration option to display local time in logs (#1513) 2023-02-19 23:04:25 +08:00
jinsongzhao
29955becc1
Fix multipart boundary with charset (#1511)
For example
Content-Type: multipart/form-data; boundary=TqmguJb_Fm_eFtAFCpWvmk5iPqrIEJJjvBFn; charset=ISO-8859-1
2023-02-18 19:35:58 +08:00
nitinanand-macrometa
54d96963f3
Use weakptr instead of shared_ptr (#1504)
Co-authored-by: Nitin Anand <gmail@an.andnit.in>
2023-02-12 21:47:20 +08:00
An Tao
ae9d5f20b3
Postgresql: don't handle events anymore after connection closing (#1499) 2023-02-04 20:06:15 +08:00
Martin Chang
7d87d7e0b2
Fix file r/w race condition in integration test (#1496) 2023-01-28 13:19:16 +08:00
Martin Chang
36d7435d1d
add coroutine parameter binding test and make tests not blocking (#1493) 2023-01-28 10:33:04 +08:00
Martin Chang
479346822f
reduce overhead of contructing string from request status (#1494) 2023-01-28 10:32:45 +08:00
An Tao
3adf168a87
Make the token bucket full when it is initialized (#1489) 2023-01-25 21:43:33 +08:00
An Tao
0b3147c157
Bump version to 1.8.3 (#1485) 2023-01-23 11:03:50 +08:00
Martin Chang
007a6ffbe3
partial fix for MSYS2 compat (#1468) 2023-01-18 16:01:56 +08:00
Nitromelon
554939d7ee
Fix error when PgListener task queue not empty (#1478)
* Fix error when task queue not empty.

* Update test, listen multiple channels.
2023-01-14 10:16:50 +08:00
Nitromelon
1618484d74
Support postgresql asynchronous notification (LISTEN/NOTIFY). (#1464) 2023-01-04 23:50:49 +08:00
Martin Chang
19f08786f0
mark awaiters as non copyable (#1457) 2022-12-18 15:12:32 +08:00
lldxflwb
80ea3c4f30
Fix a memory leak in the redis example (#1447) 2022-12-02 20:00:55 +08:00
interfector18
c5e596d942
Enable json entry as string (#1440) 2022-11-17 21:56:36 +08:00
Greisberger Christophe
28518b7bba
Fix HttpController regex path matching (#1439)
* Fixed wrong controller method called on regex paths

* Fixed test executables not linking on Windows

* Fixed compilation conversion warnings with explicit casts
2022-11-17 21:56:12 +08:00
Francesco Emanuele D'Agostino
1b11bfb668
add onSessionStart() and onSessionDestroy() events (#1412)
Co-authored-by: an-tao <antao2002@gmail.com>
2022-11-13 22:40:24 +08:00
Martin Chang
ef93c91ec7
Drogon test refactor (#1437) 2022-11-12 12:54:22 +08:00
Brecht Sanders
25ece89558
Update Utilities.cc (#1436)
Fix error when building with MinGW-w64:
```
lib/src/Utilities.cc:1226:28: error: external linkage required for symbol 'drogon::utils::internal::fixedRandomNumber' because of 'dllexport' attribute                    
```
`DROGON_EXPORT` is already specified in `lib/inc/drogon/utils/Utilities.h`, it doesn't need to be repeated in `lib/src/Utilities.cc` when defining `fixedRandomNumber`.
2022-11-12 10:43:02 +08:00
an-tao
31fa010ca9 Bump version to 1.8.2 2022-11-11 21:08:29 +08:00
An Tao
ab10d8cb22
Fix a dead lock bug when closing all database connections (#1434) 2022-11-11 09:57:18 +08:00
Martin Chang
c0d48da99f
Avoid HashDoS attacks via random per-session hash initial state (#1433) 2022-11-10 13:41:21 +08:00
an-tao
9dff8b296b Update trantor 2022-11-09 22:49:34 +08:00
An Tao
990be54ea0
Add some test cases for the sqlite datetime type (#1430) 2022-11-06 17:49:59 +08:00
An Tao
6208332de3
Add the queueInLoopCoro function (#1426) 2022-11-04 17:23:14 +08:00
James
a8be56f9bb
Fix a date race in drogon_test. (#1423) 2022-11-03 22:32:56 +08:00
An Tao
164972e2d3
Add rate limiter (#1409) 2022-10-27 22:49:16 +08:00
Kushal-Chandar
37a10318ff
fix: typo in drogon_test.h (#1419) 2022-10-24 12:11:29 +08:00
an-tao
29c67565a3 Update trantor 2022-10-12 11:09:19 +08:00
An Tao
995b8e8b82
Set Hiredis_FOUND to true when finding Hiredis library (#1406) 2022-10-10 10:02:11 +08:00
khalilluo
89588959b1
supports the mediumint column when generate the mysql model (#1393) 2022-09-28 19:32:02 +08:00
an-tao
875bca0a86 Bump version to 1.8.1 2022-09-25 23:11:18 +08:00
An Tao
4d63475203
Add support for the string_view type to SqlBinder in orm (#1391) 2022-09-23 21:56:40 +08:00
Nitromelon
cdd48686ab
Small patches on orm_lib. (#1388) 2022-09-23 21:56:14 +08:00
An Tao
d3fe59432b
Use the mysql_library_end() function to avoid memory leaks (#1387) 2022-09-20 10:29:44 +08:00
Nitromelon
1c8580a71b
Remove redundant member functions of drogon::Task. (#1381) 2022-09-20 10:25:17 +08:00
khalilluo
c913441bb4
fixed model template file Unreachable code (#1384) 2022-09-16 17:54:01 +08:00
an-tao
302bb560b6 Update trantor 2022-09-15 12:50:05 +08:00
Nitromelon
a1a0ef1af8
Support redis subscription (#1212) 2022-09-13 10:30:51 +08:00
An Tao
6a397efefe
Fix a test bug when clients start before servers (#1376) 2022-09-09 01:32:01 +08:00
An Tao
c97125b22f
Fix a conflict of ssize_t type with hiredis (#1371) 2022-09-03 22:36:46 +08:00
An Tao
574a60f812
Bump version to 1.8.0 (#1312) 2022-09-01 00:49:48 +08:00
An Tao
de1bd805fc
Add a precompilation macro in the pg pipeline test code (#1368) 2022-09-01 00:30:16 +08:00
ChaoII
ff1aac37de
Fix doc link (#1366) 2022-08-30 18:23:09 +08:00
An Tao
94c4f27d61
Set the running flag to false after calling the quit() method (#1363) 2022-08-27 01:37:08 +08:00
An Tao
29b33a7fa0
Export the getVersion method for Windows (#1362) 2022-08-25 23:35:56 +08:00
An Tao
c40bb2bc1f
Fix a bug when parsing multipart/form-data (#1358) 2022-08-25 23:04:23 +08:00
An Tao
f582a16adb
Fix a bug when converting the content-length string to size_t (#1355) 2022-08-19 14:20:37 +08:00
Ken Matsui
64b9484657
Use nullopt instead of the no-argument constructor (#1344) 2022-08-19 13:48:48 +08:00
Ken Matsui
2465753ee9
Refactor db_test.cc (#1346) 2022-08-19 12:22:13 +08:00
Nitromelon
bd9d290b82
Support coroutine filter. (#1352) 2022-08-19 09:24:02 +08:00
Nitromelon
4ef31d7c2d
Log remote real address in AccessLogger (#1351) 2022-08-15 13:34:27 +08:00
Ken Matsui
9abc9e5b6c
Accept postgres for DbClient type as well (#1347) 2022-08-12 19:47:22 +08:00
an-tao
5610bd2182 Change timeout of pipeline test for the CI environment (#1339) 2022-08-02 23:56:47 +08:00
Ken Matsui
5371b967f6
Use a raw string literal for the drogon banner (#1332) 2022-08-01 22:53:02 +08:00
An Tao
2b75af82ee
Update trantor (#1338) 2022-08-01 14:06:17 +08:00
An Tao
a1d2bd168b
Change the listener port of the cookie test (#1336) 2022-07-31 12:56:49 +08:00
Ken Matsui
9f23560a29
Delete the unmaintained test script (#1333) 2022-07-31 11:37:36 +08:00
Nitromelon
bf36db1562
Resolve real ip from HttpRequest. (#1321) 2022-07-28 23:34:35 +08:00
Ken Matsui
c9f5946eff
Implement toJson to convert std::vector to Json::Value` (#1329) 2022-07-28 22:52:52 +08:00
Ken Matsui
82bd6bceac
Refactor orm::SqlBinder (#1328) 2022-07-28 22:10:01 +08:00
Ken Matsui
cfe1681b0f
Omit redundant virtual specifiers (#1325) 2022-07-26 12:19:54 +08:00
Ken Matsui
1bc6ee1170
Ensure requiring a semi-colon after macros (#1324) 2022-07-26 12:17:07 +08:00
Ken Matsui
a582a773c1
Remove an unnecessary semi-colon (#1323) 2022-07-26 12:16:48 +08:00
Ken Matsui
5373e51f92
Remove redundancies from the CMake action (#1322) 2022-07-26 12:16:22 +08:00
Ken Matsui
474db0dd9a
Remove the virtual specifier from functions marked with override (#1320) 2022-07-26 00:33:18 +08:00
Mai-Lapyst
8b90403bae
Fix a bug when creating models with composite keys in sqlite3 (#1310) 2022-07-10 10:01:17 +08:00
An Tao
da18f21796
Fix a misuse of std::move (#1311) 2022-07-10 00:54:57 +08:00
Martin Chang
b32fa58d16
Prevent sending multiple responses for a single request (#1308) 2022-07-09 14:10:24 +08:00
LE GARREC Vincent
cf543716ce
Fix #1207 (#1305) 2022-07-06 21:13:07 +08:00
An Tao
ee9ca895c7
Fix some bugs in RedisClient (#1303) 2022-07-05 13:47:28 +08:00
Martin Chang
9524a91479
Support compressed request (#1291) 2022-07-02 22:07:48 +08:00
LE GARREC Vincent
b8f44aec2e
Rename BUILD_TRANTOR_SHARED to BUILD_SHARED_LIBS (#1299) 2022-06-29 17:29:20 +08:00
LE GARREC Vincent
e2b5a07921
Fix no BUILD_CTL with tests (#1300) 2022-06-29 17:26:37 +08:00
An Tao
46c00a317f
Throw exceptions instead of exiting when loading configuration fails (#1293) 2022-06-22 23:17:40 +08:00
Nitromelon
81dd4ebd07
Bugfix: fix Mapper::updateBy() async api. (#1290) 2022-06-21 21:01:29 +08:00
Martin Chang
7570137138
Make orm::Result compatiable with C++ STL container concepts (#1281) 2022-06-12 14:09:56 +08:00
timomrs
a42f759248
Add content type to multipart file upload (resolves issue #1252) (#1279) 2022-06-09 20:00:56 +08:00
timomrs
3b5de8863a
Resolve issue #1275 (#1276) 2022-06-07 16:12:22 +08:00
An Tao
ebf87d69d7
Support pipeline mode on PostgreSQL 14+ (#1169)
Co-authored-by: He, Wanchen <hwc14@qq.com>
2022-06-05 21:10:42 +08:00
JuergenGleiss
664d97c185
Feature/drogon ctl add namespce to view (#1245)
drogon_ctl --namespace and --path-to-namespace is allowed. If both parameters are used the value of namespace will be set in front of path-to-namespace
added an example into the template cmake.csp how to use the new optional parameter of drogon_create_views
2022-06-03 15:40:24 +08:00
MQPearth
346e2e6033
Fix deleteFutureByPrimaryKey compile fail (#1271) 2022-06-03 15:30:07 +08:00
An Tao
7af9853589
Clear all database connections before quitting (#1273) 2022-06-03 13:31:56 +08:00
varunsh
a4afc394dc
Check if host header is set before setting (#1269) 2022-05-31 11:20:05 +08:00
Nitromelon
3388c72343
Install missing header file apply.h (#1267) 2022-05-29 18:57:18 +08:00
Nitromelon
8ab868ea22
Check mysql-optionsv support in cmake. (#1265) 2022-05-29 15:17:15 +08:00
Nitromelon
bd4f3814a6
Support controller registration in plugin. (#1259) 2022-05-26 22:30:34 +08:00
Nitromelon
1bc38c7e22
Remove redundant resource release. (#1261) 2022-05-26 12:09:48 +08:00
misirlou-tg
fffb8f7e7c
Fixing link error when linking with static c-ares (#1258) 2022-05-23 14:29:04 +08:00
Particle_G
41d9d7ec58
Add support for custom SQL query (#1241) 2022-05-21 15:23:34 +08:00
Nitromelon
3b11b80b10 Fix core dump causing by logging in destructor. (#1250)
Co-authored-by: Martin Chang <marty1885@users.noreply.github.com>
Co-authored-by: an-tao <antao2002@gmail.com>
2022-05-18 13:25:26 +08:00
An Tao
cd55a198d2
Return nullptr if a plugin is not loaded when gettting it (#1251) 2022-05-17 14:22:29 +08:00
Robert Huang
3b0fd3d676
Fix HttpFile unittest error on Windows (#1191) 2022-05-17 13:20:05 +08:00
JuergenGleiss
19d9ffcfc2
Bugfix/cookie same site test without any useful checks (#1247)
Co-authored-by: an-tao <antao2002@gmail.com>
2022-05-16 11:18:10 +08:00
An Tao
4f2cbd4135
Fix some configuration file issues (#1249) 2022-05-14 13:59:49 +08:00
JuergenGleiss
c5a1888da3
Feature/option same site for session cookie (#1221) 2022-05-08 13:47:18 +08:00
Greisberger Christophe
f017b09947
Added HttpResponse::newStreamResponse() (#1156) 2022-05-02 21:04:41 +08:00
Omar Mohamed Khallaf
e8b21502e2
Add username option to redis databases (#1223)
The Redis AUTH command was extended in Redis 6, so now it is possible to
use it in the two-arguments form:
AUTH <username> <password>
and omitting the <username> defaults to user 'default'.
2022-04-30 00:48:18 +08:00
An Tao
a4ba8aff95
Reset timer afters relauching in Linux (#1232) 2022-04-30 00:45:19 +08:00
Omar Mohamed Khallaf
5892fa2f9f
fix bug when resolving redis server hostname (#1229)
Calling `drogon::app().createRedisClient` from the resolver callback
function results in a failure because of `assert(!running_);` in
`HttpAppFrameworkImpl::createRedisClient`.

This fix uses a promise whose value is set in the callback and the
client creation is done outside the callback.
2022-04-27 16:46:27 +08:00
Omar Mohamed Khallaf
c9c2675ba9
Resolve redis server hostname from config file (#1228) 2022-04-27 13:39:10 +08:00
Nitromelon
bccf509ca0
A workaround for redis sync exec (#1216) 2022-04-25 19:42:25 +08:00
DualWu
86dbf9875b
add typename for clang-14 (#1226)
Co-authored-by: dualwu <dualwu@zelostech.com>
2022-04-25 19:28:06 +08:00
Nitromelon
e53c81b229
Fix HttpClient dns cache. (#1211) 2022-04-22 13:42:39 +08:00
Omar Mohamed Khallaf
d51bae1016
Enable automatic reconnect in mysql (#1217)
Setting MYSQL_OPT_RECONNECT option to true will allow the connection to
be restablished once before giving up and returning an error.

This is useful in cases where the database is behind a loadbalancer
(e.g. ipvs) and the tcp connection is terminated after some period of
time.
2022-04-22 11:12:49 +08:00
DualWu
567e7c07ad
Add move constructor to fix clang-14 compile error (#1222)
https://github.com/drogonframework/drogon/issues/1206
2022-04-22 11:10:50 +08:00
LE GARREC Vincent
8c4896dfec
Fix tolower with cfi sanitizer (#1209) (#1210)
and update trantor with same patch.
2022-04-22 11:08:40 +08:00
Nitromelon
6971f84dae
Fix mutex lock missing. (#1214) 2022-04-14 16:52:04 +08:00
An Tao
3d3daef3c5
Fix a bug when stopping redis service (#1205) 2022-03-28 11:23:33 +08:00
faker
740c34fce3
To avoid accessing a null point, make sure result == OK before accessing the response ptr. (#1195) 2022-03-26 17:02:58 +08:00
An Tao
dd63a72dab
Update issue templates 2022-03-01 13:58:37 +08:00
Martin Chang
b9bbe45642
Fix XXXControllers created on MSVC even if specsfied not to do so (#1183)
Co-authored-by: marty1885 <marty1885@gmail.com>
2022-02-26 00:19:48 +08:00
davidschedler
b8a6188ad5
Add ‘not like‘ criteria (#1182) 2022-02-23 09:34:51 +08:00
an-tao
fc68b8c92c Bump version to 1.7.5 2022-02-19 18:42:49 +08:00
Ichiro
09a351d032
Format code controller autogen (#1138) 2022-02-19 09:37:11 +08:00
davidschedler
0e3ee5fad0
Fix missing "using namespace drogon::orm;" at autogenerated restful controller (#1178) 2022-02-16 11:10:13 +08:00
Ichiro
4b31f93767
Add Not In for ORM Criteria (#1176) 2022-02-12 21:59:49 +08:00
Kirill
3c785326c6
Prevent malformed upload path causing arbitrary write (#1174) 2022-02-11 23:54:42 +08:00
Robert Huang
8ed0434ad8
Remove unused variable and fix compile error (#1171) 2022-02-03 22:33:50 +08:00
An Tao
26c8c0b527
Update trantor (#1166) 2022-01-28 17:25:34 +08:00
X-rays5
92d39fb174
Fix sqlite3 and mariadb when using vcpkg (#1165) 2022-01-25 21:00:56 +08:00
juanetch
bbc31612fc
add max-age, samesite options to Cookie (#1159)
Co-authored-by: an-tao <antao2002@gmail.com>
2022-01-16 11:40:17 +08:00
autoantwort
bfb25a3765
Accept system lib for uuid on macOS (#1152) 2022-01-09 12:04:38 +08:00
timomrs
88f4f090a8
Allow using json_cpp in other sublibraries (#1145)
If another sublibrary also imports jsoncpp, `FindJsonCpp.cmake` fails with error message `add_library cannot create imported target Jsoncpp_lib because another target with the same name already exists.`.  Adding the `if (NOT TARGET Jsoncpp_lib)`-guard fixes this.

It might be useful to check if there's a similar problem with other sublibraries included by Drogon.
2022-01-08 12:33:35 +08:00
Nitromelon
68b2a46a29
Start listening after beginning advices (#1147) 2022-01-07 21:45:09 +08:00
MWX
e81662f29b
Update HttpRequestImpl.cc (#1148) 2022-01-06 00:33:29 +08:00
Ichiro
29732a94ef
Fix reserve bug (#1144) 2022-01-03 09:24:06 +08:00
Martin Chang
e2842c9de5
Check HTTP client is not sending requests in sync mode on the same event loop in debug mode (#1143) 2022-01-02 20:14:27 +08:00
pao-lu
720ce4e9ed
Destroy fastdb client on quit (#1142) 2021-12-31 12:31:32 +08:00
Vladimir
9db332af65
Enable setup output of logs to files at any time. (#1140)
Co-authored-by: Volodymyr Romanishyn <volodymyr.romanishyn@ingenico.com>
2021-12-29 13:20:39 +08:00
Ichiro
6c8f8bac1f
Add toString for drogon::ReqResult (#1133)
* Add to_string and to_string_view for drogon::ReqResult
2021-12-24 20:45:36 +08:00
Ichiro
bc4e8faec2
Fix lint (#1134) 2021-12-22 16:26:52 +08:00
Martin Chang
52800006a0
Avoid attempt linking to std::fs when target does not exist (#1131) 2021-12-21 22:22:57 +08:00
timomrs
03f34cb40b
Remove sudo from dependencies in Dockerfile (#1128)
After Pull request #1127 , sudo is no longer needed in the Docker image
2021-12-17 18:33:29 +08:00
timomrs
bba5253a0f
Remove sudo from build.sh (#1127)
Somewhat controversial, but in general scripts shouldn't have sudo embedded, if necessary the user should run the whole script under sudo. See for example discussions in:

https://askubuntu.com/questions/425754/how-do-i-run-a-sudo-command-inside-a-script
https://unix.stackexchange.com/questions/20284/should-i-be-using-sudo-in-scripts-that-i-write

with conflicting answers. However, removing the sudo from the script here would allow removing dependency on sudo from Dockerfile (I believe) since in Docker the install is done as root, while a user installing elsewhere is free to use sudo for the whole script.
2021-12-17 16:53:14 +08:00
Martin Chang
080123ff96
use operator<< to convert ReqResult to string (#1126) 2021-12-13 12:37:31 +08:00
Martin Chang
6b677a3ff6
Fix WS test potentially can get stuck (#1124) 2021-12-12 11:18:59 +08:00
an-tao
be3136ea26 Bump version to 1.7.4 2021-12-11 10:27:51 +08:00
Martin Chang
719d50c0a7
Remove setting c++17 in FindFilesystem (#1102) 2021-12-11 10:02:45 +08:00
An Tao
754fd2da29
Update trantor (fix sending partial files) (#1123) 2021-12-10 13:04:18 +08:00
An Tao
66e29dd9b2
Fix an error of std::bad_function_call (#1115) 2021-12-09 19:25:39 +08:00
Nitromelon
7455355419
Add more method for mapper (#1112) 2021-12-08 00:54:01 +08:00
NitroMelon
2a484536d1
Fix signal handle (#1106) 2021-12-05 18:43:49 +08:00
NitroMelon
6a55a3aa64
Fix namespace in model template. (#1107) 2021-12-05 18:29:29 +08:00
NitroMelon
e9fafc643d
Support CoroMapper method chaining (#1103) 2021-12-04 20:54:25 +08:00
SCOTT-HAMILTON
1c44cf7e4c
Handle SIGINT too (#1094)
Co-authored-by: an-tao <antao2002@gmail.com>
2021-12-02 10:42:21 +08:00
An Tao
3ad9326e2a
Fix a race condition when resetting ws (#1101) 2021-12-02 00:35:27 +08:00
Martin Chang
113d23494a
Fix CI to actually build in C++14 (#1100) 2021-12-01 21:55:38 +08:00
An Tao
7cf0a64ab6
Fix orm tests (#1099) 2021-12-01 11:18:35 +08:00
Martin Chang
8913abc400
Mark all awaiters as nodiscard (#1098) 2021-12-01 08:40:09 +08:00
An Tao
d6b09c9e1b
Fix an error when binding a function pointer to SqlBinder (#1097) 2021-12-01 08:39:42 +08:00
An Tao
f522d2d70e
Create path if it doesn't exist (#1095) 2021-11-29 18:15:18 +08:00
an-tao
bc18f56d57 Update trantor 2021-11-28 21:23:18 +08:00
An Tao
7d137362bd
Fix the error with multiple results when calling a procedure in mysql (#1091) 2021-11-28 16:26:23 +08:00
Martin Chang
6e6493299e
Support setting client certificate and SSL options on HTTP client (#1090) 2021-11-27 19:11:05 +08:00
Ichiro
faf3e0c17c
Add drogon::orm to models generation (#1092) 2021-11-26 11:29:47 +08:00
NitroMelon
ec8146774a
Add overloads for SqlBinder::operator<< with non-const ref parameter. (#1089) 2021-11-25 19:18:30 +08:00
An Tao
895552dcae
Export some symbols for Windows (#1088) 2021-11-24 23:59:00 +08:00
An Tao
df331c8a74
Add an example for using coroutines of redis clients (#1080) 2021-11-21 12:09:34 +08:00
L0ric0
953000e3fb
Fix compiler warnings (#1081)
* Fix narrowing conversion warning.

The `static_cast` does not change the behavior of the programm only explictly stating that the behavior is intended.
This change is needed as some compiler settings will treat this warning as an error.

* Do not redeclare `result` variable in insertFormattedString as it shadows variable in outer scope.

This fixes a compiler warning for shadowing variables declared in an outer scope. This change does not change the behaviour of the programm as the shadowd variable is not reused after the inner scope ends. Also the new version should represent the intention of the code better.
This change is needed as some compiler settings will treat this warning as an error.
2021-11-21 09:14:57 +08:00
Martin Chang
e4ec2c36c5
Fix build fail on CentOS8 (#1078) 2021-11-16 22:32:08 +08:00
Martin Chang
29f2d431ab
Prevent drogon_ctl create_view appending empty new lines to resulting view in c++ section (#1073) 2021-11-06 11:15:46 +08:00
Martin Chang
9e9bc7997e
use decay_t instead of remove_cvref_t (#1072) 2021-11-02 22:34:50 +08:00
Martin Chang
9448c19865
Fix coroutine objcet destructing before coroutine ends in async_run (#1069) 2021-11-02 13:56:18 +08:00
NitroMelon
0431f38a4e
Support range for static file (#1060) 2021-10-28 21:53:58 +08:00
Martin Chang
7066b09edb
fix deprcated warning when using openssl 3 (#1064) 2021-10-27 21:19:06 +08:00
Martin Chang
dff4b6c5d9
update trantor (#1059) 2021-10-26 10:07:53 +08:00
Martin Chang
e2eb674781
Fix Drogon not building caused by FindFilesystem (#1056)
* fix FindFilesystem not using the correct header for printf

* fix FS not found on Yocto
2021-10-21 19:43:53 +08:00
an-tao
5a03c9aa9f Bump version to 1.7.3 2021-10-17 11:49:20 +08:00
Neil Cook
a7f05c4214
Add option to disable brotli if desired by the builder (#1050) 2021-10-08 08:42:34 +08:00
everzone
0818384172
Add Alpine Dockerfile (#1048) 2021-10-04 23:26:09 +08:00
Martin Chang
ac4a816a99
Add async_run (#1047) 2021-10-03 16:31:52 +08:00
An Tao
4a6f298661
Update trantor (#1046) 2021-10-03 16:31:26 +08:00
An Tao
3eb5bcd1dd
Add the getOptionalParameter method (#1037) 2021-09-30 08:50:00 +08:00
An Tao
22f810a71b
Fix a race condition in testing (#1041) 2021-09-30 08:49:35 +08:00
iandrc
fdcf294ef9
fix(style): Change the NotFound page text color (#1038)
Key changes:
- Set the text color for 404 page to `"black"`

Refs:
- https://github.com/drogonframework/drogon/issues/977
2021-09-29 20:56:09 +08:00
Bertrand Darbon
9b09abe274
fix(cmake): error in FindFilesystem (#1035)
When building an application on Windows using Drogon as a dependency and with warnings treated as errors, the FindFilesystem.cmake generates this error (in CMakeError.log):

```
src.cxx(6): error C2220: the following warning is treated as an error
src.cxx(6): warning C4477: 'printf' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'const std::filesystem::path::value_type *'
src.cxx(6): note: consider using '%ls' in the format string
src.cxx(6): note: consider using '%lls' in the format string
src.cxx(6): note: consider using '%Ls' in the format string
src.cxx(6): note: consider using '%ws' in the format string
```

Documentation of std::filesystem::path: value_type: character type used by the native encoding of the filesystem: char on POSIX, wchar_t on Windows

Using generic_string() fixes this warning
2021-09-28 19:55:30 +08:00
Bertrand Darbon
c5effe9c51
fix(MutliPart): Does not respect quotes in Content-Disposition header (#1031)
* fix(MutliPart): Does not respect quotes in Content-Disposition header

Currently, Drogon MultiPart parser expects quotes for name and filename in the Content-Disposition header.

The builtin HTTP library for .NET Core (System.Net.Http.HttpClient) leaves the quotes in this header, which means that by default, .NET Core applications cannot upload files to drogon.

The related RFC https://datatracker.ietf.org/doc/html/rfc6266 allows for both usages.

This contribution aims to fix this and handle both cases (with or without quotes)
2021-09-26 08:51:13 +08:00
An Tao
8460249ab3
Update trantor (#1033) 2021-09-26 00:15:36 +08:00
an-tao
f49d71faba Modify FUNDING.yml 2021-09-25 11:10:16 +08:00
NitroMelon
c9f98e1bf3
Return on redis connection error. (#1030) 2021-09-25 00:03:23 +08:00
Martin Chang
56cb305ae3
Support custom MIME types and extensions (#1024)
* Drogon now support custom extension and MIME types
* Added contentTypeString() to retrieve the string version of content type (in case the content type is not in the ContentType enum)
* setCustomContentTypeAndString() also accepts MIME as input (instead of the full content-type header string),
* Remove webContentTypeToString()
* Added app().registerCustomExtensionMime()
* Added support to load custom extension from JSON config
2021-09-24 22:51:09 +08:00
Martin Chang
c7b6c8403f
allow outside access to the file path of a HTTP response (#1020) 2021-09-17 13:14:23 +08:00
An Tao
94c7add7a1
Fix a bug in the getIOLoop method (#1014) 2021-09-07 21:42:08 +08:00
an-tao
cdabca9de5 Update trantor 2021-09-04 23:30:16 +08:00
NitroMelon
ba5187868d
Improve AccessLogger. (#1008) 2021-09-02 08:20:49 +08:00
Martin Chang
6b0e38fc8f
Experimental HaikuOS Support (#1002) 2021-08-28 11:47:24 +08:00
an-tao
30f06515fe Update trantor 2021-08-26 23:38:35 +08:00
NitroMelon
b2bf247048
Support sending files by range (#1001) 2021-08-26 23:33:58 +08:00
marty1885
b68aeb43ae add v1.7.2 link 2021-08-24 20:08:33 +08:00
marty1885
3620228843 Bump version to 1.7.2 2021-08-24 19:43:00 +08:00
Martin Chang
133e6dc2ef
Update C++ version detection logic (#993)
* Maintain compatibility with cmake generated from older drogon_ctl
 * Use user-defined C++ version when possible
 * C++ version detection no-longer depends on std::filesystem availability
 * Link against c++fs in DrogonConfig.cmake if on those versions of GCC
 * Allow DrogonConfig to use user-defined C++ version
2021-08-24 16:34:07 +08:00
tastytea
588a7f0cd1
cmake: Use GNUInstallDirs to figure out install dirs. (#980) 2021-08-22 19:31:47 +08:00
an-tao
8049206b5f Update trantor 2021-08-18 22:45:25 +08:00
tastytea
0783d6aa3e
CMake: Add CPack for .deb and .rpm package generation. (#987)
Compile as normal, run `cpack -G DEB` or `cpack -G RPM` in build
directory.

Tested on:
  - Debian 11 (bullseye)
  - OpenSUSE Leap 15
  - Ubuntu 18.04 (bionic)

Bug: https://github.com/drogonframework/drogon/issues/983
2021-08-18 22:31:32 +08:00
An Tao
d60f962aa3
Add stop() method to the WebSocketClient class (#972)
* Fix memory leak in the WebSocketClient class

Co-authored-by: marty1885 <marty188586@gmail.com>
2021-08-15 18:17:05 +08:00
Martin Chang
1551b66307
Add missing websocket_server entry in examples/README.md (#974) 2021-08-13 23:00:59 +08:00
Martin Chang
7e4174d537
Escape connection string in drogon_ctl create model (#967) 2021-08-10 21:25:16 +08:00
Martin Chang
b1bdc747c4
Force using boost::filesystem when building for Android (#964)
Co-authored-by: Rafał Bugajewski <rb@cocobit.software>
2021-08-09 22:37:23 +08:00
Martin Chang
477c3dca7d
Fix test success message incorrectly shown when -s is flag present (#962) 2021-08-07 23:07:48 +08:00
Martin Chang
88236f9279
Add port() and host() to HttpClient (#959) 2021-08-05 23:10:05 +08:00
Martin Chang
6427fdedcc
Add websocket server example (#957) 2021-08-04 12:48:42 +08:00
an-tao
f46e3baeb1 Update trantor 2021-07-31 22:46:43 +08:00
Martin Chang
0b9d114746
Fix Failing to Build on MSYS2 (#952) 2021-07-27 10:53:04 +08:00
An Tao
da87c124ae
Use HAS_STD_FILESYSTEM_PATH in filesystem.h (#950) 2021-07-25 23:17:32 +08:00
putao520
64f9f8b87f
Fix a md5 sum bug without openssl (#951) 2021-07-25 23:16:13 +08:00
An Tao
1c04b1a419
Fix some compatibility issues introduced by std::filesystem or boost::filesystem (#947) 2021-07-23 13:08:54 +08:00
An Tao
895ab63937
Fix a link error when the version of gcc < 9 (#946) 2021-07-22 21:25:25 +08:00
Martin Chang
25cba9a2a5
Add missing include (#942) 2021-07-21 00:18:31 +08:00
an-tao
629ae0bba1 Update trantor 2021-07-18 13:37:16 +08:00
Greisberger Christophe
dbfb99ccc8
Add BUILD_DOC to cmake options (#936)
Co-authored-by: Christophe Greisberger <christophe@greisberger.fr>
2021-07-18 13:36:13 +08:00
Martin Chang
35c2d123c0
Load ParseAndAddDrogonTests in DrogonConfig (#934) 2021-07-17 22:16:03 +08:00
An Tao
991873cf60
Correctly check the case-insensitive value of the upgrade header of responses in websocket connections (#935) 2021-07-16 17:03:00 +08:00
Martin Chang
c9035962fc
Remove AppVeyor badge (#933) 2021-07-16 09:15:15 +08:00
Greisberger Christophe
5c1c81e828
Feature/support windows unicode paths (#928) 2021-07-15 23:57:12 +08:00
Nereg
5e8db234b9
Fix missing make (#931)
Fixed https://github.com/an-tao/drogon/issues/930
2021-07-15 00:45:02 +08:00
Greisberger Christophe
d888816997
Added support for paths containing unicode characters on Windows (#921)
Co-authored-by: Christophe Greisberger <christophe@greisberger.fr>
Co-authored-by: an-tao <antao2002@gmail.com>
Co-authored-by: marty1885 <marty188586@gmail.com>
2021-07-12 22:38:02 +08:00
Martin Chang
f87a6ca1b8
Disable strict compiler check on Windows with GCC (#927) 2021-07-11 12:29:37 +08:00
Martin Chang
3b600232be
error on failing to create view from CSP (#924) 2021-07-09 07:58:03 +08:00
Sebastián González
a02d8e402c
Add Redis example (#918) 2021-07-06 23:02:11 +08:00
PColis
c5398b26cb
Update CacheFile.cc (#916)
On Windows, ftell returns a 32 bits signed integer.
On Windows we had to use _ftelli64 to return a signed 64 bits integer.
2021-07-02 19:08:28 +08:00
Martin Chang
0efd0c34c1
Generic optimizations (#913) 2021-06-30 23:37:59 +08:00
James Armes
5245f136b7
Add GCC-compatible warnings to the example executables (#910) 2021-06-27 09:54:02 +08:00
Martin Chang
0e7637daf6
Fix clang-format 12 putting {} of a lambda body on the next line (#905) 2021-06-25 23:59:09 +08:00
Martin Chang
04c7c7eb22
Fix WS client example not working with integration_test_server and print error when WS encounters bad IP address (#902) 2021-06-24 23:29:50 +08:00
an-tao
dbb51c1e6a Bump version to 1.7.1 2021-06-24 14:48:38 +08:00
Martin Chang
b8d820fc2a
Fix single layer directory traversal in StaticFileRouter (#901)
The StaticFileRouter can access file in the immediate parent directory if the
client sends a specially crafted, non RFC conforming HTTP 1.x request. By
sending a HTTP request without a "/" predicating the path. The StaticFileRouter
fails to detect directory traversal since it checks for "/../" in the path.

This PR fixes the issue by detecting if there's potential for directory
traversal. If true, we follow the path and detect if it reaches out of the
document root at any point. Also added 2 new tests for edge cases in static
file serving. (Not related to the bug).

Co-authored-by: an-tao <antao2002@gmail.com>
Bug discovered by: oToToT <https://github.com/oToToT>
2021-06-24 13:04:19 +08:00
QuickWrite
065675486d
Fixed typos (#900)
Just some typos were fixed and nothing more. (Nothing significant)

What has changed:

* Some rewording and corrections

* Updated the requested changes

Co-Authored-By: Rafał Bugajewski <24480+rbugajewski@users.noreply.github.com>

* clang-format

Co-authored-by: Rafał Bugajewski <24480+rbugajewski@users.noreply.github.com>
Co-authored-by: an-tao <antao2002@gmail.com>
2021-06-23 20:44:45 +02:00
Martin Chang
6a882841f1
Fix typos (#899) 2021-06-22 15:08:06 +08:00
Martin Chang
cd46b4a488
Add jsonstore example (#894)
Adds a minimal useful RESTful API example to showcase how to build APIs in Drogon. The added example is multi-threaded and stores data in memory.
2021-06-19 22:55:44 +08:00
Rafał Bugajewski
f84b709a61
Updated Dockerfile to Ubuntu 20.04 & Fixed Timezone Hangup (#895)
Co-authored-by: an-tao <antao2002@gmail.com>
Co-authored-by: Martin Chang <marty1885@users.noreply.github.com>
2021-06-19 17:37:42 +08:00
an-tao
a38d67aedb Bump version to 1.7.0 2021-06-18 16:07:18 +08:00
Martin Chang
834e3eabdd
Fix CacheMap crash in CI tests (#890)
It is possible for the CacheMap to destruct while timeout callback is
active. This causes a very rare data race. And it's my hypothesis that
this is the reason behind CacheMap crashes on CI. This patch locks the
weels upon cestructing.
2021-06-13 10:33:30 +08:00
Philip Kovacs
a70a2844b1
Fix compiler warnings (#886)
Co-authored-by: an-tao <antao2002@gmail.com>
Co-authored-by: Martin Chang <marty1885@users.noreply.github.com>
2021-06-09 19:14:15 +08:00
An Tao
e7ec973095
Create controller instances after running instead of after being called (#888) 2021-06-09 10:58:56 +08:00
Sebastián González
b22b7c6be3
Fix helloworld url (#887) 2021-06-08 16:43:17 +08:00
An Tao
945b26dc0c
Fix routing mismatch (#885) 2021-06-07 21:35:22 +08:00
Martin Chang
4abbf76214
Optimize HttpControllersRouter for cases where regex is not needed (#883) 2021-06-07 11:57:45 +08:00
An Tao
6a3f72f2e5
Fix 'build.sh -tshared' (#882) 2021-06-04 18:45:21 +08:00
an-tao
b654e35e51 Add the setCustomStatusCode method 2021-06-01 19:30:21 +08:00
Martin Chang
c6b65485e1
Add minimal server side examples (#880) 2021-06-01 16:08:51 +08:00
Tommy Chiang
e1cbd1b987
Add SSL_CONF_cmd support (#871) 2021-05-29 16:53:46 +08:00
Martin Chang
ffc410a66e
Improve WebSocket mask handling (#875) 2021-05-29 15:11:41 +08:00
An Tao
1bddbb117a
Dos2unix (#874) 2021-05-28 09:52:34 +08:00
Philip Kovacs
802e2ae87a
change some #ifdef's to #if in db_test (#873) 2021-05-28 08:21:09 +08:00
Martin Chang
0b5075bfa9
Drogon test framework (#869) 2021-05-27 20:09:57 +08:00
An Tao
afb7e853ec
Add the int type for the Row index parameter (#872) 2021-05-27 10:10:23 +08:00
An Tao
1e87c35b8f
Fix a bug of string_view for MSVC (#870) 2021-05-25 16:51:49 +08:00
An Tao
36fb3b3a40
Fix a bug when a network failure occurs on Redis connections. (#868) 2021-05-25 08:33:53 +08:00
An Tao
65a7dadbfb
Modify the way to create sqlite3 client (#867) 2021-05-25 00:21:11 +08:00
An Tao
dc732fc954
Add l-reference version of optional<T> and r-reference version of Json::Value to SqlBinder operator '<<' (#863) 2021-05-22 16:10:39 +08:00
An Tao
8052c38f49
Make Json::Value as a SQL parameters type (#861) 2021-05-22 13:08:17 +08:00
An Tao
3601992546
Move resolverPtr when distorying an HttpClietImpl object (#860) 2021-05-20 13:15:59 +08:00
Martin Chang
32970172f6
Make AsyncTask only destruct when the coroutine reaches end of execution (#857) 2021-05-18 19:20:15 +08:00
An Tao
9a059aedef
Add the AccessLogger plugin (#854) 2021-05-17 21:45:18 +08:00
Martin Chang
706fc70abc
Fix sync_wait/co_future use-after-free (#855)
* Fix sync_wait and co_future heap use-after-free
* Fix sync_wait deadlock if on a single thread
* Fix WebSocketCoroTest crash
2021-05-17 19:41:16 +08:00
An Tao
cd093fc97e
Add the PreSendingAdvice to AOP (#853) 2021-05-16 19:38:16 +08:00
an-tao
08351ccf98 Bump version to 1.6.0 2021-05-15 18:15:13 +08:00
Martin Chang
f736e12a05
Fix double free in coroutine exception handling (#851) 2021-05-15 14:10:14 +08:00
An Tao
63738bd578
Fix [-Werror=reorder] (#852) 2021-05-15 14:09:24 +08:00
An Tao
74b3ca3db6
Set running flag to true before installing plugins (#849) 2021-05-12 23:50:29 +08:00
陈晓林
e478b63dda
Add support 'select <db>' for redis (#847)
Co-authored-by: an-tao <antao2002@gmail.com>
2021-05-12 18:32:49 +08:00
Martin Chang
0e70be0a95
Fix coroutine frame leak upon assigning to awaitable (#848) 2021-05-12 16:05:20 +08:00
Philip Kovacs
2c53cf086a
Add missing mutex include (#845) 2021-05-11 09:24:14 +08:00
An Tao
471488eef1
Use two-phase construction for the DbClientImpl and the RedisClientImpl (#844) 2021-05-10 08:31:21 +08:00
LynxesExe
f8e56d85dd
Allow users to override drogon Find modules (#843) 2021-05-09 07:26:46 +08:00
Martin Chang
6bfbf97eea
Print error before terminating in AsyncTask (#841) 2021-05-06 17:50:11 +08:00
An Tao
f99c72bd5b
Fix an error when constructing RedisClientImpl objects (#840) 2021-05-05 09:51:04 +08:00
Tommy Chiang
cb1876f26b
Remove duplicated inclusion (#838)
This remove the duplicated `#include "HttpClientImpl.h"` in `lib/src/HttpAppFrameworkImpl.cc`.
2021-05-04 22:36:59 +08:00
An Tao
74d57ab7fa
Add the validateCert parameter to the newWebSocketClient method (#835) 2021-05-02 20:15:27 +08:00
An Tao
51814b76da
Add the setTimeout() method to the ReidsClient class (#830) 2021-04-30 08:00:11 +08:00
Martin Chang
60c877f920
Use make_exception_ptr instead of throw/catch when possible (#828) 2021-04-29 17:01:18 +08:00
An Tao
685aaaa3da
Add the setTimeout() method to the DbClient class (#823) 2021-04-29 10:13:34 +08:00
An Tao
a33bf2bf34
Send the content-length header even if the body(POST,PUT,OPTIONS,PATCH) is empty (#825) 2021-04-28 18:04:57 +08:00
Martin Chang
88c6b6e7d4
Disallow coroutines to be resolved as plain subroutine handlers (#827) 2021-04-28 16:58:03 +08:00
Martin Chang
1eea826a52
Fix ORM with SQLite3 not compiling on Arch Linux (#822) 2021-04-27 16:41:16 +08:00
An Tao
87d8123276
[HttpClientImpl] Remove the related request from the buffer if it's not sent after the timeout (#818) 2021-04-24 21:05:13 +08:00
Philip Kovacs
b067771fa4
Add version/soversion to shared library (#814) 2021-04-22 13:22:13 +08:00
An Tao
b2c1c8de9e
Fix an unused-parameter warning when no sqlite library (#811) 2021-04-19 13:27:11 +08:00
An Tao
e83026230a
Little changes (#810)
1. Put parameters in query string if the content-type is not 'application/x-www-form-urlencoded'
2. Parse the mulitpart form data if the method is POST or PUT
3. Send query string when the passThrough flag is set
2021-04-18 21:00:20 +08:00
0rangeFox
df51674792
Enhancements on files part. (#803)
Co-authored-by: an-tao <antao2002@gmail.com>
2021-04-17 14:01:06 +08:00
Bertrand Darbon
0ec2f51fbf
Add option to set default handler (#802) 2021-04-16 18:49:39 +08:00
An Tao
d256e93cde
Copy CoroMapper.h to installation location (#807) 2021-04-16 15:48:19 +08:00
An Tao
ab5eb955b4
Fix unused parameter errors/warnings (#805) 2021-04-15 23:26:58 +08:00
Bertrand Darbon
44a8a2d5f7
Add GNU -Werror & fix warnings (#801) 2021-04-15 19:27:15 +08:00
An Tao
4eeba18088
Improve the MultiPartParser class (#800) 2021-04-14 23:26:38 +08:00
An Tao
8f2609d1bd
Fix a bug of the Transaction class (#798) 2021-04-13 15:54:50 +08:00
0rangeFox
f670f71484
A few mini changes to Drogon CTL. (#795) 2021-04-11 11:51:48 +08:00
an-tao
d665bedb5c Bump version to 1.5.1 2021-04-10 20:29:54 +08:00
An Tao
ba8c7b5bca
Fix a bug of reflection failure introduced by #745 (#793) 2021-04-10 20:18:51 +08:00
an-tao
8cb327606a Bump version to 1.5.0 2021-04-10 09:40:34 +08:00
0rangeFox
c65051a8f1
Remove repeated class names on relationships from model generator. (#792) 2021-04-09 22:15:49 +08:00
An Tao
4b8d08f20f
Add CoroMapper to models friends (#790) 2021-04-09 16:54:40 +08:00
Bertrand Darbon
54727a5dbe
Add exports macro to allow Shared Library with hidden symbols by default (e.g. Windows) (#745)
Co-authored-by: an-tao <antao2002@gmail.com>
2021-04-09 10:17:28 +08:00
Martin Chang
a81a5fa63e
Use lambda instead of std::bind in HttpServer (#787) 2021-04-06 23:13:53 +08:00
urlordjames
260c9a547f
set make job count to number of threads in GitHub Actions workflow (#788) 2021-04-06 22:02:56 +08:00
Martin Chang
a19d0427ed
Catch exceptions thrown by handlers (#773) 2021-03-28 10:56:23 +08:00
An Tao
564fc67649
Add a method to HttpRequest to set the user_agent header (#772) 2021-03-26 20:37:46 +08:00
mekashef
686068065a
Added newFileResponse Support for buffers in memory (#770) 2021-03-26 20:37:05 +08:00
interfector18
49181a22b2
Use canonical cmakelogic for cross compilation, (#768)
Fix clang c++20 build
2021-03-25 04:27:52 +08:00
An Tao
5f60c9fc6c
Send ping messages by default for websockets (#767) 2021-03-24 22:59:57 +08:00
interfector18
f29a29f2ba
Fix two building corner cases, CMake quality of life impovments (#766) 2021-03-24 10:32:55 +08:00
an-tao
e5c9c3a947 Update README 2021-03-23 23:13:20 +08:00
An Tao
0bf37c6052
Remove an assertion statement in the HttpClientImpl class (#764) 2021-03-23 14:36:20 +08:00
klaus triendl
bd9a149059
Use canonical way of calling max() function on Windows (#763) 2021-03-23 08:37:26 +08:00
Martin Chang
9da122a189
print error and exit when IP parsing failed in server startup (#758) 2021-03-20 00:13:58 +08:00
An Tao
d22ce4a848
Fix a bug when creating sqlite3 models (#756) 2021-03-18 01:17:37 +08:00
an-tao
4f0d29129e Revert trantor 2021-03-14 17:24:02 +08:00
JuergenGleiss
79f480c17d
Bugfix/restful api dump invalid json (#748) 2021-03-14 17:20:15 +08:00
Martin Chang
490948bb38
remove 'SSL validation' comment from HttpClient (#752) 2021-03-14 13:55:21 +08:00
An Tao
6d9aa3b44c
Add redis support (#719) 2021-03-13 19:13:54 +08:00
Roque
df04c47f74
Fix build.sh missing nproc error in build for macOS (#751) 2021-03-13 18:56:16 +08:00
Bertrand Darbon
1dfaaac5d0
Add Arch Dockerfile (#749) 2021-03-13 12:27:07 +08:00
JuergenGleiss
29a1659085
Feature/orm convert method (#739) 2021-03-12 10:41:20 +08:00
Roque
ed5ceb019d
Fix compilation errors for TimeFilter example (#743) 2021-03-12 08:11:29 +08:00
Bertrand Darbon
bcd8e27a36
feature(signal): Add option to disable signal handling (#742) 2021-03-11 22:03:02 +08:00
双草酸酯
1901801d59
Fix compile warnings in SQL client (#741) 2021-03-11 18:43:56 +08:00
Roque
71269e0179
Fixes on some name words typos (#738)
Co-authored-by: roque <roque@roque.pl>
2021-03-10 09:03:59 +08:00
an-tao
5dc02c3476 Bump version to 1.4.1 2021-03-07 20:42:32 +08:00
an-tao
e28b9aa59c Fix the same bug in the DbClientLockFree class 2021-03-07 20:40:35 +08:00
An Tao
b30c92a9a2
Fix a bug of DbClientImpl class (#735) 2021-03-07 01:28:49 +08:00
an-tao
cd389aec13 Bump version to 1.4.0 2021-03-05 23:06:16 +08:00
Martin Chang
98da3490e7
return awaiter from coroutine instead of resumable (#733) 2021-03-05 22:21:02 +08:00
Martin Chang
8bd1f5684e
Fix drogon::Task<> not destructing internal object (#729) 2021-03-01 13:36:03 +08:00
JuergenGleiss
af2bd6ba69
HttpRequest: add feature to avoid url encoding of path (#730) 2021-02-28 23:42:15 +08:00
An Tao
ef51951785
Make projects created by dg_ctl support coroutines (#727) 2021-02-27 17:39:13 +08:00
an-tao
0995749dec Update trantor 2021-02-23 14:03:10 +08:00
Martin Chang
cde19a1f57
Valivate certificate in HttpClient (#726)
Co-authored-by: an-tao <antao2002@gmail.com>
2021-02-22 11:45:33 +08:00
An Tao
0f5721119c
Support SNI in the HttpClient class (#724) 2021-02-21 16:05:58 +08:00
An Tao
ffda84627b
Modify Mapper and CoroMapper templates (#722) 2021-02-20 10:00:28 +08:00
an-tao
fd720d55d9 Modify FindMySQL.cmake 2021-02-17 10:02:52 +08:00
Martin Chang
4210dbce07
Revert OS X CI fix (#721) 2021-02-17 09:58:33 +08:00
An Tao
eb2d24197a
Fix the error when SSL handshake fails (#717) 2021-02-15 09:15:26 +08:00
interfector18
12cfdd5916
Lowercase all http headers, add webp and avif types (#718) 2021-02-15 09:14:54 +08:00
An Tao
3b8b63d17d
Add drogon::orm::CoroMapper<T> template (#712)
Co-authored-by: marty1885 <marty188586@gmail.com>
2021-02-13 18:22:17 +08:00
An Tao
cfb71cc619
Add transactions test of coroutines (#711) 2021-02-10 23:24:15 +08:00
mbehboodian
33044c823f
Fix typo in README.md (#708) 2021-02-07 17:08:41 +08:00
Martin Chang
0b5920a1f3
Fix stack use after scope error in client_example (#707) 2021-02-07 10:35:21 +08:00
interfector18
6542236b20
Add default value interface to sqlbinder for mysql and postgresql (#704) 2021-02-07 10:34:49 +08:00
An Tao
4c577e6fa9
Fix compilation errors on vs2019 (#706)
Fix compilation errors on VS2019 when coroutines are enabled
2021-02-06 19:53:30 +08:00
Martin Chang
a2142dd93e
Coroutine support (#693)
* app().registerHttpHandler() accepts coroutine as handlers
* HttpController can use coroutine as handlers'
* Http request handlers with coroutine catches exception instead of crashing the entire app
* DbClient now has execSqlCoro that is awaitable
* DbClient now has newTransactionCoro that is awaitable
* HttpClient have awaitable sendRequestCoro
* WebSocketClient have awaitable connectToServerCoro
* WebSocketClient have setAsyncMessageHandler and setAsyncConnectionClosedHandler
* drogon::AsyncTask and drogon::Task<T> as our corutine types
* Related tests
* Misc

Future work
* Coroutine for WebSocket server
* Known issues

co_future() and sync_wait may crash. It looks like GCC bug but I'm not sure.
Workarround: Make an coroutine of AsyncTask. Then launch said coroutine.
Not sure why wrapping the exact same thing in function crashes things.

Co-authored-by: an-tao <antao2002@gmail.com>
2021-02-06 17:05:58 +08:00
An Tao
7ce5768372
Return 404 or 405 responses correctly (#705) 2021-02-06 15:16:44 +08:00
An Tao
5426100bde
Fix a error in the HttpClient class when a response has no content-length header (#698) 2021-02-03 14:54:45 +08:00
Martin Chang
a060351f7a
Fix CI fail on OS X (#699) 2021-02-03 13:10:08 +08:00
双草酸酯
2919fdb7d4
Handle cross compiling properly (Fix for #654) (#694) 2021-01-24 22:44:20 +08:00
Martin Chang
0168cd0574
Bump version in CMakeLists.txt to 1.3.0 (#692) 2021-01-17 12:03:27 +08:00
an-tao
1bbc457f0d Bump version to 1.3.0 2021-01-16 22:13:26 +08:00
丁盟
64e916ccb3
Fix an error with missing composite key to sqlite3 ORM generator (#673) 2021-01-05 22:14:31 +08:00
An Tao
f26450f04b
Fix an error in sqlite3 ORM generator (#669) 2020-12-30 20:11:24 +08:00
An Tao
66fbb33956
Add format check to actions (#668) 2020-12-26 14:39:38 +08:00
Jiannan Liu
4b5885e3c0
Serve wasm files with the correct MIME type (#667) 2020-12-26 12:21:43 +08:00
An Tao
ec59dbbc3d
Add option for setting float precision in Json string (#666) 2020-12-24 20:00:29 +08:00
An Tao
1cb8b17709
Fix some bugs when creating models via drogon_ctl (#660) 2020-12-18 09:41:58 +08:00
zorosz
61bb2cf130
Based on https://github.com/an-tao/drogon/issues/627#issuecomment-727768460 (#659)
Co-authored-by: oroszz <oroszz>
2020-12-18 09:41:04 +08:00
Joakim L. Gilje
f9d714ab74
sqlite3: Insert into stmtsMap_ as string_view (#657) 2020-12-14 08:50:58 +08:00
An Tao
ce704aff5b
Update trantor (#656)
* Update trantor
* Make some minor modifications.
2020-12-14 08:49:33 +08:00
ivanka2012
d2f291689d
Fix cmake drogonctl crosscompile (#654) 2020-12-13 22:12:01 +08:00
An Tao
566297d4df
Create cmake.yml (#653) 2020-12-13 18:12:30 +08:00
An Tao
28f6338271
Remove the use of std::filesystem to adapt to old compilers (#652) 2020-12-12 20:37:44 +08:00
ivanka2012
64fe47acd8
Fix brotli link order (#651) 2020-12-12 19:39:26 +08:00
an-tao
35b4a86e06 Bump version to 1.2.0 2020-12-12 16:33:13 +08:00
ivanka2012
292894c426
Fix MinGW ORM building by enabling htonll and ntohll (#650) 2020-12-11 16:13:00 +08:00
ivanka2012
1abd8b3506
Add implicit page resolving capability (a-directory -> a-directory/index.html) (#647)
Co-authored-by: an-tao <antao2002@gmail.com>
2020-12-11 14:02:47 +08:00
An Tao
8b7ffb28d7
Add support in the SqlBinder class and the Session class (#644) 2020-12-06 11:41:06 +08:00
An Tao
7dd2d6123b
Add the reuse_port option (#634) 2020-11-25 19:47:36 +08:00
An Tao
69d687dbcb
Fix a stack-overflow error when high concurrency happening on sqlite3 (#633) 2020-11-22 20:47:38 +08:00
Martin Chang
4ca90f2415
Don't send content type in a 304 response (#630) 2020-11-18 22:31:55 +08:00
An Tao
4ce2d25d55
Return 400 if the content-length is invalid (#629) 2020-11-18 15:09:25 +08:00
Rafał Bugajewski
72a4cad9c1
Added OpenBSD as Supported Operating System 2020-11-15 15:59:52 +01:00
Rafał Bugajewski
3f0eec6427
Added OpenBSD as Supported Operating System 2020-11-15 15:58:42 +01:00
Rafał Bugajewski
3c0103d324
Added OpenBSD as Supported Operating System 2020-11-15 15:57:59 +01:00
Joakim L. Gilje
886dfc3648
Support OpenBSD (#626)
Co-authored-by: an-tao <antao2002@gmail.com>
2020-11-15 12:18:01 +08:00
An Tao
4f9ee82153
Modify the WebSocketTest controller to create a simple chat room (#625) 2020-11-14 11:48:40 +08:00
An Tao
7e8beacd1d
Fix error when receiving response without content-length header (#623) 2020-11-11 21:50:43 +08:00
an-tao
fb17efe765 Bump version to 1.1.0 2020-10-31 11:10:23 +08:00
An Tao
594911b7a2
Fix a bug in the Mapper::insertFuture() (#620) 2020-10-29 20:09:16 +08:00
An Tao
dbf21f7dbc
Fix a bug when creating sqlite3 database models (#618) 2020-10-27 21:26:01 +08:00
An Tao
de37a0ae29
Add the Host and Sec-WebSocket-Version headers when connecting to a websocket server (#615) 2020-10-25 08:36:40 +08:00
An Tao
ed2818ed89
Find mariadb client library correctly on Ubuntu 20.04 (#613) 2020-10-24 14:28:39 +08:00
Amirali Amirifar
17b3ea471d
Remove duplicate definition of args vector. (#609)
* Remove duplicate definition of `args` vector.

Removed duplicate definition of the variable `args` which could be defined in the first line rather than defining once in the if scope and once in the main function.
2020-10-13 10:29:01 +08:00
An Tao
43e7b3fec0
Add --path-to-namespace option to drogon_ctl for creating views (#607) 2020-10-12 21:51:39 +08:00
An Tao
c264c91f38
Support namespaces when creating view source files (#606) 2020-10-09 21:41:27 +08:00
An Tao
34d2fe45c3
Modify the procedure of the app().run() method (#603) 2020-10-09 15:02:05 +08:00
Martin Chang
fb7d73be06
Use TW terminology for the TW document (#601) 2020-10-07 00:20:42 +08:00
VayuDev
de0d793fc7
Fix HttpServer::isWebSocket to detect lowercase "upgrade" connection value (#594)
* Fix HttpServer::isWebSocket to detect lowercase "upgrade" connection value

The websocket library boost-beast sends the following http header:
'Connection: upgrade', while almost anything else uses:
'Connection: Upgrade'. Drogon used to only recognize the latter as
websocket request, now it recognizes both.

* Fix HttpServer::isWebSocket to detect case-insenstive "websocket"
upgrade value

This was a bug as previously, we only accepted the exact string
"websocket", although the standard specifies that it should be
case-insensetive.

Co-authored-by: VayuDev <vayudev@protonmail.com>
2020-10-04 22:53:33 +08:00
Andre Castellanos
3d9278cb82
CMAKE bug fixed when SHARED and EXAMPLES are on (#597)
Co-authored-by: andre <andre@pop-os.localdomain>
2020-10-04 11:10:23 +08:00
Haceau-Zoac
2ffd4738b2
Add zh-TW README.md (#593) 2020-10-03 23:34:29 +08:00
An Tao
0fe3f6fd8f
Use explicit lambda capture lists (#590) 2020-10-02 11:45:07 +08:00
An Tao
465d2ebfe8
Disable TLS1.0/1.1 on HTTPS by default (#588) 2020-10-01 23:40:46 +08:00
Martin Chang
ada35c43fa
Fix failing to connect to DB if parameters contains spaces (#589) 2020-10-01 19:47:51 +08:00
An Tao
bbb338bf12
Bump version to 1.0.0 (#584) 2020-09-27 22:51:09 +08:00
an-tao
5bca202c28 Update README 2020-09-20 22:14:37 +08:00
L0ric0
6fca7067da
Add ConfigLoader::ConfigLoader(const Json::Value &data) (#579) 2020-09-18 21:12:46 +08:00
an-tao
c320527f9d Delete a confusing log output 2020-09-17 23:12:33 +08:00
An Tao
d023743fa3
Fix a bug when creating models in some special cases (#577) 2020-09-17 20:48:16 +08:00
Martin Chang
c4ff98e620
remove execution permission on /tmp/drogon.lock (#575) 2020-09-16 00:59:19 +08:00
Elwin.Zhu
3222c0df84
Modify the FileUpload.csp in simple_example to avoid CORS (#573) 2020-09-15 16:20:56 +08:00
An Tao
4c9463eeb7
Modify session handling (#568)
* Change thread unsafe interfaces to safe.

* Fix some compiler warnings
2020-09-15 08:28:04 +08:00
Jiannan Liu
6f7a062221
Suppress sanitizer warning (#572)
Add default initializer for HttpConstraint::method_ member variable to avoid the following warning given by gcc's undefined behavior sanitizer (-fsanitize=undefined):

drogon/lib/inc/drogon/utils/HttpConstraint.h:30:7: runtime error: load of value 32767, which is not a valid value for type 'HttpMethod'
2020-09-14 15:11:53 +08:00
An Tao
a32170b9a3
Modify the documentation of the method fileData() (#566) 2020-09-12 13:59:04 +08:00
An Tao
11cabfb546
Remove the useless method stat() from the PluginBase class (#563) 2020-09-10 08:45:23 +08:00
An Tao
e032f9bd0e
Add getListeners() method to the HttpAppFramework class (#559) 2020-09-07 00:51:07 +08:00
Martin Chang
3a00ffde47
Add support for status code 418 (#557) 2020-09-03 21:11:25 +08:00
an-tao
19df3afb78 Update trantor 2020-08-27 19:15:14 +08:00
An Tao
4a9ba2088c
Remove the expired std::iterator template (#554) 2020-08-26 20:53:04 +08:00
An Tao
a10e6bfb1c
Modify methods related to headers (#552) 2020-08-26 20:28:19 +08:00
An Tao
4d8707df4b
Fix a bug when losting connection to MySQL server during query (#550) 2020-08-25 23:35:07 +08:00
An Tao
7117d96016
Fix an issue of simple_reverse_proxy when handling chunked transfer-e… (#549)
* Fix an issue of simple_reverse_proxy when handling chunked transfer-encoding
2020-08-25 08:07:43 +08:00
an-tao
d59021ef9f Bump version to 1.0.0-beta21 2020-08-19 23:18:59 +08:00
An Tao
2aebba9cc1
Fix zlib link error on Windows for the latest vcpkg (#545) 2020-08-19 22:23:47 +08:00
Richard
321405a93a
Fix Chinese readme (#543) 2020-08-17 10:57:18 +08:00
An Tao
f1a7462c4c
Modify the Result class in orm (#541) 2020-08-16 20:00:14 +08:00
an-tao
f0110a642d Bump version to 1.0.0-beta20 2020-08-15 16:04:10 +08:00
itgenie98
168d2afb17
Fixing bug in drogon_ctl when creating a model, that causes to write the content of the header and sourcefiles multiple times (#540) 2020-08-15 07:14:52 +08:00
An Tao
c4d727cbe6
Fix compilation warning of sprintf function (#537) 2020-08-14 08:10:56 +08:00
An Tao
3a10db99c7
Set the response Access-Control-Allow-Headers header correctly for OPTIONS requests (#534) 2020-08-13 21:41:29 +08:00
An Tao
857cacfda7
Fix boost::string_view compilation error of MysqlConnection class (#530) 2020-08-10 09:53:45 +08:00
An Tao
960309e615
Resolve an issue when sending big files (>=2gB) on Windows (#529) 2020-08-09 19:20:51 +08:00
An Tao
fda2719dd4
Fix the session bug introduced in PR #523 (#528) 2020-08-06 19:35:30 +08:00
An Tao
80a8f62e30
Change the type of result from the mktime() function in model source code (#524) 2020-08-05 20:01:51 +08:00
An Tao
dddc62a9fe
Fix a mysql issue when connections are lost (#525) 2020-08-04 20:04:43 +08:00
An Tao
43a21ddc9c
Provide users with a method to change the session ID of a session (#523) 2020-08-03 19:18:47 +08:00
An Tao
820715cd62
Set session to requests for websockets (#521) 2020-07-31 09:25:20 +08:00
An Tao
5e35055379
Build release version in docker (#520) 2020-07-30 16:27:35 +08:00
An Tao
34cefefce4
Modify parseContentType function (#518) 2020-07-25 10:01:06 +08:00
An Tao
5bd85170bf
Fix a bug when saving uploaded files on Windows (#514) 2020-07-17 13:18:52 +08:00
an-tao
dd66ba5a73 Bump version to 1.0.0-beta19 2020-07-16 21:07:00 +08:00
An Tao
c8640700ea
Add the getJsonError method (#507)
* Add the getJsonError method to the HttpRequest and the HttpResponse classes
2020-07-09 19:50:30 +08:00
An Tao
9d3efeac67
Optimize the HttpResponse class (#505) 2020-07-06 08:39:20 +08:00
An Tao
9c54fb8c69
Modify generation of models and the DbClient class (#498)
* Add setter method for automatical fields of models

* Put SQL queries into buffer before any connection being established

* Update trantor
2020-07-03 12:19:40 +08:00
An Tao
f871d1607d
Modify static files router and 404 pages generator (#497)
1.Except for the GET method, it is forbidden to use any other method for accessing static files.
2.Use following sequence to create 404 pages.
 * try to use user customized 404 handler;
 * try to use user customized error handler;
 * use default handler to create 404 pages;
2020-07-02 09:59:17 +08:00
Rick Zhuang
630beed867
Add the header <cctype> to resolve build errors in VS2017 (#495) 2020-06-27 11:43:49 +08:00
An Tao
306c072af7
Add a timeout parameter when sending HTTP requests (#493) 2020-06-27 09:45:14 +08:00
An Tao
8f6269b208
Add a method to disable unicode escaping in json string (#491) 2020-06-24 08:11:32 +08:00
An Tao
ccd51d289e
Destroy DNS resolver of HttpClient in the correct thread (#490) 2020-06-22 19:55:24 +08:00
An Tao
3424d3f2c4
Add a way to set the character set when creating DbClient objects (#486) 2020-06-20 20:21:14 +08:00
An Tao
56b5d03fed
Remove the restriction on the location of layout tags in views (#484) 2020-06-18 21:44:54 +08:00
An Tao
a9f4bff519
Properly handle chunked encoding requests. (#479) 2020-06-16 20:36:31 +08:00
itgenie98
2607f35687
Fix CORS for new HTTP PATCH method (#477)
* Fix CORS for new HTTP PATCH method, also fix HttpRequestImpl::appendToBuffer, to be able to send PATCH requests

* Fix simple_example_test to work with updated CORS
2020-06-15 10:05:05 +08:00
antao
fda6a443a8 Bump version to 1.0.0-beta18 2020-06-14 23:20:35 +08:00
itgenie98
14b5ec08ee
Add HTTP PATCH method (#476) 2020-06-14 21:57:25 +08:00
An Tao
2457f9b413
Add a method for the TERM signal handling (#475) 2020-06-14 17:36:10 +08:00
An Tao
4ebb72b0cf
Fix a bug with quoted column names in sqlite3 databases when using 'drogon_ctl create model'(#474) 2020-06-14 09:13:49 +08:00
Rafał Bugajewski
9e959397af
Fixed Model Generation for PostgreSQL Primary Keys (#471)
As per definition Drogon should return the last ID after an insert
when “a table contains an auto-increasing primary key”, but the
current detection mechanism isn’t enough to catch all cases.

PostgreSQL has the concept of generated identity columns that act as
primary key columns, but this information is held in the "is_identity"
column that wasn’t checked before.

This commit fixes #410, and also detects generated identity columns as
auto incrementing columns, so that the model generation correctly
appends " returning " statements.
2020-06-10 23:55:03 +08:00
An Tao
e7b7618c37
Use string_view to parse multipart/form-data requests (#469) 2020-06-10 11:11:24 +08:00
antao
be6f0966d5 Fix a compilation issue on windows 2020-06-09 10:09:17 +08:00
An Tao
b3d1f151b5
Fix the count() method of Mysql ORM (#468) 2020-06-09 00:54:12 +08:00
adrian
fd2a612945
add digest filter in examples (#462)
* add digest filter in examples

* Add getMd5() function to the public API

Co-authored-by: Adrián Ortiz Gutiérrez <aortiz@MacBook-Pro.local>
Co-authored-by: antao <antao2002@gmail.com>
2020-06-07 14:43:05 +08:00
ihmc3jn09hk
bbef8780fd
Fix a bug in ListenerManager::getIOLoop() (#461)
Co-authored-by: antao <antao2002@gmail.com>
2020-06-06 12:59:54 +08:00
An Tao
e015439740
Add a new joinpoint of AOP for modification on each HTTP response (#460) 2020-06-06 12:25:21 +08:00
An Tao
ecb3d3f74f
Make app().run() method callable on a non-main thread (#457) 2020-06-06 12:24:06 +08:00
VayuDev
d4d5adf88b
Added additional formats for getHttpDate function and fixed undefined behavior upon error (#453) (#456)
This patch adds support for the RFC 850 and asctime format. If an error
occurs, we now return a date with the epoch value of -1 and warn instead of
triggering undefined behavior. This is checked by a new set of tests.

Co-authored-by: VayuDev <vayudev@protonmail.com>
Co-authored-by: antao <antao2002@gmail.com>
2020-06-05 20:57:36 +08:00
An Tao
5faab6b414
Modify the WebSocketConnection class (#452)
* Add getContextRef method to the WebSocketConnection class

* Expose some functions on Windows

* Send a close message when closing a web socket connection
2020-06-04 19:11:07 +08:00
An Tao
adab48e187
Fix a Mysql connection error on Windows (#449) 2020-06-02 22:05:03 +08:00
antao
c2f6aa0109 Update the trantor library 2020-05-31 18:33:23 +08:00
Rafał Bugajewski
598d8c15b3
Added Initial Contribution Recommendations (#445)
Co-authored-by: antao <antao2002@gmail.com>
2020-05-25 21:05:05 +08:00
Vedran Miletić
e286fe869a
Fix building of ORM on FreeBSD (#444) 2020-05-25 00:00:00 +08:00
antao
49472a3cc4 Create a class template for publish subscribe pattern (#443) 2020-05-24 20:42:00 +08:00
antao
84e503a948 Bump version to 1.0.0-beta17 2020-05-23 10:47:24 +08:00
Erez Oxman
d43c2976ff
Changed link in readme.md from doxiz to docsforge (#442) 2020-05-22 00:00:07 +08:00
An Tao
7b1712003d
Modify drogon_ctl to show more compilation information (#441) 2020-05-21 21:14:40 +08:00
Vedran Miletić
375498a5a6
Fixes for FreeBSD (#440)
* Use uuid(3) to generate UUIDs on FreeBSD

FreeBSD is now handled like Windows so additional UUID libraries are
not required.

* Modify build.sh script to work on FreeBSD

- /bin/bash -> /usr/bin/env bash
- nproc -> sysctl -n hw.ncpu
2020-05-20 22:29:37 +08:00
Zach Hilman
c754d65cf0
Add additional HttpStatusCodes and implement a custom error handler (#439)
This adds:

Various lesser-used HTTP status codes to the HttpStatusCode enumeration.
Getter and setter for customErrorHandler, which is a function that generates a HttpResponsePtr given an HttpStatusCode. This is intended to be similar to the custom404 functionality, allowing a user to override the layout of the error page.
The custom404 functions were kept even though this supersedes that to avoid breaking current code.

Finally, all of the Routers were updated to use the error handler for their 405/403 responses.

If no custom error handler is set, a default is used. The default behavior is identical to what exists now, an empty body with the status code set.
2020-05-19 11:50:44 +08:00
An Tao
4423d836f4
Add methods to get DbClient connection status (#436) 2020-05-18 08:31:18 +08:00
An Tao
26dca0a910
Fix a connection bug of mariadb clients (#438) 2020-05-17 21:08:12 +08:00
An Tao
cddd17eb55
Fix some compilation warnings (#432) 2020-05-16 10:11:50 +08:00
antao
84eb05ce38 Update trantor 2020-05-10 18:41:42 +08:00
Rafał Bugajewski
398b028046
Pass Data From View to Its Layout Container (#429) 2020-05-09 14:13:20 +08:00
Rafał Bugajewski
91e7ead628
Merge pull request #427 from an-tao/drogon_ctl
Fix a bug in drogon_ctl that would skip lines longer than 8092 characters.
2020-05-08 13:35:23 +02:00
antao
8ecfe9ef84 Fix a bug in drogon_ctl 2020-05-07 18:57:03 +08:00
An Tao
490def6742
Add filters on static file locations (#422) 2020-05-03 08:21:34 +08:00
interfector18
eafdc5d357
Add causal profiling with coz (#414) 2020-04-30 13:30:37 +08:00
antao
6d6a7acd09 Bump version to 1.0.0-beta16 2020-04-27 21:49:06 +08:00
ihmc3jn09hk
a7f49d893e
Support url safe base64 codec (#417)
Co-authored-by: antao <antao2002@gmail.com>
2020-04-26 23:23:03 +08:00
An Tao
4f8290b589
Remove non standard macros (#415) 2020-04-25 02:12:44 +08:00
ihmc3jn09hk
269acbc477
Use splitString in trantor (#413)
Co-authored-by: antao <antao2002@gmail.com>
2020-04-18 11:13:53 +08:00
interfector18
17b8c337f9
Standardize Row and Result api (#409)
* Standardize Row and Result api, throw specific exceptions

* Fix drogon_ctl for sqlite3 models

* Add mysql and sqlite3 tests, add exception throwing tests

* configure mysql in travis-ci

Co-authored-by: antao <antao2002@gmail.com>
2020-04-11 11:46:47 +08:00
An Tao
7d6be171c5
Parse content-type (#408) 2020-04-07 23:30:59 +08:00
An Tao
c43ba9e514
Add support for brotli compression (#406) 2020-04-04 18:15:15 +08:00
An Tao
2fb0f845f6
Update trantor (#405) 2020-04-03 10:20:58 +08:00
antao
3a2c472694 Update drogon version to v1.0.0-beta15 2020-03-28 16:11:14 +08:00
An Tao
d7cb5b715a
Exit the listen loop first when closing (#404) 2020-03-27 20:54:57 +08:00
An Tao
c46c7f3570
Fix DrogonConfig.cmake for Windows (#403) 2020-03-24 22:08:12 +08:00
An Tao
1969effd29
Return a 404 page when requesting a directory as a static file (#401) 2020-03-24 09:26:41 +08:00
An Tao
45d2969dcb
Graceful shutdown (#393)
Call app().quit() to gracefully stop a drogon application.
2020-03-21 21:29:33 +08:00
An Tao
f5e87acd9b
Remove dependency on pkg-config (#398)
Considering that on FreeBSD, pkg-config has been replaced by pkgconfig, we should remove the dependency on pkg-config.
2020-03-21 12:41:15 +08:00
ihmc3jn09hk
98ab826cfc
Fix drogon_ctl runtime error when compiling drogon to shared library (#397)
Fix for #395
2020-03-21 08:40:25 +08:00
An Tao
06bf158676
Fix issues in the MysqlConnection class (#394) 2020-03-20 23:12:05 +08:00
antao
8551106d8f Modify Dockerfile 2020-03-18 20:08:08 +08:00
An Tao
7af67dc4da
Make CMake install files relocatable (#387) 2020-03-18 19:54:48 +08:00
interfector18
4c8dbdbb85
Ninja (#391)
Use ninja to build if found on system (in /bin/ninja)
Make make simulate ninja's default parallelism

Should help with travis_ci as default build environments have 2 cores.
2020-03-17 00:54:30 +08:00
interfector18
d0dfa242b2
Add getHomePage to HttpAppFramework (#390)
Add getHomePage to HttpAppFramework to help with SPA in scenarios a controller must take a certain action on passed parameters but redirect to homepage
2020-03-17 00:53:31 +08:00
An Tao
6c850ea886
Modify the Attributes interface of the HttpRequest class (#389) 2020-03-15 16:11:40 +08:00
ihmc3jn09hk
2401c6a88a
Fix null jsonObject from newHttpJsonRequest (#388)
* Fix null jsonObject from newHttpJsonRequest 

Refer to #372 for the response case as well
2020-03-15 00:11:46 +08:00
An Tao
9ee00da431
Fix crash with partial matched url (#386) 2020-03-14 11:36:21 +08:00
An Tao
2d87434bfb
Use a separate thread to load views dynamically (#382) 2020-03-12 14:35:46 +08:00
An Tao
dd8fbe04cd
Addressed an issue when loading layout views dynamically (#378) 2020-03-12 10:26:07 +08:00
Rafał Bugajewski
3c7ac585a6
Dynamic View Loading: Only Compile Modified “csp” Layouts (#380)
This change greatly reduces the time between multiple Drogon runs
while developing an application with the framework. Previously on a
relaunch the framework naively compiled all *.csp files if dynamic
view loading was turned on. Now there will be a check for modification
time and the compilation phase will only run if the
corresponding *.csp file is newer than the dynamic library.

Co-authored-by: Rafał Bugajewski <rb@cocobit.software>
2020-03-12 09:44:51 +08:00
An Tao
bb8b5ded79
Fix a fatal bug in the MysqlConnection class (#379) 2020-03-11 12:41:20 +08:00
An Tao
77063e28d0
Optimize the rendering of HTTP responses (#371) 2020-03-07 20:49:05 +08:00
An Tao
ebb8b7b70a
Add ENABLE_EXPORTS property in cmake configuration files (#375) 2020-03-05 22:03:41 +08:00
An Tao
56817978e6
Fix a bug on filters with WebSocketControllers (#374) 2020-03-03 15:58:26 +08:00
An Tao
49d1697bec
Fix a bug when creating json responses (#373) 2020-03-02 23:34:28 +08:00
ihmc3jn09hk
686e30b250
Fix bug for PR #369 (#370)
Missing ">" for model.csp template
2020-03-01 18:07:21 +08:00
An Tao
8d17cc567e
Fix the 'many to many' relationship (#369) 2020-03-01 16:48:18 +08:00
An Tao
810896c94c
Fix warnings on Windows (#368) 2020-03-01 11:50:47 +08:00
ihmc3jn09hk
4bd19773b5
Update for ORM time mapper (#367)
The timelocal() function is equivalent to the POSIX standard function mktime(3). There is no reason to ever use it.
https://linux.die.net/man/3/timelocal
2020-03-01 02:33:01 +08:00
An Tao
e171874524
Modify installation on Windows (#366) 2020-02-29 15:46:08 +08:00
Wang Gao
d5cd882248
Add support for MSVC 2015 (#365)
Co-authored-by: An Tao <antao2002@gmail.com>
2020-02-26 12:36:46 +08:00
bor8
53f61e9b66
Update HttpAppFrameworkImpl.cc (#363) 2020-02-24 10:05:13 +08:00
An Tao
2fb1e1ecb1
Minor modification (#362) 2020-02-23 23:27:40 +08:00
ihmc3jn09hk
eb316d8263
Update Content-Type support for PDF (#361) 2020-02-23 18:31:27 +08:00
An Tao
ee77800821
Implement br_static (#359) 2020-02-23 17:39:03 +08:00
An Tao
cc3149dc58
Modify CMakeLists.txt (#358) 2020-02-22 21:15:15 +08:00
An Tao
978bd7c32f
Fix error when finding the jsoncpp library (#356) 2020-02-22 11:34:05 +08:00
antao
c9dd14bde5 Update drogon version to v1.0.0-beta14 2020-02-17 21:12:59 +08:00
An Tao
71b60823da
Modify dynamic view loading algorithm (#339) 2020-02-16 17:19:16 +08:00
ihmc3jn09hk
3c15f65a7f
Add IOLoop access function. (#353)
Co-authored-by: An Tao <antao2002@gmail.com>
2020-02-16 16:48:35 +08:00
ihmc3jn09hk
b733eee7e4
A small fix. (#345)
* Fix missed "password" fix for MySQL.

* Update trantor

Co-authored-by: An Tao <antao2002@gmail.com>
2020-02-08 11:08:11 +08:00
An Tao
3d8c304a47
Remove get_version.sh (#344) 2020-02-06 22:13:50 +08:00
An Tao
dd5e8f8159
Support 'password' keyword in configuration files (#343)
* Support 'password' keyword in configuration files

* Update travis-ci
2020-02-04 10:58:10 +08:00
An Tao
ce675c1b87
Fix a bug in views generation (#341) 2020-02-03 08:39:48 +08:00
An Tao
58702dc41e
Port drogon to Windows (#335)
Co-authored-by: mcirsta <mforce2@gmail.com>
2020-01-25 11:58:20 +08:00
An Tao
4f319dd9c9
Fix an issue of out-of-range (#334) 2020-01-21 00:49:53 +08:00
antao
191acd0bd3 Modify the StaticFileRouter 2020-01-12 11:39:53 +08:00
antao
fb2343ac74 Add location configuration for static resources (#331) 2020-01-12 11:05:38 +08:00
An Tao
62fc82cba1
Add support for regular expressions when routing (#329) 2020-01-09 17:03:30 +08:00
antao
668533fbbd Update drogon version to v1.0.0-beta13 2020-01-04 09:37:10 +08:00
An Tao
f07d9e03e1
Use shorter stmt names in postgresql connections(#326) 2020-01-04 09:36:14 +08:00
An Tao
cb95960e2d
Modify singleton logic of DrClassMap (#325) 2020-01-03 18:02:46 +08:00
antao
249a491d2f Modify the text template 2020-01-03 12:47:08 +08:00
An Tao
bc7ec6975a
Modify the SqlBinder class (#324) 2020-01-03 10:29:06 +08:00
An Tao
53e9dcca08
Optimize database connections (#323) 2020-01-02 17:09:10 +08:00
An Tao
1c99a8a94e
Use drogon::OStringStream instead of std::stringstream in text template (#322) 2020-01-01 16:15:11 +08:00
An Tao
feb0b73e78
Modify the benchmark example (#321) 2019-12-23 14:08:56 +08:00
An Tao
27c687a0af
Support HTTP1.0 clients (#320) 2019-12-22 13:15:56 +08:00
An Tao
4809cc9508
Modify the reverse proxy example (#319) 2019-12-16 00:34:40 +08:00
An Tao
cc04a013be
Use INSTALL_LIB_DIR instead of 'CMAKE_INSTALL_PREFIX/lib' in CMakeLists.txt (#318) 2019-12-12 12:49:18 +08:00
interfector18
832c6cb48d Make shared linking possible, use option instead of set for CMake (#315) 2019-12-11 18:39:10 +08:00
An Tao
fd6df92bbc
Fix an error in the batch mode of libpq. (#317) 2019-12-11 14:23:52 +08:00
An Tao
20c43b3c2d
Merge pull request #313 from an-tao/ossp_uuid 2019-12-10 07:01:25 +08:00
An Tao
a67ab1db52
Add some unit tests (#311) 2019-12-09 22:16:09 +08:00
antao
f1b5f2797c Update 2019-12-09 17:28:25 +08:00
antao
0a990f4331 Make a patch to support the ossp UUID Library 2019-12-09 17:22:38 +08:00
An Tao
ea43d8127d
Add a reverse proxy example (#309) 2019-12-08 08:31:56 +08:00
An Tao
6571e55631
Adding unit tests to Travis CI (#310) 2019-12-07 17:43:00 +08:00
An Tao
5bb54cd4cf
Fix a bug in compressing by zlib (#308) 2019-12-07 01:26:12 +08:00
antao
d85d8f7821 Update trantor 2019-12-05 15:02:23 +08:00
antao
f9d09d1554 Update drogon version to v1.0.0-beta12 2019-11-30 12:17:53 +08:00
An Tao
5c1c73d9b6
Add the SecureSSLRedirector plugin (#306) 2019-11-30 08:35:40 +08:00
An Tao
2784a91dcb
Handle gzip errors safely (#305) 2019-11-29 00:28:12 +08:00
An Tao
93c0d7e9da
Reset the flag used to parse json to false before recycling HttpRequest objects (#304) 2019-11-28 23:33:50 +08:00
An Tao
51aff1f5eb
Update trantor (#302) 2019-11-28 17:46:51 +08:00
Philip Woods
0fa61cded3 path is now explicitly set to '/' when setting JSESSIONID (#301) 2019-11-28 09:15:27 +08:00
An Tao
40ffb2d2af
Modify some code styles (#298) 2019-11-21 11:27:47 +08:00
An Tao
b34b3a6068
Fix a bug in dg_ctl for creating models of sqlite3 (#297) 2019-11-20 13:39:56 +08:00
antao
c89835cca2 Create FUNDING.yml 2019-11-15 12:35:36 +08:00
An Tao
d46a041cba
Modify the Cookie class (#296) 2019-11-15 10:26:21 +08:00
An Tao
a8ae91bee0
Make dg_ctl a symlink (#294) 2019-11-12 11:34:01 +08:00
antao
139d2db02b Update drogon version to v1.0.0-beta11 2019-11-06 13:38:23 +08:00
antao
944d1e786d Delete useless log output 2019-11-05 14:28:17 +08:00
antao
0133e47e8f Update drogon version to v1.0.0-beta10 2019-11-04 10:19:20 +08:00
Marwan Rabbâa
fc8abadaeb fix(compilation on alpine): Replace non standard u_short alias (#292) 2019-11-03 23:32:37 +08:00
An Tao
a71e37d86e
Modify some type names to meet the Google Style (#291) 2019-11-01 19:19:25 +08:00
An Tao
dbf20200fc
Add the headers configuration option for static files (#290) 2019-10-31 15:47:12 +08:00
570 changed files with 79265 additions and 15642 deletions

View File

@ -21,23 +21,24 @@ AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
AfterCaseLabel: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
@ -52,7 +53,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DerivePointerAlignment: false
DisableFormat: false
FixNamespaceComments: true
ForEachMacros:
@ -74,6 +75,7 @@ IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertNewlineAtEOF: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
@ -93,7 +95,8 @@ PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 2000
PointerAlignment: Left
PointerAlignment: Right
ReferenceAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
@ -123,7 +126,8 @@ RawStringFormats:
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SeparateDefinitionBlocks: Always
SortIncludes: Never
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: drogonframework
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # ['https://paypal.me/antao2019']

View File

@ -1,10 +1,17 @@
---
name: Bug report
about: Create a report to help us improve
labels:
title: ''
labels: ''
assignees: ''
---
**Notice**
If you need support or clarification regarding the usage of Drogon in your project, visit the official Drogon support channel at [gitter](https://gitter.im/drogon-web/community)
Please create a new issue only if you think you have found a bug or if have a feature request/enhancement.
**Describe the bug**
A clear and concise description of what the bug is.

View File

@ -1,10 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
labels:
title: ''
labels: ''
assignees: ''
---
**Notice**
If you need support or clarification regarding the usage of Drogon in your project, visit the official Drogon support channel at [gitter](https://gitter.im/drogon-web/community)
Please create a new issue only if you think you have found a bug or if have a feature request/enhancement.
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

237
.github/workflows/cmake.yml vendored Normal file
View File

@ -0,0 +1,237 @@
name: Build & Test
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
windows:
name: windows/msvc - ${{ matrix.link }}
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
link: ["STATIC", "SHARED"]
steps:
- name: Checkout Drogon source code
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Install dependencies
run: pip install conan
- name: Create build directory
run: mkdir build
- name: Install conan packages
working-directory: ./build
run: |
conan profile detect
conan install .. -s compiler="msvc" -sbuild_type=Debug --build=missing -s compiler.cppstd=17
- name: Create Build Environment & Configure Cmake
shell: bash
working-directory: ./build
run: |
[[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF"
cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=on \
-DBUILD_SHARED_LIBS=$shared \
-DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" \
-DBUILD_CTL=ON \
-DBUILD_EXAMPLES=ON \
-DUSE_SPDLOG=ON \
-DCMAKE_INSTALL_PREFIX=../install \
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW \
-DCMAKE_CXX_STANDARD=17
- name: Build
run: cmake --build build --target install --parallel
- name: Test
shell: bash
run: ./test.sh -w
macos:
runs-on: macos-${{ matrix.osver }}
strategy:
fail-fast: false
matrix:
osver: [13, 14, 15]
steps:
- name: Checkout Drogon source code
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Install dependencies
# Already installed: brotli, zlib, lz4, sqlite3
run: brew install ninja jsoncpp mariadb hiredis redis spdlog postgresql@14
- name: Create Build Environment & Configure Cmake
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_TESTING=on \
-DUSE_SPDLOG=ON \
-DBUILD_SHARED_LIBS=OFF
- name: Build
working-directory: ./build
# Execute the build. You can specify a specific target with "--target <NAME>"
run: ninja && sudo ninja install
- name: Prepare for testing
run: |
brew services restart postgresql@14
brew services start mariadb
brew services start redis
sleep 4
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
- name: Test
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ./test.sh -t
ubuntu:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
link: [SHARED, STATIC]
compiler:
- cxx: g++
ver: 9
- cxx: g++
ver: 10
- cxx: g++
ver: 11
- cxx: g++
ver: 12
- cxx: g++
ver: 13
- cxx: clang++
ver: 11
- cxx: clang++
ver: 12
- cxx: clang++
ver: 13
- cxx: clang++
ver: 14
- cxx: clang++
ver: 15
- cxx: clang++
ver: 16
- cxx: clang++
ver: 17
include:
- link: STATIC
compiler:
cxx: g++
ver: 13
feature: coroutines
env:
CXX: ${{ matrix.compiler.cxx }}-${{ matrix.compiler.ver }}
steps:
- name: Checkout Drogon source code
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Install dependencies
run: |
# Installing packages might fail as the github image becomes outdated
sudo apt update
# These aren't available or don't work well in vcpkg
sudo apt-get install -y libjsoncpp-dev uuid-dev libssl-dev zlib1g-dev libsqlite3-dev
sudo apt-get install -y ninja-build libbrotli-dev
sudo apt-get install -y libspdlog-dev
- name: Install postgresql
run: |
sudo apt-get --purge remove postgresql postgresql-doc postgresql-common postgresql-client-common
sudo apt-get -y install postgresql-all
- name: Install g++-13
if: startsWith(matrix.compiler.cxx, 'g++') && matrix.compiler.ver == 13
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get install g++-${{ matrix.compiler.ver }}
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Install Clang
if: startsWith(matrix.compiler.cxx, 'clang') && matrix.compiler.ver < 13
run: sudo apt-get install clang-${{ matrix.compiler.ver }}
- name: Install Clang
if: startsWith(matrix.compiler.cxx, 'clang') && matrix.compiler.ver >= 13
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh ${{ matrix.compiler.ver }}
- name: Export `shared`
run: |
[[ ${{ matrix.link }} == "SHARED" ]] && shared="ON" || shared="OFF"
echo "shared=$shared" >> $GITHUB_ENV
- name: Create Build Environment & Configure Cmake
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
if: matrix.compiler.feature != 'coroutines'
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_TESTING=on \
-DUSE_SPDLOG=ON \
-DBUILD_SHARED_LIBS=$shared
- name: Create Build Environment & Configure Cmake (coroutines)
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
if: matrix.compiler.feature == 'coroutines'
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_TESTING=on \
-DUSE_SPDLOG=ON \
-DCMAKE_CXX_FLAGS="-fcoroutines" \
-DBUILD_SHARED_LIBS=$shared \
- name: Build
working-directory: ./build
# Execute the build. You can specify a specific target with "--target <NAME>"
run: ninja && sudo ninja install
- name: Prepare for testing
run: |
sudo systemctl start postgresql
sleep 1
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '12345'" postgres
- name: Test
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ./test.sh -t

80
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,80 @@
name: "CodeQL"
on:
push:
branches: [ 'master' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ 'master' ]
schedule:
- cron: '46 7 * * 5'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
env:
SHARED: ON
steps:
- name: Checkout Drogon source code
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Install dependencies
run: |
sudo apt update
sudo apt-get install -y libjsoncpp-dev uuid-dev libssl-dev zlib1g-dev libsqlite3-dev
sudo apt-get install -y ninja-build libbrotli-dev
- name: Create Build Environment & Configure Cmake
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_TESTING=on \
-DBUILD_SHARED_LIBS=$SHARED
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
- name: Build
working-directory: ./build
run: ninja && sudo ninja install
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

15
.github/workflows/codespell.yml vendored Normal file
View File

@ -0,0 +1,15 @@
# Look for typos in the codebase using codespell.
# https://github.com/codespell-project/codespell#readme
name: codespell
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: sudo apt-get install -y codespell
- run: codespell --ignore-words-list="coo,folx,ot,statics,xwindows,NotIn,aNULL," --skip="*.csp"

41
.github/workflows/cpp.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: C++
on:
push:
branches: [master]
pull_request:
permissions:
contents: read
jobs:
format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dos2unix
run: sudo apt-get install -y dos2unix
- name: Install clang-format-17
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh 17
sudo apt-get install -y clang-format-17
- name: Check formatting
run: ./format.sh && git diff --exit-code
env:
CLANG_FORMAT: clang-format-17
cpplint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install cpplint
run: pip install cpplint
- name: Run lint
run: cpplint --recursive .

28
.github/workflows/docker-publish.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Build and Push Docker Image
on:
release:
types: [created] # 当新版本被创建时触发
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
run: |
cd docker/ubuntu
docker build -t drogonframework/drogon:latest .
- name: Push Docker image
run: |
docker push drogonframework/drogon:latest

16
.gitignore vendored
View File

@ -31,11 +31,19 @@
*.out
*.app
build
cmake-build-debug
.idea
lib/inc/drogon/version.h
build/
cmake-build-debug/
cmake-build-debug-visual-studio/
.idea/
html/
latex/
.vscode
*.kdev4
.cproject
.project
.settings/
.vs/
CMakeSettings.json
install
trace.json
.cache/

1
.gitmodules vendored
View File

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

View File

@ -1,51 +0,0 @@
matrix:
include:
- os: linux
dist: xenial
- os: osx
osx_image: xcode11
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
- build-essential
- cmake
- boost1.67
homebrew:
packages:
- jsoncpp
- ossp-uuid
- openssl
- cmake
- libtool
- lz4
- mariadb
- sqlite3
before_script:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew services restart postgresql;
sleep 2;
psql -c 'create user postgres superuser;' postgres;
fi
services:
- postgresql
script:
- ./build.sh -t && ./test.sh -t

1019
CMakeLists.txt Executable file → Normal file

File diff suppressed because it is too large Load Diff

78
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,78 @@
# Contributing
**Drogon** is an open source project at its heart and every contribution is
welcome. By participating in this project you agree to stick to common sense and
contribute in an overall positive way.
## Getting Started
1. Fork, then clone the repository: `git clone
git@github.com:your-username/drogon.git`
1. Follow the [official installation steps on
Github](https://drogonframework.github.io/drogon-docs/#/ENG-02-Installation). 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.

36
CPPLINT.cfg Normal file
View File

@ -0,0 +1,36 @@
# Stop searching for additional config files.
set noparent
exclude_files=trantor
exclude_files=build
# Use non-const reference rather than a pointer.
filter=-runtime/references
# CHECK macros are from Drogon, not Google Test.
filter=-readability/check
# Don't warn about the use of C++11 or C++17 features.
filter=-build/c++11
filter=-build/c++17
filter=-build/include_subdir
# We prioritize clang-format for now.
filter=-whitespace
# We don't require a username in TODO comments.
filter=-readability/todo
# TODO: Fix these.
filter=-legal/copyright
filter=-build/namespaces
filter=-build/include
filter=-build/include_what_you_use
filter=-runtime/explicit
filter=-runtime/string
filter=-runtime/int
filter=-readability/casting
filter=-readability/braces
filter=-readability/fn_size
filter=-runtime/threadsafe_fn

File diff suppressed because it is too large Load Diff

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 locales git gcc-8 g++-8 \
openssl libssl-dev libjsoncpp-dev uuid-dev zlib1g-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

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 An Tao
Copyright (c) 2019-2023 An Tao
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,17 +1,18 @@
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
![](https://github.com/an-tao/drogon/wiki/images/drogon-white17.jpg)
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
[![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/)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/context:cpp)
[![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)
[![Build Status](https://github.com/drogonframework/drogon/actions/workflows/cmake.yml/badge.svg?branch=master)](https://github.com/drogonframework/drogon/actions)
[![Conan Center](https://img.shields.io/conan/v/drogon)](https://conan.io/center/recipes/drogon)
[![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)
[![Join our Discord](https://dcbadge.vercel.app/api/server/3DvHY6Ewuj?style=flat)](https://discord.gg/3DvHY6Ewuj)
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
English | [简体中文](./README.zh-CN.md) | [繁體中文](./README.zh-TW.md)
### Overview
**Drogon** is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon in the American TV series "Game of Thrones" that I really like.
**Drogon** is a C++17/20 based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. **Drogon** is the name of a dragon from the American TV series *Game of Thrones*, which I really enjoy.
Drogon's main application platform is Linux. It also supports Mac OS and FreeBSD. Currently, it does not support windows. Its main features are as follows:
Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows. Its main features are as follows:
* Use a non-blocking I/O network lib based on epoll (kqueue under MacOS/FreeBSD) to provide high-concurrency, high-performance network IO, please visit the [benchmarks](https://github.com/an-tao/drogon/wiki/13-Benchmarks) page and [TFB Live Results](https://tfb-status.techempower.com/) for more details;
* Use a non-blocking I/O network lib based on epoll (kqueue under macOS/FreeBSD) to provide high-concurrency, high-performance network IO, please visit the [TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite) for more details;
* Provide a completely asynchronous programming mode;
* Support Http1.0/1.1 (server side and client side);
* Based on template, a simple reflection mechanism is implemented to completely decouple the main program framework, controllers and views.
@ -24,15 +25,17 @@ Drogon's main application platform is Linux. It also supports Mac OS and FreeBSD
* Support WebSocket (server side and client side);
* Support JSON format request and response, very friendly to the Restful API application development;
* Support file download and upload;
* Support gzip compression transmission;
* Support gzip, brotli compression transmission;
* Support pipelining;
* Provide a lightweight command line tool, drogon_ctl, to simplify the creation of various classes in Drogon and the generation of view code;
* Support non-blocking I/O based asynchronously reading and writing database (PostgreSQL and MySQL(MariaDB) database);
* Support asynchronously reading and writing sqlite3 database based on thread pool;
* Support Redis with asynchronous reading and writing;
* Support ARM Architecture;
* Provide a convenient lightweight ORM implementation that supports for regular object-to-database bidirectional mapping;
* Support plugins which can be installed by the configuration file at load time;
* Support AOP with build-in joinpoints.
* Support AOP with built-in joinpoints.
* Support C++ coroutines
## A very simple example
@ -46,7 +49,7 @@ using namespace drogon;
int main()
{
app().setLogPath("./")
.setLogLevel(trantor::Logger::WARN)
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 80)
.setThreadNum(16)
.enableRunAsDaemon()
@ -68,7 +71,7 @@ int main()
Drogon provides some interfaces for adding controller logic directly in the main() function, for example, user can register a handler like this in Drogon:
```c++
app.registerHandler("/test?username={name}",
app().registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
@ -92,7 +95,7 @@ using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
virtual void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
PATH_ADD("/test",Get);
PATH_LIST_END
@ -111,7 +114,7 @@ void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
}
```
**Most of the above programs can be automatically generated by the command line tool `drogon_ctl` provided by drogon** (The cammand is `drogon_ctl create controller TestCtrl`). All the user needs to do is add their own business logic. In the example, the controller returns a `Hello, world!` string when the client accesses the `http://ip/test` URL.
**Most of the above programs can be automatically generated by the command line tool `drogon_ctl` provided by drogon** (The command is `drogon_ctl create controller TestCtrl`). All the user needs to do is add their own business logic. In the example, the controller returns a `Hello, world!` string when the client accesses the `http://ip/test` URL.
For JSON format response, we create the controller as follows:
@ -123,7 +126,7 @@ using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
virtual void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
//list path definitions here;
PATH_ADD("/json", Get);
@ -180,4 +183,40 @@ As you can see, users can use the `HttpController` to map paths and parameters a
In addition, you can also find that all handler interfaces are in asynchronous mode, where the response is returned by a callback object. This design is for performance reasons because in asynchronous mode the drogon application can handle a large number of concurrent requests with a small number of threads.
After compiling all of the above source files, we get a very simple web application. This is a good start. **for more information, please visit the [wiki](https://github.com/an-tao/drogon/wiki/01-Overview) site**
After compiling all of the above source files, we get a very simple web application. This is a good start. **For more information, please visit the [documentation](https://drogonframework.github.io/drogon-docs/#/) on GitHub**.
## Cross-compilation
Drogon supports cross-compilation, you should define the `CMAKE_SYSTEM_NAME` in toolchain file, for example:
```cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
```
You can disable building options for examples and drogon_ctl by settings `BUILD_EXAMPLES` and `BUILD_CTL` to `OFF` in the toolchain file.
## Building options
Drogon provides some building options, you can enable or disable them by setting the corresponding variables to `ON` or `OFF` in the cmake command line, cmake file etc...
| Option name | Description | Default value |
| :--- | :--- | :--- |
| BUILD_CTL | Build drogon_ctl | ON |
| BUILD_EXAMPLES | Build examples | ON |
| BUILD_ORM | Build orm | ON |
| COZ_PROFILING | Use coz for profiling | OFF |
| BUILD_SHARED_LIBS | Build drogon as a shared lib | OFF |
| BUILD_DOC | Build Doxygen documentation | OFF |
| BUILD_BROTLI | Build Brotli | ON |
| BUILD_YAML_CONFIG | Build yaml config | ON |
| USE_SUBMODULE | Use trantor as a submodule | ON |
## Contributions
This project exists thanks to all the people who contribute code.
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
Every contribution is welcome. Please refer to the [contribution guidelines](CONTRIBUTING.md) for more information.

View File

@ -1,17 +1,19 @@
![](https://github.com/an-tao/drogon/wiki/images/drogon-white.jpg)
![](https://github.com/an-tao/drogon/wiki/images/drogon-white17.jpg)
[![Build Status](https://travis-ci.com/an-tao/drogon.svg?branch=master)](https://travis-ci.com/an-tao/drogon)
[![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/)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/an-tao/drogon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/an-tao/drogon/context:cpp)
[![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)
[![Build Status](https://github.com/drogonframework/drogon/actions/workflows/cmake.yml/badge.svg?branch=master)](https://github.com/drogonframework/drogon/actions)
[![Conan Center](https://img.shields.io/conan/v/drogon)](https://conan.io/center/recipes/drogon)
[![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)
[![Join our Discord](https://dcbadge.vercel.app/api/server/3DvHY6Ewuj?style=flat)](https://discord.gg/3DvHY6Ewuj)
[![Docker image](https://img.shields.io/badge/Docker-image-blue.svg)](https://cloud.docker.com/u/drogonframework/repository/docker/drogonframework/drogon)
**Drogon**是一个基于C++14/17的Http应用框架使用Drogon可以方便的使用C++构建各种类型的Web应用服务端程序。
[English](./README.md) | 简体中文 | [繁體中文](./README.zh-TW.md)
**Drogon**是一个基于C++17/20的Http应用框架使用Drogon可以方便的使用C++构建各种类型的Web应用服务端程序。
本版本库是github上[Drogon工程](https://github.com/an-tao/drogon)的镜像库。**Drogon**是作者非常喜欢的美剧《权力的游戏》中的一条龙的名字(汉译作卓耿)和龙有关但并不是dragon的误写为了不至于引起不必要的误会这里说明一下。
Drogon的主要应用平台是Linux也支持Mac OS、FreeBSD目前还不支持Windows。它的主要特点如下
Drogon是一个跨平台框架它支持Linux也支持macOS、FreeBSDOpenBSDHaikuOSWindows。它的主要特点如下
* 网络层使用基于epoll(MacOS/FreeBSD下是kqueue)的非阻塞IO框架提供高并发、高性能的网络IO。详细请见[性能测试](https://github.com/an-tao/drogon/wiki/13-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95)和[TFB Live Results](https://tfb-status.techempower.com/)
* 网络层使用基于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)完全解耦;
@ -24,14 +26,180 @@ Drogon的主要应用平台是Linux也支持Mac OS、FreeBSD目前还不
* 支持websocket(server端和client端);
* 支持Json格式请求和应答, 对Restful API应用开发非常友好;
* 支持文件下载和上传,支持sendfile系统调用
* 支持gzip压缩传输
* 支持gzip/brotli压缩传输;
* 支持pipelining
* 提供一个轻量的命令行工具drogon_ctl帮助简化各种类的创建和视图代码的生成过程
* 基于非阻塞IO实现的异步数据库读写目前支持PostgreSQL和MySQL(MariaDB)数据库;
* 基于线程池实现sqlite3数据库的异步读写提供与上文数据库相同的接口
* 支持Redis异步读写
* 支持ARM架构
* 方便的轻量级ORM实现支持常规的对象到数据库的双向映射操作
* 支持插件,可通过配置文件在加载期动态拆装;
* 支持内建插入点的AOP
* 支持C++协程
### 更多详情请浏览 [wiki](https://github.com/an-tao/drogon/wiki/01-概述)
## 一个非常简单的例子
不像大多数C++框架那样drogon的主程序可以保持非常简单。 Drogon使用了一些小技巧使主程序和控制器解耦合. 控制器的路由设置可以在控制器类中定义或者配置文件中完成.
下面是一个典型的主程序的样子:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().setLogPath("./")
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 80)
.setThreadNum(16)
.enableRunAsDaemon()
.run();
}
```
如果使用配置文件,可以进一步简化成如下的样子:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().loadConfigFile("./config.json").run();
}
```
当然Drogon也提供了一些接口使用户可以在main()函数中直接添加控制器逻辑比如用户可以注册一个lambda处理器到drogon框架中如下所示
```c++
app().registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
{
Json::Value json;
json["result"]="ok";
json["message"]=std::string("hello,")+name;
auto resp=HttpResponse::newHttpJsonResponse(json);
callback(resp);
},
{Get,"LoginFilter"});
```
这看起来是很方便但是这并不适用于复杂的应用试想假如有数十个或者数百个处理函数要注册进框架main()函数将膨胀到不可读的程度。显然让每个包含处理函数的类在自己的定义中完成注册是更好的选择。所以除非你的应用逻辑非常简单我们不推荐使用上述接口更好的实践是我们可以创建一个HttpSimpleController对象如下
```c++
/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
PATH_ADD("/test",Get);
PATH_LIST_END
};
/// The TestCtrl.cc file
#include "TestCtrl.h"
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
//write your application logic here
auto resp = HttpResponse::newHttpResponse();
resp->setBody("<p>Hello, world!</p>");
resp->setExpiredTime(0);
callback(resp);
}
```
**上面程序的大部分代码都可以由`drogon_ctl`命令创建**(这个命令是`drogon_ctl create controller TestCtr`。用户所需做的就是添加自己的业务逻辑。在这个例子中当客户端访问URL`http://ip/test`时,控制器简单的返回了一个`Hello, world!`页面。
对于JSON格式的响应我们可以像下面这样创建控制器
```c++
/// The header file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
//list path definitions here;
PATH_ADD("/json", Get);
PATH_LIST_END
};
/// The source file
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["message"] = "Hello, World!";
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
```
让我们更进一步通过HttpController类创建一个RESTful API的例子如下所示忽略了实现文件
```c++
/// The header file
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api
{
namespace v1
{
class User : public drogon::HttpController<User>
{
public:
METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here;
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
METHOD_LIST_END
//your declaration of processing function maybe like this:
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
public:
User()
{
LOG_DEBUG << "User constructor!";
}
};
} // namespace v1
} // namespace api
```
如你所见,通过`HttpController`用户可以同时映射路径和路径参数这对RESTful API应用来说非常方便。
另外,你可以发现前面所有的处理函数接口都是异步的,处理器的响应是通过回调对象返回的。这种设计是出于对高性能的考虑,因为在异步模式下,可以使用少量的线程(比如和处理器核心数相等的线程)处理大量的并发请求。
编译上述的所有源文件后我们得到了一个非常简单的web应用程序这是一个不错的开始。**请访问GitHub上的[文档](https://drogonframework.github.io/drogon-docs/#/CHN/CHN-01-%E6%A6%82%E8%BF%B0)**
## 贡献方式
欢迎您的贡献。 请阅读[贡献指南](CONTRIBUTING.md)以获取更多的信息。
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
## QQ交流群1137909452
欢迎交流探讨。
## 微信公众号:
![](https://github.com/an-tao/drogon/wiki/images/qrcode_wechat.jpg)
会不定期推送一些Drogon的使用技巧和更新信息欢迎关注。

198
README.zh-TW.md Normal file
View File

@ -0,0 +1,198 @@
![](https://github.com/an-tao/drogon/wiki/images/drogon-white17.jpg)
[![Build Status](https://github.com/drogonframework/drogon/actions/workflows/cmake.yml/badge.svg?branch=master)](https://github.com/drogonframework/drogon/actions)
[![Conan Center](https://img.shields.io/conan/v/drogon)](https://conan.io/center/recipes/drogon)
[![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)
[![Join our Discord](https://dcbadge.vercel.app/api/server/3DvHY6Ewuj?style=flat)](https://discord.gg/3DvHY6Ewuj)
[![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++17/20 的 HTTP 應用程式框架,使用 Drogon 可以方便地用 C++ 建立各種類型的 Web App 伺服器端程式。
這個版本庫是 GitHub 上 [Drogon](https://github.com/an-tao/drogon) 的鏡像庫。**Drogon** 是作者非常喜歡的美劇《冰與火之歌:權力遊戲》中的一條龍的名字(中文譯作卓耿),和龍有關但並不是 dragon 的誤寫,為了避免不必要的誤會在此說明。
Drogon 是一個跨平台框架,支援 Linux、macOS、FreeBSD/OpenBSD、HaikuOS 和 Windows。主要特點如下
* 網路層使用基於 epollmacOS/FreeBSD 下是 kqueue的非阻塞 IO 框架,提供高並行、高效能的網路 IO。詳細請見 [TFB Tests Results](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=composite)
* 完全非同步的程式撰寫邏輯;
* 支援 HTTP 1.0/1.1(伺服器端和用戶端);
* 基於樣板template實作的簡單反射機制使主程式框架、控制器controller和視圖view完全解耦
* 支援 cookies 和內建的 session
* 支援後端算繪,將控制器產生的資料交給視圖產生 HTML 頁面,視圖由 CSP 樣板檔案描述,透過 CSP 標籤將 C++ 程式碼嵌入 HTML 頁面,由 drogon 的命令列工具在編譯階段自動產生 C++ 程式碼並編譯;
* 支援執行期的視圖頁面動態載入(動態編譯和載入 so 檔案);
* 非常方便靈活的路徑path到控制器處理函式handler的對應方案
* 支援過濾器filter方便在控制器之前執行統一的邏輯如登入驗證、HTTP Method 限制驗證等);
* 支援 HTTPS基於 OpenSSL
* 支援 WebSocket伺服器端和用戶端
* 支援 JSON 格式的請求和回應,方便開發 RESTful API
* 支援檔案下載和上傳,支援 `sendfile` 系統呼叫;
* 支援 Gzip/Brotli 壓縮傳輸;
* 支援 pipelining
* 提供輕量的命令列工具 `drogon_ctl`,幫助簡化各種類別的建立和視圖程式碼的產生過程;
* 非同步的讀寫資料庫,目前支援 PostgreSQL 和 MySQLMariaDB資料庫
* 支援非同步讀寫 Redis
* 基於執行緒池實作 sqlite3 資料庫的非同步讀寫,提供與上述資料庫相同的介面;
* 支援 ARM 架構;
* 方便的輕量級 ORM 實現,一般物件到資料庫的雙向對應;
* 支援外掛,可透過設定檔案在載入時動態載入;
* 支援內建插入點的 AOP
* 支援 C++ coroutine。
## 一個非常簡單的例子
不像大多數 C++ 框架drogon 的主程式可以非常簡單。Drogon 使用了一些小技巧使主程式和控制器解耦。控制器的路由設定可以在控制器類別中定義或在設定檔案中完成。
下面是一個典型主程式的樣子:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().setLogPath("./")
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 80)
.setThreadNum(16)
.enableRunAsDaemon()
.run();
}
```
如果使用設定檔案,可以進一步簡化成:
```c++
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().loadConfigFile("./config.json").run();
}
```
當然Drogon 也提供了一些函式,讓使用者可以在 `main()` 函式中直接加入控制器邏輯,例如,使用者可以註冊一個 lambda 處理常式到 drogon 框架中,如下所示:
```c++
app().registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
{
Json::Value json;
json["result"]="ok";
json["message"]=std::string("hello,")+name;
auto resp=HttpResponse::newHttpJsonResponse(json);
callback(resp);
},
{Get,"LoginFilter"});
```
這看起來很方便,但不適用於複雜的場景,試想如果有數十個或數百個處理函式要註冊進框架,`main()` 函式將變得難以閱讀。顯然,讓每個包含處理函式的類別在自己的定義中完成註冊是更好的選擇。所以,除非你的應用邏輯非常簡單,我們不建議使用上述介面,更好的做法是建立一個 HttpSimpleController 類別,如下:
```c++
/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
PATH_ADD("/test",Get);
PATH_LIST_END
};
/// The TestCtrl.cc file
#include "TestCtrl.h"
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
//write your application logic here
auto resp = HttpResponse::newHttpResponse();
resp->setBody("<p>Hello, world!</p>");
resp->setExpiredTime(0);
callback(resp);
}
```
**上述程式的大部分程式碼都可以由 `drogon_ctl` 指令產生**(使用指令 `drogon_ctl create controller TestCtr`)。使用者只需要加入自己的業務邏輯。在這個範例中,當用戶端存取 URL `http://ip/test` 時,控制器簡單地回傳一個 `Hello, world!` 頁面。
對於 JSON 格式的回應,我們可以這樣建立控制器:
```c++
/// The header file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN
//list path definitions here;
PATH_ADD("/json", Get);
PATH_LIST_END
};
/// The source file
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["message"] = "Hello, World!";
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
```
讓我們更進一步,透過 HttpController 類別建立一個 RESTful API 的範例,如下所示(省略實作檔案):
```c++
/// The header file
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api
{
namespace v1
{
class User : public drogon::HttpController<User>
{
public:
METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here;
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
METHOD_LIST_END
//your declaration of processing function maybe like this:
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
public:
User()
{
LOG_DEBUG << "User constructor!";
}
};
} // namespace v1
} // namespace api
```
如你所見,透過 `HttpController` 類別,使用者可以同時對應路徑和路徑參數,這對 RESTful API 應用來說非常方便。
另外,你可以發現前面所有的處理函式介面都是非同步的,處理器的回應是透過回呼物件回傳的。這種設計是考慮到效能,因為在非同步模式下,可以使用少量的執行緒(例如和處理器核心數相等的執行緒)處理大量的並行請求。
編譯上述所有原始檔案後,我們得到了一個非常簡單的網頁應用程式,這是一個不錯的開始。**請瀏覽 GitHub 上的[文件](https://drogonframework.github.io/drogon-docs/#/CHN/CHN-01-%E6%A6%82%E8%BF%B0)**
## 貢獻方式
歡迎您的貢獻。請閱讀[貢獻指南](CONTRIBUTING.md)以取得更多資訊。
<a href="https://github.com/drogonframework/drogon/graphs/contributors"><img src="https://contributors-svg.opencollective.com/drogon/contributors.svg?width=890&button=false" alt="Code contributors" /></a>
## QQ 交流群1137909452
歡迎交流討論。

View File

@ -1 +0,0 @@
theme: jekyll-theme-cayman

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#build drogon
function build_drogon() {
@ -28,9 +28,11 @@ function build_drogon() {
echo "Start building drogon ..."
if [ $1 -eq 1 ]; then
cmake .. -DMAKETEST=YES
cmake .. -DBUILD_TESTING=YES $cmake_gen
elif [ $1 -eq 2 ]; then
cmake .. -DBUILD_TESTING=YES -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=1 $cmake_gen
else
cmake ..
cmake .. -DCMAKE_BUILD_TYPE=release $cmake_gen
fi
#If errors then exit
@ -38,7 +40,7 @@ function build_drogon() {
exit -1
fi
make
$make_program $make_flags
#If errors then exit
if [ "$?" != "0" ]; then
@ -46,15 +48,54 @@ function build_drogon() {
fi
echo "Installing ..."
sudo make install
$make_program install
#Go back to the current directory
cd $current_dir
#Ok!
}
if [ "$1" = "-t" ]; then
make_program=make
make_flags=''
cmake_gen=''
parallel=1
case $(uname) in
FreeBSD)
nproc=$(sysctl -n hw.ncpu)
;;
Darwin)
nproc=$(sysctl -n hw.ncpu) # sysctl -n hw.ncpu is the equivalent to nproc on macOS.
;;
*)
nproc=$(nproc)
;;
esac
# simulate ninja's parallelism
case nproc in
1)
parallel=$(( nproc + 1 ))
;;
2)
parallel=$(( nproc + 1 ))
;;
*)
parallel=$(( nproc + 2 ))
;;
esac
if [ -f /bin/ninja ]; then
make_program=ninja
cmake_gen='-GNinja'
else
make_flags="$make_flags -j$parallel"
fi
if [ "X$1" = "X-t" ]; then
build_drogon 1
elif [ "X$1" = "X-tshared" ]; then
build_drogon 2
else
build_drogon 0
fi

View File

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

37
cmake/Packages.cmake Normal file
View File

@ -0,0 +1,37 @@
include(GNUInstallDirs)
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_CONTACT "https://github.com/drogonframework/drogon")
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_VERSION "${DROGON_VERSION}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows")
# DEB
# Figure out dependencies automatically.
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
# Should be set automatically, but it is not.
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
# The default does not produce valid Debian package names.
set(CPACK_DEBIAN_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
# RPM
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
# Figure out dependencies automatically.
set(CPACK_RPM_PACKAGE_AUTOREQ ON)
# Should be set automatically, but it is not.
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CPACK_RPM_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
include(CPack)

View File

@ -0,0 +1,79 @@
#==================================================================================================#
# Adapted and re-written from Catch2 to work with Drogon Test #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# enable_testing() #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddDrogonTests) #
# ParseAndAddDrogonTests(${PROJECT_NAME}) #
#==================================================================================================#
cmake_minimum_required(VERSION 3.5...3.31)
# 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

@ -3,25 +3,60 @@
# DROGON_INCLUDE_DIRS - include directories for Drogon
# DROGON_LIBRARIES - libraries to link against
# DROGON_EXECUTABLE - the drogon_ctl executable
# DROGON_FOUND
# Drogon_FOUND
# This module defines the following IMPORTED target:
# Drogon::Drogon
@PACKAGE_INIT@
if(NOT TRANTOR_FOUND)
# find trantor
find_package(Trantor REQUIRED)
include(CMakeFindDependencyMacro)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
find_dependency(Jsoncpp REQUIRED)
find_dependency(Trantor REQUIRED)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
find_dependency(UUID REQUIRED)
endif(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT WIN32)
find_dependency(ZLIB REQUIRED)
if(@pg_FOUND@)
find_dependency(pg)
endif()
if(@SQLite3_FOUND@)
find_dependency(SQLite3)
endif()
if(@MySQL_FOUND@)
find_dependency(MySQL)
endif()
if(@Brotli_FOUND@)
find_dependency(Brotli)
endif()
if(@COZ-PROFILER_FOUND@)
find_dependency(coz-profiler)
endif()
if(@Hiredis_FOUND@)
find_dependency(Hiredis)
endif()
if(@yaml-cpp_FOUND@)
find_dependency(yaml-cpp)
endif()
if(@BUILD_SHARED_LIBS@)
find_dependency(Threads)
endif()
if(@HAS_STD_FILESYSTEM_PATH@)
find_dependency(Filesystem)
find_package(Filesystem COMPONENTS Final REQUIRED)
endif()
# Our library dependencies (contains definitions for IMPORTED targets)
get_filename_component(DROGON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(NOT TARGET Drogon::Drogon)
include("${DROGON_CMAKE_DIR}/DrogonTargets.cmake")
include("${DROGON_CMAKE_DIR}/DrogonUtilities.cmake")
include("${DROGON_CMAKE_DIR}/ParseAndAddDrogonTests.cmake")
endif()
get_target_property(DROGON_INCLUDE_DIRS Drogon::Drogon INTERFACE_INCLUDE_DIRECTORIES)
set(DROGON_LIBRARIES Drogon::Drogon)
set(DROGON_EXECUTABLE drogon_ctl)
set(DROGON_FOUND TRUE)

View File

@ -4,7 +4,9 @@
#cmakedefine01 LIBPQ_SUPPORTS_BATCH_MODE
#cmakedefine01 USE_MYSQL
#cmakedefine01 USE_SQLITE3
#cmakedefine01 HAS_STD_FILESYSTEM_PATH
#cmakedefine OpenSSL_FOUND
#cmakedefine Boost_FOUND
#cmakedefine COMPILATION_FLAGS "@COMPILATION_FLAGS@@DROGON_CXX_STANDARD@"
#cmakedefine COMPILER_COMMAND "@COMPILER_COMMAND@"

View File

@ -0,0 +1,7 @@
#pragma once
#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

@ -0,0 +1,7 @@
#include <filesystem>
int main()
{
std::filesystem::path aPath("../");
return 0;
}

View File

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

View File

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

View File

@ -2,11 +2,8 @@
int main()
{
PQisInBatchMode(NULL);
PQbatchIsAborted(NULL);
PQqueriesInBatch(NULL);
PQbeginBatchMode(NULL);
PQendBatchMode(NULL);
PQsendEndBatch(NULL);
PQgetNextQuery(NULL);
PQenterPipelineMode(NULL);
PQexitPipelineMode(NULL);
PQpipelineSync(NULL);
PQpipelineStatus(NULL);
}

View File

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

View File

@ -0,0 +1,261 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindFilesystem
##############
This module supports the C++17 standard library's filesystem utilities. Use the
:imp-target:`std::filesystem` imported target to
Options
*******
The ``COMPONENTS`` argument to this module supports the following values:
.. find-component:: Experimental
:name: fs.Experimental
Allows the module to find the "experimental" Filesystem TS version of the
Filesystem library. This is the library that should be used with the
``std::experimental::filesystem`` namespace.
.. find-component:: Final
:name: fs.Final
Finds the final C++17 standard version of the filesystem library.
If no components are provided, behaves as if the
:find-component:`fs.Final` component was specified.
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
Imported Targets
****************
.. imp-target:: std::filesystem
The ``std::filesystem`` imported target is defined when any requested
version of the C++ filesystem library has been found, whether it is
*Experimental* or *Final*.
If no version of the filesystem library is available, this target will not
be defined.
.. note::
This target has ``cxx_std_17`` as an ``INTERFACE``
:ref:`compile language standard feature <req-lang-standards>`. Linking
to this target will automatically enable C++17 if no later standard
version is already required on the linking target.
.. _fs.variables:
Variables
*********
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
filesystem library was found, otherwise ``FALSE``.
.. variable:: CXX_FILESYSTEM_HAVE_FS
Set to ``TRUE`` when a filesystem header was found.
.. variable:: CXX_FILESYSTEM_HEADER
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
found.
.. variable:: CXX_FILESYSTEM_NAMESPACE
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
depending on whether :find-component:`fs.Final` or
:find-component:`fs.Experimental` was found.
Examples
********
Using `find_package(Filesystem)` with no component arguments:
.. code-block:: cmake
find_package(Filesystem REQUIRED)
add_executable(my-program main.cpp)
target_link_libraries(my-program PRIVATE std::filesystem)
#]=======================================================================]
if(TARGET std::filesystem)
# This module has already been processed. Don't do it again.
return()
endif()
# Ignore filesystem check if version too low
if(CMAKE_VERSION VERSION_LESS 3.10)
set(CXX_FILESYSTEM_HAVE_FS FALSE CACHE BOOL "TRUE if we have the C++ filesystem headers")
set(Filesystem_FOUND FALSE CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
return()
endif()
cmake_minimum_required(VERSION 3.10)
include(CMakePushCheckState)
include(CheckIncludeFileCXX)
# If we're not cross-compiling, try to run test executables.
# Otherwise, assume that compile + link is a sufficient check.
if(CMAKE_CROSSCOMPILING)
include(CheckCXXSourceCompiles)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_compiles("${code}" ${var})
endmacro()
else()
include(CheckCXXSourceRuns)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_runs("${code}" ${var})
endmacro()
endif()
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
# All of our tests required C++17 or later
set(BACKUP_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 17)
# Normalize and check the component list we were given
set(want_components ${Filesystem_FIND_COMPONENTS})
if(Filesystem_FIND_COMPONENTS STREQUAL "")
set(want_components Final)
endif()
# Warn on any unrecognized components
set(extra_components ${want_components})
list(REMOVE_ITEM extra_components Final Experimental)
foreach(component IN LISTS extra_components)
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
endforeach()
# Detect which of Experimental and Final we should look for
set(find_experimental TRUE)
set(find_final TRUE)
if(NOT "Final" IN_LIST want_components)
set(find_final FALSE)
endif()
if(NOT "Experimental" IN_LIST want_components)
set(find_experimental FALSE)
endif()
if(find_final)
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
if(_CXX_FILESYSTEM_HAVE_HEADER)
# We found the non-experimental header. Don't bother looking for the
# experimental one.
set(find_experimental FALSE)
endif()
else()
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
endif()
if(find_experimental)
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
else()
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
endif()
if(_CXX_FILESYSTEM_HAVE_HEADER)
set(_have_fs TRUE)
set(_fs_header filesystem)
set(_fs_namespace std::filesystem)
set(_is_experimental FALSE)
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
set(_have_fs TRUE)
set(_fs_header experimental/filesystem)
set(_fs_namespace std::experimental::filesystem)
set(_is_experimental TRUE)
else()
set(_have_fs FALSE)
endif()
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
set(_found FALSE)
if(CXX_FILESYSTEM_HAVE_FS)
# We have some filesystem library available. Do link checks
string(CONFIGURE [[
#include <cstdio>
#include <@CXX_FILESYSTEM_HEADER@>
int main() {
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
printf("%s", cwd.generic_string().c_str());
return EXIT_SUCCESS;
}
]] code @ONLY)
# HACK: Needed to compile correctly on Yocto Linux
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_REQUIRED_FLAGS ${prev_req_flags} -std=c++17)
endif ()
# Check a simple filesystem program without any linker flags
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
# Add the libstdc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
# Try the libc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
endif()
endif()
if(can_link)
add_library(std::filesystem INTERFACE IMPORTED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
set(_found TRUE)
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
# Nothing to add...
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
endif()
endif()
endif()
cmake_pop_check_state()
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
endif()
set(CMAKE_CXX_STANDARD "${BACKUP_CXX_STANDARD}")

View File

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

View File

@ -2,62 +2,72 @@
#
# Find the jsoncpp includes and library
#
# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH
# 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_INCLUDE_PREFIX, include prefix for jsoncpp
# 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_DIR
NAMES jsoncpp/json/json.h json/json.h
DOC "jsoncpp include dir"
)
find_path(JSONCPP_INCLUDE_DIRS
NAMES json/json.h
DOC "jsoncpp include dir"
PATH_SUFFIXES jsoncpp)
find_library(
JSONCPP_LIBRARY
NAMES jsoncpp
DOC "jsoncpp library"
)
find_library(JSONCPP_LIBRARIES NAMES jsoncpp DOC "jsoncpp library")
set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR})
set(JSONCPP_LIBRARIES ${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()
# 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_LIBRARY_DEBUG
NAMES jsoncppd
DOC "jsoncpp debug library"
)
# set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug
# ${JSONCPP_LIBRARIES_DEBUG})
set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug ${JSONCPP_LIBRARY_DEBUG})
# endif()
endif()
# find JSONCPP_INCLUDE_PREFIX
find_path(
JSONCPP_INCLUDE_PREFIX
NAMES json.h
PATH_SUFFIXES jsoncpp/json json
)
if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp")
set(JSONCPP_INCLUDE_PREFIX "jsoncpp")
set(JSONCPP_INCLUDE_DIRS "${JSONCPP_INCLUDE_DIRS}/jsoncpp")
else()
set(JSONCPP_INCLUDE_PREFIX "")
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
# 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_DIR JSONCPP_LIBRARY)
mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)
find_package_handle_standard_args(Jsoncpp
DEFAULT_MSG
JSONCPP_INCLUDE_DIRS
JSONCPP_LIBRARIES)
mark_as_advanced(JSONCPP_INCLUDE_DIRS JSONCPP_LIBRARIES)
if(Jsoncpp_FOUND)
if(NOT EXISTS ${JSONCPP_INCLUDE_DIRS}/json/version.h)
message(FATAL_ERROR "Error: jsoncpp lib is too old.....stop")
endif()
if(NOT WIN32)
execute_process(
COMMAND cat ${JSONCPP_INCLUDE_DIRS}/json/version.h
COMMAND grep JSONCPP_VERSION_STRING
COMMAND sed -e "s/.*define/define/"
COMMAND awk "{ printf \$3 }"
COMMAND sed -e "s/\"//g"
OUTPUT_VARIABLE jsoncpp_ver)
if(NOT Jsoncpp_FIND_QUIETLY)
message(STATUS "jsoncpp version:" ${jsoncpp_ver})
endif()
if(jsoncpp_ver LESS 1.7)
message(
FATAL_ERROR
"jsoncpp lib is too old, please get new version from https://github.com/open-source-parsers/jsoncpp"
)
endif(jsoncpp_ver LESS 1.7)
endif()
if (NOT TARGET Jsoncpp_lib)
add_library(Jsoncpp_lib INTERFACE IMPORTED)
endif()
set_target_properties(Jsoncpp_lib
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${JSONCPP_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES
"${JSONCPP_LIBRARIES}")
endif(Jsoncpp_FOUND)

View File

@ -1,114 +1,144 @@
#--------------------------------------------------------
# --------------------------------------------------------
# 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.
# 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.
# 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.
# 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
# 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.
# 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(MARIADB_INCLUDE_DIRS
NAMES mysql.h
PATH_SUFFIXES mariadb
PATHS /usr/include/mysql
/usr/local/include/mysql
/usr/include/mariadb
/usr/local/include/mariadb
/opt/mysql/mysql/include
/opt/mysql/mysql/include/mysql
/opt/mysql/include
/opt/local/include/mysql5
/usr/local/mysql/include
/usr/local/mysql/include/mysql
/usr/local/mariadb/include
/usr/local/mariadb/include/mariadb
/opt/rh/rh-mariadb105/root/usr/include
/opt/rh/rh-mariadb105/root/usr/include/mysql
$ENV{ProgramFiles}/MySQL/*/include
$ENV{SystemDrive}/MySQL/*/include)
#-------------- FIND MYSQL_INCLUDE_DIR ------------------
FIND_PATH(MYSQL_INCLUDE_DIR mysql.h
/usr/include/mysql
/usr/local/include/mysql
/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
$ENV{ProgramFiles}/MySQL/*/include
$ENV{SystemDrive}/MySQL/*/include)
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)
#----------------- FIND MYSQL_LIB_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)
if(EXISTS "${MARIADB_INCLUDE_DIRS}/mysql.h")
set(MYSQL_INCLUDE_DIRS ${MARIADB_INCLUDE_DIRS})
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql.h")
FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient
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_LIB NAMES mysqlclient_r mariadbclient
PATHS
/usr/lib/mysql
/usr/local/lib/mysql
/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)
ENDIF (WIN32)
elseif(EXISTS "${MYSQL_INCLUDE_DIRS}/mysql/mysql.h")
set(MYSQL_INCLUDE_DIRS ${MYSQL_INCLUDE_DIRS}/mysql)
endif()
IF(MYSQL_LIB)
GET_FILENAME_COMPONENT(MYSQL_LIB_DIR ${MYSQL_LIB} PATH)
ENDIF(MYSQL_LIB)
# ----------------- 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)
set(MYSQL_VERSION_STRING "")
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 mariadb
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)
EXEC_PROGRAM (grep ARGS "MARIADB_BASE_VERSION ${MYSQL_INCLUDE_DIR}/*.h|awk '{print $3}'" OUTPUT_VARIABLE MYSQL_VERSION_STRING)
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)
IF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)
SET(MYSQL_FOUND TRUE)
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)
FIND_LIBRARY(MYSQL_ZLIB zlib PATHS ${MYSQL_LIB_DIR})
FIND_LIBRARY(MYSQL_TAOCRYPT taocrypt PATHS ${MYSQL_LIB_DIR})
IF (MYSQL_LIB)
SET(MYSQL_CLIENT_LIBS ${MYSQL_LIB})
ELSE()
SET(MYSQL_CLIENT_LIBS mysqlclient_r)
ENDIF()
IF (MYSQL_ZLIB)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} zlib)
ENDIF (MYSQL_ZLIB)
IF (MYSQL_TAOCRYPT)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} taocrypt)
ENDIF (MYSQL_TAOCRYPT)
# Added needed mysqlclient dependencies on Windows
IF (WIN32)
SET(MYSQL_CLIENT_LIBS ${MYSQL_CLIENT_LIBS} ws2_32)
ENDIF (WIN32)
MESSAGE(STATUS "MySQL Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}")
MESSAGE(STATUS "MySQL client libraries: ${MYSQL_CLIENT_LIBS}")
ELSEIF (MySQL_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Cannot find MySQL. Include dir: ${MYSQL_INCLUDE_DIR} library dir: ${MYSQL_LIB_DIR}")
ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIB_DIR)
mark_as_advanced(MYSQL_INCLUDE_DIRS MYSQL_LIBRARIES)

View File

@ -1,37 +1,43 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# 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.
# * 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 sqlite found.
# 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_DIR NAMES sqlite3.h)
find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
# Look for the library.
FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3)
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_LIBRARY SQLITE3_INCLUDE_DIR)
# 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)
SET(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY})
SET(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR})
ELSE(SQLITE3_FOUND)
SET(SQLITE3_LIBRARIES)
SET(SQLITE3_INCLUDE_DIRS)
ENDIF(SQLITE3_FOUND)
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)
mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES)

View File

@ -1,119 +1,118 @@
# - Try to find UUID
# Once done this will define
# * 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
# 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.
# Redistribution and use is allowed according to the terms of the New BSD
# license. For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if(UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
# in cache already
set(UUID_FOUND TRUE)
else()
find_path(
UUID_INCLUDE_DIR
NAMES uuid.h
PATH_SUFFIXES uuid
HINTS ${UUID_DIR}/include
$ENV{UUID_DIR}/include
$ENV{UUID_DIR}
${DELTA3D_EXT_DIR}/inc
$ENV{DELTA_ROOT}/ext/inc
$ENV{DELTA_ROOT}
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include
/usr/include
/usr/include/gdal
/sw/include # Fink
/opt/local/include # DarwinPorts
/opt/csw/include # Blastwave
/opt/include
[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
/usr/freeware/include)
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
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)
find_library(UUID_LIBRARY_DEBUG
NAMES
uuidd
HINTS
${UUID_DIR}/lib
$ENV{UUID_DIR}/lib
$ENV{UUID_DIR}
${DELTA3D_EXT_DIR}/lib
$ENV{DELTA_ROOT}/ext/lib
$ENV{DELTA_ROOT}
$ENV{OSG_ROOT}/lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/lib
/sw/lib
/opt/local/lib
/opt/csw/lib
/opt/lib
/usr/freeware/lib64
)
if(NOT UUID_LIBRARY AND (BSD OR APPLE))
set(UUID_LIBRARY "")
endif()
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})
set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR})
set(UUID_LIBRARIES ${UUID_LIBRARY})
if(UUID_INCLUDE_DIRS)
if((BSD OR APPLE) OR UUID_LIBRARIES)
set(UUID_FOUND TRUE)
endif()
endif()
if (UUID_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()
else()
if(UUID_FIND_REQUIRED)
message(FATAL_ERROR "Could not find UUID")
endif()
endif()
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)
# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced view
mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
endif()
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()
set(UUID_LIBRARIES)
set(UUID_INCLUDE_DIRS)
endif()

View File

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

View File

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

16
conanfile.txt Normal file
View File

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

View File

@ -2,10 +2,15 @@
*/
{
/*
//ssl:The global ssl files setting
//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"
"cert": "../../trantor/trantor/tests/server.crt",
"key": "../../trantor/trantor/tests/server.key",
"conf": [
//["Options", "-SessionTicket"],
//["Options", "Compression"]
]
},
"listeners": [
{
@ -23,13 +28,18 @@
//cert,key: Cert file path and key file path, empty by default,
//if empty, use the global setting
"cert": "",
"key": ""
"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":"",
"name": "default",
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
"rdbms": "postgresql",
//filename: Sqlite3 db file name
@ -47,24 +57,80 @@
//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,
//connection_number: 1 by default, if the 'is_fast' is true, the number is the number of
//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.
"connection_number": 1
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
//zero or negative value means no timeout.
"timeout": -1.0,
//auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
//the wiki for more details.
"auto_batch": false
//connect_options: extra options for the connection. Only works for PostgreSQL now.
//For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
//"connect_options": { "statement_timeout": "1s" }
}
],
"redis_clients": [
{
//name: Name of the client,'default' by default
"name": "default",
//host: Server IP, 127.0.0.1 by default
"host": "127.0.0.1",
//port: Server port, 6379 by default
"port": 6379,
//username: '' by default which means 'default' in redis ACL
"username": "",
//passwd: '' by default
"passwd": "",
//db index: 0 by default
"db": 0,
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a command.
//zero or negative value means no timeout.
"timeout": -1.0
}
],*/
"app": {
//threads_num: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
//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
"threads_num": 1,
"number_of_threads": 1,
//enable_session: False by default
"enable_session": true,
"session_timeout": 0,
//document_root: Root path of HTTP document, defaut path is ./
//string value of SameSite attribute of the Set-Cookie HTTP response header
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
"session_same_site": "Null",
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
"session_cookie_key": "JSESSIONID",
//session_max_age: The max age of the session cookie, -1 by default
"session_max_age": -1,
//document_root: Root path of HTTP document, default path is ./
"document_root": "./",
//home_page: Set the HTML file of the home page, the default value is "index.html"
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
//to the request for "/".
"home_page": "index.html",
//use_implicit_page: enable implicit pages if true, true by default
"use_implicit_page": true,
//implicit_page: Set the file which would the server access in a directory that a user accessed.
//For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
"implicit_page": "index.html",
//static_file_headers: Headers for static files
/*"static_file_headers": [
{
"name": "field-name",
"value": "field-value"
}
],*/
//upload_path: The path to save the uploaded file. "uploads" by default.
//If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
@ -86,11 +152,42 @@
"xap",
"apk",
"cur",
"xml"
"xml",
"webp",
"svg"
],
//max_connections: maximum connections number,100000 by default
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
"mime": {
// "text/markdown": "md",
// "text/gemini": ["gmi", "gemini"]
},
//locations: An array of locations of static files for GET requests.
"locations": [
{
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
//"uri_prefix": "/.well-known/acme-challenge/",
//default_content_type: The default content type of the static files without
//an extension. empty string by default.
"default_content_type": "text/plain",
//alias: The location in file system, if it is prefixed with "/", it
//presents an absolute path, otherwise it presents a relative path to
//the document_root path.
//The default value is "" which means use the document root path as the location base path.
"alias": "",
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
"is_case_sensitive": false,
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
"allow_all": true,
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
"is_recursive": true,
//filters: string array, the filters applied to the location.
"filters": []
}
],
//max_connections: maximum number of connections, 100000 by default
"max_connections": 100000,
//max_connections_per_ip: maximum connections number per clinet,0 by default which means no limit
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
"max_connections_per_ip": 0,
//Load_dynamic_views: False by default, when set to true, drogon
//compiles and loads dynamically "CSP View Files" in directories defined
@ -101,8 +198,27 @@
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
"json_parser_stack_limit": 1000,
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
"enable_unicode_escaping_in_json": true,
//float_precision_in_json: set precision of float number in json.
"float_precision_in_json": {
//precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
"precision": 0,
//precision_type: must be "significant" or "decimal", defaults to "significant" that means
//setting max number of significant digits in string, "decimal" means setting max number of
//digits after "." in string
"precision_type": "significant"
},
//log: Set log output, drogon output logs to stdout by default
"log": {
//use_spdlog: Use spdlog library to log
"use_spdlog": false,
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
//"log_path": "./",
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
@ -111,34 +227,45 @@
//log_size_limit: 100000000 bytes by default,
//When the log file size reaches "log_size_limit", the log file is switched.
"log_size_limit": 100000000,
//max_files: 0 by default,
//When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
"max_files": 0,
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
//The TRACE level is only valid when built in DEBUG mode.
"log_level": "DEBUG"
"log_level": "DEBUG",
//display_local_time: false by default, if true, the log time is displayed in local time
"display_local_time": false
},
//run_as_daemon: False by default
"run_as_daemon": false,
//handle_sig_term: True by default
"handle_sig_term": true,
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
"relaunch_on_error": false,
//use_sendfile: True by default, if ture, the program
//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"
]
}],
//"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,
@ -163,6 +290,10 @@
//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",
@ -172,20 +303,57 @@
"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"
"client_max_websocket_message_size": "128K",
//reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
"reuse_port": false,
// enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
// will be rejected.
"enabled_compressed_request": false,
// enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
// See the wiki for more details.
"enable_request_stream": false,
},
//plugins: Define all plugins running in the application
"plugins": [{
//name: The class name of the plugin
//"name": "TestPlugin",
//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": {
"heartbeat_interval": 2
"plugins": [
{
//name: The class name of the plugin
"name": "drogon::plugin::PromExporter",
//dependencies: Plugins that the plugin depends on. It can be commented out
"dependencies": [],
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
//It can be commented out
"config": {
"path": "/metrics"
}
},
{
"name": "drogon::plugin::AccessLogger",
"dependencies": [],
"config": {
"use_spdlog": false,
"log_path": "",
"log_format": "",
"log_file": "access.log",
"log_size_limit": 0,
"use_local_time": true,
"log_index": 0,
// "show_microseconds": true,
// "custom_time_format": "",
// "use_real_ip": false
}
}
}],
],
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
"custom_config": {}
"custom_config": {
"realm": "drogonRealm",
"opaque": "drogonOpaque",
"credentials": [
{
"user": "drogon",
"password": "dr0g0n"
}
]
}
}

318
config.example.yaml Normal file
View File

@ -0,0 +1,318 @@
# This is a YAML format configuration file
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
# ssl:
# cert: ../../trantor/trantor/tests/server.crt
# key: ../../trantor/trantor/tests/server.key
# conf: [
# # [Options, -SessionTicket],
# # [Options, Compression]
# ]
# listeners:
# # address: Ip address,0.0.0.0 by default
# - address: 0.0.0.0
# # port: Port number
# port: 80
# # https: If true, use https for security,false by default
# https: false
# - address: 0.0.0.0
# port: 443
# https: true
# # cert,key: Cert file path and key file path, empty by default,
# # if empty, use the global setting
# cert: ''
# key: ''
# # use_old_tls: enable the TLS1.0/1.1, false by default
# use_old_tls: false
# ssl_conf: [
# # [MinProtocol, TLSv1.3]
# ]
# db_clients:
# # name: Name of the client,'default' by default
# - name: default
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
# rdbms: postgresql
# # filename: Sqlite3 db file name
# # filename: ''
# # host: Server address,localhost by default
# host: 127.0.0.1
# # port: Server port, 5432 by default
# port: 5432
# # dbname: Database name
# dbname: test
# # user: 'postgres' by default
# user: ''
# # passwd: '' by default
# passwd: ''
# # is_fast: false by default, if it is true, the client is faster but user can't call
# # any synchronous interface of it.
# is_fast: false
# # client_encoding: The character set used by the client. it is empty string by default which
# # means use the default character set.
# # client_encoding: ''
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
# # connections per IO thread, otherwise it is the total number of all connections.
# number_of_connections: 1
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
# # zero or negative value means no timeout.
# timeout: -1
# # auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
# # the wiki for more details.
# auto_batch: false
# # connect_options: extra options for the connection. Only works for PostgreSQL now.
# # For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
# # connect_options:
# # statement_timeout: '1s'
# redis_clients:
# # name: Name of the client,'default' by default
# - name: default
# # host: Server IP, 127.0.0.1 by default
# host: 127.0.0.1
# # port: Server port, 6379 by default
# port: 6379
# # username: '' by default which means 'default' in redis ACL
# username: ''
# # passwd: '' by default
# passwd: ''
# # db index: 0 by default
# db: 0
# # is_fast: false by default, if it is true, the client is faster but user can't call
# # any synchronous interface of it.
# is_fast: false
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
# # connections per IO thread, otherwise it is the total number of all connections.
# number_of_connections: 1
# # timeout: -1.0 by default, in seconds, the timeout for executing a command.
# # zero or negative value means no timeout.
# timeout: -1
app:
# number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
# is the number of CPU cores
number_of_threads: 1
# enable_session: False by default
enable_session: true
session_timeout: 0
# string value of SameSite attribute of the Set-Cookie HTTP response header
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
session_same_site: 'Null'
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
session_cookie_key: 'JSESSIONID'
# session_max_age: The max age of the session cookie, -1 by default
session_max_age: -1
# document_root: Root path of HTTP document, default path is ./
document_root: ./
# home_page: Set the HTML file of the home page, the default value is "index.html"
# If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
# to the request for "/".
home_page: index.html
# use_implicit_page: enable implicit pages if true, true by default
use_implicit_page: true
# implicit_page: Set the file which would the server access in a directory that a user accessed.
# For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
implicit_page: index.html
# static_file_headers: Headers for static files
# static_file_headers:
# - name: field-name
# value: field-value
# upload_path: The path to save the uploaded file. "uploads" by default.
# If the path isn't prefixed with /, ./ or ../,
# it is relative path of document_root path
upload_path: uploads
# file_types:
# HTTP download file types,The file types supported by drogon
# by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
# "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
# "gif", "bmp", "ico", "icns", etc.
file_types:
- gif
- png
- jpg
- js
- css
- html
- ico
- swf
- xap
- apk
- cur
- xml
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
mime: {
# text/markdown: md
# text/gemini:
# - gmi
# - gemini
}
# locations: An array of locations of static files for GET requests.
locations:
# uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
- uri_prefix: '' # /.well-known/acme-challenge/
# default_content_type: The default content type of the static files without
# an extension. empty string by default.
default_content_type: text/plain
# alias: The location in file system, if it is prefixed with "/", it
# presents an absolute path, otherwise it presents a relative path to
# the document_root path.
# The default value is "" which means use the document root path as the location base path.
alias: ''
# is_case_sensitive: indicates whether the URI prefix is case sensitive.
is_case_sensitive: false
# allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
allow_all: true
# is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
is_recursive: true
# filters: string array, the filters applied to the location.
filters: []
# max_connections: maximum number of connections, 100000 by default
max_connections: 100000
# max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
max_connections_per_ip: 0
# Load_dynamic_views: False by default, when set to true, drogon
# compiles and loads dynamically "CSP View Files" in directories defined
# by "dynamic_views_path"
load_dynamic_views: false
# dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
# it is relative path of document_root path
dynamic_views_path:
- ./views
# dynamic_views_output_path: Default by an empty string which means the output path of source
# files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
# path of the current working directory.
dynamic_views_output_path: ''
# json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
json_parser_stack_limit: 1000
# enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
enable_unicode_escaping_in_json: true
# float_precision_in_json: set precision of float number in json.
float_precision_in_json:
# precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
precision: 0
# precision_type: must be "significant" or "decimal", defaults to "significant" that means
# setting max number of significant digits in string, "decimal" means setting max number of
# digits after "." in string
precision_type: significant
# log: Set log output, drogon output logs to stdout by default
log:
# use_spdlog: Use spdlog library to log
use_spdlog: false
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
# log_path: ./
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
# drogon.log ...
logfile_base_name: ''
# log_size_limit: 100000000 bytes by default,
# When the log file size reaches "log_size_limit", the log file is switched.
log_size_limit: 100000000
# max_files: 0 by default,
# When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
max_files: 0
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
# The TRACE level is only valid when built in DEBUG mode.
log_level: DEBUG
# display_local_time: false by default, if true, the log time is displayed in local time
display_local_time: false
# run_as_daemon: False by default
run_as_daemon: false
# handle_sig_term: True by default
handle_sig_term: true
# relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
relaunch_on_error: false
# use_sendfile: True by default, if true, the program
# uses sendfile() system-call to send static files to clients;
use_sendfile: true
# use_gzip: True by default, use gzip to compress the response body's content;
use_gzip: true
# use_brotli: False by default, use brotli to compress the response body's content;
use_brotli: false
# static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
# 0 means cache forever, the negative value means no cache
static_files_cache_time: 5
# simple_controllers_map: Used to configure mapping from path to simple controller
# simple_controllers_map:
# - path: /path/name
# controller: controllerClassName
# http_methods:
# - get
# - post
# filters:
# - FilterClassName
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
# of the connection without read or write
idle_connection_timeout: 60
# server_header_field: Set the 'Server' header field in each response sent by drogon,
# empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
server_header_field: ''
# enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
# value is true.
enable_server_header: true
# enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
# value is true.
enable_date_header: true
# keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
# After the maximum number of requests are made, the connection is closed.
# The default value of 0 means no limit.
keepalive_requests: 0
# pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
# After the maximum number of requests are made, the connection is closed.
# The default value of 0 means no limit.
pipelining_requests: 0
# gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
# file with the extension ".gz" in the same path and send the compressed file to the client.
# The default value of gzip_static is true.
gzip_static: true
# br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
# file with the extension ".br" in the same path and send the compressed file to the client.
# The default value of br_static is true.
br_static: true
# client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
client_max_body_size: 1M
# max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
# If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
# Setting it to "" means no limit.
client_max_memory_body_size: 64K
# client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
client_max_websocket_message_size: 128K
# reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
reuse_port: false
# enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
# will be rejected.
enabled_compressed_request: false
# enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
# See the wiki for more details.
enable_request_stream: false
# plugins: Define all plugins running in the application
plugins:
# name: The class name of the plugin
- name: drogon::plugin::PromExporter
# dependencies: Plugins that the plugin depends on. It can be commented out
dependencies: []
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
# It can be commented out
config:
path: /metrics
- name: drogon::plugin::AccessLogger
dependencies: []
config:
use_spdlog: false
log_path: ''
log_format: ''
log_file: access.log
log_size_limit: 0
use_local_time: true
log_index: 0
# show_microseconds: true
# custom_time_format: ''
# use_real_ip: false
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
custom_config:
realm: drogonRealm
opaque: drogonOpaque
credentials:
- user: drogon
password: dr0g0n

42
docker/alpine/Dockerfile Normal file
View File

@ -0,0 +1,42 @@
FROM alpine:3.14
ARG USER=drogon
ARG UID=1000
ARG GID=1000
ARG USER_HOME=/drogon
ENV TZ=UTC
RUN apk update && apk --no-cache --upgrade add tzdata \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
RUN apk --no-cache --upgrade add \
sudo curl wget cmake make pkgconfig git gcc g++ \
openssl libressl-dev jsoncpp-dev util-linux-dev zlib-dev c-ares-dev \
postgresql-dev mariadb-dev sqlite-dev hiredis-dev
RUN addgroup -S -g $GID $USER \
&& adduser -D -u $UID -G $USER -h $USER_HOME $USER \
&& mkdir -p /etc/sudoers.d \
&& echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER \
&& chmod 0440 /etc/sudoers.d/$USER
USER $USER
WORKDIR $USER_HOME
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
CC=gcc \
CXX=g++ \
AR=gcc-ar \
RANLIB=gcc-ranlib \
DROGON_INSTALLED_ROOT=$USER_HOME/install
RUN wget -O $USER_HOME/version.json https://api.github.com/repos/an-tao/drogon/git/refs/heads/master \
&& git clone https://github.com/an-tao/drogon $DROGON_INSTALLED_ROOT
RUN cd $DROGON_INSTALLED_ROOT \
&& sed -i 's/bash/sh/' ./build.sh \
&& ./build.sh

32
docker/alpine/README.md Normal file
View File

@ -0,0 +1,32 @@
## Build Docker Image
```shell
$ cd drogon/docker/alpine # from this repository
$ docker build --no-cache --build-arg UID=`id -u` --build-arg GID=`id -g` -t drogon-alpine . # include last dot(.)
```
## Create a Drogon Project
```shell
$ cd ~/drogon_app # example
$ docker run --rm -v="$PWD:/drogon/app" -w="/drogon/app" drogon-alpine drogon_ctl create project hello_world
```
## Build the Project
```shell
$ cd hello_world
$ docker run --rm --volume="$PWD:/drogon/app" -w="/drogon/app/build" drogon-alpine sh -c "cmake .. && make"
```
## Start Server
```shell
$ docker run --name drogon_test --rm -u 0 -v="$PWD/build:/drogon/app" -w="/drogon/app" -p 8080:80 -d drogon-alpine ./hello_world # expose port 80 to 8080
```
## Stop Server
```shell
$ docker kill drogon_test
```

21
docker/arch/Dockerfile Normal file
View File

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

30
docker/ubuntu/Dockerfile Normal file
View File

@ -0,0 +1,30 @@
FROM ubuntu:22.04
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update -yqq \
&& apt-get install -yqq --no-install-recommends software-properties-common \
sudo curl wget cmake make pkg-config locales git gcc-11 g++-11 \
openssl libssl-dev libjsoncpp-dev uuid-dev zlib1g-dev libc-ares-dev\
postgresql-server-dev-all libmariadb-dev libsqlite3-dev libhiredis-dev\
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
CC=gcc-11 \
CXX=g++-11 \
AR=gcc-ar-11 \
RANLIB=gcc-ranlib-11 \
IROOT=/install
ENV DROGON_ROOT="$IROOT/drogon"
ADD https://api.github.com/repos/drogonframework/drogon/git/refs/heads/master $IROOT/version.json
RUN git clone https://github.com/drogonframework/drogon $DROGON_ROOT
WORKDIR $DROGON_ROOT
RUN ./build.sh

View File

@ -17,17 +17,33 @@ add_executable(_drogon_ctl
create.cc
create_view.cc)
target_link_libraries(_drogon_ctl ${PROJECT_NAME})
if (WIN32 AND BUILD_SHARED_LIBS)
set(DROGON_FILE $<TARGET_FILE:drogon>)
if (USE_SUBMODULE)
set(TRANTOR_FILE $<TARGET_FILE:trantor>)
else()
set(TRANTOR_FILE $<TARGET_FILE:Trantor::Trantor>)
endif()
add_custom_command(TARGET _drogon_ctl POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DCTL_FILE=${DROGON_FILE}
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
-P
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
add_custom_command(TARGET _drogon_ctl POST_BUILD
COMMAND ${CMAKE_COMMAND}
-DCTL_FILE=${TRANTOR_FILE}
-DINSTALL_BIN_DIR=$<TARGET_FILE_DIR:_drogon_ctl>
-P
${CMAKE_CURRENT_SOURCE_DIR}/CopyDlls.cmake)
endif()
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/templates/*.csp)
foreach(cspFile ${SCP_LIST})
message(STATUS "cspFile:" ${cspFile})
exec_program(basename
ARGS
"${cspFile} .csp"
OUTPUT_VARIABLE
classname)
get_filename_component(classname ${cspFile} NAME_WE)
message(STATUS "view classname:" ${classname})
add_custom_command(OUTPUT ${classname}.h ${classname}.cc
COMMAND _drogon_ctl
COMMAND $<TARGET_FILE:_drogon_ctl>
ARGS
create
view
@ -39,15 +55,33 @@ 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
trantor
makeVersion
_drogon_ctl)
add_dependencies(drogon_ctl _drogon_ctl)
if(WIN32)
target_link_libraries(drogon_ctl PRIVATE ws2_32 rpcrt4 iphlpapi)
endif(WIN32)
if(APPLE)
target_link_libraries(drogon_ctl PRIVATE resolv)
endif()
message(STATUS "bin:" ${INSTALL_BIN_DIR})
install(TARGETS drogon_ctl RUNTIME DESTINATION ${INSTALL_BIN_DIR})
install(PROGRAMS $<TARGET_FILE_DIR:drogon_ctl>/drogon_ctl
DESTINATION ${INSTALL_BIN_DIR}
RENAME dg_ctl)
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)

View File

@ -22,18 +22,22 @@ 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

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

View File

@ -1,7 +1,7 @@
/**
*
* create.cc
* An Tao
* @file create.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -18,13 +18,15 @@
#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> //create HttpView source "
"files from csp file\n\n"
"drogon_ctl create view <csp file name> [-o <output path>] [-n "
"<namespace>] [--path-to-namespace] //create HttpView source files "
"from csp files, namespace is prefixed of path-to-namespace\n\n"
"drogon_ctl create controller [-s] <[namespace::]class_name> //"
"create HttpSimpleController source files\n\n"
"drogon_ctl create controller -h <[namespace::]class_name> //"
@ -40,7 +42,8 @@ std::string create::detail()
"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]//"
"drogon_ctl create model <model_path> [-o <output path>] "
"[--table=<table_name>] [-f]//"
"create model classes in model_path\n";
}

View File

@ -17,21 +17,25 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create : public DrObject<create>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create some source files(Use 'drogon_ctl help create' for more "
"information)";
}
virtual bool isTopCommand() override
bool isTopCommand() override
{
return true;
}
virtual std::string detail() override;
std::string detail() override;
};
} // namespace drogon_ctl

View File

@ -95,8 +95,11 @@ void create_controller::newSimpleControllerHeaderFile(
const std::string &className)
{
file << "#pragma once\n";
file << "\n";
file << "#include <drogon/HttpSimpleController.h>\n";
file << "\n";
file << "using namespace drogon;\n";
file << "\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
@ -111,19 +114,19 @@ void create_controller::newSimpleControllerHeaderFile(
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::HttpSimpleController<"
file << "class " << class_name << " : public drogon::HttpSimpleController<"
<< class_name << ">\n";
file << "{\n";
file << " public:\n";
file << " virtual void asyncHandleHttpRequest(const HttpRequestPtr& "
file << " void asyncHandleHttpRequest(const HttpRequestPtr& "
"req, std::function<void (const HttpResponsePtr &)> &&callback) "
"override;\n";
file << " PATH_LIST_BEGIN\n";
file << " //list path definitions here;\n";
file << " // list path definitions here;\n";
file << " "
"//PATH_ADD(\"/"
"path\",\"filter1\",\"filter2\",HttpMethod1,HttpMethod2...);\n";
"// PATH_ADD(\"/"
"path\", \"filter1\", \"filter2\", HttpMethod1, HttpMethod2...);\n";
file << " PATH_LIST_END\n";
file << "};\n";
while (namespaceCount > 0)
@ -132,26 +135,29 @@ void create_controller::newSimpleControllerHeaderFile(
file << "}\n";
}
}
void create_controller::newSimpleControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename)
{
file << "#include \"" << filename << ".h\"\n";
file << "\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos)
{
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
file << "\n";
class_name = className.substr(pos + 2);
}
file << "void " << class_name
<< "::asyncHandleHttpRequest(const HttpRequestPtr& req, "
"std::function<void (const HttpResponsePtr &)> &&callback)\n";
file << "{\n";
file << " //write your application logic here\n";
file << "}";
file << " // write your application logic here\n";
file << "}\n";
}
void create_controller::newWebsockControllerHeaderFile(
@ -159,8 +165,11 @@ void create_controller::newWebsockControllerHeaderFile(
const std::string &className)
{
file << "#pragma once\n";
file << "\n";
file << "#include <drogon/WebSocketController.h>\n";
file << "\n";
file << "using namespace drogon;\n";
file << "\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
@ -175,23 +184,22 @@ void create_controller::newWebsockControllerHeaderFile(
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::WebSocketController<"
file << "class " << class_name << " : public drogon::WebSocketController<"
<< class_name << ">\n";
file << "{\n";
file << " public:\n";
file
<< " virtual void handleNewMessage(const WebSocketConnectionPtr&,\n";
file << " void handleNewMessage(const WebSocketConnectionPtr&,\n";
file << " std::string &&,\n";
file << " const WebSocketMessageType &) "
"override;\n";
file << " virtual void handleNewConnection(const HttpRequestPtr &,\n";
file << " void handleNewConnection(const HttpRequestPtr &,\n";
file << " const "
"WebSocketConnectionPtr&)override;\n";
file << " virtual void handleConnectionClosed(const "
"WebSocketConnectionPtr&)override;\n";
"WebSocketConnectionPtr&) override;\n";
file << " void handleConnectionClosed(const "
"WebSocketConnectionPtr&) override;\n";
file << " WS_PATH_LIST_BEGIN\n";
file << " //list path definitions here;\n";
file << " //WS_PATH_ADD(\"/path\",\"filter1\",\"filter2\",...);\n";
file << " // list path definitions here;\n";
file << " // WS_PATH_ADD(\"/path\", \"filter1\", \"filter2\", ...);\n";
file << " WS_PATH_LIST_END\n";
file << "};\n";
while (namespaceCount > 0)
@ -200,37 +208,42 @@ void create_controller::newWebsockControllerHeaderFile(
file << "}\n";
}
}
void create_controller::newWebsockControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename)
{
file << "#include \"" << filename << ".h\"\n";
file << "\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos)
{
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
file << "\n";
class_name = className.substr(pos + 2);
}
file << "void " << class_name
<< "::handleNewMessage(const WebSocketConnectionPtr& wsConnPtr, "
"std::string &&message, const WebSocketMessageType &type)\n";
file << "{\n";
file << " //write your application logic here\n";
file << " // write your application logic here\n";
file << "}\n";
file << "\n";
file << "void " << class_name
<< "::handleNewConnection(const HttpRequestPtr &req,const "
<< "::handleNewConnection(const HttpRequestPtr &req, const "
"WebSocketConnectionPtr& wsConnPtr)\n";
file << "{\n";
file << " //write your application logic here\n";
file << " // write your application logic here\n";
file << "}\n";
file << "\n";
file << "void " << class_name
<< "::handleConnectionClosed(const WebSocketConnectionPtr& "
"wsConnPtr)\n";
file << "{\n";
file << " //write your application logic here\n";
file << " // write your application logic here\n";
file << "}\n";
}
@ -239,8 +252,11 @@ void create_controller::newHttpControllerHeaderFile(
const std::string &className)
{
file << "#pragma once\n";
file << "\n";
file << "#include <drogon/HttpController.h>\n";
file << "\n";
file << "using namespace drogon;\n";
file << "\n";
std::string class_name = className;
std::string namepace_path = "/";
auto pos = class_name.find("::");
@ -255,33 +271,33 @@ void create_controller::newHttpControllerHeaderFile(
file << "{\n";
pos = class_name.find("::");
}
file << "class " << class_name << ":public drogon::HttpController<"
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 "
file << " // use METHOD_ADD to add your custom processing function "
"here;\n";
file << " //METHOD_ADD(" << class_name
<< "::get,\"/{2}/{1}\",Get);"
"//path is "
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 "
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 << " // 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 << " // 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)
{
@ -289,22 +305,25 @@ void create_controller::newHttpControllerHeaderFile(
file << "}\n";
}
}
void create_controller::newHttpControllerSourceFile(
std::ofstream &file,
const std::string &className,
const std::string &filename)
{
file << "#include \"" << filename << ".h\"\n";
file << "\n";
auto pos = className.rfind("::");
auto class_name = className;
if (pos != std::string::npos)
{
auto namespacename = className.substr(0, pos);
file << "using namespace " << namespacename << ";\n";
file << "\n";
class_name = className.substr(pos + 2);
}
file << "//add definition of your processing function here\n";
file << "// Add definition of your processing function here\n";
}
void create_controller::createController(std::vector<std::string> &httpClasses,
@ -360,20 +379,21 @@ void create_controller::createController(const std::string &className,
}
if (type == Http)
{
std::cout << "create a http controller:" << className << std::endl;
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::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;
std::cout << "Create a websocket controller: " << className
<< std::endl;
newWebsockControllerHeaderFile(oHeadFile, className);
newWebsockControllerSourceFile(oSourceFile, className, ctlName);
}
@ -444,8 +464,8 @@ void create_controller::createARestfulController(const std::string &className,
std::cerr << err.what() << std::endl;
exit(1);
}
std::cout << "create a http restful API controller:" << className
std::cout << "Create a http restful API controller: " << className
<< std::endl;
std::cout << "file name: " << ctlName << ".h and " << ctlName << ".cc"
std::cout << "File name: " << ctlName << ".h and " << ctlName << ".cc"
<< std::endl;
}

View File

@ -18,14 +18,16 @@
#include <drogon/DrTemplateBase.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_controller : public DrObject<create_controller>,
public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create controller files";
}

View File

@ -18,7 +18,9 @@
#include <string>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fstream>
#include <regex>
@ -67,6 +69,7 @@ static void createFilterSourceFile(std::ofstream &file,
data.insert("filename", fileName);
file << templ->genText(data);
}
void create_filter::handleCommand(std::vector<std::string> &parameters)
{
if (parameters.size() < 1)

View File

@ -17,18 +17,20 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_filter : public DrObject<create_filter>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create filter class files";
}
protected:
std::string _outputPath = ".";
std::string outputPath_{"."};
};
} // namespace drogon_ctl

File diff suppressed because it is too large Load Diff

View File

@ -30,24 +30,26 @@ 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;
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::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
return tolower(c);
});
std::string::size_type startPos = 0;
std::string::size_type pos;
std::string ret;
@ -66,7 +68,7 @@ inline std::string nameTransform(const std::string &origName, bool isType)
break;
}
while (str[pos] == '_' || str[pos] == '.')
pos++;
++pos;
if (str[pos] >= 'a' && str[pos] <= 'z')
str[pos] += ('A' - 'a');
startPos = pos;
@ -75,54 +77,137 @@ inline std::string nameTransform(const std::string &origName, bool isType)
ret[0] += ('A' - 'a');
return ret;
}
std::string escapeIdentifier(const std::string &identifier,
const std::string &rdbms);
class PivotTable
{
public:
PivotTable() = default;
PivotTable(const Json::Value &json)
: tableName_(json.get("table_name", "").asString())
{
_tableName = json.get("table_name", "").asString();
if (_tableName.empty())
if (tableName_.empty())
{
throw std::runtime_error("table_name can't be empty");
}
_originalKey = json.get("original_key", "").asString();
if (_originalKey.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())
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;
pivot.tableName_ = tableName_;
pivot.originalKey_ = targetKey_;
pivot.targetKey_ = originalKey_;
return pivot;
}
const std::string &tableName() const
{
return _tableName;
return tableName_;
}
const std::string &originalKey() const
{
return _originalKey;
return originalKey_;
}
const std::string &targetKey() const
{
return _targetKey;
return targetKey_;
}
private:
std::string _tableName;
std::string _originalKey;
std::string _targetKey;
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:
@ -132,54 +217,58 @@ class Relationship
HasMany,
ManyToMany
};
Relationship(const Json::Value &relationship)
{
auto type = relationship.get("type", "has one").asString();
if (type == "has one")
{
_type = Relationship::Type::HasOne;
type_ = Relationship::Type::HasOne;
}
else if (type == "has many")
{
_type = Relationship::Type::HasMany;
type_ = Relationship::Type::HasMany;
}
else if (type == "many to many")
{
_type = Relationship::Type::ManyToMany;
type_ = Relationship::Type::ManyToMany;
}
else
{
char message[128];
sprintf(message, "Invalid relationship type: %s", type.data());
snprintf(message,
sizeof(message),
"Invalid relationship type: %s",
type.data());
throw std::runtime_error(message);
}
_originalTableName =
originalTableName_ =
relationship.get("original_table_name", "").asString();
if (_originalTableName.empty())
if (originalTableName_.empty())
{
throw std::runtime_error("original_table_name can't be empty");
}
_originalKey = relationship.get("original_key", "").asString();
if (_originalKey.empty())
originalKey_ = relationship.get("original_key", "").asString();
if (originalKey_.empty())
{
throw std::runtime_error("original_key can't be empty");
}
_originalTableAlias =
originalTableAlias_ =
relationship.get("original_table_alias", "").asString();
_targetTableName = relationship.get("target_table_name", "").asString();
if (_targetTableName.empty())
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())
targetKey_ = relationship.get("target_key", "").asString();
if (targetKey_.empty())
{
throw std::runtime_error("target_key can't be empty");
}
_targetTableAlias =
targetTableAlias_ =
relationship.get("target_table_alias", "").asString();
_enableReverse = relationship.get("enable_reverse", false).asBool();
if (_type == Type::ManyToMany)
enableReverse_ = relationship.get("enable_reverse", false).asBool();
if (type_ == Type::ManyToMany)
{
auto &pivot = relationship["pivot_table"];
if (pivot.isNull())
@ -187,84 +276,97 @@ class Relationship
throw std::runtime_error(
"ManyToMany relationship needs a pivot table");
}
_pivotTable = PivotTable(pivot);
pivotTable_ = PivotTable(pivot);
}
}
Relationship() = default;
Relationship reverse() const
{
Relationship r;
if (_type == Type::HasMany)
if (type_ == Type::HasMany)
{
r._type = Type::HasOne;
r.type_ = Type::HasOne;
}
else
{
r._type = _type;
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();
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;
return type_;
}
bool enableReverse() const
{
return _enableReverse;
return enableReverse_;
}
const std::string &originalTableName() const
{
return _originalTableName;
return originalTableName_;
}
const std::string &originalTableAlias() const
{
return _originalTableAlias;
return originalTableAlias_;
}
const std::string &originalKey() const
{
return _originalKey;
return originalKey_;
}
const std::string &targetTableName() const
{
return _targetTableName;
return targetTableName_;
}
const std::string &targetTableAlias() const
{
return _targetTableAlias;
return targetTableAlias_;
}
const std::string &targetKey() const
{
return _targetKey;
return targetKey_;
}
const PivotTable &pivotTable() const
{
return _pivotTable;
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;
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
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create Model classes files";
}
@ -276,18 +378,22 @@ class create_model : public DrObject<create_model>, public CommandHandler
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);
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<Relationship>> &relationships,
std::map<std::string, std::vector<ConvertMethod>> &convertMethods);
#endif
#if USE_MYSQL
void createModelClassFromMysql(
@ -295,12 +401,14 @@ class create_model : public DrObject<create_model>, public CommandHandler
const DbClientPtr &client,
const std::string &tableName,
const Json::Value &restfulApiConfig,
const std::vector<Relationship> &relationships);
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<Relationship>> &relationships,
std::map<std::string, std::vector<ConvertMethod>> &convertMethods);
#endif
#if USE_SQLITE3
void createModelClassFromSqlite3(
@ -308,16 +416,19 @@ class create_model : public DrObject<create_model>, public CommandHandler
const DbClientPtr &client,
const std::string &tableName,
const Json::Value &restfulApiConfig,
const std::vector<Relationship> &relationships);
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<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;
std::string dbname_;
bool forceOverwrite_{false};
std::string outputPath_;
};
} // namespace drogon_ctl

View File

@ -18,7 +18,9 @@
#include <string>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fstream>
#include <regex>
@ -67,6 +69,7 @@ static void createPluginSourceFile(std::ofstream &file,
data.insert("filename", fileName);
file << templ->genText(data);
}
void create_plugin::handleCommand(std::vector<std::string> &parameters)
{
if (parameters.size() < 1)

View File

@ -17,18 +17,20 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_plugin : public DrObject<create_plugin>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create plugin class files";
}
protected:
std::string _outputPath = ".";
std::string outputPath_{"."};
};
} // namespace drogon_ctl

View File

@ -14,10 +14,16 @@
#include "create_project.h"
#include <drogon/DrTemplateBase.h>
#include <drogon/utils/Utilities.h>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <io.h>
#include <direct.h>
#endif
#include <fstream>
using namespace drogon_ctl;
@ -32,6 +38,7 @@ void create_project::handleCommand(std::vector<std::string> &parameters)
auto pName = parameters[0];
createProject(pName);
}
static void newCmakeFile(std::ofstream &cmakeFile,
const std::string &projectName)
{
@ -40,30 +47,59 @@ static void newCmakeFile(std::ofstream &cmakeFile,
auto templ = DrTemplateBase::newTemplate("cmake.csp");
cmakeFile << templ->genText(data);
}
static void newMainFile(std::ofstream &mainFile)
{
auto templ = DrTemplateBase::newTemplate("demoMain");
mainFile << templ->genText();
}
static void newGitIgFile(std::ofstream &gitFile)
{
auto templ = DrTemplateBase::newTemplate("gitignore.csp");
gitFile << templ->genText();
}
static void newConfigFile(std::ofstream &configFile)
static void newConfigJsonFile(std::ofstream &configJsonFile)
{
auto templ = DrTemplateBase::newTemplate("config");
configFile << templ->genText();
auto templ = DrTemplateBase::newTemplate("config_json");
configJsonFile << templ->genText();
}
static void newConfigYamlFile(std::ofstream &configYamlFile)
{
auto templ = DrTemplateBase::newTemplate("config_yaml");
configYamlFile << templ->genText();
}
static void newModelConfigFile(std::ofstream &configFile)
{
auto templ = DrTemplateBase::newTemplate("model_json");
configFile << templ->genText();
}
static void newTestMainFile(std::ofstream &mainFile)
{
auto templ = DrTemplateBase::newTemplate("test_main");
mainFile << templ->genText();
}
static void newTestCmakeFile(std::ofstream &testCmakeFile,
const std::string &projectName)
{
HttpViewData data;
data.insert("ProjectName", projectName);
auto templ = DrTemplateBase::newTemplate("test_cmake");
testCmakeFile << templ->genText(data);
}
void create_project::createProject(const std::string &projectName)
{
#ifdef _WIN32
if (_access(projectName.data(), 0) == 0)
#else
if (access(projectName.data(), 0) == 0)
#endif
{
std::cerr
<< "The directory already exists, please use another project name!"
@ -71,25 +107,37 @@ void create_project::createProject(const std::string &projectName)
exit(1);
}
std::cout << "create a project named " << projectName << std::endl;
mkdir(projectName.data(), 0755);
// 1.create CMakeLists.txt
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);
mkdir("views", 0755);
mkdir("controllers", 0755);
mkdir("filters", 0755);
mkdir("plugins", 0755);
mkdir("build", 0755);
mkdir("models", 0755);
drogon::utils::createPath("views");
drogon::utils::createPath("controllers");
drogon::utils::createPath("filters");
drogon::utils::createPath("plugins");
drogon::utils::createPath("build");
drogon::utils::createPath("models");
drogon::utils::createPath("test");
std::ofstream gitFile(".gitignore", std::ofstream::out);
newGitIgFile(gitFile);
std::ofstream configFile("config.json", std::ofstream::out);
newConfigFile(configFile);
std::ofstream configJsonFile("config.json", std::ofstream::out);
newConfigJsonFile(configJsonFile);
std::ofstream configYamlFile("config.yaml", std::ofstream::out);
newConfigYamlFile(configYamlFile);
std::ofstream modelConfigFile("models/model.json", std::ofstream::out);
newModelConfigFile(modelConfigFile);
std::ofstream testMainFile("test/test_main.cc", std::ofstream::out);
newTestMainFile(testMainFile);
std::ofstream testCmakeFile("test/CMakeLists.txt", std::ofstream::out);
newTestCmakeFile(testCmakeFile, projectName);
}

View File

@ -16,19 +16,21 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_project : public DrObject<create_project>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create a project";
}
protected:
std::string _outputPath = ".";
std::string outputPath_{"."};
void createProject(const std::string &projectName);
};
} // namespace drogon_ctl

View File

@ -1,7 +1,7 @@
/**
*
* create_view.cc
* An Tao
* @file create_view.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -14,6 +14,7 @@
#include "create_view.h"
#include "cmd.h"
#include <drogon/utils/Utilities.h>
#include <iostream>
#include <fstream>
#include <string>
@ -45,13 +46,14 @@ static std::string &replace_all(std::string &str,
{
str = str.replace(pos, old_value.length(), new_value);
pos += new_value.length() - old_value.length();
pos++;
++pos;
}
else
break;
}
return str;
}
static void parseCxxLine(std::ofstream &oSrcFile,
const std::string &line,
const std::string &streamName,
@ -65,6 +67,7 @@ static void parseCxxLine(std::ofstream &oSrcFile,
oSrcFile << tmp << "\n";
}
}
static void outputVal(std::ofstream &oSrcFile,
const std::string &streamName,
const std::string &viewDataName,
@ -75,12 +78,12 @@ static void outputVal(std::ofstream &oSrcFile,
<< "\"];\n";
oSrcFile << " if(val.type()==typeid(const char *)){\n";
oSrcFile << " " << streamName
<< "<<*any_cast<const char *>(&val);\n";
<< "<<*(std::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";
<< "<<*(std::any_cast<const std::string>(&val));\n";
oSrcFile << " }\n";
oSrcFile << "}\n";
}
@ -109,11 +112,15 @@ static void parseLine(std::ofstream &oSrcFile,
{
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)
if (returnFlag && !cxx_flag)
oSrcFile << streamName << "<<\"\\n\";\n";
return;
}
@ -149,10 +156,10 @@ static void parseLine(std::ofstream &oSrcFile,
std::string keyName = newLine.substr(0, pos);
auto iter = keyName.begin();
while (iter != keyName.end() && *iter == ' ')
iter++;
++iter;
auto iterEnd = iter;
while (iterEnd != keyName.end() && *iterEnd != ' ')
iterEnd++;
++iterEnd;
keyName = std::string(iter, iterEnd);
outputVal(oSrcFile, streamName, viewDataName, keyName);
std::string tailLine =
@ -182,10 +189,10 @@ static void parseLine(std::ofstream &oSrcFile,
std::string keyName = newLine.substr(0, pos);
auto iter = keyName.begin();
while (iter != keyName.end() && *iter == ' ')
iter++;
++iter;
auto iterEnd = iter;
while (iterEnd != keyName.end() && *iterEnd != ' ')
iterEnd++;
++iterEnd;
keyName = std::string(iter, iterEnd);
outputSubView(oSrcFile, streamName, viewDataName, keyName);
std::string tailLine =
@ -243,39 +250,95 @@ static void parseLine(std::ofstream &oSrcFile,
void create_view::handleCommand(std::vector<std::string> &parameters)
{
for (auto iter = parameters.begin(); iter != parameters.end(); iter++)
for (auto iter = parameters.begin(); iter != parameters.end();)
{
auto file = *iter;
auto &file = *iter;
if (file == "-o" || file == "--output")
{
iter = parameters.erase(iter);
if (iter != parameters.end())
{
_outputPath = *iter;
outputPath_ = *iter;
iter = parameters.erase(iter);
}
break;
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);
if (createViewFile(file) != 0)
exit(1);
}
}
int create_view::createViewFile(const std::string &script_filename)
{
std::cout << "create HttpView Class file by " << script_filename
<< std::endl;
if (pathToNamespaceFlag_)
{
std::string::size_type pos1 = 0, pos2 = 0;
if (script_filename.length() >= 2 && script_filename[0] == '.' &&
(script_filename[1] == '/' || script_filename[1] == '\\'))
{
pos1 = pos2 = 2;
}
else if (script_filename.length() >= 1 &&
(script_filename[0] == '/' || script_filename[0] == '\\'))
{
pos1 = pos2 = 1;
}
while (pos2 < script_filename.length() - 1)
{
if (script_filename[pos2] == '/' || script_filename[pos2] == '\\')
{
if (pos2 > pos1)
{
namespaces_.push_back(
script_filename.substr(pos1, pos2 - pos1));
}
pos1 = ++pos2;
}
else
{
++pos2;
}
}
}
std::string npPrefix;
for (auto &np : namespaces_)
{
npPrefix += np;
npPrefix += "_";
}
std::ifstream infile(script_filename.c_str(), std::ifstream::in);
if (infile)
{
@ -288,16 +351,22 @@ int create_view::createViewFile(const std::string &script_filename)
className = className.substr(pos + 1);
}
std::cout << "className=" << className << std::endl;
std::string headFileName = _outputPath + "/" + className + ".h";
std::string sourceFilename = _outputPath + "/" + className + ".cc";
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, infile);
newViewSourceFile(oSourceFile, className, npPrefix, infile);
}
else
return -1;
@ -309,29 +378,41 @@ int create_view::createViewFile(const std::string &script_filename)
}
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";
file << "using namespace drogon;\n";
file << "class " << className << ":public DrTemplate<" << className
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 DrTemplateData &) override;\n};";
"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 \"" << className << ".h\"\n";
file << "#include \"" << namespacePrefix << className << ".h\"\n";
file << "#include <drogon/utils/OStringStream.h>\n";
file << "#include <drogon/utils/Utilities.h>\n";
file << "#include <string>\n";
file << "#include <sstream>\n";
file << "#include <map>\n";
file << "#include <vector>\n";
file << "#include <set>\n";
@ -343,19 +424,26 @@ void create_view::newViewSourceFile(std::ofstream &file,
file << "#include <deque>\n";
file << "#include <queue>\n";
// file << "using namespace std;\n";
// file <<"void __attribute__((constructor)) startup()\n";
// file <<"{std::cout<<\"dynamic lib start to load!\"<<std::endl;}\n";
// file <<"void __attribute__((destructor)) shutdown()\n";
// file <<"{std::cout<<\"dynamic lib start to unload!\"<<std::endl;}\n";
std::string buffer;
char line[8192];
int import_flag = 0;
while (infile.getline(line, sizeof(line)))
// 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);)
{
buffer = line;
std::string::size_type pos(0);
if (!import_flag)
@ -364,12 +452,12 @@ void create_view::newViewSourceFile(std::ofstream &file,
std::transform(lowerBuffer.begin(),
lowerBuffer.end(),
lowerBuffer.begin(),
::tolower);
[](unsigned char c) { return tolower(c); });
if ((pos = lowerBuffer.find(cxx_include)) != std::string::npos)
{
// std::cout<<"haha find it!"<<endl;
std::string newLine = buffer.substr(pos + cxx_include.length());
import_flag = 1;
import_flag = true;
if ((pos = newLine.find(cxx_end)) != std::string::npos)
{
newLine = newLine.substr(0, pos);
@ -389,7 +477,6 @@ void create_view::newViewSourceFile(std::ofstream &file,
{
std::string newLine = buffer.substr(0, pos);
file << newLine << "\n";
break;
}
else
@ -400,14 +487,29 @@ void create_view::newViewSourceFile(std::ofstream &file,
}
}
// std::cout<<"import_flag="<<import_flag<<std::endl;
if (import_flag == 0)
if (!import_flag)
{
infile.clear();
infile.seekg(0, std::ifstream::beg);
}
// std::cout<<"file pos:"<<infile.tellg()<<std::endl;
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& "
@ -416,18 +518,37 @@ void create_view::newViewSourceFile(std::ofstream &file,
std::string streamName = className + "_tmp_stream";
// oSrcFile <<"\tstd::string "<<bodyName<<";\n";
file << "\tstd::stringstream " << streamName << ";\n";
file << "\tdrogon::OStringStream " << streamName << ";\n";
file << "\tstd::string layoutName{\"" << layoutName << "\"};\n";
int cxx_flag = 0;
while (infile.getline(line, sizeof(line)))
for (std::string buffer; std::getline(infile, buffer);)
{
buffer = line;
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 << "return " << streamName << ".str();\n}\n";
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,7 +1,7 @@
/**
*
* create_view.h
* An Tao
* @file create_view.h
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -17,24 +17,29 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class create_view : public DrObject<create_view>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "create view class files";
}
protected:
std::string _outputPath = ".";
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

@ -17,6 +17,7 @@
#include <iostream>
#include <memory>
using namespace drogon_ctl;
void help::handleCommand(std::vector<std::string> &parameters)
{
if (parameters.size() == 0)

View File

@ -17,17 +17,20 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class help : public DrObject<help>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "display this message";
}
virtual bool isTopCommand() override
bool isTopCommand() override
{
return true;
}

View File

@ -1,7 +1,7 @@
/**
*
* main.cc
* An Tao
* @file main.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -13,21 +13,20 @@
*/
#include "cmd.h"
#include <string>
#include <vector>
#include <iostream>
int main(int argc, char *argv[])
{
std::vector<std::string> args;
if (argc < 2)
{
std::vector<std::string> args = {"help"};
args = {"help"};
exeCommand(args);
return 0;
}
std::vector<std::string> args;
for (int i = 1; i < argc; i++)
for (int i = 1; i < argc; ++i)
{
args.push_back(argv[i]);
}

View File

@ -18,10 +18,17 @@
#include <iostream>
#include <memory>
#include <iomanip>
#include <stdlib.h>
#include <cstdlib>
#include <json/json.h>
#include <fstream>
#include <string>
#include <unordered_map>
#ifndef _WIN32
#include <unistd.h>
#endif
using namespace drogon_ctl;
std::string press::detail()
{
return "Use press command to do stress testing\n"
@ -29,17 +36,19 @@ std::string press::detail()
" -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"
" -k disable SSL certificate validation(default: enable)\n"
" -f customize http request json file(default: disenable)\n"
" -q no progress indication(default: show)\n\n"
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
"http://localhost:8080/index.html\n";
"http://localhost:8080/index.html -f ./http_request.json\n";
}
void outputErrorAndExit(const string_view &err)
void outputErrorAndExit(const std::string_view &err)
{
std::cout << err << std::endl;
exit(1);
}
void press::handleCommand(std::vector<std::string> &parameters)
{
for (auto iter = parameters.begin(); iter != parameters.end(); iter++)
@ -49,7 +58,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
{
if (param == "-n")
{
iter++;
++iter;
if (iter == parameters.end())
{
outputErrorAndExit("No number of requests!");
@ -57,7 +66,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto &num = *iter;
try
{
_numOfRequests = std::stoll(num);
numOfRequests_ = std::stoll(num);
}
catch (...)
{
@ -70,7 +79,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto num = param.substr(2);
try
{
_numOfRequests = std::stoll(num);
numOfRequests_ = std::stoll(num);
}
catch (...)
{
@ -83,7 +92,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
{
if (param == "-t")
{
iter++;
++iter;
if (iter == parameters.end())
{
outputErrorAndExit("No number of threads!");
@ -91,7 +100,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto &num = *iter;
try
{
_numOfThreads = std::stoll(num);
numOfThreads_ = std::stoll(num);
}
catch (...)
{
@ -104,7 +113,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto num = param.substr(2);
try
{
_numOfThreads = std::stoll(num);
numOfThreads_ = std::stoll(num);
}
catch (...)
{
@ -117,7 +126,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
{
if (param == "-c")
{
iter++;
++iter;
if (iter == parameters.end())
{
outputErrorAndExit("No number of connections!");
@ -125,7 +134,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto &num = *iter;
try
{
_numOfConnections = std::stoll(num);
numOfConnections_ = std::stoll(num);
}
catch (...)
{
@ -138,7 +147,7 @@ void press::handleCommand(std::vector<std::string> &parameters)
auto num = param.substr(2);
try
{
_numOfConnections = std::stoll(num);
numOfConnections_ = std::stoll(num);
}
catch (...)
{
@ -147,88 +156,230 @@ void press::handleCommand(std::vector<std::string> &parameters)
continue;
}
}
// else if (param == "-k")
// {
// _keepAlive = true;
// continue;
// }
else if (param.find("-f") == 0)
{
if (param == "-f")
{
++iter;
if (iter == parameters.end())
{
outputErrorAndExit("No http request json file!");
}
httpRequestJsonFile_ = *iter;
continue;
}
else
{
httpRequestJsonFile_ = param.substr(2);
continue;
}
}
else if (param == "-k")
{
certValidation_ = false;
continue;
}
else if (param == "-q")
{
_processIndication = false;
processIndication_ = false;
}
else if (param[0] != '-')
{
_url = param;
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.find("http") != 0 ||
_url.find("://") == std::string::npos)
// 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);
auto pos = url_.find("://");
auto posOfPath = url_.find('/', pos + 3);
if (posOfPath == std::string::npos)
{
_host = _url;
_path = "/";
host_ = url_;
path_ = "/";
}
else
{
_host = _url.substr(0, posOfPath);
_path = _url.substr(posOfPath);
host_ = url_.substr(0, posOfPath);
path_ = url_.substr(posOfPath);
}
}
// std::cout << "host=" << _host << std::endl;
// std::cout << "path=" << _path << std::endl;
/*
http_request.json
{
"method": "POST",
"header": {
"token": "e2e9d0fe-dd14-4eaf-8ac1-0997730a805d"
},
"body": {
"passwd": "123456",
"account": "10001"
}
}
*/
if (!httpRequestJsonFile_.empty())
{
Json::Value httpRequestJson;
std::ifstream httpRequestFile(httpRequestJsonFile_,
std::ifstream::binary);
if (!httpRequestFile.is_open())
{
outputErrorAndExit(std::string{"No "} + httpRequestJsonFile_);
}
httpRequestFile >> httpRequestJson;
if (!httpRequestJson.isMember("method"))
{
outputErrorAndExit("No contain method");
}
auto methodStr = httpRequestJson["method"].asString();
std::transform(methodStr.begin(),
methodStr.end(),
methodStr.begin(),
::toupper);
auto toHttpMethod = [&]() -> drogon::HttpMethod {
if (methodStr == "GET")
{
return drogon::HttpMethod::Get;
}
else if (methodStr == "POST")
{
return drogon::HttpMethod::Post;
}
else if (methodStr == "HEAD")
{
return drogon::HttpMethod::Head;
}
else if (methodStr == "PUT")
{
return drogon::HttpMethod::Put;
}
else if (methodStr == "DELETE")
{
return drogon::HttpMethod::Delete;
}
else if (methodStr == "OPTIONS")
{
return drogon::HttpMethod::Options;
}
else if (methodStr == "PATCH")
{
return drogon::HttpMethod::Patch;
}
else
{
outputErrorAndExit("invalid method");
}
return drogon::HttpMethod::Get;
};
std::unordered_map<std::string, std::string> header;
if (httpRequestJson.isMember("header"))
{
auto &jsonValue = httpRequestJson["header"];
for (const auto &key : jsonValue.getMemberNames())
{
if (jsonValue[key].isString())
{
header[key] = jsonValue[key].asString();
}
else
{
header[key] = jsonValue[key].toStyledString();
}
}
}
std::string body;
if (httpRequestJson.isMember("body"))
{
Json::FastWriter fastWriter;
body = fastWriter.write(httpRequestJson["body"]);
}
createHttpRequestFunc_ = [this,
method = toHttpMethod(),
body = std::move(body),
header =
std::move(header)]() -> HttpRequestPtr {
auto request = HttpRequest::newHttpRequest();
request->setPath(path_);
request->setMethod(method);
for (const auto &[field, val] : header)
request->addHeader(field, val);
if (!body.empty())
request->setBody(body);
return request;
};
}
// std::cout << "host=" << host_ << std::endl;
// std::cout << "path=" << path_ << std::endl;
doTesting();
}
void press::doTesting()
{
createRequestAndClients();
if (_clients.empty())
if (clients_.empty())
{
outputErrorAndExit("No connection!");
}
_stat._startDate = trantor::Date::now();
for (auto &client : _clients)
statistics_.startDate_ = trantor::Date::now();
for (auto &client : clients_)
{
sendRequest(client);
}
_loopPool->wait();
loopPool_->wait();
}
void press::createRequestAndClients()
{
_loopPool = std::make_unique<trantor::EventLoopThreadPool>(_numOfThreads);
_loopPool->start();
for (size_t i = 0; i < _numOfConnections; i++)
loopPool_ = std::make_unique<trantor::EventLoopThreadPool>(numOfThreads_);
loopPool_->start();
for (size_t i = 0; i < numOfConnections_; ++i)
{
auto client =
HttpClient::newHttpClient(_host, _loopPool->getNextLoop());
auto client = HttpClient::newHttpClient(host_,
loopPool_->getNextLoop(),
false,
certValidation_);
client->enableCookies();
_clients.push_back(client);
clients_.push_back(client);
}
}
void press::sendRequest(const HttpClientPtr &client)
{
auto numOfRequest = _stat._numOfRequestsSent++;
if (numOfRequest >= _numOfRequests)
auto numOfRequest = statistics_.numOfRequestsSent_++;
if (numOfRequest >= numOfRequests_)
{
return;
}
auto request = HttpRequest::newHttpRequest();
request->setPath(_path);
request->setMethod(Get);
HttpRequestPtr request;
if (createHttpRequestFunc_)
{
request = createHttpRequestFunc_();
}
else
{
request = HttpRequest::newHttpRequest();
request->setPath(path_);
request->setMethod(Get);
}
// std::cout << "send!" << std::endl;
client->sendRequest(
request,
@ -237,23 +388,23 @@ void press::sendRequest(const HttpClientPtr &client)
if (r == ReqResult::Ok)
{
// std::cout << "OK" << std::endl;
goodNum = ++_stat._numOfGoodResponse;
badNum = _stat._numOfBadResponse;
_stat._bytesRecieved += resp->body().length();
goodNum = ++statistics_.numOfGoodResponse_;
badNum = statistics_.numOfBadResponse_;
statistics_.bytesRecieved_ += resp->body().length();
auto delay = trantor::Date::now().microSecondsSinceEpoch() -
request->creationDate().microSecondsSinceEpoch();
_stat._totalDelay += delay;
statistics_.totalDelay_ += delay;
}
else
{
goodNum = _stat._numOfGoodResponse;
badNum = ++_stat._numOfBadResponse;
if (badNum > _numOfRequests / 10)
goodNum = statistics_.numOfGoodResponse_;
badNum = ++statistics_.numOfBadResponse_;
if (badNum > numOfRequests_ / 10)
{
outputErrorAndExit("Too many errors");
}
}
if (goodNum + badNum >= _numOfRequests)
if (goodNum + badNum >= numOfRequests_)
{
outputResults();
}
@ -266,7 +417,7 @@ void press::sendRequest(const HttpClientPtr &client)
});
}
if (_processIndication)
if (processIndication_)
{
auto rec = goodNum + badNum;
if (rec % 100000 == 0)
@ -280,34 +431,37 @@ void press::sendRequest(const HttpClientPtr &client)
void press::outputResults()
{
static std::mutex mtx;
size_t totalSent = 0;
size_t totalRecv = 0;
for (auto &client : _clients)
for (auto &client : clients_)
{
totalSent += client->bytesSent();
totalRecv += client->bytesReceived();
}
auto now = trantor::Date::now();
auto microSecs = now.microSecondsSinceEpoch() -
_stat._startDate.microSecondsSinceEpoch();
statistics_.startDate_.microSecondsSinceEpoch();
double seconds = (double)microSecs / 1000000.0;
size_t rps = _stat._numOfGoodResponse / seconds;
auto rps = static_cast<size_t>(statistics_.numOfGoodResponse_ / seconds);
std::cout << std::endl;
std::cout << "TOTALS: " << _numOfConnections << " connect, "
<< _numOfRequests << " requests, " << _stat._numOfGoodResponse
<< " success, " << _stat._numOfBadResponse << " fail"
<< std::endl;
std::cout << "TOTALS: " << numOfConnections_ << " connect, "
<< numOfRequests_ << " requests, "
<< statistics_.numOfGoodResponse_ << " success, "
<< statistics_.numOfBadResponse_ << " fail" << std::endl;
std::cout << "TRAFFIC: " << _stat._bytesRecieved / _stat._numOfGoodResponse
std::cout << "TRAFFIC: "
<< statistics_.bytesRecieved_ / statistics_.numOfGoodResponse_
<< " avg bytes, "
<< (totalRecv - _stat._bytesRecieved) / _stat._numOfGoodResponse
<< " avg overhead, " << _stat._bytesRecieved << " bytes, "
<< totalRecv - _stat._bytesRecieved << " overhead" << std::endl;
<< (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)(_stat._totalDelay) / _stat._numOfGoodResponse / 1000
<< (double)(statistics_.totalDelay_) /
statistics_.numOfGoodResponse_ / 1000
<< " ms avg req time" << std::endl;
std::cout << "SPEED: download " << totalRecv / seconds / 1000

View File

@ -20,6 +20,7 @@
#include <drogon/HttpClient.h>
#include <trantor/utils/Date.h>
#include <trantor/net/EventLoopThreadPool.h>
#include <functional>
#include <string>
#include <atomic>
#include <memory>
@ -31,44 +32,50 @@ namespace drogon_ctl
{
struct Statistics
{
std::atomic_size_t _numOfRequestsSent = ATOMIC_VAR_INIT(0);
std::atomic_size_t _bytesRecieved = ATOMIC_VAR_INIT(0);
std::atomic_size_t _numOfGoodResponse = ATOMIC_VAR_INIT(0);
std::atomic_size_t _numOfBadResponse = ATOMIC_VAR_INIT(0);
std::atomic_size_t _totalDelay = ATOMIC_VAR_INIT(0);
trantor::Date _startDate;
trantor::Date _endDate;
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
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "Do stress testing(Use 'drogon_ctl help press' for more "
"information)";
}
virtual bool isTopCommand() override
bool isTopCommand() override
{
return true;
}
virtual std::string detail() override;
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;
size_t numOfThreads_{1};
size_t numOfRequests_{1};
size_t numOfConnections_{1};
std::string httpRequestJsonFile_;
std::function<HttpRequestPtr()> createHttpRequestFunc_;
bool certValidation_{true};
bool processIndication_{true};
std::string url_;
std::string host_;
std::string path_;
void doTesting();
void createRequestAndClients();
void sendRequest(const HttpClientPtr &client);
void outputResults();
std::unique_ptr<trantor::EventLoopThreadPool> _loopPool;
std::vector<HttpClientPtr> _clients;
Statistics _stat;
std::unique_ptr<trantor::EventLoopThreadPool> loopPool_;
std::vector<HttpClientPtr> clients_;
Statistics statistics_;
};
} // namespace drogon_ctl

View File

@ -1,56 +1,75 @@
cmake_minimum_required (VERSION 3.5)
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)
if(HAS_ANY AND HAS_STRING_VIEW)
check_include_file_cxx(coroutine HAS_COROUTINE)
if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "")
# Do nothing
elseif (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE)
set(CMAKE_CXX_STANDARD 20)
elseif (HAS_ANY AND HAS_STRING_VIEW)
set(CMAKE_CXX_STANDARD 17)
else()
else ()
set(CMAKE_CXX_STANDARD 14)
endif()
endif ()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable([[ProjectName]] main.cc)
add_executable(${PROJECT_NAME} main.cc)
##########
# If you include the drogon source code locally in your project, use this method to add drogon
# ##############################################################################
# If you include the drogon source code locally in your project, use this method
# to add drogon
# add_subdirectory(drogon)
# target_link_libraries([[ProjectName]] PRIVATE drogon)
##########
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
#
# and comment out the following lines
find_package(Drogon CONFIG REQUIRED)
target_link_libraries([[ProjectName]] PRIVATE Drogon::Drogon)
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([[ProjectName]] PRIVATE ${Boost_INCLUDE_DIRS})
else()
# ##############################################################################
if (CMAKE_CXX_STANDARD LESS 17)
message(FATAL_ERROR "c++17 or higher is required")
elseif (CMAKE_CXX_STANDARD LESS 20)
message(STATUS "use c++17")
endif()
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)
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp)
foreach(cspFile ${SCP_LIST})
message(STATUS "cspFile:" ${cspFile})
EXEC_PROGRAM(basename ARGS "${cspFile} .csp" OUTPUT_VARIABLE classname)
message(STATUS "view classname:" ${classname})
ADD_CUSTOM_COMMAND(OUTPUT ${classname}.h ${classname}.cc
COMMAND drogon_ctl
ARGS create view ${cspFile}
DEPENDS ${cspFile}
VERBATIM )
set(VIEWSRC ${VIEWSRC} ${classname}.cc)
endforeach()
drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
${CMAKE_CURRENT_BINARY_DIR})
# use the following line to create views with namespaces.
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
# ${CMAKE_CURRENT_BINARY_DIR} TRUE)
# use the following line to create views with namespace CHANGE_ME prefixed
# and path namespaces.
# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views
# ${CMAKE_CURRENT_BINARY_DIR} TRUE CHANGE_ME)
target_include_directories([[ProjectName]] PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
target_sources([[ProjectName]] PRIVATE ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC})
target_include_directories(${PROJECT_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/models)
target_sources(${PROJECT_NAME}
PRIVATE
${SRC_DIR}
${CTL_SRC}
${FILTER_SRC}
${PLUGIN_SRC}
${MODEL_SRC})
# ##############################################################################
# uncomment the following line for dynamically loading views
# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON)
# ##############################################################################
add_subdirectory(test)

View File

@ -0,0 +1,350 @@
/* This is a JSON format configuration file
*/
{
/*
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
"ssl": {
"cert": "../../trantor/trantor/tests/server.crt",
"key": "../../trantor/trantor/tests/server.key",
"conf": [
//["Options", "-SessionTicket"],
//["Options", "Compression"]
]
},
"listeners": [
{
//address: Ip address,0.0.0.0 by default
"address": "0.0.0.0",
//port: Port number
"port": 80,
//https: If true, use https for security,false by default
"https": false
},
{
"address": "0.0.0.0",
"port": 443,
"https": true,
//cert,key: Cert file path and key file path, empty by default,
//if empty, use the global setting
"cert": "",
"key": "",
//use_old_tls: enable the TLS1.0/1.1, false by default
"use_old_tls": false,
"ssl_conf": [
//["MinProtocol", "TLSv1.3"]
]
}
],
"db_clients": [
{
//name: Name of the client,'default' by default
"name": "default",
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
"rdbms": "postgresql",
//filename: Sqlite3 db file name
//"filename":"",
//host: Server address,localhost by default
"host": "127.0.0.1",
//port: Server port, 5432 by default
"port": 5432,
//dbname: Database name
"dbname": "test",
//user: 'postgres' by default
"user": "",
//passwd: '' by default
"passwd": "",
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//client_encoding: The character set used by the client. it is empty string by default which
//means use the default character set.
//"client_encoding": "",
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a SQL query.
//zero or negative value means no timeout.
"timeout": -1.0,
//auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
//the wiki for more details.
"auto_batch": false
//connect_options: extra options for the connection. Only works for PostgreSQL now.
//For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
//"connect_options": { "statement_timeout": "1s" }
}
],
"redis_clients": [
{
//name: Name of the client,'default' by default
"name": "default",
//host: Server IP, 127.0.0.1 by default
"host": "127.0.0.1",
//port: Server port, 6379 by default
"port": 6379,
//username: '' by default which means 'default' in redis ACL
"username": "",
//passwd: '' by default
"passwd": "",
//db index: 0 by default
"db": 0,
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"number_of_connections": 1,
//timeout: -1.0 by default, in seconds, the timeout for executing a command.
//zero or negative value means no timeout.
"timeout": -1.0
}
],*/
"app": {
//number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
//is the number of CPU cores
"number_of_threads": 1,
//enable_session: False by default
"enable_session": false,
"session_timeout": 0,
//string value of SameSite attribute of the Set-Cookie HTTP response header
//valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
"session_same_site" : "Null",
//session_cookie_key: The cookie key of the session, "JSESSIONID" by default
"session_cookie_key": "JSESSIONID",
//session_max_age: The max age of the session cookie, -1 by default
"session_max_age": -1,
//document_root: Root path of HTTP document, default path is ./
"document_root": "./",
//home_page: Set the HTML file of the home page, the default value is "index.html"
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
//to the request for "/".
"home_page": "index.html",
//use_implicit_page: enable implicit pages if true, true by default
"use_implicit_page": true,
//implicit_page: Set the file which would the server access in a directory that a user accessed.
//For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
"implicit_page": "index.html",
//static_file_headers: Headers for static files
/*"static_file_headers": [
{
"name": "field-name",
"value": "field-value"
}
],*/
//upload_path: The path to save the uploaded file. "uploads" by default.
//If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"upload_path": "uploads",
/* file_types:
* HTTP download file types,The file types supported by drogon
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
* "gif", "bmp", "ico", "icns", etc. */
"file_types": [
"gif",
"png",
"jpg",
"js",
"css",
"html",
"ico",
"swf",
"xap",
"apk",
"cur",
"xml",
"webp",
"svg"
],
// mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
// note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
"mime": {
// "text/markdown": "md",
// "text/gemini": ["gmi", "gemini"]
},
//locations: An array of locations of static files for GET requests.
"locations": [
{
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
//"uri_prefix": "/.well-known/acme-challenge/",
//default_content_type: The default content type of the static files without
//an extension. empty string by default.
"default_content_type": "text/plain",
//alias: The location in file system, if it is prefixed with "/", it
//presents an absolute path, otherwise it presents a relative path to
//the document_root path.
//The default value is "" which means use the document root path as the location base path.
"alias": "",
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
"is_case_sensitive": false,
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
"allow_all": true,
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
"is_recursive": true,
//filters: string array, the filters applied to the location.
"filters": []
}
],
//max_connections: maximum number of connections, 100000 by default
"max_connections": 100000,
//max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
"max_connections_per_ip": 0,
//Load_dynamic_views: False by default, when set to true, drogon
//compiles and loads dynamically "CSP View Files" in directories defined
//by "dynamic_views_path"
"load_dynamic_views": false,
//dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
"json_parser_stack_limit": 1000,
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
"enable_unicode_escaping_in_json": true,
//float_precision_in_json: set precision of float number in json.
"float_precision_in_json": {
//precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
"precision": 0,
//precision_type: must be "significant" or "decimal", defaults to "significant" that means
//setting max number of significant digits in string, "decimal" means setting max number of
//digits after "." in string
"precision_type": "significant"
},
//log: Set log output, drogon output logs to stdout by default
"log": {
//use_spdlog: Use spdlog library to log
"use_spdlog": false,
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
//"log_path": "./",
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
//drogon.log ...
"logfile_base_name": "",
//log_size_limit: 100000000 bytes by default,
//When the log file size reaches "log_size_limit", the log file is switched.
"log_size_limit": 100000000,
//max_files: 0 by default,
//When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
"max_files": 0,
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
//The TRACE level is only valid when built in DEBUG mode.
"log_level": "DEBUG",
//display_local_time: false by default, if true, the log time is displayed in local time
"display_local_time": false
},
//run_as_daemon: False by default
"run_as_daemon": false,
//handle_sig_term: True by default
"handle_sig_term": true,
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
"relaunch_on_error": false,
//use_sendfile: True by default, if true, the program
//uses sendfile() system-call to send static files to clients;
"use_sendfile": true,
//use_gzip: True by default, use gzip to compress the response body's content;
"use_gzip": true,
//use_brotli: False by default, use brotli to compress the response body's content;
"use_brotli": false,
//static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
//0 means cache forever, the negative value means no cache
"static_files_cache_time": 5,
//simple_controllers_map: Used to configure mapping from path to simple controller
//"simple_controllers_map": [
// {
// "path": "/path/name",
// "controller": "controllerClassName",
// "http_methods": [
// "get",
// "post"
// ],
// "filters": [
// "FilterClassName"
// ]
// }
//],
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
//of the connection without read or write
"idle_connection_timeout": 60,
//server_header_field: Set the 'Server' header field in each response sent by drogon,
//empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
"server_header_field": "",
//enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
//value is true.
"enable_server_header": true,
//enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
//value is true.
"enable_date_header": true,
//keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"keepalive_requests": 0,
//pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"pipelining_requests": 0,
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".gz" in the same path and send the compressed file to the client.
//The default value of gzip_static is true.
"gzip_static": true,
//br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".br" in the same path and send the compressed file to the client.
//The default value of br_static is true.
"br_static": true,
//client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_body_size": "1M",
//max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
//If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
//Setting it to "" means no limit.
"client_max_memory_body_size": "64K",
//client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_websocket_message_size": "128K",
//reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
"reuse_port": false,
// enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
// Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
// Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
// will be rejected.
"enabled_compressed_request": false,
// enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
// See the wiki for more details.
"enable_request_stream": false,
},
//plugins: Define all plugins running in the application
"plugins": [
{
//name: The class name of the plugin
"name": "drogon::plugin::PromExporter",
//dependencies: Plugins that the plugin depends on. It can be commented out
"dependencies": [],
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
//It can be commented out
"config": {
"path": "/metrics"
}
},
{
"name": "drogon::plugin::AccessLogger",
"dependencies": [],
"config": {
"use_spdlog": false,
"log_path": "",
"log_format": "",
"log_file": "access.log",
"log_size_limit": 0,
"use_local_time": true,
"log_index": 0,
// "show_microseconds": true,
// "custom_time_format": "",
// "use_real_ip": false
}
}
],
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
"custom_config": {}
}

View File

@ -0,0 +1,313 @@
# This is a YAML format configuration file
# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
# ssl:
# cert: ../../trantor/trantor/tests/server.crt
# key: ../../trantor/trantor/tests/server.key
# conf: [
# # [Options, -SessionTicket],
# # [Options, Compression]
# ]
# listeners:
# # address: Ip address,0.0.0.0 by default
# - address: 0.0.0.0
# # port: Port number
# port: 80
# # https: If true, use https for security,false by default
# https: false
# - address: 0.0.0.0
# port: 443
# https: true
# # cert,key: Cert file path and key file path, empty by default,
# # if empty, use the global setting
# cert: ''
# key: ''
# # use_old_tls: enable the TLS1.0/1.1, false by default
# use_old_tls: false
# ssl_conf: [
# # [MinProtocol, TLSv1.3]
# ]
# db_clients:
# # name: Name of the client,'default' by default
# - name: default
# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
# rdbms: postgresql
# # filename: Sqlite3 db file name
# # filename: ''
# # host: Server address,localhost by default
# host: 127.0.0.1
# # port: Server port, 5432 by default
# port: 5432
# # dbname: Database name
# dbname: test
# # user: 'postgres' by default
# user: ''
# # passwd: '' by default
# passwd: ''
# # is_fast: false by default, if it is true, the client is faster but user can't call
# # any synchronous interface of it.
# is_fast: false
# # client_encoding: The character set used by the client. it is empty string by default which
# # means use the default character set.
# # client_encoding: ''
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
# # connections per IO thread, otherwise it is the total number of all connections.
# number_of_connections: 1
# # timeout: -1 by default, in seconds, the timeout for executing a SQL query.
# # zero or negative value means no timeout.
# timeout: -1
# # auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see
# # the wiki for more details.
# auto_batch: false
# # connect_options: extra options for the connection. Only works for PostgreSQL now.
# # For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS
# # connect_options:
# # statement_timeout: '1s'
# redis_clients:
# # name: Name of the client,'default' by default
# - name: default
# # host: Server IP, 127.0.0.1 by default
# host: 127.0.0.1
# # port: Server port, 6379 by default
# port: 6379
# # username: '' by default which means 'default' in redis ACL
# username: ''
# # passwd: '' by default
# passwd: ''
# # db index: 0 by default
# db: 0
# # is_fast: false by default, if it is true, the client is faster but user can't call
# # any synchronous interface of it.
# is_fast: false
# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of
# # connections per IO thread, otherwise it is the total number of all connections.
# number_of_connections: 1
# # timeout: -1.0 by default, in seconds, the timeout for executing a command.
# # zero or negative value means no timeout.
# timeout: -1
app:
# number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
# is the number of CPU cores
number_of_threads: 1
# enable_session: False by default
enable_session: false
session_timeout: 0
# string value of SameSite attribute of the Set-Cookie HTTP response header
# valid value is either 'Null' (default), 'Lax', 'Strict' or 'None'
session_same_site: 'Null'
# session_cookie_key: The cookie key of the session, "JSESSIONID" by default
session_cookie_key: 'JSESSIONID'
# session_max_age: The max age of the session cookie, -1 by default
session_max_age: -1
# document_root: Root path of HTTP document, default path is ./
document_root: ./
# home_page: Set the HTML file of the home page, the default value is "index.html"
# If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
# to the request for "/".
home_page: index.html
# use_implicit_page: enable implicit pages if true, true by default
use_implicit_page: true
# implicit_page: Set the file which would the server access in a directory that a user accessed.
# For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html.
implicit_page: index.html
# static_file_headers: Headers for static files
# static_file_headers:
# - name: field-name
# value: field-value
# upload_path: The path to save the uploaded file. "uploads" by default.
# If the path isn't prefixed with /, ./ or ../,
# it is relative path of document_root path
upload_path: uploads
# file_types:
# HTTP download file types,The file types supported by drogon
# by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
# "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
# "gif", "bmp", "ico", "icns", etc.
file_types:
- gif
- png
- jpg
- js
- css
- html
- ico
- swf
- xap
- apk
- cur
- xml
# mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types
# note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them.
mime: {
# text/markdown: md
# text/gemini:
# - gmi
# - gemini
}
# locations: An array of locations of static files for GET requests.
locations:
# uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
- uri_prefix: '' # /.well-known/acme-challenge/
# default_content_type: The default content type of the static files without
# an extension. empty string by default.
default_content_type: text/plain
# alias: The location in file system, if it is prefixed with "/", it
# presents an absolute path, otherwise it presents a relative path to
# the document_root path.
# The default value is "" which means use the document root path as the location base path.
alias: ''
# is_case_sensitive: indicates whether the URI prefix is case sensitive.
is_case_sensitive: false
# allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
allow_all: true
# is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
is_recursive: true
# filters: string array, the filters applied to the location.
filters: []
# max_connections: maximum number of connections, 100000 by default
max_connections: 100000
# max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit
max_connections_per_ip: 0
# Load_dynamic_views: False by default, when set to true, drogon
# compiles and loads dynamically "CSP View Files" in directories defined
# by "dynamic_views_path"
load_dynamic_views: false
# dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
# it is relative path of document_root path
dynamic_views_path:
- ./views
# dynamic_views_output_path: Default by an empty string which means the output path of source
# files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
# path of the current working directory.
dynamic_views_output_path: ''
# json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library.
json_parser_stack_limit: 1000
# enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
enable_unicode_escaping_in_json: true
# float_precision_in_json: set precision of float number in json.
float_precision_in_json:
# precision: 0 by default, 0 means use the default precision of the jsoncpp lib.
precision: 0
# precision_type: must be "significant" or "decimal", defaults to "significant" that means
# setting max number of significant digits in string, "decimal" means setting max number of
# digits after "." in string
precision_type: significant
# log: Set log output, drogon output logs to stdout by default
log:
# use_spdlog: Use spdlog library to log
use_spdlog: false
# log_path: Log file path,empty by default,in which case,logs are output to the stdout
# log_path: ./
# logfile_base_name: Log file base name,empty by default which means drogon names logfile as
# drogon.log ...
logfile_base_name: ''
# log_size_limit: 100000000 bytes by default,
# When the log file size reaches "log_size_limit", the log file is switched.
log_size_limit: 100000000
# max_files: 0 by default,
# When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete.
max_files: 0
# log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
# The TRACE level is only valid when built in DEBUG mode.
log_level: DEBUG
# display_local_time: false by default, if true, the log time is displayed in local time
display_local_time: false
# run_as_daemon: False by default
run_as_daemon: false
# handle_sig_term: True by default
handle_sig_term: true
# relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
relaunch_on_error: false
# use_sendfile: True by default, if true, the program
# uses sendfile() system-call to send static files to clients;
use_sendfile: true
# use_gzip: True by default, use gzip to compress the response body's content;
use_gzip: true
# use_brotli: False by default, use brotli to compress the response body's content;
use_brotli: false
# static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
# 0 means cache forever, the negative value means no cache
static_files_cache_time: 5
# simple_controllers_map: Used to configure mapping from path to simple controller
# simple_controllers_map:
# - path: /path/name
# controller: controllerClassName
# http_methods:
# - get
# - post
# filters:
# - FilterClassName
# idle_connection_timeout: Defaults to 60 seconds, the lifetime
# of the connection without read or write
idle_connection_timeout: 60
# server_header_field: Set the 'Server' header field in each response sent by drogon,
# empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
server_header_field: ''
# enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
# value is true.
enable_server_header: true
# enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
# value is true.
enable_date_header: true
# keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
# After the maximum number of requests are made, the connection is closed.
# The default value of 0 means no limit.
keepalive_requests: 0
# pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
# After the maximum number of requests are made, the connection is closed.
# The default value of 0 means no limit.
pipelining_requests: 0
# gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
# file with the extension ".gz" in the same path and send the compressed file to the client.
# The default value of gzip_static is true.
gzip_static: true
# br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
# file with the extension ".br" in the same path and send the compressed file to the client.
# The default value of br_static is true.
br_static: true
# client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
client_max_body_size: 1M
# max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
# If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
# Setting it to "" means no limit.
client_max_memory_body_size: 64K
# client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
# One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
client_max_websocket_message_size: 128K
# reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time.
reuse_port: false
# enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies.
# Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests.
# Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request
# will be rejected.
enabled_compressed_request: false
# enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests.
# See the wiki for more details.
enable_request_stream: false
# plugins: Define all plugins running in the application
plugins:
# name: The class name of the plugin
- name: drogon::plugin::PromExporter
# dependencies: Plugins that the plugin depends on. It can be commented out
dependencies: []
# config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
# It can be commented out
config:
path: /metrics
- name: drogon::plugin::AccessLogger
dependencies: []
config:
use_spdlog: false
log_path: ''
log_format: ''
log_file: access.log
log_size_limit: 0
use_local_time: true
log_index: 0
# show_microseconds: true
# custom_time_format: ''
# use_real_ip: false
# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
custom_config: {}

View File

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

View File

@ -22,9 +22,9 @@ class [[className]] : public HttpFilter<[[className]]>
{
public:
[[className]]() {}
virtual void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) override;
void doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
FilterChainCallback &&fccb) override;
};
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>

View File

@ -1,20 +1,73 @@
# 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
# Compiled Object files
*.slo
*.lo
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
# 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
@ -22,15 +75,487 @@
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
build
cmake-build-debug
.idea
### 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

@ -14,23 +14,27 @@ using namespace drogon_ctl;
#include <drogon/orm/Field.h>
#include <drogon/orm/SqlBinder.h>
#include <drogon/orm/Mapper.h>
#include <drogon/orm/BaseBuilder.h>
#ifdef __cpp_impl_coroutine
#include <drogon/orm/CoroMapper.h>
#endif
#include <trantor/utils/Date.h>
#include <trantor/utils/Logger.h>
#include <json/json.h>
#include <string>
#include <string_view>
#include <memory>
#include <vector>
#include <tuple>
#include <stdint.h>
#include <iostream>
using namespace drogon::orm;
namespace drogon
{
namespace orm
{
class DbClient;
typedef std::shared_ptr<DbClient> DbClientPtr;
using DbClientPtr = std::shared_ptr<DbClient>;
}
}
namespace drogon_model
@ -39,27 +43,32 @@ namespace [[dbName]]
{
<%c++
auto &schema=@@.get<std::string>("schema");
if(!schema.empty())
{
$$<<"namespace "<<schema<<"\n";
$$<<"{\n";
}
auto &relationships=@@.get<std::vector<Relationship>>("relationships");
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);
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++
if(relationship.type() == Relationship::Type::ManyToMany)
{
auto &pivotTableName=relationship.pivotTable().tableName();
auto pivotTableClassName=nameTransform(pivotTableName, true);
%>
class {%pivotTableClassName%};
<%c++
}
}
%>
@ -72,21 +81,21 @@ class [[className]]
auto cols=@@.get<std::vector<ColumnInfo>>("columns");
for(size_t i=0;i<cols.size();i++)
{
$$<<" static const std::string _"<<cols[i]._colName<<";\n";
$$<<" static const std::string _"<<cols[i].colName_<<";\n";
}
%>
};
const static int primaryKeyNumber;
const static std::string tableName;
const static bool hasPrimaryKey;
static const int primaryKeyNumber;
static const std::string tableName;
static const bool hasPrimaryKey;
<%c++if(@@.get<int>("hasPrimaryKey")<=1){%>
const static std::string primaryKeyName;
static const std::string primaryKeyName;
<%c++if(!@@.get<std::string>("primaryKeyType").empty()){%>
typedef [[primaryKeyType]] PrimaryKeyType;
using PrimaryKeyType = [[primaryKeyType]];
const PrimaryKeyType &getPrimaryKey() const;
<%c++}else{%>
typedef void PrimaryKeyType;
using PrimaryKeyType = void;
int getPrimaryKey() const { assert(false); return 0; }
<%c++}%>
<%c++}else{
@ -99,8 +108,8 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
typelist += ",";
}
%>
const static std::vector<std::string> primaryKeyName;
typedef std::tuple<{%typelist%}> PrimaryKeyType;//<%c++
static const 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++)
{
@ -121,7 +130,7 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
* @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;
explicit [[className]](const drogon::orm::Row &r, const ssize_t indexOffset = 0) noexcept;
/**
* @brief constructor
@ -158,36 +167,35 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
<%c++
for(const auto &col:cols)
{
$$<<" /** For column "<<col._colName<<" */\n";
if(!col._colType.empty())
$$<<" /** 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>")
$$<<" ///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";
$$<<" 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";
if(!col._isAutoVal)
{
$$<<" ///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>")
$$<<" 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";
$$<<" void set"<<col.colTypeName_<<"(const std::string &p"<<col.colTypeName_<<") noexcept;\n";
}
if(!col._notNull)
if(!col.notNull_)
{
$$<<" void set"<<col._colTypeName<<"ToNull() noexcept;\n";
$$<<" void set"<<col.colTypeName_<<"ToNull() noexcept;\n";
}
}
}
else
$$<<" //FIXME!!"<<" getValueOf"<<col._colTypeName<<"() const noexcept;\n";
$$<<" //FIXME!!"<<" getValueOf"<<col.colTypeName_<<"() const noexcept;\n";
$$<<"\n";
}
%>
@ -220,18 +228,20 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
{%relationshipClassName%} get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
{%alind%} const std::function<void({%relationshipClassName%})> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
{%relationshipClassName%} get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void({%relationshipClassName%})> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
}
@ -245,18 +255,20 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
std::vector<{%relationshipClassName%}> get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
{%alind%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
std::vector<{%relationshipClassName%}> get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void(std::vector<{%relationshipClassName%}>)> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
}
@ -272,25 +284,34 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
}
std::string alind(alias.length(), ' ');
%>
void get{%alias%}(const DbClientPtr &clientPtr,
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> get{%alias%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%alias%}(const drogon::orm::DbClientPtr &clientPtr,
{%alind%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
{%alind%} const ExceptionCallback &ecb) const;
{%alind%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
else
{
std::string relationshipClassInde(relationshipClassName.length(), ' ');
%>
void get{%relationshipClassName%}(const DbClientPtr &clientPtr,
std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>> get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr) const;
void get{%relationshipClassName%}(const drogon::orm::DbClientPtr &clientPtr,
{%relationshipClassInde%} const std::function<void(std::vector<std::pair<{%relationshipClassName%},{%pivotTableClassName%}>>)> &rcb,
{%relationshipClassInde%} const ExceptionCallback &ecb) const;
{%relationshipClassInde%} const drogon::orm::ExceptionCallback &ecb) const;
<%c++
}
}
}
%>
private:
friend Mapper<[[className]]>;
friend drogon::orm::Mapper<[[className]]>;
friend drogon::orm::BaseBuilder<[[className]], true, true>;
friend drogon::orm::BaseBuilder<[[className]], true, false>;
friend drogon::orm::BaseBuilder<[[className]], false, true>;
friend drogon::orm::BaseBuilder<[[className]], false, false>;
#ifdef __cpp_impl_coroutine
friend drogon::orm::CoroMapper<[[className]]>;
#endif
static const std::vector<std::string> &insertColumns() noexcept;
void outputArgs(drogon::orm::internal::SqlBinder &binder) const;
const std::vector<std::string> updateColumns() const;
@ -300,22 +321,22 @@ auto cols=@@.get<std::vector<ColumnInfo>>("columns");
<%c++
for(auto col:cols)
{
if(!col._colType.empty())
$$<<" std::shared_ptr<"<<col._colType<<"> _"<<col._colValName<<";\n";
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;
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 };
static const std::vector<MetaData> metaData_;
bool dirtyFlag_[{%cols.size()%}]={ false };
public:
static const std::string &sqlForFindingByPrimaryKey()
{
@ -390,26 +411,43 @@ if(@@.get<int>("hasPrimaryKey")<=1){
bool selFlag=false;
for(size_t i=0;i<cols.size();i++)
{
if(cols[i]._isAutoVal)
if(cols[i].isAutoVal_)
{
if(@@.get<std::string>("rdbms")=="sqlite3")
{
continue;
}
if(@@.get<int>("hasPrimaryKey")>0)
{
selFlag = true;
}
$$<<" sql += \""<<cols[i]._colName<<",\";\n";
$$<<" sql += \""<<cols[i].colName_<<",\";\n";
$$<<" ++parametersCount;\n";
continue;
}
if(cols[i]._colType.empty())
if(cols[i].colType_.empty())
continue;
if(cols[i]._hasDefaultVal)
if(cols[i].hasDefaultVal_)
{
$$<<" sql += \""<<cols[i]._colName<<",\";\n";
$$<<" ++parametersCount;\n";
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%}])
if(!dirtyFlag_[{%i%}])
{
needSelection=true;
}
@ -419,9 +457,9 @@ if(@@.get<int>("hasPrimaryKey")<=1){
else
{
%>
if(_dirtyFlag[{%i%}])
if(dirtyFlag_[{%i%}])
{
sql += "{%cols[i]._colName%},";
sql += "{%cols[i].colName_%},";
++parametersCount;
}
<%c++
@ -451,23 +489,26 @@ if(@@.get<std::string>("rdbms")=="postgresql")
}
for(size_t i=0;i<cols.size();i++)
{
if(cols[i]._isAutoVal)
if(cols[i].isAutoVal_)
{
if(@@.get<std::string>("rdbms")!="sqlite3")
{
%>
sql +="default,";
<%c++
}
continue;
}
if(cols[i]._colType.empty())
if(cols[i].colType_.empty())
continue;
%>
if(_dirtyFlag[{%i%}])
if(dirtyFlag_[{%i%}])
{
<%c++
if(@@.get<std::string>("rdbms")=="postgresql")
{
%>
n = sprintf(placeholderStr,"$%d,",placeholder++);
n = snprintf(placeholderStr,sizeof(placeholderStr),"$%d,",placeholder++);
sql.append(placeholderStr, n);
<%c++
}else
@ -480,7 +521,7 @@ if(@@.get<std::string>("rdbms")=="postgresql")
%>
}
<%c++
if(cols[i]._hasDefaultVal)
if(cols[i].hasDefaultVal_&&@@.get<std::string>("rdbms")!="sqlite3")
{
%>
else

View File

@ -13,10 +13,31 @@
"schema": "public",
//user: User name
"user": "",
//password: Password
"passwd": "",
//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": [{

View File

@ -23,11 +23,11 @@ class [[className]] : public drogon::Plugin<[[className]]>
[[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;
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;
void shutdown() override;
};
<%c++for(size_t i=0;i<namespaceVector.size();i++){%>

View File

@ -451,17 +451,17 @@ void [[className]]Base::update(const HttpRequestPtr &req,
<%c++
tableInfo = @@.get<DrTemplateData>("tableInfo");
const auto &cols=tableInfo.get<std::vector<ColumnInfo>>("columns");
for(size_t i=0; i<cols.size(); i++)
for(size_t i=0; i<cols.size(); ++i)
{
auto &col = cols[i];
if(i < (cols.size()-1))
{
%>
"{%col._colName%}",
"{%col.colName_%}",
<%c++
}else{
%>
"{%col._colName%}"
"{%col.colName_%}"
<%c++
}
}
@ -475,17 +475,17 @@ for(size_t i=0; i<cols.size(); i++)
*/
enableMasquerading({
<%c++
for(size_t i=0; i<cols.size(); i++)
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.
"{%col.colName_%}", // the alias for the {%col.colName_%} column.
<%c++
}else{
%>
"{%col._colName%}" // the alias for the {%col._colName%} column.
"{%col.colName_%}" // the alias for the {%col.colName_%} column.
<%c++
}
}

View File

@ -19,6 +19,7 @@ auto modelName = tableInfo.get<std::string>("className");
$$<<"#include \""<<modelName<<".h\"\n";
bool hasPrimaryKey = (tableInfo.get<int>("hasPrimaryKey")==1);
$$<<"using namespace drogon;\n";
$$<<"using namespace drogon::orm;\n";
$$<<"using namespace drogon_model::"<<tableInfo.get<std::string>("dbName");
auto &schema=tableInfo.get<std::string>("schema");
@ -71,13 +72,13 @@ class [[className]]Base : public RestfulController
orm::DbClientPtr getDbClient()
{
return drogon::app().get{%(@@.get<bool>("isFastDbClient")?"Fast":"")%}DbClient(_dbClientName);
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]]";
const std::string dbClientName_{"[[dbClientName]]"};
};
<%c++ for(size_t i=0;i<namespaceVector.size();++i)
{

View File

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.5)
project([[ProjectName]]_test CXX)
add_executable(${PROJECT_NAME} test_main.cc)
# ##############################################################################
# If you include the drogon source code locally in your project, use this method
# to add drogon
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
#
# and comment out the following lines
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
ParseAndAddDrogonTests(${PROJECT_NAME})

View File

@ -0,0 +1,32 @@
#define DROGON_TEST_MAIN
#include <drogon/drogon_test.h>
#include <drogon/drogon.h>
DROGON_TEST(BasicTest)
{
// Add your tests here
}
int main(int argc, char** argv)
{
using namespace drogon;
std::promise<void> p1;
std::future<void> f1 = p1.get_future();
// Start the main loop on another thread
std::thread thr([&]() {
// Queues the promise to be fulfilled after starting the loop
app().getLoop()->queueInLoop([&p1]() { p1.set_value(); });
app().run();
});
// The future is only satisfied after the event loop started
f1.get();
int status = test::run(argc, argv);
// Ask the event loop to shutdown and wait
app().getLoop()->queueInLoop([]() { app().quit(); });
thr.join();
return status;
}

View File

@ -15,23 +15,54 @@
#include "version.h"
#include <drogon/config.h>
#include <drogon/version.h>
#include <drogon/utils/Utilities.h>
#include <trantor/net/Resolver.h>
#include <trantor/utils/Utilities.h>
#include <iostream>
using namespace drogon_ctl;
static const char banner[] =
" _ \n"
" __| |_ __ ___ __ _ ___ _ __ \n"
" / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n"
"| (_| | | | (_) | (_| | (_) | | | |\n"
" \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n"
" |___/ \n";
R"( _
__| |_ __ ___ __ _ ___ _ __
/ _` | '__/ _ \ / _` |/ _ \| '_ \
| (_| | | | (_) | (_| | (_) | | | |
\__,_|_| \___/ \__, |\___/|_| |_|
|___/
)";
void version::handleCommand(std::vector<std::string> &parameters)
{
const auto tlsBackend = trantor::utils::tlsBackend();
const bool tlsSupported = drogon::utils::supportsTls();
std::cout << banner << std::endl;
std::cout << "A utility for drogon" << std::endl;
std::cout << "Version:" << VERSION << std::endl;
std::cout << "Git commit:" << VERSION_MD5 << std::endl;
std::cout << "Compile config:" << COMPILATION_FLAGS << " " << INCLUDING_DIRS
<< std::endl;
std::cout << "Version: " << DROGON_VERSION << std::endl;
std::cout << "Git commit: " << DROGON_VERSION_SHA1 << std::endl;
std::cout << "Compilation: \n Compiler: " << COMPILER_COMMAND
<< "\n Compiler ID: " << COMPILER_ID
<< "\n Compilation flags: " << COMPILATION_FLAGS
<< INCLUDING_DIRS << std::endl;
std::cout << "Libraries: \n postgresql: "
<< (USE_POSTGRESQL ? "yes" : "no") << " (pipeline mode: "
<< (LIBPQ_SUPPORTS_BATCH_MODE ? "yes)\n" : "no)\n")
<< " mariadb: " << (USE_MYSQL ? "yes\n" : "no\n")
<< " sqlite3: " << (USE_SQLITE3 ? "yes\n" : "no\n");
std::cout << " ssl/tls backend: " << tlsBackend << "\n";
#ifdef USE_BROTLI
std::cout << " brotli: yes\n";
#else
std::cout << " brotli: no\n";
#endif
#ifdef USE_REDIS
std::cout << " hiredis: yes\n";
#else
std::cout << " hiredis: no\n";
#endif
std::cout << " c-ares: "
<< (trantor::Resolver::isCAresUsed() ? "yes\n" : "no\n");
#ifdef HAS_YAML_CPP
std::cout << " yaml-cpp: yes\n";
#else
std::cout << " yaml-cpp: no\n";
#endif
}

View File

@ -17,20 +17,24 @@
#include <drogon/DrObject.h>
#include "CommandHandler.h"
using namespace drogon;
namespace drogon_ctl
{
class version : public DrObject<version>, public CommandHandler
{
public:
virtual void handleCommand(std::vector<std::string> &parameters) override;
virtual std::string script() override
void handleCommand(std::vector<std::string> &parameters) override;
std::string script() override
{
return "display version of this tool";
}
virtual bool isTopCommand() override
bool isTopCommand() override
{
return true;
}
version()
{
}

View File

@ -1,84 +1,62 @@
link_libraries(${PROJECT_NAME})
file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/simple_example/*.csp)
foreach(cspFile ${SCP_LIST})
message(STATUS "cspFile:" ${cspFile})
exec_program(basename
ARGS
"${cspFile} .csp"
OUTPUT_VARIABLE
classname)
message(STATUS "view classname:" ${classname})
add_custom_command(OUTPUT ${classname}.h ${classname}.cc
COMMAND drogon_ctl
ARGS
create
view
${cspFile}
DEPENDS ${cspFile}
VERBATIM)
set(VIEWSRC ${VIEWSRC} ${classname}.cc)
endforeach()
set(simple_example_sources
simple_example/CustomCtrl.cc
simple_example/CustomHeaderFilter.cc
simple_example/DoNothingPlugin.cc
simple_example/ForwardCtrl.cc
simple_example/JsonTestController.cc
simple_example/ListParaCtl.cc
simple_example/PipeliningTest.cc
simple_example/TestController.cc
simple_example/TestPlugin.cc
simple_example/TestViewCtl.cc
simple_example/WebSocketTest.cc
simple_example/api_Attachment.cc
simple_example/api_v1_ApiTest.cc
simple_example/TimeFilter.cc
simple_example/main.cc)
add_executable(webapp ${simple_example_sources} ${VIEWSRC})
add_dependencies(webapp drogon_ctl)
set(client_example_sources client_example/main.cc)
set(benchmark_sources benchmark/BenchmarkCtrl.cc benchmark/JsonCtrl.cc
benchmark/main.cc)
# AUX_SOURCE_DIRECTORY(simple_example_test DIR_TEST)
add_executable(client ${client_example_sources})
add_executable(client client_example/main.cc)
add_executable(websocket_client websocket_client/WebSocketClient.cc)
add_executable(websocket_server websocket_server/WebSocketServer.cc)
add_executable(benchmark ${benchmark_sources})
add_executable(webapp_test simple_example_test/main.cc)
add_executable(pipelining_test simple_example_test/HttpPipeliningTest.cc)
add_executable(websocket_test simple_example_test/WebSocketTest.cc)
add_executable(multiple_ws_test simple_example_test/MultipleWsTest.cc)
add_executable(helloworld helloworld/main.cc
helloworld/HelloController.cc
helloworld/HelloViewController.cc)
drogon_create_views(helloworld
${CMAKE_CURRENT_SOURCE_DIR}/helloworld
${CMAKE_CURRENT_BINARY_DIR})
add_executable(file_upload file_upload/file_upload.cc)
drogon_create_views(file_upload
${CMAKE_CURRENT_SOURCE_DIR}/file_upload
${CMAKE_CURRENT_BINARY_DIR})
add_executable(login_session login_session/main.cc)
drogon_create_views(login_session
${CMAKE_CURRENT_SOURCE_DIR}/login_session
${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(TARGET webapp POST_BUILD
COMMAND gzip
ARGS
-c
${CMAKE_CURRENT_SOURCE_DIR}/simple_example/index.html
>
${CMAKE_CURRENT_BINARY_DIR}/index.html.gz
VERBATIM)
add_custom_command(
TARGET webapp POST_BUILD
COMMAND ${CMAKE_COMMAND}
-E
copy_if_different
${PROJECT_SOURCE_DIR}/config.example.json
${PROJECT_SOURCE_DIR}/drogon.jpg
${CMAKE_CURRENT_SOURCE_DIR}/simple_example/index.html
${PROJECT_SOURCE_DIR}/trantor/trantor/tests/server.pem
$<TARGET_FILE_DIR:webapp>)
add_executable(jsonstore jsonstore/main.cc)
add_executable(redis_simple redis/main.cc
redis/controllers/Client.cc
redis/controllers/WsClient.cc)
add_executable(redis_chat redis_chat/main.cc
redis_chat/controllers/Chat.cc)
add_executable(async_stream async_stream/main.cc
async_stream/RequestStreamExampleCtrl.cc)
add_executable(cors cors/main.cc)
set(example_targets
webapp
webapp_test
client
benchmark
pipelining_test
websocket_test
multiple_ws_test)
client
websocket_client
websocket_server
helloworld
file_upload
login_session
jsonstore
redis_simple
redis_chat
async_stream
cors)
# Add warnings for our example targets--some warnings (such as -Wunused-parameter) only appear
# when the templated functions are instantiated at their point of use.
if(NOT ${CMAKE_PLATFORM_NAME} STREQUAL "Windows" AND CMAKE_CXX_COMPILER_ID MATCHES GNU)
foreach(target ${example_targets})
target_compile_options(${target} PRIVATE -Wall -Wextra -Werror)
endforeach()
endif()
set_property(TARGET ${example_targets}
PROPERTY CXX_STANDARD ${DROGON_CXX_STANDARD})

View File

@ -2,10 +2,21 @@
The following examples can help you understand how to use Drogon:
1. [benchmark](https://github.com/an-tao/drogon/tree/master/examples/benchmark) - Basic benchmark example. see [wiki benchmarks](https://github.com/an-tao/drogon/wiki/13-Benchmarks)
2. [client_example](https://github.com/an-tao/drogon/tree/master/examples/client_example/main.cc) - A client example.
3. [simple_example](https://github.com/an-tao/drogon/tree/master/examples/simple_example) - A simple example showing how to create a web application using Drogon.
4. [simple_example_test](https://github.com/an-tao/drogon/tree/master/examples/simple_example_test) - Some tests for the `simple_example`.
1. [helloworld](https://github.com/drogonframework/drogon/tree/master/examples/helloworld) - The multiple ways of "Hello, World!"
2. [client_example](https://github.com/drogonframework/drogon/tree/master/examples/client_example/main.cc) - A client example
3. [websocket_client](https://github.com/drogonframework/drogon/tree/master/examples/websocket_client/WebSocketClient.cc) - An example on how to use the WebSocket client
4. [login_session](https://github.com/drogonframework/drogon/tree/master/examples/login_session) - How to use the built-in session system to handle login and out
5. [file_upload](https://github.com/drogonframework/drogon/tree/master/examples/file_upload) - How to handle file uploads in Drogon
6. [simple_reverse_proxy](https://github.com/drogonframework/drogon/tree/master/examples/simple_reverse_proxy) - An example showing how to use Drogon as a HTTP reverse
proxy with a simple round robin
7. [benchmark](https://github.com/drogonframework/drogon/tree/master/examples/benchmark) - Basic benchmark(https://github.com/drogonframework/drogon/wiki/13-Benchmarks) example
8. [jsonstore](https://github.com/drogonframework/drogon/tree/master/examples/jsonstore) - Implementation of a [jsonstore](https://github.com/bluzi/jsonstore)-like storage service that is concurrent and stores in memory. Serving as a showcase on how to build a minimally useful RESTful APIs in Drogon
9. [redis](https://github.com/drogonframework/drogon/tree/master/examples/redis) - A simple example of Redis
10. [websocket_server](https://github.com/drogonframework/drogon/tree/master/examples/websocket_server) - A example websocket chat room server
11. [redis_cache](https://github.com/drogonframework/drogon/tree/master/examples/redis_cache) - An example for using coroutines of Redis clients
12. [redis_chat](https://github.com/drogonframework/drogon/tree/master/examples/redis_chat) - A chatroom server built with websocket and Redis pub/sub service
13. [prometheus_example](https://github.com/drogonframework/drogon/tree/master/examples/prometheus_example) - An example of how to use the Prometheus exporter in Drogon
14. [cors](https://github.com/drogonframework/drogon/tree/master/examples/cors) - An example demonstrating how to implement CORS (Cross-Origin Resource Sharing) support in Drogon
### [TechEmpower Framework Benchmarks](https://github.com/TechEmpower/FrameworkBenchmarks) test suite
@ -13,4 +24,4 @@ I created a benchmark suite for the `tfb`, see [here](https://github.com/TechEmp
### Another test suite
I also created a test suite for another web frameworks benchmark repository, see [here](https://github.com/the-benchmarker/web-frameworks/tree/master/cpp/drogon), in this project, drogon is used as a sub-module (locally include in the project).
I also created a test suite for another web frameworks benchmark repository, see [here](https://github.com/the-benchmarker/web-frameworks/tree/master/cpp/drogon). In this project, Drogon is used as a sub-module (locally include in the project).

View File

@ -0,0 +1,167 @@
#include <drogon/drogon.h>
#include <drogon/HttpController.h>
#include <drogon/HttpRequest.h>
#include <fstream>
using namespace drogon;
class StreamEchoReader : public RequestStreamReader
{
public:
StreamEchoReader(ResponseStreamPtr respStream)
: respStream_(std::move(respStream))
{
}
void onStreamData(const char *data, size_t length) override
{
LOG_INFO << "onStreamData[" << length << "]";
respStream_->send({data, length});
}
void onStreamFinish(std::exception_ptr ptr) override
{
if (ptr)
{
try
{
std::rethrow_exception(ptr);
}
catch (const std::exception &e)
{
LOG_ERROR << "onStreamError: " << e.what();
}
}
else
{
LOG_INFO << "onStreamFinish";
}
respStream_->close();
}
private:
ResponseStreamPtr respStream_;
};
class RequestStreamExampleCtrl : public HttpController<RequestStreamExampleCtrl>
{
public:
METHOD_LIST_BEGIN
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_echo, "/stream_echo", Post);
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_upload,
"/stream_upload",
Post);
METHOD_LIST_END
void stream_echo(
const HttpRequestPtr &,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) const
{
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
[stream](ResponseStreamPtr respStream) {
stream->setStreamReader(
std::make_shared<StreamEchoReader>(std::move(respStream)));
});
callback(resp);
}
void stream_upload(
const HttpRequestPtr &req,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) const
{
struct Entry
{
MultipartHeader header;
std::string tmpName;
std::ofstream file;
};
auto files = std::make_shared<std::vector<Entry>>();
auto reader = RequestStreamReader::newMultipartReader(
req,
[files](MultipartHeader &&header) {
LOG_INFO << "Multipart name: " << header.name
<< ", filename:" << header.filename
<< ", contentType:" << header.contentType;
files->push_back({std::move(header)});
auto tmpName = drogon::utils::genRandomString(40);
if (!files->back().header.filename.empty())
{
files->back().tmpName = tmpName;
files->back().file.open("uploads/" + tmpName,
std::ios::trunc);
}
},
[files](const char *data, size_t length) {
if (files->back().tmpName.empty())
{
return;
}
auto &currentFile = files->back().file;
if (length == 0)
{
LOG_INFO << "file finish";
if (currentFile.is_open())
{
currentFile.flush();
currentFile.close();
}
return;
}
LOG_INFO << "data[" << length << "]: ";
if (currentFile.is_open())
{
LOG_INFO << "write file";
currentFile.write(data, length);
}
else
{
LOG_ERROR << "file not open";
}
},
[files, callback = std::move(callback)](std::exception_ptr ex) {
if (ex)
{
try
{
std::rethrow_exception(std::move(ex));
}
catch (const StreamError &e)
{
LOG_ERROR << "stream error: " << e.what();
}
catch (const std::exception &e)
{
LOG_ERROR << "multipart error: " << e.what();
}
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
resp->setBody("error\n");
callback(resp);
}
else
{
LOG_INFO << "stream finish, received " << files->size()
<< " files";
Json::Value respJson;
for (const auto &item : *files)
{
if (item.tmpName.empty())
continue;
Json::Value entry;
entry["name"] = item.header.name;
entry["filename"] = item.header.filename;
entry["tmpName"] = item.tmpName;
respJson.append(entry);
}
auto resp = HttpResponse::newHttpJsonResponse(respJson);
callback(resp);
}
});
stream->setStreamReader(std::move(reader));
}
};

View File

@ -0,0 +1,113 @@
#include <drogon/drogon.h>
#include <chrono>
#include <functional>
#include <mutex>
#include <unordered_map>
#include <trantor/utils/Logger.h>
#include <trantor/net/callbacks.h>
#include <trantor/net/TcpConnection.h>
using namespace drogon;
using namespace std::chrono_literals;
std::mutex mutex;
std::unordered_map<trantor::TcpConnectionPtr, std::function<void()>>
connMapping;
int main()
{
app().registerHandler(
"/stream",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
const auto &weakConnPtr = req->getConnectionPtr();
if (auto connPtr = weakConnPtr.lock())
{
std::lock_guard lk(mutex);
connMapping.emplace(std::move(connPtr), [] {
LOG_INFO << "call stop or other options!!!!";
});
}
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
[](drogon::ResponseStreamPtr stream) {
std::thread([stream =
std::shared_ptr<drogon::ResponseStream>{
std::move(stream)}]() mutable {
std::cout << std::boolalpha << stream->send("hello ")
<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << std::boolalpha << stream->send("world");
std::this_thread::sleep_for(std::chrono::seconds(2));
stream->close();
}).detach();
});
resp->setContentTypeCodeAndCustomString(
ContentType::CT_APPLICATION_JSON, "application/json");
callback(resp);
});
// Example: register a stream-mode function handler
app().registerHandler(
"/stream_req",
[](const HttpRequestPtr &req,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) {
if (!stream)
{
LOG_INFO << "stream mode is not enabled";
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
resp->setBody("no stream");
callback(resp);
return;
}
auto reader = RequestStreamReader::newReader(
[](const char *data, size_t length) {
LOG_INFO << "piece[" << length
<< "]: " << std::string_view{data, length};
},
[callback = std::move(callback)](std::exception_ptr ex) {
auto resp = HttpResponse::newHttpResponse();
if (ex)
{
try
{
std::rethrow_exception(std::move(ex));
}
catch (const std::exception &e)
{
LOG_ERROR << "stream error: " << e.what();
}
resp->setStatusCode(k400BadRequest);
resp->setBody("error\n");
callback(resp);
}
else
{
LOG_INFO << "stream finish";
resp->setBody("success\n");
callback(resp);
}
});
stream->setStreamReader(std::move(reader));
},
{Post});
LOG_INFO << "Server running on 127.0.0.1:8848";
app().enableRequestStream(); // This is for request stream.
app().setConnectionCallback([](const trantor::TcpConnectionPtr &conn) {
if (conn->disconnected())
{
std::lock_guard lk(mutex);
if (auto it = connMapping.find(conn); it != connMapping.end())
{
LOG_INFO << "disconnect";
connMapping[conn]();
connMapping.erase(conn);
}
}
});
app().addListener("127.0.0.1", 8848).run();
}

View File

@ -1,6 +1,7 @@
#include "BenchmarkCtrl.h"
void BenchmarkCtrl::asyncHandleHttpRequest(
const HttpRequestPtr &req,
const HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
// write your application logic here

View File

@ -1,10 +1,11 @@
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class BenchmarkCtrl : public drogon::HttpSimpleController<BenchmarkCtrl>
{
public:
virtual void asyncHandleHttpRequest(
void asyncHandleHttpRequest(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN

View File

@ -1,10 +1,11 @@
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(
const HttpRequestPtr &req,
const HttpRequestPtr &,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["message"] = "Hello, World!";
auto resp = HttpResponse::newHttpJsonResponse(ret);
auto resp = HttpResponse::newHttpJsonResponse(std::move(ret));
callback(resp);
}

View File

@ -1,10 +1,11 @@
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
public:
virtual void asyncHandleHttpRequest(
void asyncHandleHttpRequest(
const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) override;
PATH_LIST_BEGIN

View File

@ -1,16 +1,23 @@
#include <drogon/drogon.h>
using namespace drogon;
int main()
{
app().setLogPath("./");
app().setLogLevel(trantor::Logger::WARN);
app().addListener("0.0.0.0", 7770);
app().setThreadNum(16);
app().enableRunAsDaemon();
// app().enableRelaunchOnError();
// app().loop()->runEvery(1, []() {
// LOG_WARN << "HAHA";
// });
app().run();
app()
.setLogPath("./")
.setLogLevel(trantor::Logger::kWarn)
.addListener("0.0.0.0", 7770)
.setThreadNum(0)
.registerSyncAdvice([](const HttpRequestPtr &req) -> HttpResponsePtr {
const auto &path = req->path();
if (path.length() == 1 && path[0] == '/')
{
auto response = HttpResponse::newHttpResponse();
response->setBody("<p>Hello, world!</p>");
return response;
}
return nullptr;
})
.run();
}

View File

@ -1,28 +1,65 @@
#include <drogon/drogon.h>
#include <iostream>
#include <future>
#include <iostream>
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/tcp.h>
#endif
using namespace drogon;
int nth_resp = 0;
int main()
{
trantor::Logger::setLogLevel(trantor::Logger::TRACE);
trantor::Logger::setLogLevel(trantor::Logger::kTrace);
{
int count = 0;
auto client = HttpClient::newHttpClient("http://www.baidu.com");
client->setSockOptCallback([](int fd) {
std::cout << "setSockOptCallback:" << fd << std::endl;
#ifdef __linux__
int optval = 10;
::setsockopt(fd,
SOL_TCP,
TCP_KEEPCNT,
&optval,
static_cast<socklen_t>(sizeof optval));
::setsockopt(fd,
SOL_TCP,
TCP_KEEPIDLE,
&optval,
static_cast<socklen_t>(sizeof optval));
::setsockopt(fd,
SOL_TCP,
TCP_KEEPINTVL,
&optval,
static_cast<socklen_t>(sizeof optval));
#endif
});
auto req = HttpRequest::newHttpRequest();
req->setMethod(drogon::Get);
req->setPath("/s");
req->setParameter("wd", "weixin");
req->setParameter("wd", "wx");
req->setParameter("oq", "wx");
for (int i = 0; i < 10; i++)
for (int i = 0; i < 10; ++i)
{
client->sendRequest(
req,
[&count](ReqResult result, const HttpResponsePtr &response) {
req, [](ReqResult result, const HttpResponsePtr &response) {
if (result != ReqResult::Ok)
{
std::cout
<< "error while sending request to server! result: "
<< result << std::endl;
return;
}
std::cout << "receive response!" << std::endl;
// auto headers=response.
count++;
++nth_resp;
std::cout << response->getBody() << std::endl;
auto cookies = response->cookies();
for (auto const &cookie : cookies)
@ -32,9 +69,11 @@ int main()
<< ":domain=" << cookie.second.domain()
<< std::endl;
}
std::cout << "count=" << count << std::endl;
std::cout << "count=" << nth_resp << std::endl;
});
}
std::cout << "requestsBufferSize:" << client->requestsBufferSize()
<< std::endl;
}
app().run();

153
examples/cors/main.cc Normal file
View File

@ -0,0 +1,153 @@
#include <drogon/HttpAppFramework.h>
#include <drogon/HttpResponse.h>
#include <drogon/drogon.h>
#include "trantor/utils/Logger.h"
using namespace drogon;
/// Configure Cross-Origin Resource Sharing (CORS) support.
///
/// This function registers both synchronous pre-processing advice for handling
/// OPTIONS preflight requests and post-handling advice to inject CORS headers
/// into all responses dynamically based on the incoming request headers.
void setupCors()
{
// Register sync advice to handle CORS preflight (OPTIONS) requests
drogon::app().registerSyncAdvice([](const drogon::HttpRequestPtr &req)
-> drogon::HttpResponsePtr {
if (req->method() == drogon::HttpMethod::Options)
{
auto resp = drogon::HttpResponse::newHttpResponse();
// Set Access-Control-Allow-Origin header based on the Origin
// request header
const auto &origin = req->getHeader("Origin");
if (!origin.empty())
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
// Set Access-Control-Allow-Methods based on the requested method
const auto &requestMethod =
req->getHeader("Access-Control-Request-Method");
if (!requestMethod.empty())
{
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
}
// Allow credentials to be included in cross-origin requests
resp->addHeader("Access-Control-Allow-Credentials", "true");
// Set allowed headers from the Access-Control-Request-Headers
// header
const auto &requestHeaders =
req->getHeader("Access-Control-Request-Headers");
if (!requestHeaders.empty())
{
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
}
return std::move(resp);
}
return {};
});
// Register post-handling advice to add CORS headers to all responses
drogon::app().registerPostHandlingAdvice(
[](const drogon::HttpRequestPtr &req,
const drogon::HttpResponsePtr &resp) -> void {
// Set Access-Control-Allow-Origin based on the Origin request
// header
const auto &origin = req->getHeader("Origin");
if (!origin.empty())
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
// Reflect the requested Access-Control-Request-Method back in the
// response
const auto &requestMethod =
req->getHeader("Access-Control-Request-Method");
if (!requestMethod.empty())
{
resp->addHeader("Access-Control-Allow-Methods", requestMethod);
}
// Allow credentials to be included in cross-origin requests
resp->addHeader("Access-Control-Allow-Credentials", "true");
// Reflect the requested Access-Control-Request-Headers back
const auto &requestHeaders =
req->getHeader("Access-Control-Request-Headers");
if (!requestHeaders.empty())
{
resp->addHeader("Access-Control-Allow-Headers", requestHeaders);
}
});
}
/**
* Main function to start the Drogon application with CORS-enabled routes.
* This example includes:
* - A simple GET endpoint `/hello` that returns a greeting message.
* - A POST endpoint `/echo` that echoes back the request body.
* You can test with curl to test the CORS support:
*
```
curl -i -X OPTIONS http://localhost:8000/echo \
-H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type"
```
or
```
curl -i -X POST http://localhost:8000/echo \
-H "Origin: http://localhost:3000" \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
```
*/
int main()
{
// Listen on port 8000 for all interfaces
app().addListener("0.0.0.0", 8000);
// Setup CORS support
setupCors();
// Register /hello route for GET and OPTIONS methods
app().registerHandler(
"/hello",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
auto resp = HttpResponse::newHttpResponse();
resp->setBody("Hello from Drogon!");
// Log client IP address
LOG_INFO << "Request to /hello from " << req->getPeerAddr().toIp();
callback(resp);
},
{Get, Options});
// Register /echo route for POST and OPTIONS methods
app().registerHandler(
"/echo",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
auto resp = HttpResponse::newHttpResponse();
resp->setBody(std::string("Echo: ").append(req->getBody()));
// Log client IP and request body
LOG_INFO << "Request to /echo from " << req->getPeerAddr().toIp();
LOG_INFO << "Echo content: " << req->getBody();
callback(resp);
},
{Post, Options});
// Start the application main loop
app().run();
return 0;
}

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>File upload</title>
<script type="text/javascript">
var xhr;
//File uploading method
function UpladFile() {
var fileObj = document.getElementById("file").files[0]; // js get file object
var url = "/upload_endpoint";
var form = new FormData(); // FormData object
form.append("file", fileObj); // File object
xhr = new XMLHttpRequest(); // XMLHttpRequest object
xhr.open("post", url, true); //post
xhr.onload = uploadComplete;
xhr.onerror = uploadFailed;
xhr.upload.onprogress = progressFunction;
xhr.upload.onloadstart = function(){
ot = new Date().getTime();
oloaded = 0;
};
xhr.send(form);
}
function uploadComplete(evt) {
var data = evt.target.responseText;
alert("File has been uploaded.\n" + data);
}
function uploadFailed(evt) {
alert("Upload failed!");
}
function cancleUploadFile(){
xhr.abort();
}
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
if (evt.lengthComputable) {//
progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
}
var time = document.getElementById("time");
var nt = new Date().getTime();
var pertime = (nt-ot)/1000;
ot = new Date().getTime();
var perload = evt.loaded - oloaded;
oloaded = evt.loaded;
var speed = perload/pertime;
var bspeed = speed;
var units = 'b/s';
if(speed/1024>1){
speed = speed/1024;
units = 'k/s';
}
if(speed/1024>1){
speed = speed/1024;
units = 'M/s';
}
speed = speed.toFixed(1);
var resttime = ((evt.total-evt.loaded)/bspeed).toFixed(1);
time.innerHTML = ',Speed: '+speed+units+', the remaining time: '+resttime+'s';
if(bspeed==0) time.innerHTML = 'Upload cancelled';
}
</script>
</head>
<body>
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
<span id="percentage"></span><span id="time"></span>
<br /><br />
<input type="file" id="file" name="myfile" />
<input type="button" onclick="UpladFile()" value="Upload" />
<input type="button" onclick="cancleUploadFile()" value="Cancel" />
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More