Merge pull request #53 from oatpp/grand_api_docs_PR

Grand api docs pr
This commit is contained in:
Leonid Stryzhevskyi 2019-03-24 15:37:57 +02:00 committed by GitHub
commit 06190194ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 5382 additions and 1355 deletions

View File

@ -40,8 +40,6 @@ add_library(oatpp
oatpp/core/collection/LinkedList.hpp
oatpp/core/collection/ListMap.cpp
oatpp/core/collection/ListMap.hpp
oatpp/core/concurrency/Runnable.cpp
oatpp/core/concurrency/Runnable.hpp
oatpp/core/concurrency/SpinLock.cpp
oatpp/core/concurrency/SpinLock.hpp
oatpp/core/concurrency/Thread.cpp

View File

@ -25,7 +25,22 @@
#include "Checker.hpp"
namespace oatpp { namespace test {
PerformanceChecker::PerformanceChecker(const char* tag)
: m_tag(tag)
, m_ticks(oatpp::base::Environment::getMicroTickCount())
{}
PerformanceChecker::~PerformanceChecker(){
v_int64 elapsedTicks = oatpp::base::Environment::getMicroTickCount() - m_ticks;
OATPP_LOGD(m_tag, "%d(micro)", elapsedTicks);
}
v_int64 PerformanceChecker::getElapsedTicks(){
return oatpp::base::Environment::getMicroTickCount() - m_ticks;
}
ThreadLocalObjectsChecker::ThreadLocalObjectsChecker(const char* tag)
: m_tag(tag)
, m_objectsCount(oatpp::base::Environment::getThreadLocalObjectsCount())

View File

@ -28,28 +28,40 @@
#include "oatpp/core/base/Environment.hpp"
namespace oatpp { namespace test {
/**
* Helper class to check performance of code block.
*/
class PerformanceChecker {
private:
const char* m_tag;
v_int64 m_ticks;
public:
PerformanceChecker(const char* tag)
: m_tag(tag)
, m_ticks(oatpp::base::Environment::getMicroTickCount())
{}
~PerformanceChecker(){
v_int64 elapsedTicks = oatpp::base::Environment::getMicroTickCount() - m_ticks;
OATPP_LOGD(m_tag, "%d(micro)", elapsedTicks);
}
v_int64 getElapsedTicks(){
return oatpp::base::Environment::getMicroTickCount() - m_ticks;
}
/**
* Constructor.
* @param tag - log tag.
*/
PerformanceChecker(const char* tag);
/**
* Non virtual destructor.
* Will print time elapsed ticks on destruction.
*/
~PerformanceChecker();
/**
* Get elapsed time from checker creation.
* @return - ticks in microseconds.
*/
v_int64 getElapsedTicks();
};
/**
* Helper class to check block of code on memory leaks.
* Checks &id:oatpp::base::Countable; objects, and objects allocated on memory pools.
*/
class ThreadLocalObjectsChecker {
private:
class MemoryPoolData {
@ -63,7 +75,17 @@ private:
v_counter m_objectsCount;
v_counter m_objectsCreated;
public:
/**
* Constructor.
* @param tag - log tag.
*/
ThreadLocalObjectsChecker(const char* tag);
/**
* Non virtual destructor.
* Will halt program execution if memory leaks detected.
*/
~ThreadLocalObjectsChecker();
};

View File

@ -62,6 +62,9 @@ void UnitTest::run(v_int32 times) {
OATPP_LOGD("Pool", "name: '%s' [%d(objs)]", pool->getName().c_str(), pool->getObjectsCount());
it ++;
}
exit(EXIT_FAILURE);
}
}

View File

@ -28,27 +28,51 @@
#include "oatpp/core/base/Environment.hpp"
namespace oatpp { namespace test {
/**
* Base class for unit tests.
*/
class UnitTest{
protected:
const char* const TAG;
public:
/**
* Constructor.
* @param testTAG - tag used for logs.
*/
UnitTest(const char* testTAG)
: TAG(testTAG)
{}
virtual ~UnitTest(){
}
/**
* Default virtual destructor.
*/
virtual ~UnitTest() = default;
/**
* Run this test repeatedly for specified number of times.
* @param times - number of times to run this test.
*/
void run(v_int32 times);
/**
* Run this test.
*/
void run(){
run(1);
}
/**
* Override this method. It should contain test logic.
*/
virtual void onRun() = 0;
/**
* Run this test repeatedly for specified number of times.
* @tparam T - Test class.
* @param times - number of times to run this test.
*/
template<class T>
static void runTest(v_int32 times){
T test;
@ -57,7 +81,13 @@ public:
};
#define OATPP_RUN_TEST(TEST) oatpp::test::UnitTest::runTest<TEST>(1)
/**
* Convenience macro to run test. <br>
* Usage Example:<br>
* `OATPP_RUN_TEST(oatpp::test::web::FullTest);`
*/
#define OATPP_RUN_TEST(TEST) \
oatpp::test::UnitTest::runTest<TEST>(1)
}}

View File

@ -30,9 +30,16 @@
#include "oatpp/encoding/Hex.hpp"
namespace oatpp { namespace algorithm {
/**
* Implementation of CRC-32. Cyclic redundancy check algorithm.
*/
class CRC32 {
public:
/**
* Precalculated table
*/
static const p_word32 TABLE_04C11DB7;
public:
@ -42,7 +49,17 @@ public:
* Generates v_word32 table[256] for polynomial
*/
static p_word32 generateTable(v_word32 poly);
/**
* Calculate CRC32 value for buffer of defined size
* @param buffer
* @param size
* @param crc
* @param initValue
* @param xorOut
* @param table
* @return - CRC32 value (v_word32)
*/
static v_word32 calc(const void *buffer, v_int32 size, v_word32 crc = 0, v_word32 initValue = 0xFFFFFFFF, v_word32 xorOut = 0xFFFFFFFF, p_word32 table = TABLE_04C11DB7);
};

View File

@ -22,6 +22,26 @@
*
***************************************************************************/
/**[info]
* This file contains "defines" for ApiClient code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(ApiClient)
* ...
* // Generated API-Calls.
* ...
* #include OATPP_CODEGEN_END(ApiClient)
* ```
*
*
* *For details see:*
* <ul>
* <li>[ApiClient component](https://oatpp.io/docs/components/api-client/)</li>
* <li>&id:oatpp::web::client::ApiClient;</li>
* </ul>
*/
#include "oatpp/core/macro/basic.hpp"
#include "oatpp/core/macro/codegen.hpp"
@ -41,6 +61,10 @@
// INIT
/**
* Codegen macoro to be used in classes extending &id:oatpp::web::client::ApiClient; to generate required fields/methods/constructors for ApiClient.
* @param NAME - name of the ApiClient class.
*/
#define API_CLIENT_INIT(NAME) \
public: \
NAME(const std::shared_ptr<oatpp::web::client::RequestExecutor>& requestExecutor, \
@ -176,6 +200,13 @@ OATPP_MACRO_FOREACH(OATPP_MACRO_API_CLIENT_PARAM_DECL, LIST) \
#define OATPP_API_CALL__(X, NAME, METHOD, PATH, LIST) OATPP_API_CALL_(X, NAME, METHOD, PATH, LIST)
#define OATPP_API_CALL___(NAME, METHOD, PATH, LIST) OATPP_API_CALL__(OATPP_MACRO_HAS_ARGS LIST, NAME, METHOD, PATH, LIST)
/**
* Codegen macoro to be used in `oatpp::web::client::ApiClient` to generate REST API-Calls.
* @param METHOD - Http method ("GET", "POST", "PUT", etc.)
* @param PATH - Path to endpoint (without host)
* @param NAME - Name of the generated method
* @return - std::shared_ptr to &id:oatpp::web::protocol::http::incoming::Response;
*/
#define API_CALL(METHOD, PATH, NAME, ...) \
OATPP_API_CALL___(NAME, METHOD, PATH, (__VA_ARGS__))
@ -239,5 +270,12 @@ oatpp::async::Action NAME(\
#define OATPP_API_CALL_ASYNC__(X, NAME, METHOD, PATH, LIST) OATPP_API_CALL_ASYNC_(X, NAME, METHOD, PATH, LIST)
#define OATPP_API_CALL_ASYNC___(NAME, METHOD, PATH, LIST) OATPP_API_CALL_ASYNC__(OATPP_MACRO_HAS_ARGS LIST, NAME, METHOD, PATH, LIST)
/**
* Codegen macoro to be used in `oatpp::web::client::ApiClient` to generate Asynchronous REST API-Calls.
* @param METHOD - Http method ("GET", "POST", "PUT", etc.)
* @param PATH - Path to endpoint (without host)
* @param NAME - Name of the generated method
* @return - &id:oatpp::async::Action;
*/
#define API_CALL_ASYNC(METHOD, PATH, NAME, ...) \
OATPP_API_CALL_ASYNC___(NAME, METHOD, PATH, (__VA_ARGS__))

View File

@ -21,6 +21,27 @@
* limitations under the License.
*
***************************************************************************/
/**[info]
* This file contains "defines" for ApiController code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(ApiController)
* ...
* // Generated Endpoints.
* ...
* #include OATPP_CODEGEN_END(ApiController)
* ```
*
*
* *For details see:*
* <ul>
* <li>[ApiController component](https://oatpp.io/docs/components/api-controller/)</li>
* <li>&id:oatpp::web::server::api::ApiController;</li>
* </ul>
*/
#include "oatpp/core/macro/basic.hpp"
#include "oatpp/core/macro/codegen.hpp"
@ -390,12 +411,19 @@ OATPP_MACRO_API_CONTROLLER_ENDPOINT_(X, NAME, METHOD, PATH, LIST)
#define OATPP_MACRO_API_CONTROLLER_ENDPOINT___(NAME, METHOD, PATH, LIST) \
OATPP_MACRO_API_CONTROLLER_ENDPOINT__(OATPP_MACRO_HAS_ARGS LIST, NAME, METHOD, PATH, LIST)
/**
* Codegen macoro to be used in `oatpp::web::server::api::ApiController` to generate Endpoint.
* @param METHOD - Http method ("GET", "POST", "PUT", etc.).
* @param PATH - Path to endpoint (without host).
* @param NAME - Name of the generated method.
* @return - std::shared_ptr to &id:oatpp::web::protocol::http::outgoing::Response;.
*/
#define ENDPOINT(METHOD, PATH, NAME, ...) \
OATPP_MACRO_API_CONTROLLER_ENDPOINT___(NAME, METHOD, PATH, (__VA_ARGS__))
// ENDPOINT ASYNC MACRO // ------------------------------------------------------
/**
/*
* 1 - Method to obtain endpoint call function ptr
* 2 - Endpoint info singleton
*/
@ -414,7 +442,7 @@ std::shared_ptr<Endpoint::Info> Z__EDNPOINT_INFO_GET_INSTANCE_##NAME() { \
return info; \
}
/**
/*
* 1 - Endpoint info instance
* 2 - Endpoint instance
*/
@ -434,7 +462,13 @@ const std::shared_ptr<Endpoint> Z__ENDPOINT_##NAME = createEndpoint(m_endpoints,
Z__ENDPOINT_METHOD_##NAME(this), \
Z__CREATE_ENDPOINT_INFO_##NAME());
/**
* Codegen macoro to be used in `oatpp::web::server::api::ApiController` to generate Asynchronous Endpoint.
* @param METHOD - Http method ("GET", "POST", "PUT", etc.).
* @param PATH - Path to endpoint (without host).
* @param NAME - Name of the generated method.
* @return - &id:oatpp::async::Action;.
*/
#define ENDPOINT_ASYNC(METHOD, PATH, NAME) \
OATPP_MACRO_API_CONTROLLER_ENDPOINT_ASYNC_DECL_DEFAULTS(NAME, METHOD, PATH) \
OATPP_MACRO_API_CONTROLLER_ENDPOINT_ASYNC_DECL(NAME, METHOD, PATH) \
@ -448,6 +482,10 @@ oatpp::async::Action Z__PROXY_METHOD_##NAME(oatpp::async::AbstractCoroutine* par
\
class NAME : public HandlerCoroutine<NAME, __ControllerType>
/**
* Auxiliary codegen macro for `ENDPOINT_ASYNC` to generate correct constructor for Asynchronous Endpoint Coroutine.
* @NAME - Name of the endpoint. Exact the same name as was passed to `ENDPOINT_ASYNC` macro.
*/
#define ENDPOINT_ASYNC_INIT(NAME) \
public: \
\

View File

@ -22,11 +22,36 @@
*
***************************************************************************/
/**[info]
* This file contains "defines" for DTO code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(DTO)
* ...
* // Generated Endpoints.
* ...
* #include OATPP_CODEGEN_END(DTO)
* ```
*
*
* *For details see:*
* <ul>
* <li>[Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/)</li>
* <li>&id:oatpp::data::mapping::type::Object;</li>
* </ul>
*/
#include "oatpp/core/macro/basic.hpp"
#include "oatpp/core/macro/codegen.hpp"
// Defaults
/**
* Codegen macoro to be used in classes extending &id:oatpp::data::mapping::type::Object; to generate required fields/methods/constructors for DTO object.
* @param TYPE_NAME - name of the DTO class.
* @param TYPE_EXTEND - name of the parent DTO class. If DTO extends &id:oatpp::data::mapping::type::Object; TYPE_EXETENDS should be `Object`.
*/
#define DTO_INIT(TYPE_NAME, TYPE_EXTEND) \
public: \
typedef TYPE_NAME Z__CLASS; \
@ -113,6 +138,12 @@ TYPE NAME
#define OATPP_MACRO_DTO_FIELD__(X, TYPE, NAME, LIST) OATPP_MACRO_DTO_FIELD_(X, TYPE, NAME, LIST)
#define OATPP_MACRO_DTO_FIELD___(TYPE, NAME, LIST) OATPP_MACRO_DTO_FIELD__(OATPP_MACRO_HAS_ARGS LIST, TYPE, NAME, LIST)
/**
* Codegen macro to generate fields of DTO object.
* @param TYPE - type of the field.
* @param NAME - name of the field.
* @param QUALIFIER_NAME - additional (optional) field to specify serialized name of the field. If not specified it will be same as NAME.
*/
#define DTO_FIELD(TYPE, NAME, ...) \
OATPP_MACRO_DTO_FIELD___(TYPE, NAME, (__VA_ARGS__))

View File

@ -22,6 +22,26 @@
*
***************************************************************************/
/**[info]
* This file contains "undefs" for ApiClient code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(ApiClient)
* ...
* // Generated API-Calls.
* ...
* #include OATPP_CODEGEN_END(ApiClient)
* ```
*
*
* *For details see:*
* <ul>
* <li>[ApiClient component](https://oatpp.io/docs/components/api-client/)</li>
* <li>&id:oatpp::web::client::ApiClient;</li>
* </ul>
*/
#undef OATPP_MACRO_API_CLIENT_PARAM_MACRO
#undef OATPP_MACRO_API_CLIENT_PARAM_TYPE
#undef OATPP_MACRO_API_CLIENT_PARAM_NAME

View File

@ -22,6 +22,26 @@
*
***************************************************************************/
/**[info]
* This file contains "undefs" for ApiController code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(ApiController)
* ...
* // Generated Endpoints.
* ...
* #include OATPP_CODEGEN_END(ApiController)
* ```
*
*
* *For details see:*
* <ul>
* <li>[ApiController component](https://oatpp.io/docs/components/api-controller/)</li>
* <li>&id:oatpp::web::server::api::ApiController;</li>
* </ul>
*/
#undef OATPP_MACRO_API_CONTROLLER_PARAM_MACRO
#undef OATPP_MACRO_API_CONTROLLER_PARAM_INFO
#undef OATPP_MACRO_API_CONTROLLER_PARAM_TYPE

View File

@ -22,6 +22,26 @@
*
***************************************************************************/
/**[info]
* This file contains "undefs" for DTO code generating macro. <br>
* Usage:<br>
*
* ```cpp
* #include OATPP_CODEGEN_BEGIN(DTO)
* ...
* // Generated Endpoints.
* ...
* #include OATPP_CODEGEN_END(DTO)
* ```
*
*
* *For details see:*
* <ul>
* <li>[Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/)</li>
* <li>&id:oatpp::data::mapping::type::Object;</li>
* </ul>
*/
#undef DTO_INIT
// Fields

View File

@ -29,14 +29,46 @@
#include "oatpp/core/data/mapping/type/Primitive.hpp"
namespace oatpp {
/**
* Mapping-Enabled String type. &id:oatpp::data::mapping::type::String; <br>
* For `oatpp::String` methods see &id:oatpp::base::StrBuffer;
*/
typedef oatpp::data::mapping::type::String String;
/**
* Mapping-Enabled 8-bits int. Can hold nullptr value. &id:oatpp::data::mapping::type::Int8;
*/
typedef oatpp::data::mapping::type::Int8 Int8;
/**
* Mapping-Enabled 16-bits int. Can hold nullptr value. &id:oatpp::data::mapping::type::Int16;
*/
typedef oatpp::data::mapping::type::Int16 Int16;
/**
* Mapping-Enabled 32-bits int. Can hold nullptr value. &id:oatpp::data::mapping::type::Int32;
*/
typedef oatpp::data::mapping::type::Int32 Int32;
/**
* Mapping-Enabled 64-bits int. Can hold nullptr value. &id:oatpp::data::mapping::type::Int64;
*/
typedef oatpp::data::mapping::type::Int64 Int64;
/**
* Mapping-Enabled 32-bits float. Can hold nullptr value. &id:oatpp::data::mapping::type::Float32;
*/
typedef oatpp::data::mapping::type::Float32 Float32;
/**
* Mapping-Enabled 64-bits float (double). Can hold nullptr value. &id:oatpp::data::mapping::type::Float64;
*/
typedef oatpp::data::mapping::type::Float64 Float64;
/**
* Mapping-Enabled Boolean. Can hold nullptr value. &id:oatpp::data::mapping::type::Boolean;
*/
typedef oatpp::data::mapping::type::Boolean Boolean;
}

View File

@ -25,12 +25,17 @@
#include "Coroutine.hpp"
namespace oatpp { namespace async {
const Action Action::_WAIT_RETRY(TYPE_WAIT_RETRY, nullptr, nullptr);
const Action Action::_REPEAT(TYPE_REPEAT, nullptr, nullptr);
const Action Action::_FINISH(TYPE_FINISH, nullptr, nullptr);
const Action Action::_ABORT(TYPE_ABORT, nullptr, nullptr);
Error::Error(const char* pMessage, bool pIsExceptionThrown)
: message(pMessage)
, isExceptionThrown(pIsExceptionThrown)
{}
Action::Action(v_int32 type,
AbstractCoroutine* coroutine,
FunctionPtr functionPtr)

View File

@ -33,37 +33,95 @@ namespace oatpp { namespace async {
class AbstractCoroutine; // FWD
class Processor; // FWD
/**
* Class to hold and communicate errors between Coroutines
*/
class Error {
public:
Error(const char* pMessage, bool pIsExceptionThrown = false)
: message(pMessage)
, isExceptionThrown(pIsExceptionThrown)
{}
/**
* Constructor.
* @param pMessage - Error message.
* @param pIsExceptionThrown - Indicate that this error is a result of thrown exception.
*/
Error(const char* pMessage, bool pIsExceptionThrown = false);
/**
* Error message
*/
const char* message;
/**
* Indicates that this error is a result of thrown exception. Re-throw if true to catch original exception.
*/
bool isExceptionThrown;
};
/**
* Class Action represents an asynchronous action.
*/
class Action {
friend Processor;
friend AbstractCoroutine;
public:
typedef Action (AbstractCoroutine::*FunctionPtr)();
public:
/**
* Indicate that Action is to start coroutine. Value = 0.
*/
static constexpr const v_int32 TYPE_COROUTINE = 0;
/**
* Indicate that Action is to YIELD control to other method of Coroutine. Value = 1.
*/
static constexpr const v_int32 TYPE_YIELD_TO = 1;
/**
* Indicate that Action is to WAIT and then RETRY call to current method of Coroutine. Value = 2.
*/
static constexpr const v_int32 TYPE_WAIT_RETRY = 2;
/**
* Indicate that Action is to REPEAT call to current method of Coroutine. Value = 3.
*/
static constexpr const v_int32 TYPE_REPEAT = 3;
/**
* Indicate that Action is to FINISH current Coroutine and return control to a caller-Coroutine. Value = 4.
*/
static constexpr const v_int32 TYPE_FINISH = 4;
/**
* Deprecated
*/
static constexpr const v_int32 TYPE_ABORT = 5;
/**
* Indicate that Error occurred
*/
static constexpr const v_int32 TYPE_ERROR = 6;
public:
/**
* Predefined WAIT_RETRY action
*/
static const Action _WAIT_RETRY;
/**
* Predefined REPEAT action
*/
static const Action _REPEAT;
/**
* Predefined FINISH action
*/
static const Action _FINISH;
/**
* Deprecated
*/
static const Action _ABORT;
private:
v_int32 m_type;
@ -73,20 +131,39 @@ private:
protected:
void free();
public:
Action(v_int32 type,
AbstractCoroutine* coroutine,
FunctionPtr functionPtr);
/**
* Constructor.
* @param type - type of the Action.
* @param coroutine - pointer to a Coroutine to start if type == TYPE_COROUTINE. nullptr otherwise.
* @param functionPtr - pointer to a function to YIELD control to if type == TYPE_YIELD_TO. nullptr otherwise.
*/
Action(v_int32 type, AbstractCoroutine* coroutine, FunctionPtr functionPtr);
/**
* Constructor. Construct error reporting action.
* @param error - Error message.
*/
Action(const Error& error);
/**
* Check if action is an error reporting action.
* @return `true` if action is an error reporting action.
*/
bool isError();
};
/**
* Abstract Coroutine. Base class for Coroutines. It provides state management, coroutines stack management and error reporting functionality.
*/
class AbstractCoroutine {
friend oatpp::collection::FastQueue<AbstractCoroutine>;
friend Processor;
public:
/**
* Convenience typedef for Action
*/
typedef oatpp::async::Action Action;
typedef Action (AbstractCoroutine::*FunctionPtr)();
public:
@ -183,7 +260,11 @@ private:
protected:
Action m_parentReturnAction = Action::_FINISH;
public:
/**
* Make one Coroutine iteration.
* @return - control Action.
*/
Action iterate() {
try {
return takeAction(_CP->call(_FP));
@ -202,22 +283,46 @@ public:
}
return action;
};*/
/**
* Virtual Destructor
*/
virtual ~AbstractCoroutine(){
m_parentReturnAction.free();
}
/**
* Entrypoint of Coroutine.
* @return - Action
*/
virtual Action act() = 0;
/**
* Call function of Coroutine specified by ptr.<br>
* This method is called from iterate().<br>
* Coroutine keeps track of function ptr and calls corresponding function on each iteration.
* When Coroutine starts, function ptr points to act().
* @param ptr - pointer of the function to call.
* @return - Action.
*/
virtual Action call(FunctionPtr ptr) = 0;
/**
* Internal function. Should free Coroutine on MemoryPool/Bench
* free() also calls virtual destructor:
* Coroutine::free() --> Bench::free(Coroutine* coroutine) { ... coroutine->~Coroutine(); ... }
* Internal function. Should free Coroutine on MemoryPool/Bench.<br>
* Method free() also calls virtual destructor:<br>
* `Coroutine::free() --> Bench::free(Coroutine* coroutine) { ... coroutine->~Coroutine(); ... }`
*/
virtual void free() = 0;
virtual MemberCaller getMemberCaller() const = 0;
/**
* Default implementation of handleError(error) function.
* User may override this function in order to handle errors.
* @param error - error.
* @return - Action. If handleError function returns Error,
* current coroutine will finish, return control to caller coroutine and handleError is called for caller coroutine.
*/
virtual Action handleError(const Error& error) {
return error;
}
@ -226,48 +331,103 @@ public:
Action callWithParams(FunctionPtr ptr, Args... args) {
return getMemberCaller().call<Action>(ptr, args...);
}
/**
* Start new Coroutine as a "nested" Coroutine, keeping track of a coroutine call stack.
* @tparam C - Coroutine to start.
* @tparam Args - arguments to be passed to a starting coroutine.
* @param actionOnReturn - Action to be called once new coroutine finished.
* @param args - actual parameters passed to startCoroutine call.
* @return - start Coroutine Action.
*/
template<typename C, typename ... Args>
Action startCoroutine(const Action& actionOnReturn, Args... args) {
C* coroutine = C::getBench().obtain(args...);
coroutine->m_parentReturnAction = actionOnReturn;
return Action(Action::TYPE_COROUTINE, coroutine, nullptr);
}
/**
* Start new Coroutine for result as a "nested" Coroutine, keeping track of a coroutine call stack.
* After Coroutine finished result value should be passed to callback function. <br>
* Example call:<br>
* `startCoroutineForResult<CoroutineWithResult>(&MyCoroutine::onResult);`
* @tparam CoroutineType - Coroutine to start.
* @tparam ParentCoroutineType - calling Coroutine type.
* @tparam CallbackArgs - callback arguments.
* @tparam Args - arguments to be passed to a starting coroutine.
* @param function - Callback to receive result.
* @param args - actual parameters passed to startCoroutine call.
* @return - start Coroutine Action.
*/
template<typename CoroutineType, typename ParentCoroutineType, typename ... CallbackArgs, typename ...Args>
Action startCoroutineForResult(Action (ParentCoroutineType::*function)(CallbackArgs...), Args... args) {
CoroutineType* coroutine = CoroutineType::getBench().obtain(args...);
coroutine->m_callback = reinterpret_cast<FunctionPtr>(function);
return Action(Action::TYPE_COROUTINE, coroutine, nullptr);
}
/**
* Check if coroutine is finished
* @return - true if finished
*/
bool finished() const {
return _CP == nullptr;
}
/**
* Get parent coroutine
* @return - pointer to a parent coroutine
*/
AbstractCoroutine* getParent() const {
return m_parent;
}
};
/**
* Coroutine template. <br>
* Example usage:<br>
* `class MyCoroutine : public oatpp::async::Coroutine<MyCoroutine>`
* @tparam T - child class type
*/
template<class T>
class Coroutine : public AbstractCoroutine {
public:
typedef Action (T::*Function)();
/**
* Convenience typedef for Bench
*/
typedef oatpp::base::memory::Bench<T> Bench;
public:
/**
* Get Bench for this Coroutine type.<br>
* Used for system needs. End user should not use it.
* @return
*/
static Bench& getBench(){
static thread_local Bench bench(512);
return bench;
}
public:
/**
* Call function of Coroutine specified by ptr. <br>
* Overridden `AbstractCoroutine::call()` method.
* @param ptr - pointer of the function to call.
* @return - Action.
*/
Action call(FunctionPtr ptr) override {
Function f = static_cast<Function>(ptr);
return (static_cast<T*>(this)->*f)();
}
/**
* Free Coroutine instance.
* See &l:AbstractCoroutine::free ();.
*/
void free() override {
Coroutine<T>::getBench().free(static_cast<T*>(this));
}
@ -275,33 +435,66 @@ public:
MemberCaller getMemberCaller() const override {
return MemberCaller((void*) this);
}
/**
* Convenience method to generate Action of `type == Action::TYPE_YIELD_TO`.
* @param function - pointer to function.
* @return - yield Action.
*/
Action yieldTo(Function function) const {
return Action(Action::TYPE_YIELD_TO, nullptr, static_cast<FunctionPtr>(function));
}
/**
* Convenience method to generate Action of `type == Action::TYPE_WAIT_RETRY`.
* @return - WAIT_RETRY Action.
*/
const Action& waitRetry() const {
return Action::_WAIT_RETRY;
}
/**
* Convenience method to generate Action of `type == Action::TYPE_REPEAT`.
* @return - repeat Action.
*/
const Action& repeat() const {
return Action::_REPEAT;
}
/**
* Convenience method to generate Action of `type == Action::TYPE_FINISH`.
* @return - finish Action.
*/
const Action& finish() const {
return Action::_FINISH;
}
/**
* Deprecated.
* @return - abort Action.
*/
const Action& abort() const {
return Action::_ABORT;
}
/**
* Convenience method to generate error reporting Action.
* @param message - error message.
* @return - error reporting Action.
*/
Action error(const char* message) {
return Action(Error(message));
}
};
/**
* Coroutine with result template. <br>
* Example usage:<br>
* `class CoroutineWithResult : public oatpp::async::CoroutineWithResult<CoroutineWithResult, const char*>`
* @tparam T - child class type.
* @tparam Args - return argumet type.
*/
template<class T, typename ...Args>
class CoroutineWithResult : public AbstractCoroutine {
friend AbstractCoroutine;
@ -316,12 +509,22 @@ public:
private:
FunctionPtr m_callback;
public:
/**
* Call function of Coroutine specified by ptr. <br>
* Overridden AbstractCoroutine::call() method.
* @param ptr - pointer of the function to call.
* @return - Action.
*/
virtual Action call(FunctionPtr ptr) override {
Function f = static_cast<Function>(ptr);
return (static_cast<T*>(this)->*f)();
}
/**
* Free Coroutine instance.
* See &l:AbstractCoroutine::free ();.
*/
virtual void free() override {
CoroutineWithResult<T, Args...>::getBench().free(static_cast<T*>(this));
}
@ -329,28 +532,56 @@ public:
MemberCaller getMemberCaller() const override {
return MemberCaller((void*) this);
}
/**
* Convenience method to generate Action of `type == Action::TYPE_YIELD_TO`.
* @param function - pointer to function.
* @return - yield Action.
*/
Action yieldTo(Function function) const {
return Action(Action::TYPE_YIELD_TO, nullptr, static_cast<FunctionPtr>(function));
}
/**
* Convenience method to generate Action of `type == Action::TYPE_WAIT_RETRY`.
* @return - WAIT_RETRY Action.
*/
const Action& waitRetry() const {
return Action::_WAIT_RETRY;
}
/**
* Convenience method to generate Action of `type == Action::TYPE_REPEAT`.
* @return - repeat Action.
*/
const Action& repeat() const {
return Action::_REPEAT;
}
/**
* Deprecated. <br>
* Call caller's Callback passing returned value, and generate Action of `type == Action::TYPE_FINISH`.
* @param args - argumets to be passed to callback.
* @return - finish Action.
*/
const Action& _return(Args... args) {
m_parentReturnAction = getParent()->callWithParams(m_callback, args...);
return Action::_FINISH;
}
/**
* Deprecated.
* @return - abort Action.
*/
const Action& abort() const {
return Action::_ABORT;
}
/**
* Convenience method to generate error reporting Action.
* @param message - error message.
* @return - error reporting Action.
*/
Action error(const char* message) {
return Action(Error(message));
}

View File

@ -83,13 +83,11 @@ void Executor::SubmissionProcessor::addTaskSubmission(const std::shared_ptr<Task
Executor::Executor(v_int32 threadsCount)
: m_threadsCount(threadsCount)
, m_threads(new std::shared_ptr<oatpp::concurrency::Thread>[m_threadsCount])
, m_processors(new std::shared_ptr<SubmissionProcessor>[m_threadsCount])
, m_threads(new std::thread[m_threadsCount])
, m_processors(new SubmissionProcessor[m_threadsCount])
{
for(v_int32 i = 0; i < m_threadsCount; i ++) {
auto processor = std::make_shared<SubmissionProcessor>();
m_processors[i] = processor;
m_threads[i] = oatpp::concurrency::Thread::createShared(processor);
m_threads[i] = std::thread(&SubmissionProcessor::run, &m_processors[i]);
}
}
@ -100,19 +98,19 @@ Executor::~Executor() {
void Executor::join() {
for(v_int32 i = 0; i < m_threadsCount; i ++) {
m_threads[i]->join();
m_threads[i].join();
}
}
void Executor::detach() {
for(v_int32 i = 0; i < m_threadsCount; i ++) {
m_threads[i]->detach();
m_threads[i].detach();
}
}
void Executor::stop() {
for(v_int32 i = 0; i < m_threadsCount; i ++) {
m_processors[i]->stop();
m_processors[i].stop();
}
}

View File

@ -37,7 +37,12 @@
#include <condition_variable>
namespace oatpp { namespace async {
/**
* Asynchronous Executor.<br>
* Executes coroutines in multiple &id:oatpp::async::Processor;
* allocating one thread per processor.
*/
class Executor {
private:
@ -47,7 +52,7 @@ private:
virtual AbstractCoroutine* createCoroutine() = 0;
};
/**
/*
* Sequence generating templates
* used to convert tuple to parameters pack
* Example: expand SequenceGenerator<3>:
@ -82,7 +87,7 @@ private:
};
class SubmissionProcessor : public oatpp::concurrency::Runnable {
class SubmissionProcessor {
private:
typedef oatpp::collection::LinkedList<std::shared_ptr<TaskSubmission>> Tasks;
private:
@ -99,37 +104,64 @@ private:
SubmissionProcessor();
public:
void run() override;
void run();
void stop();
void addTaskSubmission(const std::shared_ptr<TaskSubmission>& task);
};
public:
/**
* Default number of threads to run coroutines.
*/
static const v_int32 THREAD_NUM_DEFAULT;
private:
v_int32 m_threadsCount;
std::shared_ptr<oatpp::concurrency::Thread>* m_threads;
std::shared_ptr<SubmissionProcessor>* m_processors;
//std::shared_ptr<oatpp::concurrency::Thread>* m_threads;
std::thread* m_threads;
SubmissionProcessor* m_processors;
std::atomic<v_word32> m_balancer;
public:
/**
* Constructor.
* @param threadsCount - Number of threads to run coroutines.
*/
Executor(v_int32 threadsCount = THREAD_NUM_DEFAULT);
/**
* Non-virtual Destructor.
*/
~Executor();
/**
* Join all worker-threads.
*/
void join();
/**
* Detach all worker-threads.
*/
void detach();
/**
* Stop Executor. <br>
* After all worker-threads are stopped. Join should unblock.
*/
void stop();
/**
* Execute Coroutine.
* @tparam CoroutineType - type of coroutine to execute.
* @tparam Args - types of arguments to be passed to Coroutine constructor.
* @param params - actual arguments to be passed to Coroutine constructor.
*/
template<typename CoroutineType, typename ... Args>
void execute(Args... params) {
auto processor = m_processors[m_balancer % m_threadsCount];
auto& processor = m_processors[m_balancer % m_threadsCount];
auto submission = std::make_shared<SubmissionTemplate<CoroutineType, Args...>>(params...);
processor->addTaskSubmission(submission);
processor.addTaskSubmission(submission);
m_balancer ++;
}

View File

@ -29,7 +29,11 @@
#include "oatpp/core/collection/FastQueue.hpp"
namespace oatpp { namespace async {
/**
* Asynchronous Processor.<br>
* Responsible for processing and managing multiple Coroutines.
*/
class Processor {
private:
@ -43,9 +47,29 @@ private:
v_int64 m_inactivityTick = 0;
public:
/**
* Add Coroutine to processor.
* @param coroutine - pointer to Coroutine.
*/
void addCoroutine(AbstractCoroutine* coroutine);
/**
* Add Coroutine to processor in "waiting queue"
* @param coroutine
*/
void addWaitingCoroutine(AbstractCoroutine* coroutine);
/**
* Iterate Coroutines.
* @param numIterations - number of iterations.
* @return - `true` if there are active Coroutines.
*/
bool iterate(v_int32 numIterations);
/**
* Check if there is no more Coroutines in processor.
* @return - `true` if all coroutines in all queues are finished.
*/
bool isEmpty() {
return m_activeQueue.first == nullptr && m_waitingQueue.first == nullptr;
}

View File

@ -27,6 +27,16 @@
#include <cstring>
namespace oatpp { namespace base {
CommandLineArguments::CommandLineArguments()
: m_argc(0)
, m_argv(nullptr)
{}
CommandLineArguments::CommandLineArguments(int argc, const char * argv[])
: m_argc(argc)
, m_argv(argv)
{}
bool CommandLineArguments::Parser::hasArgument(int argc, const char * argv[], const char* argName) {
return getArgumentIndex(argc, argv, argName) >= 0;

View File

@ -29,37 +29,63 @@
namespace oatpp { namespace base {
/**
* Class for storing and managing Command Line arguments.
*/
class CommandLineArguments {
public:
/**
* Command Line arguments parser.
*/
class Parser {
public:
/**
* returns true if getArgumentIndex(argName) >= 0
* Check the specified argument is present among command line arguments.
* @param argc - count of arguments in argv array.
* @param argv - array of arguments.
* @param argName - name of the target argument.
* @return - `true` if `getArgumentIndex(argName) >= 0`
*/
static bool hasArgument(int argc, const char * argv[], const char* argName);
/**
* get index of the argument with the name == argName
*/
static v_int32 getArgumentIndex(int argc, const char * argv[], const char* argName);
/**
* return argument wich starts with the prefix
* ex:
* for cmd = "-k -c 1000 -n 100 'http://127.0.0.1:8000/'"
* getArgumentWhichStartsWith("http") == http://127.0.0.1:8000/
* if no argument found defaultValue returned
* Get index of the argument specified by name in the argv[] array.
* @param argc - count of arguments in argv array.
* @param argv - array of arguments.
* @param argName - name of the target argument.
* @return - index of the argument in argv[] array. -1 if there is no such argument.
*/
static v_int32 getArgumentIndex(int argc, const char * argv[], const char* argName);
/**
* Get argument which starts with the prefix. <br>
* Example: <br>
* For command line: `-k -c 1000 -n 100 http://127.0.0.1:8000/` <br>
* `getArgumentWhichStartsWith("http") == http://127.0.0.1:8000/`
* @param argc - count of arguments in argv array.
* @param argv - array of arguments.
* @param argNamePrefix - prefix to search.
* @param defaultValue - default value to return in case not found.
* @return - argument which starts with the specified prefix.
*/
static const char* getArgumentStartingWith(int argc, const char * argv[], const char* argNamePrefix, const char* defaultValue = nullptr);
/**
* return value preceded by the argument
* ex:
* for cmd = "-k -c 1000 -n 100"
* getNamedArgumentValue("-c") == "1000"
* getNamedArgumentValue("-n") == "100"
* Get value preceded by the argument. <br>
* Example: <br>
* For command line: `-k -c 1000 -n 100` <br>
* `getNamedArgumentValue("-c") == "1000"`, `getNamedArgumentValue("-n") == "100"`
* @param argc - count of arguments in argv array.
* @param argv - array of arguments.
* @param argName - name of the preceded argument.
* @param defaultValue - default value to return in case not found.
* @return - value preceded by the argument.
*/
static const char* getNamedArgumentValue(int argc, const char * argv[], const char* argName, const char* defaultValue = nullptr);
@ -69,29 +95,59 @@ private:
int m_argc;
const char ** m_argv;
public:
CommandLineArguments()
: m_argc(0)
, m_argv(nullptr)
{}
CommandLineArguments(int argc, const char * argv[])
: m_argc(argc)
, m_argv(argv)
{}
/**
* Default constructor.
*/
CommandLineArguments();
/**
* Constructor.
* @param argc - count of arguments in argv[] array.
* @param argv - array of arguments.
*/
CommandLineArguments(int argc, const char * argv[]);
/**
* Check the specified argument is present.
* @param argName - name of the target argument.
* @return - `true` if present.
*/
bool hasArgument(const char* argName) {
return Parser::hasArgument(m_argc, m_argv, argName);
}
/**
* Get index of the argument specified by name.
* @param argName - name of the target argument.
* @return - index of the argument in argv[] array. -1 if there is no such argument.
*/
v_int32 getArgumentIndex(const char* argName) {
return Parser::getArgumentIndex(m_argc, m_argv, argName);
}
/**
* Get argument which starts with the prefix. <br>
* Example: <br>
* For command line: `-k -c 1000 -n 100 'http://127.0.0.1:8000/'` <br>
* `getArgumentWhichStartsWith("http") == http://127.0.0.1:8000/`
* @param argNamePrefix - prefix to search.
* @param defaultValue - default value to return in case not found.
* @return - argument which starts with the specified prefix. defaultValue if not found.
*/
const char* getArgumentStartingWith(const char* argNamePrefix, const char* defaultValue = nullptr) {
return Parser::getArgumentStartingWith(m_argc, m_argv, argNamePrefix, defaultValue);
}
/**
* Get value preceded by the argument. <br>
* Example: <br>
* For command line: `-k -c 1000 -n 100` <br>
* `getNamedArgumentValue("-c") == "1000"`, `getNamedArgumentValue("-n") == "100"`
* @param argName - name of the preceded argument.
* @param defaultValue - default value to return in case not found.
* @return - value preceded by the argument. defaultValue if not found.
*/
const char* getNamedArgumentValue(const char* argName, const char* defaultValue = nullptr) {
return Parser::getNamedArgumentValue(m_argc, m_argv, argName, defaultValue);
}

View File

@ -32,6 +32,12 @@ Countable::Countable() {
#endif
}
Countable::Countable(const Countable& other) {
#ifndef OATPP_DISABLE_ENV_OBJECT_COUNTERS
Environment::incObjects();
#endif
}
Countable::~Countable(){
#ifndef OATPP_DISABLE_ENV_OBJECT_COUNTERS
Environment::decObjects();

View File

@ -29,10 +29,26 @@
#include "./Environment.hpp"
namespace oatpp { namespace base{
/**
* Class instantiations of which can be counted.
*/
class Countable {
public:
/**
* Constructor. Increment counter calling &id:oatpp::base::Environment::incObjects;.
*/
Countable();
/**
* Copy constructor. Increment counter calling &id:oatpp::base::Environment::incObjects;.
* @param other
*/
Countable(const Countable& other);
/**
* Virtual destructor. Decrement counter calling &id:oatpp::base::Environment::decObjects;.
*/
virtual ~Countable();
};

View File

@ -71,13 +71,31 @@ typedef std::atomic_int_fast64_t v_atomicCounter;
typedef v_int64 v_counter;
namespace oatpp { namespace base{
/**
* Interface for system-wide Logger.<br>
* All calls to `OATPP_DISABLE_LOGV`, `OATPP_DISABLE_LOGE`, `OATPP_DISABLE_LOGD` should come here.
*/
class Logger {
public:
/**
* Virtual Destructor.
*/
virtual ~Logger() = default;
/**
* Log message with priority, tag, message.
* @param priority - priority channel of the message.
* @param tag - tag of the log message.
* @param message - message.
*/
virtual void log(v_int32 priority, const std::string& tag, const std::string& message) = 0;
};
/**
* Class to manage application environment.<br>
* Manage object counters, manage components, and do system health-checks.
*/
class Environment{
private:
static v_atomicCounter m_objectsCount;
@ -90,7 +108,11 @@ private:
private:
static std::unordered_map<std::string, std::unordered_map<std::string, void*>> m_components;
public:
/**
* Class representing system component.
* @tparam T - component type.
*/
template <typename T>
class Component {
private:
@ -98,7 +120,12 @@ public:
std::string m_name;
T m_object;
public:
/**
* Constructor.
* @param name - component name.
* @param object - component object.
*/
Component(const std::string& name, const T& object)
: m_type(typeid(T).name())
, m_name(name)
@ -106,15 +133,26 @@ public:
{
Environment::registerComponent(m_type, m_name, &m_object);
}
/**
* Constructor.
* @param object - component object.
*/
Component(const T& object)
: Component("NoName", object)
{}
/**
* Non-virtual Destructor.
*/
~Component() {
Environment::unregisterComponent(m_type, m_name);
}
/**
* Get object stored in the component.
* @return - object.
*/
T getObject() {
return m_object;
}
@ -125,29 +163,106 @@ private:
static void registerComponent(const std::string& typeName, const std::string& componentName, void* component);
static void unregisterComponent(const std::string& typeName, const std::string& componentName);
public:
/**
* Initialize environment and do basic health-checks.
*/
static void init();
/**
* De-initialize environment and do basic health-checks.
* Check for memory leaks.
*/
static void destroy();
/**
* increment counter of objects.
*/
static void incObjects();
/**
* decrement counter of objects.
*/
static void decObjects();
/**
* Get count of objects currently allocated and stored in the memory.
* @return
*/
static v_counter getObjectsCount();
/**
* Get count of objects created for a whole system lifetime.
* @return - count of objects.
*/
static v_counter getObjectsCreated();
/**
* Same as `getObjectsCount()` but `thread_local`
* @return - count of objects.
*/
static v_counter getThreadLocalObjectsCount();
/**
* Same as `getObjectsCreated()` but `thread_local`
* @return - count of objects.
*/
static v_counter getThreadLocalObjectsCreated();
/**
* Set environment logger.
* @param logger - pointer to logger.
*/
static void setLogger(Logger* logger);
/**
* Print debug information of compilation config.<br>
* Print values for: <br>
* - `OATPP_DISABLE_ENV_OBJECT_COUNTERS`<br>
* - `OATPP_DISABLE_POOL_ALLOCATIONS`<br>
* - `OATPP_THREAD_HARDWARE_CONCURRENCY`<br>
* - `OATPP_THREAD_DISTRIBUTED_MEM_POOL_SHARDS_COUNT`<br>
* - `OATPP_ASYNC_EXECUTOR_THREAD_NUM_DEFAULT`
*/
static void printCompilationConfig();
/**
* Call `Logger::log()`
* @param priority - priority channel of the message.
* @param tag - tag of the log message.
* @param message - message.
*/
static void log(v_int32 priority, const std::string& tag, const std::string& message);
/**
* Format message and call `Logger::log()`<br>
* Message is formatted using `vsnprintf` method.
* @param priority - priority channel of the message.
* @param tag - tag of the log message.
* @param message - message.
* @param ... - format arguments.
*/
static void logFormatted(v_int32 priority, const std::string& tag, const char* message, ...);
/**
* Get component object by typeName.
* @param typeName - type name of the component.
* @return - pointer to a component object.
*/
static void* getComponent(const std::string& typeName);
/**
* Get component object by typeName and componentName.
* @param typeName - type name of the component.
* @param componentName - component qualifier name.
* @return - pointer to a component object.
*/
static void* getComponent(const std::string& typeName, const std::string& componentName);
/**
* Get ticks count in microseconds.
* @return - ticks count in microseconds.
*/
static v_int64 getMicroTickCount();
};

View File

@ -70,7 +70,19 @@ p_char8 StrBuffer::allocStrBuffer(const void* originData, v_int32 size, bool cop
}
return (p_char8) originData;
}
StrBuffer::StrBuffer()
: m_data((p_char8)"[<nullptr>]")
, m_size(11)
, m_hasOwnData(false)
{}
StrBuffer::StrBuffer(const void* data, v_int32 size, bool copyAsOwnData)
: m_data(allocStrBuffer(data, size, copyAsOwnData))
, m_size(size)
, m_hasOwnData(copyAsOwnData)
{}
StrBuffer::~StrBuffer() {
if(m_hasOwnData) {
delete [] m_data;

View File

@ -32,6 +32,9 @@
namespace oatpp { namespace base {
/**
* String buffer class.
*/
class StrBuffer : public oatpp::base::Countable {
private:
@ -63,105 +66,305 @@ private:
void setAndCopy(const void* data, const void* originData, v_int32 size);
static std::shared_ptr<StrBuffer> allocShared(const void* data, v_int32 size, bool copyAsOwnData);
/**
* Allocate memory for string or use originData
* if copyAsOwnData == false return originData
/*
* Allocate memory for string or use originData<br>
* if copyAsOwnData == false return originData
*/
static p_char8 allocStrBuffer(const void* originData, v_int32 size, bool copyAsOwnData);
public:
StrBuffer()
: m_data((p_char8)"[<nullptr>]")
, m_size(11)
, m_hasOwnData(false)
{}
StrBuffer(const void* data, v_int32 size, bool copyAsOwnData)
: m_data(allocStrBuffer(data, size, copyAsOwnData))
, m_size(size)
, m_hasOwnData(copyAsOwnData)
{}
/**
* Constructor. Default.
*/
StrBuffer();
/**
* Constructor.
* @param data - pointer to data.
* @param size - size of the data.
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
*/
StrBuffer(const void* data, v_int32 size, bool copyAsOwnData);
public:
/**
* virtual Destructor.
*/
virtual ~StrBuffer();
/**
* Create shared StrBuffer of specified size.
* @param size - size of the buffer.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createShared(v_int32 size);
/**
* Create shared StrBuffer with data, size, and copyAsOwnData parameters.
* @param data - buffer data.
* @param size - size of the data.
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createShared(const void* data, v_int32 size, bool copyAsOwnData = true);
/**
* Create shared StrBuffer with data, and copyAsOwnData parameters.
* @param data - buffer data.
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createShared(const char* data, bool copyAsOwnData = true);
/**
* Create shared StrBuffer from other StrBuffer.
* @param other - other StrBuffer.
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createShared(StrBuffer* other, bool copyAsOwnData = true);
/**
* Create shared StrBuffer of size=size1 + size2 and data=data1 + data2.
* @param data1 - pointer to data1.
* @param size1 - size of the data1.
* @param data2 - pointer to data2.
* @param size2 - size of the data2.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createSharedConcatenated(const void* data1, v_int32 size1, const void* data2, v_int32 size2);
/**
* Create shared StrBuffer from c-string.
* @param data - data.
* @param copyAsOwnData - if true then allocate own buffer and copy data to that buffer.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> createFromCString(const char* data, bool copyAsOwnData = true) {
if(data != nullptr) {
return allocShared(data, (v_int32) std::strlen(data), copyAsOwnData);
}
return nullptr;
}
/**
* Load data from file and store in StrBuffer.
* If file not found return nullptr
* @param filename - name of the file.
* @return - shared_ptr to StrBuffer.
*/
static std::shared_ptr<StrBuffer> loadFromFile(const char* filename);
void saveToFile(const char* filename);
p_char8 getData() const;
v_int32 getSize() const;
const char* c_str() const;
std::string std_str() const;
bool hasOwnData() const;
/**
* (correct for ACII only)
* Save content of the buffer to file.
* @param filename - name of the file.
*/
void saveToFile(const char* filename);
/**
* Get pointer to data of the buffer.
* @return - pointer to data of the buffer.
*/
p_char8 getData() const;
/**
* Get buffer size.
* @return - buffer size.
*/
v_int32 getSize() const;
/**
* Get pointer to data of the buffer as `const* char`.
* @return - pointer to data of the buffer.
*/
const char* c_str() const;
/**
* Get copy of the buffer data as `std::string`.
* @return - copy of the buffer data as `std::string`.
*/
std::string std_str() const;
/**
* Is this object is responsible for freeing buffer data.
* @return - true if this object is responsible for freeing buffer data.
*/
bool hasOwnData() const;
/**
* Create lowercase copy of the buffer.<br>
* (correct for ASCII only)
* @return - copy of the buffer containing lowercase variants of ascii symbols.
*/
std::shared_ptr<StrBuffer> toLowerCase() const;
/**
* (correct for ACII only)
* Create uppercase copy of the buffer.<br>
* (correct for ASCII only)
* @return - copy of the buffer containing uppercase variants of ascii symbols.
*/
std::shared_ptr<StrBuffer> toUpperCase() const;
/**
* Check string equality of the buffer to data of specified size.
* @param data - pointer to data to be compared with the buffer data.
* @param size - size of the data.
* @return - true if all chars of buffer are same as in data, and size == this.getSize().
*/
bool equals(const void* data, v_int32 size) const;
/**
* Check string equality of the buffer to data of specified size.
* @param data - pointer to data to be compared with the buffer data.
* @return - true if all chars of buffer are same as in data, and std::strlen(data) == this.getSize().
*/
bool equals(const char* data) const;
/**
* Check string equality to other buffer.
* @param other - pointer to other StrBuffer to be compared with the buffer data.
* @return - true if all chars of one buffer are same as in other, and other.getSize() == this.getSize().
*/
bool equals(StrBuffer* other) const;
/**
* Check if buffer starts with specified data, size.
* @param data - data as `const void*`.
* @param size - size of the data.
* @return - true if buffer starts with specified data.
*/
bool startsWith(const void* data, v_int32 size) const;
/**
* Check if buffer starts with specified data.
* @param data - data as `const char*`.
* @return - true if buffer starts with specified data.
*/
bool startsWith(const char* data) const;
/**
* Check if buffer starts with specified data.
* @param data - data as `StrBuffer`.
* @return - true if buffer starts with specified data.
*/
bool startsWith(StrBuffer* data) const;
public:
static v_int32 compare(const void* data1, const void* data2, v_int32 size);
static v_int32 compare(StrBuffer* str1, StrBuffer* str2);
static bool equals(const void* data1, const void* data2, v_int32 size);
static bool equals(const char* data1, const char* data2);
static bool equals(StrBuffer* str1, StrBuffer* str2);
// Case Insensitive (correct for ASCII only)
static bool equalsCI(const void* data1, const void* data2, v_int32 size);
static bool equalsCI(const char* data1, const char* data2);
static bool equalsCI(StrBuffer* str1, StrBuffer* str2);
// Case Insensitive Fast (ASCII only, correct compare if one of strings contains letters only)
static bool equalsCI_FAST(const void* data1, const void* data2, v_int32 size);
static bool equalsCI_FAST(const char* data1, const char* data2);
static bool equalsCI_FAST(StrBuffer* str1, StrBuffer* str2);
static bool equalsCI_FAST(StrBuffer* str1, const char* str2);
/**
* lower case chars in the buffer @data (correct for ACII only)
* Compare data1, data2 using `std::memcmp`.
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @param size - number of characters to compare.
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
* 0 if all count bytes of data1 and data2 are equal.<br>
* Positive value if the first differing byte in data1 is greater than the corresponding byte in data2.
*/
static v_int32 compare(const void* data1, const void* data2, v_int32 size);
/**
* Compare data1, data2 using `std::memcmp`.
* @param data1 - data1 as `StrBuffer`.
* @param data2 - data2 as `StrBuffer`.
* @return - Negative value if the first differing byte (reinterpreted as unsigned char) in data1 is less than the corresponding byte in data2.<br>
* 0 if all count bytes of data1 and data2 are equal.<br>
* Positive value if the first differing byte in data1 is greater than the corresponding byte in data2.
*/
static v_int32 compare(StrBuffer* data1, StrBuffer* data2);
/**
* Check string equality of data1 to data2.
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @param size - number of characters to compare.
* @return - `true` if equals.
*/
static bool equals(const void* data1, const void* data2, v_int32 size);
/**
* Check string equality of data1 to data2.
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @return - `true` if equals.
*/
static bool equals(const char* data1, const char* data2);
/**
* Check string equality of str1 to str2.
* @param str1 - pointer to str1.
* @param str2 - pointer to str2.
* @return - `true` if equals.
*/
static bool equals(StrBuffer* str1, StrBuffer* str2);
/**
* Check Case Insensitive string equality of data1 to data2.
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @param size - number of characters to compare.
* @return - `true` if equals.
*/
static bool equalsCI(const void* data1, const void* data2, v_int32 size);
/**
* Check Case Insensitive string equality of data1 to data2.
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @return - `true` if equals.
*/
static bool equalsCI(const char* data1, const char* data2);
/**
* Check Case Insensitive string equality of str1 to str2.
* @param str1 - pointer to str1.
* @param str2 - pointer to str2.
* @return - `true` if equals.
*/
static bool equalsCI(StrBuffer* str1, StrBuffer* str2);
/**
* Check Case Insensitive string equality of data1 to data2. (ASCII only, correct compare if one of strings contains letters only)
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @param size - number of characters to compare.
* @return - `true` if equals.
*/
static bool equalsCI_FAST(const void* data1, const void* data2, v_int32 size);
/**
* Check Case Insensitive string equality of data1 to data2. (ASCII only, correct compare if one of strings contains letters only)
* @param data1 - pointer to data1.
* @param data2 - pointer to data2.
* @return - `true` if equals.
*/
static bool equalsCI_FAST(const char* data1, const char* data2);
/**
* Check Case Insensitive string equality of str1 to str2. (ASCII only, correct compare if one of strings contains letters only)
* @param str1 - pointer to str1.
* @param str2 - pointer to str2.
* @return - `true` if equals.
*/
static bool equalsCI_FAST(StrBuffer* str1, StrBuffer* str2);
/**
* Check Case Insensitive string equality of str1 to str2. (ASCII only, correct compare if one of strings contains letters only)
* @param str1 - pointer to str1 as `StrBuffer`.
* @param str2 - pointer to str2 as `const char*`
* @return - `true` if equals.
*/
static bool equalsCI_FAST(StrBuffer* str1, const char* str2);
/**
* Change characters in data to lowercase.
* @param data - pointer to data.
* @param size - size of the data.
*/
static void lowerCase(const void* data, v_int32 size);
/**
* upper case chars in the buffer @data (correct for ACII only)
* Change characters in data to uppercase.
* @param data - pointer to data.
* @param size - size of the data.
*/
static void upperCase(const void* data, v_int32 size);

View File

@ -23,3 +23,12 @@
***************************************************************************/
#include "Allocator.hpp"
namespace oatpp { namespace base { namespace memory {
AllocatorPoolInfo::AllocatorPoolInfo(const char* pPoolName, v_int32 pPoolChunkSize)
: poolName(pPoolName)
, poolChunkSize(pPoolChunkSize)
{}
}}}

View File

@ -29,16 +29,35 @@
namespace oatpp { namespace base { namespace memory {
/**
* Pool Information for Pool Allocators.
*/
class AllocatorPoolInfo {
public:
AllocatorPoolInfo(const char* pPoolName, v_int32 pPoolChunkSize)
: poolName(pPoolName)
, poolChunkSize(pPoolChunkSize)
{}
/**
* Constructor.
* @param pPoolName - memory pool name.
* @param pPoolChunkSize - memory pool chunk size. For more about chunk size see &id:oatpp::base::memory::MemoryPool::MemoryPool;.
*/
AllocatorPoolInfo(const char* pPoolName, v_int32 pPoolChunkSize);
/**
* Memory pool name.
*/
const char* const poolName;
/**
* Memory pool chunk size.
* For more about chunk size see &id:oatpp::base::memory::MemoryPool::MemoryPool;.
*/
const v_int32 poolChunkSize;
};
/**
* Allocator to allocate shared object on &id:oatpp::base::memory::MemoryPool;
* Used to allocate shared_ptr control block and an object in the same memory entry of the pool.
* @tparam T - type of the object to allocate.
*/
template<class T>
class PoolSharedObjectAllocator {
public:
@ -79,7 +98,11 @@ template <typename T, typename U>
inline bool operator != (const PoolSharedObjectAllocator<T>& a, const PoolSharedObjectAllocator<U>& b) {
return !(a == b);
}
/**
* Same as &l:PoolSharedObjectAllocator; but uses `thread_local` &id:oatpp::base::memory::MemoryPool;.
* @tparam T - type of the object to allocate.
*/
template<class T>
class ThreadLocalPoolSharedObjectAllocator {
public:
@ -120,17 +143,26 @@ template <typename T, typename U>
inline bool operator != (const ThreadLocalPoolSharedObjectAllocator<T>& a, const ThreadLocalPoolSharedObjectAllocator<U>& b) {
return !(a == b);
}
/**
* Extra information for, and about allocation.
* Used for variable-size objects allocations. (ex.: for strings).
*/
class AllocationExtras {
public:
AllocationExtras(v_int32 pExtraWanted)
: extraWanted(pExtraWanted)
: extraWanted(pExtraWanted)
{}
const v_int32 extraWanted;
void* extraPtr;
v_int32 baseSize;
};
/**
* Allocator for shared objects.
* Used to allocate object and shared_ptr's control block in the same memory entry.
* @tparam T - type of the object to allocate.
*/
template<class T>
class SharedObjectAllocator {
public:
@ -160,7 +192,12 @@ public:
}
};
/**
* Allocator for shared objects. Allocates objects on the pool provided.
* @tparam T - type of object to allocate.
* @tparam P - type of memory pool to allocate object on.
*/
template<class T, class P>
class CustomPoolSharedObjectAllocator {
public:
@ -203,7 +240,7 @@ template <typename T, typename U>
inline bool operator != (const SharedObjectAllocator<T>& a, const SharedObjectAllocator<U>& b) {
return !(a == b);
}
template<typename T, typename ... Args>
static std::shared_ptr<T> allocateSharedWithExtras(AllocationExtras& extras, Args... args){
typedef SharedObjectAllocator<T> _Allocator;

View File

@ -28,6 +28,31 @@
namespace oatpp { namespace base { namespace memory {
MemoryPool::MemoryPool(const std::string& name, v_int32 entrySize, v_int32 chunkSize)
: m_name(name)
, m_entrySize(entrySize)
, m_chunkSize(chunkSize)
, m_id(++poolIdCounter)
, m_rootEntry(nullptr)
, m_atom(false)
, m_objectsCount(0)
{
allocChunk();
oatpp::concurrency::SpinLock lock(POOLS_ATOM);
POOLS[m_id] = this;
}
MemoryPool::~MemoryPool() {
auto it = m_chunks.begin();
while (it != m_chunks.end()) {
p_char8 chunk = *it;
delete [] chunk;
it++;
}
oatpp::concurrency::SpinLock lock(POOLS_ATOM);
POOLS.erase(m_id);
}
void MemoryPool::allocChunk() {
#ifdef OATPP_DISABLE_POOL_ALLOCATIONS
// DO NOTHING

View File

@ -34,7 +34,11 @@
#include <cstring>
namespace oatpp { namespace base { namespace memory {
/**
* Memory Pool allocates memory chunks. Each chunk consists of specified number of fixed-size entries.
* Entries can be obtained and freed by user. When memory pool runs out of free entries, new chunk is allocated.
*/
class MemoryPool {
public:
static oatpp::concurrency::SpinLock::Atom POOLS_ATOM;
@ -70,58 +74,114 @@ private:
oatpp::concurrency::SpinLock::Atom m_atom;
v_int32 m_objectsCount;
public:
MemoryPool(const std::string& name, v_int32 entrySize, v_int32 chunkSize)
: m_name(name)
, m_entrySize(entrySize)
, m_chunkSize(chunkSize)
, m_id(++poolIdCounter)
, m_rootEntry(nullptr)
, m_atom(false)
, m_objectsCount(0)
{
allocChunk();
oatpp::concurrency::SpinLock lock(POOLS_ATOM);
POOLS[m_id] = this;
}
virtual ~MemoryPool() {
auto it = m_chunks.begin();
while (it != m_chunks.end()) {
p_char8 chunk = *it;
delete [] chunk;
it++;
}
oatpp::concurrency::SpinLock lock(POOLS_ATOM);
POOLS.erase(m_id);
}
/**
* Constructor.
* @param name - name of the pool.
* @param entrySize - size of the entry in bytes returned in call to &l:MemoryPool::obtain ();.
* @param chunkSize - number of entries in one chunk.
*/
MemoryPool(const std::string& name, v_int32 entrySize, v_int32 chunkSize);
/**
* Virtual destructor.
*/
virtual ~MemoryPool();
/**
* Obtain pointer to memory entry.
* When entry is no more needed, user must call &id:oatpp::base::memory::MemoryPool::free; and pass obtained entry pointer as a parameter.
* @return - pointer to memory entry.
*/
void* obtain();
/*
* Do not use it.
* Same as &l:MemoryPool::obtain (); but lock free. <br>
* TODO - check if this method is ever used.
* @return - pointer to memory entry.
*/
void* obtainLockFree();
/*
* For internal use only.
* TODO - make it private.
* @param entry
*/
void freeByEntryHeader(EntryHeader* entry);
/**
* Free obtained earlier memory entry.
* This method is static, because entry "knows" to what pool it belongs.
* @param entry - entry obtained by call to &l:MemoryPool::obtain ();
*/
static void free(void* entry);
/**
* Get name of the memory pool.
* @return - memory pool name as `std::string`.
*/
std::string getName();
/**
* Get size of the memory entry in bytes which can be obtained by call to &l:MemoryPool::obtain ();.
* @return - size of the enrty in bytes.
*/
v_int32 getEntrySize();
/**
* Get size of the memory allocated by memory pool.
* @return - size of the memory allocated by memory pool.
*/
v_int64 getSize();
/**
* Get number of entries currently in use.
* @return - number of entries currently in use.
*/
v_int32 getObjectsCount();
};
/**
* Creates multiple MemoryPools (&l:MemoryPool;) to reduce concurrency blocking in call to &l:ThreadDistributedMemoryPool::obtain ();
*/
class ThreadDistributedMemoryPool {
private:
v_int32 m_shardsCount;
MemoryPool** m_shards;
public:
/**
* Default number of MemoryPools (&l:MemoryPool;) "shards" to create.
*/
static const v_int32 SHARDS_COUNT_DEFAULT;
public:
/**
* Constructor.
* @param name - name of the memory pool.
* @param entrySize - size of memory pool entry.
* @param chunkSize - number of entries in chunk.
* @param shardsCount - number of MemoryPools (&l:MemoryPool;) "shards" to create.
*/
ThreadDistributedMemoryPool(const std::string& name, v_int32 entrySize, v_int32 chunkSize,
v_int32 shardsCount = SHARDS_COUNT_DEFAULT);
virtual ~ThreadDistributedMemoryPool();
/**
* Obtain pointer to memory entry.
* When entry is no more needed, user must call &id:oatpp::base::memory::MemoryPool::free; and pass obtained entry pointer as a parameter.
* @return - pointer to memory entry.
*/
void* obtain();
};
/**
* Not thread-safe pool of objects of specified type.
* @tparam T - object type.
*/
template<typename T>
class Bench {
private:
@ -163,7 +223,11 @@ private:
Block* m_blocks;
T** m_index;
public:
/**
* Constructor.
* @param growSize - number of objects to allocate when no free objects left.
*/
Bench(v_int32 growSize)
: m_growSize(growSize)
, m_size(0)
@ -173,7 +237,10 @@ public:
{
grow();
}
/**
* Non virtual destructor.
*/
~Bench(){
auto curr = m_blocks;
while (curr != nullptr) {
@ -183,7 +250,13 @@ public:
}
delete [] m_index;
}
/**
* Construct object and get pointer to constructed object.
* @tparam Args - arguments to be passed to object constructor.
* @param args - actual arguments to pass to object constructor.
* @return - pointer to constructed object.
*/
template<typename ... Args>
T* obtain(Args... args) {
if(m_indexPosition == m_size) {
@ -191,7 +264,11 @@ public:
}
return new (m_index[m_indexPosition ++]) T(args...);
}
/**
* Call object destructor and put it on "bench".
* @param entry - object to be freed.
*/
void free(T* entry) {
entry->~T();
m_index[--m_indexPosition] = entry;

View File

@ -30,6 +30,12 @@
namespace oatpp { namespace base { namespace memory {
/**
* Macro to declare object pool class which uses &id:oatpp::base::memory::PoolSharedObjectAllocator; to allocate objects.
* @param NAME - name of the memory pool.
* @param TYPE - type of the object.
* @param CHUNK_SIZE - chunk size for &id:oatpp::base::memory::MemoryPool;.
*/
#define SHARED_OBJECT_POOL(NAME, TYPE, CHUNK_SIZE) \
class NAME { \
public: \
@ -54,7 +60,12 @@ public: \
\
};
/**
* Macro to declare object pool class which uses &id:oatpp::base::memory::ThreadLocalPoolSharedObjectAllocator; to allocate objects.
* @param NAME - name of the memory pool.
* @param TYPE - type of the object.
* @param CHUNK_SIZE - chunk size for &id:oatpp::base::memory::MemoryPool;.
*/
#define SHARED_OBJECT_POOL_THREAD_LOCAL(NAME, TYPE, CHUNK_SIZE) \
class NAME { \
public: \
@ -78,7 +89,15 @@ public: \
} \
\
};
/**
* Macro to declare: &id:oatpp::base::memory::MemoryPool; for object, plus class-specific operators
* `static void* operator new(std::size_t sz)`, `static void operator delete(void* ptr, std::size_t sz)`,
* `static void* operator new(std::size_t sz, void* entry)`, `static void operator delete(void* ptr, void* entry)`.
* @param NAME - name of the memory pool.
* @param TYPE - type of the object.
* @param CHUNK_SIZE - chunk size for &id:oatpp::base::memory::MemoryPool;.
*/
#define OBJECT_POOL(POOL_NAME, TYPE, CHUNK_SIZE) \
class POOL_NAME { \
public: \
@ -115,6 +134,14 @@ static void* operator new(std::size_t sz, void* entry) { \
static void operator delete(void* ptr, void* entry) { \
}
/**
* Macro to declare: `thread_local` &id:oatpp::base::memory::MemoryPool; for object, plus class-specific operators
* `static void* operator new(std::size_t sz)`, `static void operator delete(void* ptr, std::size_t sz)`,
* `static void* operator new(std::size_t sz, void* entry)`, `static void operator delete(void* ptr, void* entry)`.
* @param NAME - name of the memory pool.
* @param TYPE - type of the object.
* @param CHUNK_SIZE - chunk size for &id:oatpp::base::memory::MemoryPool;.
*/
#define OBJECT_POOL_THREAD_LOCAL(POOL_NAME, TYPE, CHUNK_SIZE) \
class POOL_NAME { \
public: \

View File

@ -1,25 +0,0 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#include "Runnable.hpp"

View File

@ -1,41 +0,0 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#ifndef concurrency_Runnable_hpp
#define concurrency_Runnable_hpp
namespace oatpp { namespace concurrency {
class Runnable {
public:
virtual void run() = 0;
};
}}
#endif /* concurrency_Runnable_hpp */

View File

@ -30,17 +30,40 @@
namespace oatpp { namespace concurrency {
/**
* SpinLock implementation based on atomic.
*/
class SpinLock {
public:
/**
* Convenience typedef for atomic bool.
*/
typedef std::atomic<bool> Atom;
private:
Atom* m_atom;
public:
/**
* Constructor. Lock on construction.
* @param atom - atomic boolean.
*/
SpinLock(Atom& atom);
/**
* Non virtual destructor. Unlock on destruction.
*/
~SpinLock();
/**
* Spin-Lock using atomic boolean.
* @param atom - atomic boolean.
*/
static void lock(Atom& atom);
/**
* Spin-Unlock using atomic boolean.
* @param atom - atomic boolean.
*/
static void unlock(Atom& atom);
};

View File

@ -30,17 +30,17 @@
namespace oatpp { namespace concurrency {
v_int32 Thread::setThreadAffinityToOneCpu(std::thread::native_handle_type nativeHandle, v_int32 cpuIndex) {
v_int32 setThreadAffinityToOneCpu(std::thread::native_handle_type nativeHandle, v_int32 cpuIndex) {
return setThreadAffinityToCpuRange(nativeHandle, cpuIndex, cpuIndex);
}
v_int32 Thread::setThreadAffinityToCpuRange(std::thread::native_handle_type nativeHandle, v_int32 fromCpu, v_int32 toCpu) {
v_int32 setThreadAffinityToCpuRange(std::thread::native_handle_type nativeHandle, v_int32 firstCpuIndex, v_int32 lastCpuIndex) {
#if defined(_GNU_SOURCE)
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
for(v_int32 i = fromCpu; i <= toCpu; i++) {
for(v_int32 i = firstCpuIndex; i <= lastCpuIndex; i++) {
CPU_SET(i, &cpuset);
}
@ -56,7 +56,7 @@ v_int32 Thread::setThreadAffinityToCpuRange(std::thread::native_handle_type nati
#endif
}
v_int32 Thread::calcHardwareConcurrency() {
v_int32 calcHardwareConcurrency() {
#if !defined(OATPP_THREAD_HARDWARE_CONCURRENCY)
v_int32 concurrency = std::thread::hardware_concurrency();
if(concurrency == 0) {
@ -69,7 +69,7 @@ v_int32 Thread::calcHardwareConcurrency() {
#endif
}
v_int32 Thread::getHardwareConcurrency() {
v_int32 getHardwareConcurrency() {
static v_int32 concurrency = calcHardwareConcurrency();
return concurrency;
}

View File

@ -25,70 +25,37 @@
#ifndef oatpp_concurrency_Thread_hpp
#define oatpp_concurrency_Thread_hpp
#include "./Runnable.hpp"
#include "oatpp/core/base/memory/ObjectPool.hpp"
#include "oatpp/core/base/Countable.hpp"
#include "oatpp/core/base/Environment.hpp"
#include <thread>
namespace oatpp { namespace concurrency {
class Thread : public base::Countable {
public:
OBJECT_POOL(Thread_Pool, Thread, 32)
SHARED_OBJECT_POOL(Shared_Thread_Pool, Thread, 32)
private:
static v_int32 calcHardwareConcurrency();
public:
/**
* Set thread affinity one thread
*/
static v_int32 setThreadAffinityToOneCpu(std::thread::native_handle_type nativeHandle, v_int32 cpuIndex);
/**
* Set thread affinity [fromCpu..toCpu].
* from and to indexes included
*/
static v_int32 setThreadAffinityToCpuRange(std::thread::native_handle_type nativeHandle, v_int32 fromCpu, v_int32 toCpu);
/**
* returns OATPP_THREAD_HARDWARE_CONCURRENCY config value if set.
* else return std::thread::hardware_concurrency()
* else return 1
*/
static v_int32 getHardwareConcurrency();
private:
std::thread m_thread;
public:
Thread(const std::shared_ptr<Runnable>& runnable) {
m_thread = std::thread([runnable]{
runnable->run();
});
}
public:
static std::shared_ptr<Thread> createShared(const std::shared_ptr<Runnable>& runnable){
return Shared_Thread_Pool::allocateShared(runnable);
}
void join(){
m_thread.join();
}
void detach(){
m_thread.detach();
}
std::thread* getStdThread() {
return &m_thread;
}
};
/**
* Set thread affinity to one CPU.
* @param nativeHandle - `std::thread::native_handle_type`.
* @param cpuIndex - index of CPU.
* @return - zero on success. Negative value on failure.
* -1 if platform that runs application does not support this call.
*/
v_int32 setThreadAffinityToOneCpu(std::thread::native_handle_type nativeHandle, v_int32 cpuIndex);
/**
* Set thread affinity [firstCpuIndex..lastCpuIndex].
* @param nativeHandle - `std::thread::native_handle_type`.
* @param firstCpuIndex - from CPU-index.
* @param lastCpuIndex - to CPU-index included.
* @return - zero on success. Negative value on failure.
* -1 if platform that runs application does not support this call.
*/
v_int32 setThreadAffinityToCpuRange(std::thread::native_handle_type nativeHandle, v_int32 firstCpuIndex, v_int32 lastCpuIndex);
/**
* Get hardware concurrency.
* @return - OATPP_THREAD_HARDWARE_CONCURRENCY config value if set <br>
* else return std::thread::hardware_concurrency() <br>
* else return 1. <br>
*/
v_int32 getHardwareConcurrency();
}}

View File

@ -29,15 +29,19 @@
namespace oatpp { namespace data {
/**
* Represents I/O handle (ex.: file descriptor).
*/
typedef int v_io_handle;
/**
* All I/O buffer operations (like read/write(buffer, size)) should return
* v_io_size.
* All I/O buffer operations (like read/write(buffer, size)) should return v_io_size. <br>
*
* Possible return values:
* On Success - [1..max_int64]
* On Error - IOError values.
* <ul>
* <li>**On Success** - [1..max_int64].</li>
* <li>**On Error** - IOError values.</li>
* </ul>
*
* All other values are considered to be a fatal error.
* application should be terminated.

View File

@ -36,10 +36,6 @@ FIFOBuffer::FIFOBuffer(void* buffer, v_io_size bufferSize,
, m_canRead(canRead)
{}
FIFOBuffer::FIFOBuffer(void* buffer, v_io_size bufferSize)
: FIFOBuffer(buffer, bufferSize, 0, 0, false)
{}
void FIFOBuffer::setBufferPosition(data::v_io_size readPosition, data::v_io_size writePosition, bool canRead) {
m_readPosition = readPosition;
m_writePosition = writePosition;
@ -367,11 +363,6 @@ SynchronizedFIFOBuffer::SynchronizedFIFOBuffer(void* buffer, v_io_size bufferSiz
, m_atom(false)
{}
SynchronizedFIFOBuffer::SynchronizedFIFOBuffer(void* buffer, v_io_size bufferSize)
: m_fifo(buffer, bufferSize)
, m_atom(false)
{}
void SynchronizedFIFOBuffer::setBufferPosition(data::v_io_size readPosition, data::v_io_size writePosition, bool canRead) {
oatpp::concurrency::SpinLock lock(m_atom);
m_fifo.setBufferPosition(readPosition, writePosition, canRead);
@ -387,10 +378,6 @@ data::v_io_size SynchronizedFIFOBuffer::availableToWrite() {
return m_fifo.availableToWrite();
}
data::v_io_size SynchronizedFIFOBuffer::getBufferSize() const {
return m_fifo.getBufferSize();
}
data::v_io_size SynchronizedFIFOBuffer::read(void *data, data::v_io_size count) {
oatpp::concurrency::SpinLock lock(m_atom);
return m_fifo.read(data, count);

View File

@ -45,17 +45,44 @@ private:
bool m_canRead;
public:
/**
* Constructor.
* @param buffer - pointer to buffer used for reads/writes.
* @param bufferSize - buffer size.
* @param readPosition - initial read position in buffer.
* @param writePosition - initial write position in buffer.
* @param canRead - flag to resolve ambiguity when readPosition == writePosition. If(readPosition == writePosition && canRead) then
* &l:FIFOBuffer::availableToRead (); returns buffer size, and &l:FIFOBuffer::availableToWrite (); returns 0.
*/
FIFOBuffer(void* buffer, v_io_size bufferSize,
data::v_io_size readPosition, data::v_io_size writePosition,
bool canRead);
FIFOBuffer(void* buffer, v_io_size bufferSize);
data::v_io_size readPosition = 0, data::v_io_size writePosition = 0,
bool canRead = false);
/**
* Set read and write positions in buffer.
* @param readPosition - read position in buffer.
* @param writePosition - write position in buffer.
* @param canRead - flag to resolve ambiguity when readPosition == writePosition. If(readPosition == writePosition && canRead) then
* &l:FIFOBuffer::availableToRead (); returns buffer size, and &l:FIFOBuffer::availableToWrite (); returns 0.
*/
void setBufferPosition(data::v_io_size readPosition, data::v_io_size writePosition, bool canRead);
/**
* Amount of bytes currently available to read from buffer.
* @return &id:oatpp::data::v_io_size;.
*/
data::v_io_size availableToRead() const;
/**
* Amount of buffer space currently available for data writes.
* @return &id:oatpp::data::v_io_size;.
*/
data::v_io_size availableToWrite() const;
/**
* Get FIFOBuffer size.
* @return - FIFOBuffer size.
*/
data::v_io_size getBufferSize() const;
/**
@ -63,7 +90,6 @@ public:
* @param data
* @param count
* @return [1..count], IOErrors.
*
*/
data::v_io_size read(void *data, data::v_io_size count);
@ -75,7 +101,6 @@ public:
*/
data::v_io_size write(const void *data, data::v_io_size count);
/**
* call read and then write bytes read to output stream
* @param stream
@ -121,20 +146,54 @@ private:
oatpp::concurrency::SpinLock::Atom m_atom;
public:
/**
* Constructor.
* @param buffer - pointer to buffer used for reads/writes.
* @param bufferSize - buffer size.
* @param readPosition - initial read position in buffer.
* @param writePosition - initial write position in buffer.
* @param canRead - flag to resolve ambiguity when readPosition == writePosition. If(readPosition == writePosition && canRead) then
* &l:SynchronizedFIFOBuffer::availableToRead (); returns buffer size, and &l:SynchronizedFIFOBuffer::availableToWrite (); returns 0.
*/
SynchronizedFIFOBuffer(void* buffer, v_io_size bufferSize,
data::v_io_size readPosition, data::v_io_size writePosition,
bool canRead);
SynchronizedFIFOBuffer(void* buffer, v_io_size bufferSize);
data::v_io_size readPosition = 0, data::v_io_size writePosition = 0,
bool canRead = false);
/**
* Set read and write positions in buffer.
* @param readPosition - read position in buffer.
* @param writePosition - write position in buffer.
* @param canRead - flag to resolve ambiguity when readPosition == writePosition. If(readPosition == writePosition && canRead) then
* &l:SynchronizedFIFOBuffer::availableToRead (); returns buffer size, and &l:SynchronizedFIFOBuffer::availableToWrite (); returns 0.
*/
void setBufferPosition(data::v_io_size readPosition, data::v_io_size writePosition, bool canRead);
/**
* Amount of bytes currently available to read from buffer.
* @return &id:oatpp::data::v_io_size;.
*/
data::v_io_size availableToRead();
/**
* Amount of buffer space currently available for data writes.
* @return &id:oatpp::data::v_io_size;.
*/
data::v_io_size availableToWrite();
data::v_io_size getBufferSize() const;
/**
* read up to count bytes from the buffer to data
* @param data
* @param count
* @return [1..count], IOErrors.
*/
data::v_io_size read(void *data, data::v_io_size count);
/**
* write up to count bytes from data to buffer
* @param data
* @param count
* @return [1..count], IOErrors.
*/
data::v_io_size write(const void *data, data::v_io_size count);
/* No implementation of other methods */

View File

@ -25,7 +25,25 @@
#include "IOBuffer.hpp"
namespace oatpp { namespace data{ namespace buffer {
const v_int32 IOBuffer::BUFFER_SIZE = 4096;
IOBuffer::IOBuffer()
: m_entry(getBufferPool().obtain())
{}
std::shared_ptr<IOBuffer> IOBuffer::createShared(){
return Shared_IOBuffer_Pool::allocateShared();
}
IOBuffer::~IOBuffer() {
oatpp::base::memory::MemoryPool::free(m_entry);
}
void* IOBuffer::getData(){
return m_entry;
}
v_int32 IOBuffer::getSize(){
return BUFFER_SIZE;
}
}}}

View File

@ -28,44 +28,57 @@
#include "oatpp/core/base/memory/ObjectPool.hpp"
#include "oatpp/core/base/Countable.hpp"
namespace oatpp { namespace data{ namespace buffer {
/**
* Predefined buffer implementation for I/O operations.
* Allocates buffer bytes using &id:oatpp::base::memory::ThreadDistributedMemoryPool;.
*/
class IOBuffer : public oatpp::base::Countable {
public:
OBJECT_POOL(IOBuffer_Pool, IOBuffer, 32)
SHARED_OBJECT_POOL(Shared_IOBuffer_Pool, IOBuffer, 32)
public:
static const v_int32 BUFFER_SIZE;
/**
* Buffer size constant.
*/
static constexpr v_int32 BUFFER_SIZE = 4096;
private:
// TODO FastAlloc
static oatpp::base::memory::ThreadDistributedMemoryPool& getBufferPool(){
static oatpp::base::memory::ThreadDistributedMemoryPool pool("IOBuffer_Buffer_Pool", BUFFER_SIZE, 32);
static oatpp::base::memory::ThreadDistributedMemoryPool pool("IOBuffer_Buffer_Pool", BUFFER_SIZE, 16);
return pool;
}
private:
void* m_entry;
public:
IOBuffer()
: m_entry(getBufferPool().obtain())
{}
/**
* Constructor.
*/
IOBuffer();
public:
static std::shared_ptr<IOBuffer> createShared(){
return Shared_IOBuffer_Pool::allocateShared();
}
~IOBuffer() {
oatpp::base::memory::MemoryPool::free(m_entry);
}
void* getData(){
return m_entry;
}
v_int32 getSize(){
return BUFFER_SIZE;
}
/**
* Create shared IOBuffer.
* @return
*/
static std::shared_ptr<IOBuffer> createShared();
/**
* Virtual destructor.
*/
~IOBuffer();
/**
* Get pointer to buffer data.
* @return
*/
void* getData();
/**
* Get buffer size.
* @return - should always return &l:IOBuffer::BUFFER_SIZE;.
*/
v_int32 getSize();
};

View File

@ -23,3 +23,21 @@
***************************************************************************/
#include "ObjectMapper.hpp"
namespace oatpp { namespace data { namespace mapping {
ObjectMapper::ObjectMapper(const Info& info)
: m_info(info)
{}
const ObjectMapper::Info& ObjectMapper::getInfo() const {
return m_info;
}
oatpp::String ObjectMapper::writeToString(const type::AbstractObjectWrapper& variant) const {
auto stream = stream::ChunkedBuffer::createShared();
write(stream, variant);
return stream->toString();
}
}}}

View File

@ -36,45 +36,80 @@
#include "oatpp/core/parser/ParsingError.hpp"
namespace oatpp { namespace data { namespace mapping {
/**
* Abstract ObjectMapper class.
*/
class ObjectMapper {
public:
/**
* Metadata for ObjectMapper.
*/
class Info {
public:
/**
* Constructor.
* @param _http_content_type
*/
Info(const char* _http_content_type)
: http_content_type(_http_content_type)
{}
/**
* Value for Content-Type http header when DTO is serialized via specified ObjectMapper.
*/
const char* const http_content_type;
};
private:
Info m_info;
public:
ObjectMapper(const Info& info)
: m_info(info)
{}
const Info& getInfo() const {
return m_info;
}
virtual void write(const std::shared_ptr<oatpp::data::stream::OutputStream>& stream,
const type::AbstractObjectWrapper& variant) const = 0;
virtual type::AbstractObjectWrapper read(oatpp::parser::Caret& caret,
const type::Type* const type) const = 0;
oatpp::String writeToString(const type::AbstractObjectWrapper& variant) const {
auto stream = stream::ChunkedBuffer::createShared();
write(stream, variant);
return stream->toString();
}
/**
* Constructor.
* @param info - Metadata for ObjectMapper.
*/
ObjectMapper(const Info& info);
/**
* Get ObjectMapper metadata.
* @return - ObjectMapper metadata.
*/
const Info& getInfo() const;
/**
* Serialize object to stream. Implement this method.
* @param stream - &id:oatpp::data::stream::OutputStream; to serialize object to.
* @param variant - Object to serialize.
*/
virtual void write(const std::shared_ptr<oatpp::data::stream::OutputStream>& stream,
const type::AbstractObjectWrapper& variant) const = 0;
/**
* Deserialize object. Implement this method.
* @param caret - &id:oatpp::parser::Caret; over serialized buffer.
* @param type - pointer to object type. See &id:oatpp::data::mapping::type::Type;.
* @return - deserialized object wrapped in &id:oatpp::data::mapping::type::AbstractObjectWrapper;.
*/
virtual mapping::type::AbstractObjectWrapper read(oatpp::parser::Caret& caret,
const mapping::type::Type* const type) const = 0;
/**
* Serialize object to String.
* @param variant - Object to serialize.
* @return - serialized object as &id:oatpp::String;.
*/
oatpp::String writeToString(const type::AbstractObjectWrapper& variant) const;
/**
* Deserialize object.
* If nullptr is returned - check caret.getError()
* @tparam Class
* @param caret
* @return
* @tparam Class - object class.
* @param caret - &id:oatpp::parser::Caret; over serialized buffer.
* @return - deserialized Object.
* @throws - depends on implementation.
*/
template<class Class>
typename Class::ObjectWrapper readFromCaret(oatpp::parser::Caret& caret) const {
@ -83,10 +118,12 @@ public:
}
/**
* This method will throw on error
* @tparam Class
* @param str
* @return
* Deserialize object.
* @tparam Class - object class.
* @param str - serialized data.
* @return - deserialized Object.
* @throws - &id:oatpp::parser::ParsingError;
* @throws - depends on implementation.
*/
template<class Class>
typename Class::ObjectWrapper readFromString(const oatpp::String& str) const {

View File

@ -37,16 +37,27 @@
namespace oatpp { namespace data { namespace mapping { namespace type {
namespace __class {
/**
* AbstractObject class.
*/
class AbstractObject {
public:
static const char* const CLASS_NAME;
};
/**
* Template for Object class of type T.
* @tparam T - object type.
*/
template<class T>
class Object : public AbstractObject {
public:
/**
* Get type describing this class.
* @return - &id:oatpp::data::mapping::type::Type;
*/
static Type* getType(){
static Type* type = static_cast<Type*>(T::Z__CLASS_GET_TYPE());
return type;
@ -55,7 +66,11 @@ namespace __class {
};
}
/**
* Base class for all DTO objects.
* For more info about Data Transfer Object (DTO) see [Data Transfer Object (DTO)](https://oatpp.io/docs/components/dto/).
*/
class Object : public oatpp::base::Countable {
public:
typedef oatpp::data::mapping::type::String String;

View File

@ -48,6 +48,9 @@ namespace __class {
}
/**
* Mapping-enables String is &id:oatpp::data::mapping::type::ObjectWrapper; over &id:oatpp::base::StrBuffer;
*/
class String : public oatpp::data::mapping::type::ObjectWrapper<oatpp::base::StrBuffer, __class::String> {
public:
String(const std::shared_ptr<oatpp::base::StrBuffer>& ptr, const type::Type* const valueType);
@ -124,14 +127,22 @@ public:
String operator + (const char* a, const String& b);
String operator + (const String& b, const char* a);
String operator + (const String& a, const String& b);
/**
* Template for primitive mapping-enabled types.
* @tparam ValueType - type of the value ex.: v_int32.
* @tparam Clazz - Class holding static class information.
*/
template<typename ValueType, class Clazz>
class Primitive : public oatpp::base::Countable {
public:
OBJECT_POOL(Primitive_Type_Pool, Primitive, 32)
SHARED_OBJECT_POOL(Shared_Primitive_Type_Pool, Primitive, 32)
public:
/**
* ObjectWrapper template for &l:Primitive;.
*/
class ObjectWrapper : public oatpp::data::mapping::type::ObjectWrapper<Primitive, Clazz> {
public:
ObjectWrapper(const std::shared_ptr<Primitive>& ptr, const type::Type* const valueType)
@ -205,35 +216,84 @@ private:
ValueType m_value;
public:
/**
* Constructor.
* @param value - initial value.
*/
Primitive(const ValueType& value)
: m_value(value)
{}
public:
/**
* Create shared primitive.
* @param value - initial value.
* @return - `std::shared_ptr` to Primitive.
*/
static std::shared_ptr<Primitive> createShared(const ValueType& value){
return Shared_Primitive_Type_Pool::allocateShared(value);
}
/**
* Create shared primitive upcasted to &id:oatpp::base::Countable;.
* @param value - initial value.
* @return - `std::shared_ptr` to primitive upcasted to &id:oatpp::base::Countable;.
*/
static std::shared_ptr<Countable> createAbstract(const ValueType& value){
return std::static_pointer_cast<Countable>(Shared_Primitive_Type_Pool::allocateShared(value));
}
/**
* Set value.
* @param value.
*/
void setValue(const ValueType& value) {
m_value = value;
}
/**
* Get value.
* @return - value.
*/
ValueType getValue() {
return m_value;
}
};
/**
* Int8 is an ObjectWrapper over &l:Primitive; and __class::Int8.
*/
typedef Primitive<v_int8, __class::Int8>::ObjectWrapper Int8;
/**
* Int16 is an ObjectWrapper over &l:Primitive; and __class::Int16.
*/
typedef Primitive<v_int16, __class::Int16>::ObjectWrapper Int16;
/**
* Int32 is an ObjectWrapper over &l:Primitive; and __class::Int32.
*/
typedef Primitive<v_int32, __class::Int32>::ObjectWrapper Int32;
/**
* Int64 is an ObjectWrapper over &l:Primitive; and __class::Int64.
*/
typedef Primitive<v_int64, __class::Int64>::ObjectWrapper Int64;
/**
* Float32 is an ObjectWrapper over &l:Primitive; and __class::Float32.
*/
typedef Primitive<v_float32, __class::Float32>::ObjectWrapper Float32;
/**
* Float64 is an ObjectWrapper over &l:Primitive; and __class::Float64.
*/
typedef Primitive<v_float64, __class::Float64>::ObjectWrapper Float64;
/**
* Boolean is an ObjectWrapper over &l:Primitive; and __class::Boolean.
*/
typedef Primitive<bool, __class::Boolean>::ObjectWrapper Boolean;
namespace __class {

View File

@ -37,7 +37,10 @@ namespace __class {
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type::Properties
void Type::Properties::pushBack(Property* property) {
m_map.insert({property->name, property});
m_list.push_back(property);
@ -47,5 +50,55 @@ void Type::Properties::pushFrontAll(Properties* properties) {
m_map.insert(properties->m_map.begin(), properties->m_map.end());
m_list.insert(m_list.begin(), properties->m_list.begin(), properties->m_list.end());
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type::Property
Type::Property::Property(Properties* properties, v_int64 pOffset, const char* pName, Type* pType)
: offset(pOffset)
, name(pName)
, type(pType)
{
properties->pushBack(this);
}
void Type::Property::set(void* object, const AbstractObjectWrapper& value) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
*property = value;
}
AbstractObjectWrapper Type::Property::get(void* object) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
return *property;
}
AbstractObjectWrapper& Type::Property::getAsRef(void* object) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
return *property;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type
Type::Type(const char* pName, const char* pNameQualifier)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(nullptr)
, properties(nullptr)
{}
Type::Type(const char* pName, const char* pNameQualifier, Creator pCreator)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(pCreator)
, properties(nullptr)
{}
Type::Type(const char* pName, const char* pNameQualifier, Creator pCreator, Properties* pProperties)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(pCreator)
, properties(pProperties)
{}
}}}}

View File

@ -36,20 +36,42 @@ namespace oatpp { namespace data { namespace mapping { namespace type {
class Type; // FWD
namespace __class {
/**
* Void Object Class.
*/
class Void {
public:
/**
* Name of the class - CLASS_NAME = "Void".
*/
static const char* const CLASS_NAME;
/**
* Get class type information.
* @return - &l:Type;
*/
static Type* getType();
};
}
/**
* PolymorphicWrapper holds std::shared_ptr to object, object static type, plus object dynamic type information.
* @tparam T - Object Type
*/
template <class T>
class PolymorphicWrapper {
protected:
std::shared_ptr<T> m_ptr;
public:
/**
* Static object type
*/
typedef T ObjectType;
public:
/**
* PolymorphicWrapper has no static object Class info.
* It treats object as of class &id:oatpp::data::mapping::type::__class::Void;.
*/
typedef __class::Void Class;
public:
@ -133,7 +155,11 @@ public:
explicit operator bool() const {
return m_ptr.operator bool();
}
/**
* Value type information.
* See &l:Type;.
*/
const Type* const valueType;
};
@ -142,12 +168,23 @@ template<class T, class F>
inline PolymorphicWrapper<T> static_wrapper_cast(const F& from){
return PolymorphicWrapper<T>(std::static_pointer_cast<T>(from.getPtr()), from.valueType);
}
/**
* ObjectWrapper holds std::shared_ptr to object, object static type, object static class information, plus object dynamic type information.
* @tparam T - Object type.
* @tparam Clazz - Static Object class information.
*/
template <class T, class Clazz>
class ObjectWrapper : public PolymorphicWrapper<T>{
public:
/**
* Object type.
*/
typedef T ObjectType;
public:
/**
* Static object class information.
*/
typedef Clazz Class;
public:
ObjectWrapper(const std::shared_ptr<T>& ptr, const type::Type* const valueType)
@ -202,105 +239,162 @@ public:
}
};
/**
* PolymorphicWrapper over &id:oatpp::base::Countable; object.
*/
typedef PolymorphicWrapper<oatpp::base::Countable> AbstractObjectWrapper;
/**
* Object type data.
*/
class Type {
public:
typedef AbstractObjectWrapper (*Creator)();
public:
class Property; // FWD
public:
/**
* Object type properties table.
*/
class Properties {
private:
std::unordered_map<std::string, Property*> m_map;
std::list<Property*> m_list;
public:
void pushBack(Property* property);
void pushFrontAll(Properties* properties);
/**
* get properties as unordered map for random access
* Add property to the end of the list.
* @param property
*/
void pushBack(Property* property);
/**
* Add all properties to the beginning of the list.
* @param properties
*/
void pushFrontAll(Properties* properties);
/**
* Get properties as unordered map for random access.
* @return reference to std::unordered_map of std::string to &id:oatpp::data::mapping::type::Type::Property;*.
*/
const std::unordered_map<std::string, Property*>& getMap() const {
return m_map;
}
/**
* get properties in ordered way
* Get properties in ordered way.
* @return std::list of &id:oatpp::data::mapping::type::Type::Property;*.
*/
const std::list<Property*>& getList() const {
return m_list;
}
};
//typedef std::unordered_map<std::string, Property*> Properties;
public:
/**
* Class to map object properties.
*/
class Property {
private:
const v_int64 offset;
public:
Property(Properties* properties, v_int64 pOffset, const char* pName, Type* pType)
: offset(pOffset)
, name(pName)
, type(pType)
{
properties->pushBack(this);
}
/**
* Constructor.
* @param properties - &l:Type::Properties;*. to push this property to.
* @param pOffset - memory offset of object field from object start address.
* @param pName - name of the property.
* @param pType - &l:Type; of the property.
*/
Property(Properties* properties, v_int64 pOffset, const char* pName, Type* pType);
/**
* Property name.
*/
const char* const name;
/**
* Property type.
*/
const Type* const type;
void set(void* object, const AbstractObjectWrapper& value) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
*property = value;
}
AbstractObjectWrapper get(void* object) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
return *property;
}
AbstractObjectWrapper& getAsRef(void* object) {
AbstractObjectWrapper* property = (AbstractObjectWrapper*)(((v_int64) object) + offset);
return *property;
}
/**
* Set value of object field mapped by this property.
* @param object - object address.
* @param value - value to set.
*/
void set(void* object, const AbstractObjectWrapper& value);
/**
* Get value of object field mapped by this property.
* @param object - object address.
* @return - value of the field.
*/
AbstractObjectWrapper get(void* object);
/**
* Get reference to ObjectWrapper of the object field.
* @param object - object address.
* @return - reference to ObjectWrapper of the object field.
*/
AbstractObjectWrapper& getAsRef(void* object);
};
public:
Type(const char* pName, const char* pNameQualifier)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(nullptr)
, properties(nullptr)
{}
Type(const char* pName, const char* pNameQualifier, Creator pCreator)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(pCreator)
, properties(nullptr)
{}
Type(const char* pName, const char* pNameQualifier, Creator pCreator, Properties* pProperties)
: name(pName)
, nameQualifier(pNameQualifier)
, creator(pCreator)
, properties(pProperties)
{}
/**
* Constructor.
* @param pName - type name.
* @param pNameQualifier - type name qualifier.
*/
Type(const char* pName, const char* pNameQualifier);
/**
* Constructor.
* @param pName - type name.
* @param pNameQualifier - type name qualifier.
* @param pCreator - function pointer of Creator - function to create instance of this type.
*/
Type(const char* pName, const char* pNameQualifier, Creator pCreator);
/**
* Constructor.
* @param pName - type name.
* @param pNameQualifier - type name qualifier.
* @param pCreator - function pointer of Creator - function to create instance of this type.
* @param pProperties - pointer to type properties.
*/
Type(const char* pName, const char* pNameQualifier, Creator pCreator, Properties* pProperties);
/**
* Type name.
*/
const char* const name;
/**
* Type name qualifier.
*/
const char* const nameQualifier;
/**
* List of type parameters - for templated types.
*/
std::list<Type*> params;
/**
* Creator - function to create instance of this type.
*/
const Creator creator;
/**
* Pointer to type properties.
*/
const Properties* const properties;
};

View File

@ -31,7 +31,9 @@
namespace oatpp { namespace data { namespace share {
/**
* MemoryLabel represent a part of the whole memory buffer refered by handle
* MemoryLabel represent a part of the whole memory buffer refered by handle.
* Advantage of MemoryLabel use is that you may just "label" some data instead of allocating buffer for it's copy.
* You may allocate separate buffer for data copy later once you need it.
*/
class MemoryLabel {
protected:
@ -39,32 +41,66 @@ protected:
p_char8 m_data;
v_int32 m_size;
public:
/**
* Default constructor. Null MemoryLabel.
*/
MemoryLabel()
: m_memoryHandle(nullptr)
, m_data(nullptr)
, m_size(0)
{}
/**
* Constructor.
* @param memHandle - memory handle. `std::shared_ptr` to buffer pointed by a memory label.
* @param data - pointer to data.
* @param size - size of the data in bytes.
*/
MemoryLabel(const std::shared_ptr<base::StrBuffer>& memHandle, p_char8 data, v_int32 size);
/**
* Get pointer to labeled data.
* @return - pointer to data.
*/
p_char8 getData() const {
return m_data;
}
/**
* Get data size.
* @return - size of the data.
*/
v_int32 getSize() const {
return m_size;
}
/**
* Get memory handle which this memory label holds.
* @return - `std::shared_ptr` to &id:oatpp::base::StrBuffer;.
*/
std::shared_ptr<base::StrBuffer> getMemoryHandle() const {
return m_memoryHandle;
}
/**
* Check if labeled data equals to data specified.
* Data is compared using &id:oatpp::base::StrBuffer::equals;.
* @param data - data to compare with labeled data.
* @return - `true` if equals.
*/
bool equals(const char* data) const {
v_int32 size = (v_int32) std::strlen(data);
return m_size == size && base::StrBuffer::equals(m_data, data, m_size);
}
/**
* Check if labeled data equals to data specified.
* Data is compared using &id:oatpp::base::StrBuffer::equals;.
* @param data - data to compare with labeled data.
* @param size - data size.
* @return - `true` if equals.
*/
bool equals(const void* data, v_int32 size) const {
return m_size == size && base::StrBuffer::equals(m_data, data, m_size);
}

View File

@ -34,7 +34,18 @@ const data::v_io_size ChunkedBuffer::CHUNK_ENTRY_SIZE_INDEX_SHIFT = 11;
const data::v_io_size ChunkedBuffer::CHUNK_ENTRY_SIZE =
(1 << ChunkedBuffer::CHUNK_ENTRY_SIZE_INDEX_SHIFT);
const data::v_io_size ChunkedBuffer::CHUNK_CHUNK_SIZE = 32;
ChunkedBuffer::ChunkedBuffer()
: m_size(0)
, m_chunkPos(0)
, m_firstEntry(nullptr)
, m_lastEntry(nullptr)
{}
ChunkedBuffer::~ChunkedBuffer() {
clear();
}
ChunkedBuffer::ChunkEntry* ChunkedBuffer::obtainNewEntry(){
auto result = new ChunkEntry(getSegemntPool().obtain(), nullptr);
if(m_firstEntry == nullptr) {
@ -187,19 +198,22 @@ oatpp::String ChunkedBuffer::getSubstring(data::v_io_size pos,
readSubstring(str->getData(), pos, count);
return str;
}
// TODO - refactor this.
bool ChunkedBuffer::flushToStream(const std::shared_ptr<OutputStream>& stream){
data::v_io_size pos = m_size;
auto curr = m_firstEntry;
while (pos > 0) {
if(pos > CHUNK_ENTRY_SIZE) {
auto res = stream->write(curr->chunk, CHUNK_ENTRY_SIZE);
// TODO handle I/O errors.
if(res != CHUNK_ENTRY_SIZE) {
return false;
}
pos -= res;
} else {
auto res = stream->write(curr->chunk, pos);
// TODO handle I/O errors.
if(res != pos) {
return false;
}

View File

@ -31,7 +31,10 @@
#include "oatpp/core/async/Coroutine.hpp"
namespace oatpp { namespace data{ namespace stream {
/**
* Buffer wich can grow by chunks and implements &id:oatpp::data::stream::OutputStream; interface.
*/
class ChunkedBuffer : public oatpp::base::Countable, public OutputStream, public std::enable_shared_from_this<ChunkedBuffer> {
public:
static const char* ERROR_ASYNC_FAILED_TO_WRITE_ALL_DATA;
@ -126,54 +129,102 @@ private:
public:
ChunkedBuffer()
: m_size(0)
, m_chunkPos(0)
, m_firstEntry(nullptr)
, m_lastEntry(nullptr)
{}
~ChunkedBuffer() {
clear();
}
/**
* Constructor.
*/
ChunkedBuffer();
/**
* Virtual Destructor.
*/
~ChunkedBuffer();
public:
/**
* Deleted copy constructor.
*/
ChunkedBuffer(const ChunkedBuffer&) = delete;
ChunkedBuffer& operator=(const ChunkedBuffer&) = delete;
public:
/**
* Create shared ChunkedBuffer.
* @return `std::shared_ptr` to ChunkedBuffer.
*/
static std::shared_ptr<ChunkedBuffer> createShared(){
return Shared_ChunkedBuffer_Pool::allocateShared();
}
/**
* Write data to ChunkedBuffer. Implementation of &id:oatpp::data::stream::OutputStream::write; method.
* @param data - data to write.
* @param count - size of data in bytes.
* @return - actual number of bytes written.
*/
data::v_io_size write(const void *data, data::v_io_size count) override;
data::v_io_size readSubstring(void *buffer,
data::v_io_size pos,
data::v_io_size count);
/**
* Read part of ChunkedBuffer to buffer.
* @param buffer - buffer to write data to.
* @param pos - starting position in ChunkedBuffer to read data from.
* @param count - number of bytes to read.
* @return - actual number of bytes read from ChunkedBuffer and written to buffer.
*/
data::v_io_size readSubstring(void *buffer, data::v_io_size pos, data::v_io_size count);
/**
* return substring of the data written to stream; NOT NULL
* Create &id:oatpp::String; from part of ChunkedBuffer.
*/
/**
* Create &id:oatpp::String; from part of ChunkedBuffer.
* @param pos - starting position in ChunkedBuffer.
* @param count - size of bytes to write to substring.
* @return - &id:oatpp::String;
*/
oatpp::String getSubstring(data::v_io_size pos, data::v_io_size count);
/**
* return data written to stream as oatpp::String; NOT NULL
* Create &id:oatpp::String; from all data in ChunkedBuffer.
* @return - &id:oatpp::String;
*/
oatpp::String toString() {
return getSubstring(0, m_size);
}
/**
* Write all data from ChunkedBuffer to &id:oatpp::data::stream::OutputStream;.
* ChunkedBuffer will not be cleared during this call!
* @param stream - &id:oatpp::data::stream::OutputStream; stream to write all data to.
* @return - `true` if no errors occured. **will be refactored to return actual amount of bytes flushed**.
*/
bool flushToStream(const std::shared_ptr<OutputStream>& stream);
/**
* Write all data from ChunkedBuffer to &id:oatpp::data::stream::OutputStream; in asynchronous manner.
* @param parentCoroutine - caller coroutine. &id:oatpp::async::AbstractCoroutine;.
* @param actionOnFinish - action to do once finished. &id:oatpp::async::Action;.
* @param stream - &id:oatpp::data::stream::OutputStream; stream to write all data to.
* @return - &id:oatpp::async::Action;.
*/
oatpp::async::Action flushToStreamAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
const oatpp::async::Action& actionOnFinish,
const std::shared_ptr<OutputStream>& stream);
std::shared_ptr<Chunks> getChunks();
/**
* Get number of bytes written to ChunkedBuffer.
* @return - number of bytes written to ChunkedBuffer.
*/
data::v_io_size getSize();
/**
* Clear data in ChunkedBuffer.
*/
void clear();
};

View File

@ -28,14 +28,31 @@
#include "./Stream.hpp"
namespace oatpp { namespace data{ namespace stream {
/**
* Stream writer delegate which can write data to stream provided.
*/
class WriterDelegate {
public:
/**
* Write data to provided stream.
* @param stream - stream to write data to.
* @return - actual number of bytes written to stream. &id:oatpp::data::v_io_size;.
*/
virtual data::v_io_size writeToStream(const std::shared_ptr<OutputStream>& stream) = 0;
};
/**
* Stream reader delegate which can read data from stream provided.
*/
class ReaderDelegate {
public:
/**
* Read data from provided stream.
* @param stream - stream to read data from.
* @return - actual number of bytes read. &id:oatpp::data::v_io_size;.
*/
virtual data::v_io_size readFromStream(const std::shared_ptr<InputStream>& stream) = 0;
};

View File

@ -51,45 +51,110 @@ public:
static const char* const ERROR_ASYNC_UNKNOWN_CODE;
};
/**
* Output Stream.
*/
class OutputStream {
public:
/**
* Write data to stream up to count bytes, and return number of bytes actually written
* It is a legal case if return result < count. Caller should handle this!
* @param data - data to write.
* @param count - number of bytes to write.
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;.
*/
virtual data::v_io_size write(const void *data, data::v_io_size count) = 0;
/**
* Same as `write((p_char8)data, std::strlen(data));`.
* @param data - data to write.
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;.
*/
data::v_io_size write(const char* data){
return write((p_char8)data, std::strlen(data));
}
/**
* Same as `write(str->getData(), str->getSize());`
* @param str - data to write.
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;.
*/
data::v_io_size write(const oatpp::String& str){
return write(str->getData(), str->getSize());
}
/**
* Same as `write(&c, 1);`.
* @param c - one char to write.
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;.
*/
data::v_io_size writeChar(v_char8 c){
return write(&c, 1);
}
/**
* Convert value to string and write to stream.
* @param value
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;. <br>
* **Careful!!!** - use this method on your own risk as it's hard to understand if all data was written to stream.
*/
data::v_io_size writeAsString(v_int32 value);
/**
* Convert value to string and write to stream.
* @param value
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;. <br>
* **Careful!!!** - use this method on your own risk as it's hard to understand if all data was written to stream.
*/
data::v_io_size writeAsString(v_int64 value);
/**
* Convert value to string and write to stream.
* @param value
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;. <br>
* **Careful!!!** - use this method on your own risk as it's hard to understand if all data was written to stream.
*/
data::v_io_size writeAsString(v_float32 value);
/**
* Convert value to string and write to stream.
* @param value
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;. <br>
* **Careful!!!** - use this method on your own risk as it's hard to understand if all data was written to stream.
*/
data::v_io_size writeAsString(v_float64 value);
/**
* Convert value to string and write to stream.
* @param value
* @return - actual number of bytes written. &id:oatpp::data::v_io_size;. <br>
* **Careful!!!** - use this method on your own risk as it's hard to understand if all data was written to stream.
*/
data::v_io_size writeAsString(bool value);
};
/**
* Input Stream.
*/
class InputStream {
public:
/**
* Read data from stream up to count bytes, and return number of bytes actually read
* It is a legal case if return result < count. Caller should handle this!
* @param data - buffer to read dat to.
* @param count - size of the buffer.
* @return - actual number of bytes read.
*/
virtual data::v_io_size read(void *data, data::v_io_size count) = 0;
};
/**
* I/O Stream.
*/
class IOStream : public InputStream, public OutputStream {
public:
typedef data::v_io_size v_size;

View File

@ -22,6 +22,10 @@
*
***************************************************************************/
/**[info]
* This file contains source code for basic helper macros used for code-generator.
*/
#ifndef oatpp_macro_ForEach_hpp
#define oatpp_macro_ForEach_hpp

View File

@ -22,6 +22,19 @@
*
***************************************************************************/
/**[info]
* This file contains source code for `OATPP_CODEGEN_BEGIN(NAME)` and `OATPP_CODEGEN_END(NAME)` macros. <br>
* <br>
*
* More about use of `OATPP_CODEGEN_BEGIN` and `OATPP_CODEGEN_BEGIN` see: <br>
* <ul>
* <li>[ApiController component](https://oatpp.io/docs/components/api-controller/)</li>
* <li>[ApiClient component](https://oatpp.io/docs/components/api-client/)</li>
* <li>[Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/)</li>
* </ul>
*
*/
#ifndef codegen_hpp
#define codegen_hpp

View File

@ -22,6 +22,18 @@
*
***************************************************************************/
/**[info]
* This file contains source code for `OATPP_CREATE_COMPONENT` and `OATPP_COMPONENT` macros which are part of
* oatpp Dependency Injection (DI) framework. <br>
* <br>
* For usage examples see example-projects:
* <ul>
* <li>[CRUD - example](https://github.com/oatpp/example-crud)</li>
* <li>[HLS Media Stream - example](https://github.com/oatpp/example-hls-media-stream)</li>
* <li>[Async API - example](https://github.com/oatpp/example-async-api)</li>
* </ul>
*/
#ifndef oatpp_macro_component_hpp
#define oatpp_macro_component_hpp
@ -62,10 +74,21 @@ OATPP_MACRO_COMPONENT_(X, TYPE, NAME, LIST)
#define OATPP_MACRO_COMPONENT___(TYPE, NAME, LIST) \
OATPP_MACRO_COMPONENT__(OATPP_MACRO_HAS_ARGS LIST, TYPE, NAME, LIST)
/**
* Inject component. Create variable of type=TYPE and name=NAME and assign registered component to it.
* @param TYPE - type of the component.
* @param NAME - name of the variable.
* @param QUALIFIER_NAME - qualifier name is needed if there are multiple components registered of the same type.
* If there is one component registered only then TYPE info is enought to search for component.
*/
#define OATPP_COMPONENT(TYPE, NAME, ...) \
OATPP_MACRO_COMPONENT___(TYPE, NAME, (__VA_ARGS__))
/**
* Create component that then can be injected in other application classes.
* @param TYPE - type of the component.
* @param NAME - name of the component field.
*/
#define OATPP_CREATE_COMPONENT(TYPE, NAME) \
oatpp::base::Environment::Component<TYPE> NAME = oatpp::base::Environment::Component<TYPE>

View File

@ -43,27 +43,70 @@ public:
static const char* const ERROR_NAME_EXPECTED;
public:
/**
* Class to label parsing data.
*/
class Label {
private:
Caret* m_caret;
v_int32 m_start;
v_int32 m_end;
public:
/**
* Constructor.
* @param caret.
*/
Label(Caret* caret);
/**
* Set current caret position as a starting point for label.
*/
void start();
/**
* Fix current caret position as an end point for label.
*/
void end();
/**
* Get pointer to a labeled data.
* @return
*/
p_char8 getData();
/**
* Get size of labeled data.
* @return
*/
v_int32 getSize();
/**
* Create &id:oatpp::String; from labeled data.
* @param saveAsOwnData - `true` - allocate new memory block for string. `false` - string will point to the same data as label.
* @return - &id:oatpp::String;.
*/
oatpp::String toString(bool saveAsOwnData);
/**
* Same as`toString(true).`
* @return - &id:oatpp::String;.
*/
oatpp::String toString();
/**
* Create `std::string` from labeled data.
* @return - `std::string`.
*/
std::string std_str();
explicit operator bool() const;
};
/**
* Caret state saver guard.
*/
class StateSaveGuard {
private:
Caret& m_caret;
@ -72,11 +115,33 @@ public:
v_int32 m_savedErrorCode;
public:
/**
* Constructor.
* @param caret.
*/
StateSaveGuard(Caret& caret);
/**
* Destructor. Restore saved state.
*/
~StateSaveGuard();
/**
* Get caret saved position.
* @return
*/
v_int32 getSavedPosition();
/**
* Get caret saved error message.
* @return
*/
const char* getSavedErrorMessage();
/**
* Get caret saved error code.
* @return
*/
v_int32 getSavedErrorCode();
};

View File

@ -35,26 +35,101 @@
#include <string>
namespace oatpp { namespace utils { namespace conversion {
/**
* String to 32-bit integer.
* @param str - string as `const char*`.
* @return - 32-bit integer value.
*/
v_int32 strToInt32(const char* str);
/**
* String to 32-bit integer.
* @param str - string as `oatpp::String`.
* @param success - out parameter. `true` if operation was successful. `false` otherwise.
* @return - 32-bit integer value.
*/
v_int32 strToInt32(const oatpp::String& str, bool& success);
/**
* String to 64-bit integer.
* @param str - string as `const char*`.
* @return - 64-bit integer value.
*/
v_int64 strToInt64(const char* str);
/**
* String to 64-bit integer.
* @param str - string as `oatpp::String`.
* @param success - out parameter. `true` if operation was successful. `false` otherwise.
* @return - 64-bit integer value.
*/
v_int64 strToInt64(const oatpp::String& str, bool& success);
/**
* Convert 32-bit integer to it's string representation.
* @param value - 32-bit integer value.
* @param data - buffer to write data to.
* @return - length of the resultant string.
*/
v_int32 int32ToCharSequence(v_int32 value, p_char8 data);
/**
* Convert 64-bit integer to it's string representation.
* @param value - 64-bit integer value.
* @param data - buffer to write data to.
* @return - length of the resultant string.
*/
v_int32 int64ToCharSequence(v_int64 value, p_char8 data);
/**
* Convert 32-bit integer to it's string representation.
* @param value - 32-bit integer value.
* @return - value as `oatpp::String`
*/
oatpp::String int32ToStr(v_int32 value);
/**
* Convert 64-bit integer to it's string representation.
* @param value - 64-bit integer value.
* @return - value as `oatpp::String`
*/
oatpp::String int64ToStr(v_int64 value);
/**
* Convert 32-bit integer to it's string representation.
* @param value - 32-bit integer value.
* @return - value as `std::string`
*/
std::string int32ToStdStr(v_int32 value);
/**
* Convert 64-bit integer to it's string representation.
* @param value - 64-bit integer value.
* @return - value as `std::string`
*/
std::string int64ToStdStr(v_int64 value);
/**
* Write value of primitive type (int, float, etc.) as it's string representation with pattern.
* @tparam T - primitive value type (int, float, etc.).
* @param value - actual value.
* @param data - buffer to write data to.
* @param pattern - pattern as for `sprintf`.
* @return - length of the resultant string.
*/
template<typename T>
v_int32 primitiveToCharSequence(T value, p_char8 data, const char* pattern){
return sprintf((char*)data, pattern, value);
}
/**
* Write value of primitive type (int, float, etc.) as it's string representation with pattern.
* @tparam T - primitive value type (int, float, etc.).
* @param value - actual value.
* @param pattern - pattern as for `sprintf`.
* @return - length of the resultant string.
*/
template<typename T>
oatpp::String primitiveToStr(T value, const char* pattern){
v_char8 buff [100];
@ -64,21 +139,88 @@ namespace oatpp { namespace utils { namespace conversion {
}
return oatpp::String::empty();
}
/**
* String to 32-bit float.
* @param str - string as `const char*`.
* @return - 32-bit float value.
*/
v_float32 strToFloat32(const char* str);
/**
* String to 32-bit float.
* @param str - string as `oatpp::String`.
* @param success - out parameter. `true` if operation was successful. `false` otherwise.
* @return - 32-bit float value.
*/
v_float32 strToFloat32(const oatpp::String& str, bool& success);
/**
* String to 64-bit float.
* @param str - string as `const char*`.
* @return - 64-bit float value.
*/
v_float64 strToFloat64(const char* str);
/**
* String to 64-bit float.
* @param str - string as `oatpp::String`.
* @param success - out parameter. `true` if operation was successful. `false` otherwise.
* @return - 64-bit float value.
*/
v_float64 strToFloat64(const oatpp::String& str, bool& success);
/**
* Convert 32-bit float to it's string representation.
* @param value - 32-bit float value.
* @param data - buffer to write data to.
* @return - length of the resultant string.
*/
v_int32 float32ToCharSequence(v_float32 value, p_char8 data);
/**
* Convert 64-bit float to it's string representation.
* @param value - 64-bit float value.
* @param data - buffer to write data to.
* @return - length of the resultant string.
*/
v_int32 float64ToCharSequence(v_float64 value, p_char8 data);
/**
* Convert 32-bit float to it's string representation.
* @param value - 32-bit float value.
* @return - value as `oatpp::String`
*/
oatpp::String float32ToStr(v_float32 value);
/**
* Convert 64-bit float to it's string representation.
* @param value - 64-bit float value.
* @return - value as `oatpp::String`
*/
oatpp::String float64ToStr(v_float64 value);
/**
* Convert boolean to it's string representation.
* @param value - boolean value.
* @return - value as `oatpp::String`;
*/
oatpp::String boolToStr(bool value);
/**
* parse string to boolean value.
* @param str - string to parse.
* @param success - out parameter. `true` if operation was successful. `false` otherwise.
* @return - boolean value.
*/
bool strToBool(const oatpp::String& str, bool& success);
/**
* Write value of oatpp-primitive type (oatpp::Int32, oatpp::Int64, oatpp::Boolean, etc.) as it's string representation.
* @tparam T - oatpp-primitive type (oatpp::Int32, oatpp::Int64, oatpp::Boolean, etc.).
* @param primitive - ObjectWrapper.
* @return - value as string.
*/
template<class T>
oatpp::String
primitiveToStr(const oatpp::data::mapping::type::PolymorphicWrapper<T>& primitive) {

View File

@ -28,13 +28,23 @@
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace encoding {
/**
* Base64 - encoder/decoder.
*/
class Base64 {
public:
/**
* DecodingError.
*/
class DecodingError : public std::runtime_error {
public:
/**
* Constructor.
* @param message - error message.
*/
DecodingError(const char* message)
:std::runtime_error(message)
{}
@ -47,57 +57,103 @@ private:
public:
/**
* Alphabet is array of 65 chars. 64 chars encoding chars, and 65th padding char
* Standard base64 Alphabet - `['A'-'Z', 'a'-'z', '0'-'9', '+', '/', '=']`.
* Alphabet is array of 65 chars. 64 chars encoding chars, and 65th padding char.<br>
*/
static const char* const ALPHABET_BASE64;
/**
* URL base64 Alphabet - `['A'-'Z', 'a'-'z', '0'-'9', '-', '_', '=']`.
* Alphabet is array of 65 chars. 64 chars encoding chars, and 65th padding char.<br>
*/
static const char* const ALPHABET_BASE64_URL;
/**
* URL safe base64 Alphabet - `['A'-'Z', 'a'-'z', '0'-'9', '.', '_', '-']`.
* Alphabet is array of 65 chars. 64 chars encoding chars, and 65th padding char.<br>
*/
static const char* const ALPHABET_BASE64_URL_SAFE;
/**
* alphabet auxiliary chars - last 3 chars of alphabet including padding char.
* Standard base64 Alphabet auxiliary chars ['+', '/', '='].
* alphabet auxiliary chars - last 3 chars of alphabet including padding char.
*/
static const char* const ALPHABET_BASE64_AUXILIARY_CHARS;
static const char* const ALPHABET_BASE64_URL_AUXILIARY_CHARS;
static const char* const ALPHABET_BASE64_URL_SAFE_AUXILIARY_CHARS;
/**
* Returns size of encoding result of a string of the given size
* URL base64 Alphabet auxiliary chars ['-', '_', '='].
* alphabet auxiliary chars - last 3 chars of alphabet including padding char.
*/
static const char* const ALPHABET_BASE64_URL_AUXILIARY_CHARS;
/**
* URL safe base64 Alphabet auxiliary chars ['.', '_', '='].
* alphabet auxiliary chars - last 3 chars of alphabet including padding char.
*/
static const char* const ALPHABET_BASE64_URL_SAFE_AUXILIARY_CHARS;
/**
* Calculate size of encoding result of a string of the given size.
* @param size - size of string to encode.
* @return - size of encoding result of a string of the given size
*/
static v_int32 calcEncodedStringSize(v_int32 size);
/**
* Returns size of decoding result. this method assumes that data passed as a param consists of standard base64 set of chars
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 and three configurable auxiliary chars.
*
* if data passed is not a base64 string then -1 is returned
* Calculate size of decoding result. this method assumes that data passed as a param consists of standard base64 set of chars
* `['A'-'Z', 'a'-'z', '0'-'9']` and three configurable auxiliary chars.
* @param data - pointer to data.
* @param size - size of the data.
* @param base64StrLength - out parameter. Size of base64 valid encoded string. It may appear to be less then size.
* @param auxiliaryChars - configurable auxiliary chars.
* @return - size of decoded data. If data passed is not a base64 string then -1 is returned.
*/
static v_int32 calcDecodedStringSize(const char* data, v_int32 size, v_int32& base64StrLength, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* return (calcDecodedStringSize(data, size, auxiliaryChars) >= 0);
* Check if data is a valid base64 encoded string.
* @param data - pointer to data.
* @param size - data size.
* @param auxiliaryChars - configurable auxiliary chars.
* @return `(calcDecodedStringSize(data, size, base64StrLength, auxiliaryChars) >= 0)`.
*/
static bool isBase64String(const char* data, v_int32 size, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* encode data as base64 string
* Encode data as base64 string.
* @param data - pointer to data.
* @param size - data size.
* @param alphabet - base64 alphabet to use.
* @return - encoded base64 string as &id:oatpp::String;.
*/
static oatpp::String encode(const void* data, v_int32 size, const char* alphabet = ALPHABET_BASE64);
/**
* return encode(data->getData(), data->getSize(), alphabet);
* Encode data as base64 string.
* @param data - data to encode.
* @param alphabet - base64 alphabet to use.
* @return - encoded base64 string as &id:oatpp::String;.
*/
static oatpp::String encode(const oatpp::String& data, const char* alphabet = ALPHABET_BASE64);
/**
* decode() this method assumes that data passed as a param consists of standard base64 set of chars
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 and three configurable auxiliary chars.
*
* throws DecodingError(). in case invalid char found
* Decode base64 encoded data. This method assumes that data passed as a param consists of standard base64 set of chars
* `['A'-'Z', 'a'-'z', '0'-'9']` and three configurable auxiliary chars.
* @param data - pointer to data to decode.
* @param size - encoded data size.
* @param auxiliaryChars - configurable auxiliary chars.
* @return - decoded data as &id:oatpp::String;.
* @throws - &l:Base64::DecodingError;
*/
static oatpp::String decode(const char* data, v_int32 size, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);
/**
* return decode(data->getData(), data->getSize(), auxiliaryChars);
* Decode base64 encoded data. This method assumes that data passed as a param consists of standard base64 set of chars
* `['A'-'Z', 'a'-'z', '0'-'9']` and three configurable auxiliary chars.
* @param data - data to decode.
* @param auxiliaryChars - configurable auxiliary chars.
* @return - decoded data as &id:oatpp::String;.
* @throws - &l:Base64::DecodingError;
*/
static oatpp::String decode(const oatpp::String& data, const char* auxiliaryChars = ALPHABET_BASE64_AUXILIARY_CHARS);

View File

@ -27,8 +27,6 @@
namespace oatpp { namespace encoding {
const char* const Hex::ERROR_UNKNOWN_SYMBOL = "UNKNOWN_SYMBOL";
const v_char8 Hex::A_D[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/*
const v_word16 Hex::A_W16[] = {
@ -103,7 +101,7 @@ void Hex::writeWord32(v_word32 value, p_char8 buffer){
writeWord16(value, buffer + 4);
}
const char* Hex::readWord16(p_char8 buffer, v_word16& value) {
v_int32 Hex::readWord16(p_char8 buffer, v_word16& value) {
value = 0;
for(v_int32 i = 0; i < 4; i++){
v_char8 a = buffer[i];
@ -117,10 +115,10 @@ const char* Hex::readWord16(p_char8 buffer, v_word16& value) {
return ERROR_UNKNOWN_SYMBOL;
}
}
return nullptr;
return 0;
}
const char* Hex::readWord32(p_char8 buffer, v_word32& value) {
v_int32 Hex::readWord32(p_char8 buffer, v_word32& value) {
value = 0;
for(v_int32 i = 0; i < 8; i++){
v_char8 a = buffer[i];
@ -134,7 +132,7 @@ const char* Hex::readWord32(p_char8 buffer, v_word32& value) {
return ERROR_UNKNOWN_SYMBOL;
}
}
return nullptr;
return 0;
}
}}

View File

@ -31,20 +31,50 @@
#include "oatpp/core/base/Environment.hpp"
namespace oatpp { namespace encoding {
/**
* Utility class for hex string encoding/decoding .
*/
class Hex {
public:
static const v_char8 A_D[];
static const v_word16 A_W16[];
public:
static const char* const ERROR_UNKNOWN_SYMBOL;
/**
* Unknown symbol error.
*/
static constexpr v_int32 ERROR_UNKNOWN_SYMBOL = 1;
public:
/**
* Write value as hex string to buffer.
* @param value - value to write.
* @param buffer - buffer for resultant string.
*/
static void writeWord16(v_word16 value, p_char8 buffer);
/**
* Write value as hex string to buffer.
* @param value - value to write.
* @param buffer - buffer for resultant string.
*/
static void writeWord32(v_word32 value, p_char8 buffer);
static const char* readWord16(p_char8 buffer, v_word16& value);
static const char* readWord32(p_char8 buffer, v_word32& value);
/**
* Parse 4-char hex string to int16.
* @param buffer - buffer containing string to parse.
* @param value - out parameter. Resultant value.
* @return - 0 on success. Negative value on failure.
*/
static v_int32 readWord16(p_char8 buffer, v_word16& value);
/**
* Parse 8-char hex string to int32.
* @param buffer - buffer containing string to parse.
* @param value - out parameter. Resultant value.
* @return - 0 on success. Negative value on failure.
*/
static v_int32 readWord32(p_char8 buffer, v_word32& value);
};

View File

@ -28,14 +28,56 @@
#include "oatpp/core/base/Environment.hpp"
namespace oatpp { namespace encoding {
/**
* Helper class for processing unicode characters.
*/
class Unicode {
public:
/**
* Get length in bytes of UTF-8 character by its first byte.
* @param firstByte - first byte of UTF-8 character.
* @return - length in bytes of UTF-8 character.
*/
static v_int32 getUtf8CharSequenceLength(v_char8 firstByte);
/**
* Get length in bytes of UTF-8 character by its code.
* @param code - code of UTF-8 character.
* @return - length in bytes of UTF-8 character.
*/
static v_int32 getUtf8CharSequenceLengthForCode(v_word32 code);
static v_int32 encodeUtf8Char(p_char8 sequence, v_int32& length); // returns code
static v_int32 decodeUtf8Char(v_int32 code, p_char8 buffer); // returns length
/**
* Get code of UTF-8 character.
* @param sequence - pointer to first byte of UTF-8 character.
* @param length - out parameter. Length in bytes of UTF-8 character.
* @return - code of UTF-8 character.
*/
static v_int32 encodeUtf8Char(p_char8 sequence, v_int32& length);
/**
* Write UTF-8 character to buffer.
* @param code - UTF-8 character code.
* @param buffer - pointer to write UTF-8 character to.
* @return - length in bytes of UTF-8 character.
*/
static v_int32 decodeUtf8Char(v_int32 code, p_char8 buffer);
/**
* Get corresponding UTF-16 surrogate pair for symbol code.
* @param code - symbol code.
* @param high - out parameter. High surrogate.
* @param low - out parameter. Low surrogate.
*/
static void codeToUtf16SurrogatePair(v_int32 code, v_int16& high, v_int16& low);
/**
* Get symbol code of corresponding UTF-16 surrogate pair.
* @param high - High surrogate.
* @param low - Low surrogate.
* @return - symbol code.
*/
static v_int32 utf16SurrogatePairToCode(v_int16 high, v_int16 low);
};

View File

@ -29,7 +29,10 @@
#include "oatpp/core/data/stream/Stream.hpp"
namespace oatpp { namespace network {
/**
* TCP Connection implementation. Extends &id:oatpp::base::Countable; and &id:oatpp::data::stream::IOStream;.
*/
class Connection : public oatpp::base::Countable, public oatpp::data::stream::IOStream {
public:
OBJECT_POOL(Connection_Pool, Connection, 32);
@ -37,20 +40,53 @@ public:
private:
data::v_io_handle m_handle;
public:
/**
* Constructor.
* @param handle - file descriptor (socket handle). See &id:oatpp::data::v_io_handle;.
*/
Connection(data::v_io_handle handle);
public:
/**
* Create shared Connection.
* @param handle - file descriptor (socket handle). See &id:oatpp::data::v_io_handle;.
* @return - shared_ptr to Connection.
*/
static std::shared_ptr<Connection> createShared(data::v_io_handle handle){
return Shared_Connection_Pool::allocateShared(handle);
}
/**
* Virtual Destructor (See &id:oatpp::base::Countable;).
* Close socket handle.
*/
~Connection();
/**
* Implementation of &id:oatpp::data::stream::IOStream::write;.
* @param buff - buffer containing data to write.
* @param count - bytes count you want to write.
* @return - actual amount of bytes written. See &id:oatpp::data::v_io_size;.
*/
data::v_io_size write(const void *buff, data::v_io_size count) override;
/**
* Implementation of &id:oatpp::data::stream::IOStream::read;.
* @param buff - buffer to read data to.
* @param count - buffer size.
* @return - actual amount of bytes read. See &id:oatpp::data::v_io_size;.
*/
data::v_io_size read(void *buff, data::v_io_size count) override;
/**
* Close socket handle.
*/
void close();
/**
* Get socket handle.
* @return - socket handle. &id:oatpp::data::v_io_handle;.
*/
data::v_io_handle getHandle(){
return m_handle;
}

View File

@ -33,30 +33,63 @@
namespace oatpp { namespace network {
/**
* Abstract ConnectionProvider.
* It may be anything that returns oatpp::data::stream::IOStream
* Abstract ConnectionProvider. <br>
* Basically it returns whatever stream (&id:oatpp::data::stream::IOStream;). <br>
* User of ConnectionProvider should care about IOStream only.
* All other properties are optional
* All other properties are optional.
*/
class ConnectionProvider {
public:
/**
* Predefined property key for HOST.
*/
static const char* const PROPERTY_HOST;
/**
* Predefined property key for PORT.
*/
static const char* const PROPERTY_PORT;
public:
/**
* Convenience typedef for &id:oatpp::data::stream::IOStream;.
*/
typedef oatpp::data::stream::IOStream IOStream;
/**
* Convenience typedef for &id:oatpp::async::Action;.
*/
typedef oatpp::async::Action Action;
typedef oatpp::async::Action (oatpp::async::AbstractCoroutine::*AsyncCallback)(const std::shared_ptr<IOStream>&);
private:
std::unordered_map<oatpp::data::share::StringKeyLabelCI, oatpp::data::share::StringKeyLabel> m_properties;
protected:
/**
/*
* Set optional property
*/
void setProperty(const oatpp::String& key, const oatpp::String& value);
public:
virtual ~ConnectionProvider() {}
/**
* Virtual default destructor.
*/
virtual ~ConnectionProvider() = default;
/**
* Implement this method.
* Get IOStream representing connection to resource.
* @return - &id:oatpp::data::stream::IOStream;.
*/
virtual std::shared_ptr<IOStream> getConnection() = 0;
/**
* Implement this method.
* Obtain IOStream representing connection to resource.
* IOStream should be returned as a parameter to callback.
* @param parentCoroutine - caller coroutine. &id:oatpp::async::AbstractCoroutine;.
* @param callback - pointer to callback function.
* @return - &id:oatpp::async::Action;.
*/
virtual Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback) = 0;
@ -66,8 +99,8 @@ public:
virtual void close() = 0;
/**
* Some optional properties that user might want to know.
* All properties are optional and user should not rely on this
* Some optional properties that user might want to know. <br>
* Note: All properties are optional and user should not rely on this.
*/
const std::unordered_map<oatpp::data::share::StringKeyLabelCI, oatpp::data::share::StringKeyLabel>& getProperties();

View File

@ -35,67 +35,97 @@
namespace oatpp { namespace network {
// TODO - refactor to use oatpp::data::share::MemoryLabel
class Url : public oatpp::base::Countable {
/**
* Class holding URL information.
*/
class Url {
public:
/**
* Convenience typedef for &id:oatpp::data::share::StringKeyLabel;.
*/
typedef oatpp::data::share::StringKeyLabel StringKeyLabel;
public:
/**
* Parameters - map string to string.
*/
typedef std::unordered_map<oatpp::String, oatpp::String> Parameters;
/**
* Parameters as &id:oatpp::data::share::StringKeyLabel;.
* Advantage of oatpp::data::share::StringKeyLabel - is that there is no memory allocations needed to create "Memory Label".
*/
typedef std::unordered_map<StringKeyLabel, StringKeyLabel> ParametersAsLabels;
public:
/**
* Structure representing URL Authority information.
*/
struct Authority {
/**
* User info.
*/
oatpp::String userInfo;
/**
* Host.
*/
oatpp::String host;
/**
* Port. Treat -1 as undefined or as default.
*/
v_int32 port = -1;
};
public:
/**
* Url parser.
*/
class Parser {
public:
/**
* parse "<scheme>:"
* example "http", "https", "ftp"
* returns lowercase string before ':' char
* caret should be at the first char of the scheme
* parse `<scheme>`:
* example "http", "https", "ftp"
* returns lowercase string before ':' char
* caret should be at the first char of the scheme
*/
static oatpp::String parseScheme(oatpp::parser::Caret& caret);
/**
* parse url authority components.
* userinfo is not parsed into login and password separately as
* inclusion of password in userinfo is deprecated and ignored here
* caret should be at the first char of the authority (not at "//")
* parse url authority components.
* userinfo is not parsed into login and password separately as
* inclusion of password in userinfo is deprecated and ignored here
* caret should be at the first char of the authority (not at "//")
*/
static Url::Authority parseAuthority(oatpp::parser::Caret& caret);
/**
* parse path of the url
* caret should be at the first char of the path
* parse path of the url
* caret should be at the first char of the path
*/
static oatpp::String parsePath(oatpp::parser::Caret& caret);
/**
* parse query params in form of "?<paramName>=<paramValue>&<paramName>=<paramValue>..." referred by ParsingCaret
* and put that params to Parameters map
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by ParsingCaret
* and put that params to Parameters map
*/
static void parseQueryParamsToMap(Url::Parameters& params, oatpp::parser::Caret& caret);
/**
* parse query params in form of "?<paramName>=<paramValue>&<paramName>=<paramValue>..." referred by str
* and put that params to Parameters map
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by str
* and put that params to Parameters map
*/
static void parseQueryParamsToMap(Url::Parameters& params, const oatpp::String& str);
/**
* parse query params in form of "?<paramName>=<paramValue>&<paramName>=<paramValue>..." referred by ParsingCaret
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by ParsingCaret
*/
static Url::Parameters parseQueryParams(oatpp::parser::Caret& caret);
/**
* parse query params in form of "?<paramName>=<paramValue>&<paramName>=<paramValue>..." referred by str
* parse query params in form of `"?<paramName>=<paramValue>&<paramName>=<paramValue>..."` referred by str
*/
static Url::Parameters parseQueryParams(const oatpp::String& str);
@ -103,7 +133,7 @@ public:
* Same as parseQueryParams() but use StringKeyLabel instead of a String.
* Zero allocations. Use this method for better performance.
* @param str
* @return std::unordered_map<StringKeyLabel, StringKeyLabel>
* @return `std::unordered_map<StringKeyLabel, StringKeyLabel>`. See &l:Url::StringKeyLabel;.
*/
static ParametersAsLabels labelQueryParams(const oatpp::String& str);
@ -124,10 +154,25 @@ public:
};
public:
/**
* Url scheme. Ex.: [http, https, ftp, etc.]
*/
oatpp::String scheme;
/**
* Utl authority.
*/
Authority authority;
/**
* Path to resource.
*/
oatpp::String path;
/**
* Query params.
*/
Parameters queryParams;
};

View File

@ -31,30 +31,66 @@
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace network { namespace client {
/**
* Simple provider of clinet TCP connections.
*/
class SimpleTCPConnectionProvider : public base::Countable, public ClientConnectionProvider {
protected:
oatpp::String m_host;
v_word16 m_port;
public:
/**
* Constructor.
* @param host - host name without schema and port. Ex.: "oatpp.io", "127.0.0.1", "localhost".
* @param port - server port.
*/
SimpleTCPConnectionProvider(const oatpp::String& host, v_word16 port);
public:
/**
* Create shared client SimpleTCPConnectionProvider.
* @param host - host name without schema and port. Ex.: "oatpp.io", "127.0.0.1", "localhost".
* @param port - server port.
* @return - `std::shared_ptr` to SimpleTCPConnectionProvider.
*/
static std::shared_ptr<SimpleTCPConnectionProvider> createShared(const oatpp::String& host, v_word16 port){
return std::make_shared<SimpleTCPConnectionProvider>(host, port);
}
/**
* Implements &id:oatpp::network::ConnectionProvider::close;. Here does nothing.
*/
void close() override {
// DO NOTHING
}
/**
* Get connection.
* @return - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
*/
std::shared_ptr<IOStream> getConnection() override;
/**
* Get connection in asynchronous manner.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;.
* @param callback - pointer to callback function.
* @return - &id:oatpp::async::Action;.
*/
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, AsyncCallback callback) override;
/**
* Get host name.
* @return - host name.
*/
oatpp::String getHost() {
return m_host;
}
/**
* Get port.
* @return - port.
*/
v_word16 getPort(){
return m_port;
}

View File

@ -29,13 +29,16 @@
namespace oatpp { namespace network { namespace server {
/**
* Abstract ConnectionHandler.
*/
class ConnectionHandler {
public:
/**
* Handle provided connection here
* @param connection
* @param connection - see &id:oatpp::data::stream::IOStream;.
*/
virtual void handleConnection(const std::shared_ptr<oatpp::data::stream::IOStream>& connection) = 0;

View File

@ -34,6 +34,13 @@ const v_int32 Server::STATUS_RUNNING = 1;
const v_int32 Server::STATUS_STOPPING = 2;
const v_int32 Server::STATUS_DONE = 3;
Server::Server(const std::shared_ptr<ServerConnectionProvider>& connectionProvider,
const std::shared_ptr<ConnectionHandler>& connectionHandler)
: m_status(STATUS_CREATED)
, m_connectionProvider(connectionProvider)
, m_connectionHandler(connectionHandler)
{}
void Server::mainLoop(){
setStatus(STATUS_CREATED, STATUS_RUNNING);

View File

@ -29,8 +29,6 @@
#include "oatpp/network/ConnectionProvider.hpp"
#include "oatpp/core/concurrency/Runnable.hpp"
#include "oatpp/core/Types.hpp"
#include "oatpp/core/base/Countable.hpp"
@ -40,7 +38,11 @@
namespace oatpp { namespace network { namespace server {
class Server : public base::Countable, public concurrency::Runnable{
/**
* Server calls &id:oatpp::network::ConnectionProvider::getConnection; in the loop and passes obtained Connection
* to &id:oatpp::network::server::ConnectionHandler;.
*/
class Server : public base::Countable {
private:
void mainLoop();
@ -58,32 +60,70 @@ private:
std::shared_ptr<ConnectionHandler> m_connectionHandler;
public:
Server(
const std::shared_ptr<ServerConnectionProvider>& connectionProvider,
const std::shared_ptr<ConnectionHandler>& connectionHandler
)
: m_status(STATUS_CREATED)
, m_connectionProvider(connectionProvider)
, m_connectionHandler(connectionHandler)
{}
/**
* Constructor.
* @param connectionProvider - &id:oatpp::network::ConnectionProvider;.
* @param connectionHandler - &id:oatpp::network::server::ConnectionHandler;.
*/
Server(const std::shared_ptr<ServerConnectionProvider>& connectionProvider,
const std::shared_ptr<ConnectionHandler>& connectionHandler);
public:
/**
* Status constant.
*/
static const v_int32 STATUS_CREATED;
/**
* Status constant.
*/
static const v_int32 STATUS_RUNNING;
/**
* Status constant.
*/
static const v_int32 STATUS_STOPPING;
/**
* Status constant.
*/
static const v_int32 STATUS_DONE;
/**
* Create shared Server.
* @param connectionProvider - &id:oatpp::network::ConnectionProvider;.
* @param connectionHandler - &id:oatpp::network::server::ConnectionHandler;.
* @return - `std::shared_ptr` to Server.
*/
static std::shared_ptr<Server> createShared(const std::shared_ptr<ServerConnectionProvider>& connectionProvider,
const std::shared_ptr<ConnectionHandler>& connectionHandler){
const std::shared_ptr<ConnectionHandler>& connectionHandler){
return std::make_shared<Server>(connectionProvider, connectionHandler);
}
void run() override;
/**
* Call &id:oatpp::network::ConnectionProvider::getConnection; in the loop and passes obtained Connection
* to &id:oatpp::network::server::ConnectionHandler;.
*/
void run();
/**
* Break server loop.
* Note: thread can still be blocked on the &l:Server::run (); call as it may be waiting for ConnectionProvider to provide connection.
*/
void stop();
/**
* Get server status.
* @return - one of:<br>
* <ul>
* <li>&l:Server::STATUS_CREATED;</li>
* <li>&l:Server::STATUS_RUNNING;</li>
* <li>&l:Server::STATUS_STOPPING;</li>
* <li>&l:Server::STATUS_DONE;</li>
* </ul>
*/
v_int32 getStatus();
};

View File

@ -31,7 +31,10 @@
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace network { namespace server {
/**
* Simple provider of TCP connections.
*/
class SimpleTCPConnectionProvider : public base::Countable, public ServerConnectionProvider {
private:
v_word16 m_port;
@ -41,22 +44,52 @@ private:
private:
oatpp::data::v_io_handle instantiateServer();
public:
/**
* Constructor.
* @param port - port to listen for incoming connections.
* @param nonBlocking - set `true` to provide non-blocking &id:oatpp::data::stream::IOStream; for connection.
* `false` for blocking &id:oatpp::data::stream::IOStream;. Default `false`.
*/
SimpleTCPConnectionProvider(v_word16 port, bool nonBlocking = false);
public:
/**
* Create shared SimpleTCPConnectionProvider.
* @param port - port to listen for incoming connections.
* @param nonBlocking - set `true` to provide non-blocking &id:oatpp::data::stream::IOStream; for connection.
* `false` for blocking &id:oatpp::data::stream::IOStream;. Default `false`.
*/
static std::shared_ptr<SimpleTCPConnectionProvider> createShared(v_word16 port, bool nonBlocking = false){
return std::make_shared<SimpleTCPConnectionProvider>(port, nonBlocking);
}
/**
* Virtual destructor.
*/
~SimpleTCPConnectionProvider();
/**
* Close accept-socket.
*/
void close() override;
/**
* Get incoming connection.
* @return &id:oatpp::data::stream::IOStream;.
*/
std::shared_ptr<IOStream> getConnection() override;
/**
* No need to implement this.<br>
* For Asynchronous IO in oatpp it is considered to be a good practice
* to accept connections in a seperate thread with the blocking accept()
* and then process connections in Asynchronous manner with non-blocking read/write.
* <br>
* *It may be implemented later*
*/
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback) override {
/**
/*
* No need to implement this.
* For Asynchronous IO in oatpp it is considered to be a good practice
* to accept connections in a seperate thread with the blocking accept()
@ -66,7 +99,11 @@ public:
*/
throw std::runtime_error("[oatpp::network::server::SimpleTCPConnectionProvider::getConnectionAsync()]: Error. Not implemented.");
}
/**
* Get port.
* @return
*/
v_word16 getPort(){
return m_port;
}

View File

@ -30,10 +30,17 @@
#include "oatpp/core/collection/LinkedList.hpp"
namespace oatpp { namespace network { namespace virtual_ {
/**
* "Virtual" Interface provides functionality for accepting "virtual" connections.
* "virtual" connection is represented by &id:oatpp::network::virtual_::Socket;.
*/
class Interface : public oatpp::base::Countable {
public:
/**
* "Future" for &id:oatpp::network::virtual_::Socket;.
*/
class ConnectionSubmission {
private:
std::shared_ptr<Socket> m_socket;
@ -41,12 +48,35 @@ public:
std::condition_variable m_condition;
bool m_pending;
public:
/**
* Constructor.
*/
ConnectionSubmission() : m_pending(true) {}
/**
* Set socket to be returned in call to &l:Interface::ConnectionSubmission::getSocket ();/&l:Interface::ConnectionSubmission::getSocketNonBlocking ();.
* @param socket - &id:oatpp::network::virtual_::Socket;.
*/
void setSocket(const std::shared_ptr<Socket>& socket);
/**
* Block and wait for socket.
* @return - `std::shared_ptr` to &id:oatpp::network::virtual_::Socket;.
*/
std::shared_ptr<Socket> getSocket();
/**
* Check if socket already available.
* User should repeat call if `(!socket && isPending())`.
* @return - `std::shared_ptr` to &id:oatpp::network::virtual_::Socket;.
*/
std::shared_ptr<Socket> getSocketNonBlocking();
/**
* Check if submission has not been processed yet.
* @return - `true` if still waiting for acceptor to accept connection submission.
*/
bool isPending();
};
@ -59,25 +89,49 @@ private:
std::condition_variable m_condition;
oatpp::collection::LinkedList<std::shared_ptr<ConnectionSubmission>> m_submissions;
public:
/**
* Constructor.
* @param name - interface name.
*/
Interface(const oatpp::String& name)
: m_name(name)
{}
public:
/**
* Create shared Interface.
* @param name - interface name.
* @return - `std::shared_ptr` to Interface.
*/
static std::shared_ptr<Interface> createShared(const oatpp::String& name) {
return std::make_shared<Interface>(name);
}
/**
* Connect to interface.
* @return - &l:Interface::ConnectionSubmission;.
*/
std::shared_ptr<ConnectionSubmission> connect();
/**
* Connect to interface.
* @return - &l:Interface::ConnectionSubmission; on success. Empty `std::shared_ptr` on failure.
*/
std::shared_ptr<ConnectionSubmission> connectNonBlocking();
/**
*
* @param waitingHandle
* @return
* Block and wait for incloming connection.
* @param waitingHandle - reference to a boolean variable.
* User may set waitingHandle = false and call &l:Interface::notifyAcceptors (); in order to break waiting loop. and exit accept() method.
* @return - `std::shared_ptr` to &id:oatpp::network::virtual_::Socket;.
*/
std::shared_ptr<Socket> accept(const bool& waitingHandle = true);
/**
* Check if incoming connection is available. NonBlocking.
* @return - `std::shared_ptr` to &id:oatpp::network::virtual_::Socket; if available.
* Empty `std::shared_ptr` if no incoming connection is available at the moment.
*/
std::shared_ptr<Socket> acceptNonBlocking();
/**
@ -85,7 +139,11 @@ public:
* Those threads that have waitingHandle changed to false will be unblocked.
*/
void notifyAcceptors();
/**
* Get interface name.
* @return - &id:oatpp::String;.
*/
oatpp::String getName() {
return m_name;
}

View File

@ -113,5 +113,34 @@ data::v_io_size Pipe::Writer::write(const void *data, data::v_io_size count) {
return result;
}
Pipe::Pipe()
: m_open(true)
, m_writer(this)
, m_reader(this)
, m_buffer()
, m_fifo(m_buffer.getData(), m_buffer.getSize())
{}
std::shared_ptr<Pipe> Pipe::createShared(){
return std::make_shared<Pipe>();
}
Pipe::Writer* Pipe::getWriter() {
return &m_writer;
}
Pipe::Reader* Pipe::getReader() {
return &m_reader;
}
void Pipe::close() {
{
std::lock_guard<std::mutex> lock(m_mutex);
m_open = false;
}
m_conditionRead.notify_one();
m_conditionWrite.notify_one();
}
}}}

View File

@ -37,67 +37,111 @@
namespace oatpp { namespace network { namespace virtual_ {
/**
* Virtual pipe implementation. Can be used for unidirectional data transfer between different threads of the same process. <br>
* Under the hood it uses &id:oatpp::data::buffer::SynchronizedFIFOBuffer; over the &id:oatpp::data::buffer::IOBuffer;.
*/
class Pipe : public oatpp::base::Countable {
public:
/**
* Pipe Reader. Extends &id:oatpp::data::stream::InputStream;.
* Provides read interface for the pipe. Can work in both blocking and nonblocking regime.
*/
class Reader : public oatpp::data::stream::InputStream {
friend Pipe;
private:
Pipe* m_pipe;
bool m_nonBlocking;
/**
/*
* this one used for testing purposes only
*/
data::v_io_size m_maxAvailableToRead;
public:
protected:
Reader(Pipe* pipe, bool nonBlocking = false)
: m_pipe(pipe)
, m_nonBlocking(nonBlocking)
, m_maxAvailableToRead(-1)
{}
public:
/**
* Set `true` to make non-blocking reads using &l:Pipe::Reader::read ();.
* @param nonBlocking - `true` for nonblocking read.
*/
void setNonBlocking(bool nonBlocking) {
m_nonBlocking = nonBlocking;
}
/**
* this one used for testing purposes only
* set to -1 in order to ignore this value
* Limit the available amount of bytes to read from pipe.<br>
* This method is used for testing purposes only.<br>
* set to -1 in order to ignore this value.<br>
* @param maxAvailableToRead - maximum available amount of bytes to read.
*/
void setMaxAvailableToRead(data::v_io_size maxAvailableToRead);
/**
* Implements &id:oatpp::data::stream::InputStream::read; method.
* Read data from pipe.
* @param data - buffer to read data to.
* @param count - max count of bytes to read.
* @return - &id:oatpp::data::v_io_size;.
*/
data::v_io_size read(void *data, data::v_io_size count) override;
};
/**
* Pipe writer. Extends &id:oatpp::data::stream::OutputStream;.
* Provides write interface for the pipe. Can work in both blocking and nonblocking regime.
*/
class Writer : public oatpp::data::stream::OutputStream {
friend Pipe;
private:
Pipe* m_pipe;
bool m_nonBlocking;
/**
/*
* this one used for testing purposes only
*/
data::v_io_size m_maxAvailableToWrtie;
public:
protected:
Writer(Pipe* pipe, bool nonBlocking = false)
: m_pipe(pipe)
, m_nonBlocking(nonBlocking)
, m_maxAvailableToWrtie(-1)
{}
public:
/**
* Set `true` to make non-blocking writes using &l:Pipe::Writer::write ();.
* @param nonBlocking - `true` for nonblocking write.
*/
void setNonBlocking(bool nonBlocking) {
m_nonBlocking = nonBlocking;
}
/**
* this one used for testing purposes only
* set to -1 in order to ignore this value
* Limit the available space for data writes in pipe.<br>
* This method is used for testing purposes only.<br>
* set to -1 in order to ignore this value.<br>
* @param maxAvailableToWrite - maximum available amount of bytes to write.
*/
void setMaxAvailableToWrite(data::v_io_size maxAvailableToWrite);
/**
* Implements &id:oatpp::data::stream::OutputStream::write; method.
* Write data to pipe.
* @param data - data to write to pipe.
* @param count - data size.
* @return - &id:oatpp::data::v_io_size;.
*/
data::v_io_size write(const void *data, data::v_io_size count) override;
};
@ -114,35 +158,37 @@ private:
std::condition_variable m_conditionRead;
std::condition_variable m_conditionWrite;
public:
Pipe()
: m_open(true)
, m_writer(this)
, m_reader(this)
, m_buffer()
, m_fifo(m_buffer.getData(), m_buffer.getSize())
{}
static std::shared_ptr<Pipe> createShared(){
return std::make_shared<Pipe>();
}
Writer* getWriter() {
return &m_writer;
}
Reader* getReader() {
return &m_reader;
}
void close() {
{
std::lock_guard<std::mutex> lock(m_mutex);
m_open = false;
}
m_conditionRead.notify_one();
m_conditionWrite.notify_one();
}
/**
* Constructor.
*/
Pipe();
/**
* Create shared pipe.
* @return - `std::shared_ptr` to Pipe.
*/
static std::shared_ptr<Pipe> createShared();
/**
* Get pointer to &l:Pipe::Writer; for this pipe.
* There can be only one &l:Pipe::Writer; per pipe.
* @return - &l:Pipe::Writer;.
*/
Writer* getWriter();
/**
* Get pointer to &l:Pipe::Reader; for this pipe.
* There can be only one &l:Pipe::Reader; per pipe.
* @return - &l:Pipe::Reader;.
*/
Reader* getReader();
/**
* Mark pipe as closed.
*/
void close();
};

View File

@ -25,7 +25,20 @@
#include "Socket.hpp"
namespace oatpp { namespace network { namespace virtual_ {
Socket::Socket(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut)
: m_pipeIn(pipeIn)
, m_pipeOut(pipeOut)
{}
Socket::~Socket() {
close();
}
std::shared_ptr<Socket> Socket::createShared(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut) {
return std::make_shared<Socket>(pipeIn, pipeOut);
}
void Socket::setMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite) {
m_pipeIn->getReader()->setMaxAvailableToRead(maxToRead);
m_pipeOut->getWriter()->setMaxAvailableToWrite(maxToWrite);

View File

@ -28,37 +28,71 @@
#include "./Pipe.hpp"
namespace oatpp { namespace network { namespace virtual_ {
/**
* Virtual socket implementation. Can be used as a bidirectional data transfer between different threads of the same process. <br>
* Under the hood it uses a pair of &id:oatpp::network::virtual_::Pipe;. One to write data to, and one to read data from.
* Extends &id:oatpp::base::Countable; and &id:oatpp::data::stream::IOStream;.
*/
class Socket : public oatpp::base::Countable, public oatpp::data::stream::IOStream {
private:
std::shared_ptr<Pipe> m_pipeIn;
std::shared_ptr<Pipe> m_pipeOut;
public:
Socket(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut)
: m_pipeIn(pipeIn)
, m_pipeOut(pipeOut)
{}
public:
static std::shared_ptr<Socket> createShared(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut) {
return std::make_shared<Socket>(pipeIn, pipeOut);
}
~Socket() {
close();
}
/**
* this one used for testing purposes only
* set to -1 in order to ignore this value
* Constructor.
* @param pipeIn - pipe to read data from.
* @param pipeOut - pipe to write data to.
*/
Socket(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut);
public:
/**
* Create shared socket.
* @param pipeIn - pipe to read data from.
* @param pipeOut - pipe to write data to.
* @return - `std::shared_ptr` to Socket.
*/
static std::shared_ptr<Socket> createShared(const std::shared_ptr<Pipe>& pipeIn, const std::shared_ptr<Pipe>& pipeOut);
/**
* Virtual destructor. Close corresponding pipes.
*/
~Socket();
/**
* Limit the available amount of bytes to read from socket and limit the available amount of bytes to write to socket. <br>
* This method is used for testing purposes only.<br>
* @param maxToRead - maximum available amount of bytes to read.
* @param maxToWrite - maximum available amount of bytes to write.
*/
void setMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite);
/**
* Read data from socket.
* @param data - buffer to read data to.
* @param count - buffer size.
* @return - actual amount of data read from socket.
*/
data::v_io_size read(void *data, data::v_io_size count) override;
/**
* Write data to socket.
* @param data - data to write to socket.
* @param count - data size.
* @return - actual amount of data written to socket.
*/
data::v_io_size write(const void *data, data::v_io_size count) override;
/**
* Set socket for nonblocking I/O.
* @param nonBlocking - `true` for nonblocking.
*/
void setNonBlocking(bool nonBlocking);
/**
* Close socket pipes.
*/
void close();
};

View File

@ -26,6 +26,19 @@
namespace oatpp { namespace network { namespace virtual_ { namespace client {
ConnectionProvider::ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface)
: m_interface(interface)
, m_maxAvailableToRead(-1)
, m_maxAvailableToWrite(-1)
{
setProperty(PROPERTY_HOST, m_interface->getName());
setProperty(PROPERTY_PORT, "0");
}
std::shared_ptr<ConnectionProvider> ConnectionProvider::createShared(const std::shared_ptr<virtual_::Interface>& interface) {
return std::make_shared<ConnectionProvider>(interface);
}
void ConnectionProvider::close() {
}

View File

@ -29,40 +29,60 @@
#include "oatpp/network/ConnectionProvider.hpp"
namespace oatpp { namespace network { namespace virtual_ { namespace client {
/**
* Provider of "virtual" connections for client.
* See &id:oatpp::network::virtual_::Interface;, &id:oatpp::network::virtual_::Socket; <br>
* Extends &id:oatpp::network::ClientConnectionProvider;.
*/
class ConnectionProvider : public oatpp::network::ClientConnectionProvider {
private:
std::shared_ptr<virtual_::Interface> m_interface;
data::v_io_size m_maxAvailableToRead;
data::v_io_size m_maxAvailableToWrite;
public:
ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface)
: m_interface(interface)
, m_maxAvailableToRead(-1)
, m_maxAvailableToWrite(-1)
{
setProperty(PROPERTY_HOST, m_interface->getName());
setProperty(PROPERTY_PORT, "0");
}
static std::shared_ptr<ConnectionProvider> createShared(const std::shared_ptr<virtual_::Interface>& interface) {
return std::make_shared<ConnectionProvider>(interface);
}
/**
* this one used for testing purposes only
* set to -1 in order to ignore this value
* Constructor.
* @param interface - &id:oatpp::network::virtual_::Interface;.
*/
ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface);
/**
* Create shared ConnectionProvider.
* @param interface - &id:oatpp::network::virtual_::Interface;.
* @return - `std::shared_ptr` to ConnectionProvider.
*/
static std::shared_ptr<ConnectionProvider> createShared(const std::shared_ptr<virtual_::Interface>& interface);
/**
* Limit the available amount of bytes to read from socket and limit the available amount of bytes to write to socket. <br>
* This method is used for testing purposes only.<br>
* @param maxToRead - maximum available amount of bytes to read.
* @param maxToWrite - maximum available amount of bytes to write.
*/
void setSocketMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite) {
m_maxAvailableToRead = maxToRead;
m_maxAvailableToWrite = maxToWrite;
}
/**
* Implementation of &id:oatpp::network::ClientConnection::Close; method.
*/
void close() override;
/**
* Get connection.
* @return - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
*/
std::shared_ptr<IOStream> getConnection() override;
/**
* Get connection in asynchronous manner.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;.
* @param callback - pointer to callback function.
* @return - &id:oatpp::async::Action;.
*/
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback) override;

View File

@ -26,6 +26,26 @@
namespace oatpp { namespace network { namespace virtual_ { namespace server {
ConnectionProvider::ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking)
: m_interface(interface)
, m_nonBlocking(nonBlocking)
, m_open(true)
, m_maxAvailableToRead(-1)
, m_maxAvailableToWrite(-1)
{
setProperty(PROPERTY_HOST, m_interface->getName());
setProperty(PROPERTY_PORT, "0");
}
std::shared_ptr<ConnectionProvider> ConnectionProvider::createShared(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking) {
return std::make_shared<ConnectionProvider>(interface, nonBlocking);
}
void ConnectionProvider::setSocketMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite) {
m_maxAvailableToRead = maxToRead;
m_maxAvailableToWrite = maxToWrite;
}
void ConnectionProvider::close() {
m_open = false;
m_interface->notifyAcceptors();

View File

@ -29,7 +29,12 @@
#include "oatpp/network/ConnectionProvider.hpp"
namespace oatpp { namespace network { namespace virtual_ { namespace server {
/**
* Provider of "virtual" connections.
* See &id:oatpp::network::virtual_::Interface;, &id:oatpp::network::virtual_::Socket; <br>
* Extends &id:oatpp::network::ServerConnectionProvider;.
*/
class ConnectionProvider : public oatpp::network::ServerConnectionProvider {
private:
std::shared_ptr<virtual_::Interface> m_interface;
@ -38,38 +43,53 @@ private:
data::v_io_size m_maxAvailableToRead;
data::v_io_size m_maxAvailableToWrite;
public:
ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking = false)
: m_interface(interface)
, m_nonBlocking(nonBlocking)
, m_open(true)
, m_maxAvailableToRead(-1)
, m_maxAvailableToWrite(-1)
{
setProperty(PROPERTY_HOST, m_interface->getName());
setProperty(PROPERTY_PORT, "0");
}
static std::shared_ptr<ConnectionProvider> createShared(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking = false) {
return std::make_shared<ConnectionProvider>(interface, nonBlocking);
}
/**
* this one used for testing purposes only
* set to -1 in order to ignore this value
* Constructor.
* @param interface - &id:oatpp::network::virtual_::Interface;.
* @param nonBlocking - `true` to set non blocking regime for provided connections.
*/
void setSocketMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite) {
m_maxAvailableToRead = maxToRead;
m_maxAvailableToWrite = maxToWrite;
}
ConnectionProvider(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking = false);
/**
* Create shared ConnectionProvider.
* @param interface - &id:oatpp::network::virtual_::Interface;.
* @param nonBlocking - `true` to set non blocking regime for provided connections.
* @return - `std::shared_ptr` to ConnectionProvider.
*/
static std::shared_ptr<ConnectionProvider> createShared(const std::shared_ptr<virtual_::Interface>& interface, bool nonBlocking = false);
/**
* Limit the available amount of bytes to read from socket and limit the available amount of bytes to write to socket. <br>
* This method is used for testing purposes only.<br>
* @param maxToRead - maximum available amount of bytes to read.
* @param maxToWrite - maximum available amount of bytes to write.
*/
void setSocketMaxAvailableToReadWrtie(data::v_io_size maxToRead, data::v_io_size maxToWrite);
/**
* Break accepting loop.
*/
void close() override;
/**
* Get incoming connection.
* @return &id:oatpp::data::stream::IOStream;.
*/
std::shared_ptr<IOStream> getConnection() override;
/**
* **NOT IMPLEMENTED!**<br>
* No need to implement this.<br>
* For Asynchronous IO in oatpp it is considered to be a good practice
* to accept connections in a seperate thread with the blocking accept()
* and then process connections in Asynchronous manner with non-blocking read/write.
* <br>
* *It may be implemented later.*
*/
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback) override {
/**
/*
* No need to implement this.
* For Asynchronous IO in oatpp it is considered to be a good practice
* to accept connections in a seperate thread with the blocking accept()

View File

@ -29,10 +29,6 @@
namespace oatpp { namespace parser { namespace json{
const char* const Utils::ERROR_INVALID_ESCAPED_CHAR = "ERROR_INVALID_ESCAPED_CHAR";
const char* const Utils::ERROR_INVALID_SURROGATE_PAIR = "ERROR_INVALID_SURROGATE_PAIR";
const char* const Utils::ERROR_PARSER_QUOTE_EXPECTED = "'\"' - EXPECTED";
v_int32 Utils::calcEscapedStringSize(p_char8 data, v_int32 size, v_int32& safeSize) {
v_int32 result = 0;
v_int32 i = 0;
@ -77,8 +73,8 @@ v_int32 Utils::calcEscapedStringSize(p_char8 data, v_int32 size, v_int32& safeSi
return result;
}
v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* & error, v_int32& errorPosition) {
error = nullptr;
v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition) {
errorCode = 0;
v_int32 result = 0;
v_int32 i = 0;
@ -87,7 +83,7 @@ v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* &
if(a == '\\'){
if(i + 1 == size){
error = ERROR_INVALID_ESCAPED_CHAR;
errorCode = ERROR_CODE_INVALID_ESCAPED_CHAR;
errorPosition = i;
return 0;
}
@ -100,20 +96,20 @@ v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* &
} else if(b == 'u'){
if(i + 6 > size){
error = ERROR_INVALID_ESCAPED_CHAR;
errorCode = ERROR_CODE_INVALID_ESCAPED_CHAR;
errorPosition = i;
return 0;
}
if(data[i + 2] == '+') { // not JSON standard case
if(i + 11 > size){
error = ERROR_INVALID_ESCAPED_CHAR;
errorCode = ERROR_CODE_INVALID_ESCAPED_CHAR;
errorPosition = i;
return 0;
}
v_word32 code;
error = encoding::Hex::readWord32(&data[i + 3], code);
if(error != nullptr){
errorCode = encoding::Hex::readWord32(&data[i + 3], code);
if(errorCode != 0){
errorPosition = i + 3;
return 0;
}
@ -121,21 +117,21 @@ v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* &
result += encoding::Unicode::getUtf8CharSequenceLengthForCode(code);
} else {
v_word16 code;
error = encoding::Hex::readWord16(&data[i + 2], code);
if(error != nullptr){
errorCode = encoding::Hex::readWord16(&data[i + 2], code);
if(errorCode != 0){
errorPosition = i + 2;
return 0;
}
if(code >= 0xD800 && code <= 0xDBFF){
if(i + 12 > size){
error = ERROR_INVALID_SURROGATE_PAIR;
errorCode = ERROR_CODE_INVALID_SURROGATE_PAIR;
errorPosition = i;
return 0;
}
v_word16 low;
error = encoding::Hex::readWord16(&data[i + 8], low);
if(error != nullptr){
errorCode = encoding::Hex::readWord16(&data[i + 8], low);
if(errorCode != 0){
errorPosition = i + 8;
return 0;
}
@ -145,7 +141,7 @@ v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* &
i += 12;
result += encoding::Unicode::getUtf8CharSequenceLengthForCode(bigCode);
} else {
error = ERROR_INVALID_SURROGATE_PAIR;
errorCode = ERROR_CODE_INVALID_SURROGATE_PAIR;
errorPosition = i;
return 0;
}
@ -157,7 +153,7 @@ v_int32 Utils::calcUnescapedStringSize(p_char8 data, v_int32 size, const char* &
}
} else {
error = ERROR_INVALID_ESCAPED_CHAR;
errorCode = ERROR_CODE_INVALID_ESCAPED_CHAR;
errorPosition = i;
return 0;
}
@ -322,10 +318,10 @@ void Utils::unescapeStringToBuffer(p_char8 data, v_int32 size, p_char8 resultDat
}
oatpp::String Utils::unescapeString(p_char8 data, v_int32 size, const char* & error, v_int32& errorPosition) {
oatpp::String Utils::unescapeString(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition) {
v_int32 unescapedSize = calcUnescapedStringSize(data, size, error, errorPosition);
if(error != nullptr){
v_int32 unescapedSize = calcUnescapedStringSize(data, size, errorCode, errorPosition);
if(errorCode != 0){
return nullptr;
}
auto result = String(unescapedSize);
@ -338,10 +334,10 @@ oatpp::String Utils::unescapeString(p_char8 data, v_int32 size, const char* & er
}
std::string Utils::unescapeStringToStdString(p_char8 data, v_int32 size, const char* & error, v_int32& errorPosition){
std::string Utils::unescapeStringToStdString(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition){
v_int32 unescapedSize = calcUnescapedStringSize(data, size, error, errorPosition);
if(error != nullptr){
v_int32 unescapedSize = calcUnescapedStringSize(data, size, errorCode, errorPosition);
if(errorCode != 0){
return "";
}
std::string result;
@ -394,11 +390,11 @@ oatpp::String Utils::parseString(ParsingCaret& caret) {
v_int32 pos = caret.getPosition();
const char* error;
v_int32 errorCode;
v_int32 errorPosition;
auto result = unescapeString(data, size, error, errorPosition);
if(error != nullptr){
caret.setError("[oatpp::parser::json::Utils::parseString()]: Error. Call to unescapeString() failed");
auto result = unescapeString(data, size, errorCode, errorPosition);
if(errorCode != 0){
caret.setError("[oatpp::parser::json::Utils::parseString()]: Error. Call to unescapeString() failed", errorCode);
caret.setPosition(pos + errorPosition);
} else {
caret.setPosition(pos + size + 1);
@ -421,11 +417,11 @@ std::string Utils::parseStringToStdString(ParsingCaret& caret){
v_int32 pos = caret.getPosition();
const char* error;
v_int32 errorCode;
v_int32 errorPosition;
const std::string& result = unescapeStringToStdString(data, size, error, errorPosition);
if(error != nullptr){
caret.setError("[oatpp::parser::json::Utils::parseStringToStdString()]: Error. Call to unescapeStringToStdString() failed");
const std::string& result = unescapeStringToStdString(data, size, errorCode, errorPosition);
if(errorCode != 0){
caret.setError("[oatpp::parser::json::Utils::parseStringToStdString()]: Error. Call to unescapeStringToStdString() failed", errorCode);
caret.setPosition(pos + errorPosition);
} else {
caret.setPosition(pos + size + 1);

View File

@ -31,38 +31,27 @@
#include <string>
namespace oatpp { namespace parser { namespace json{
/**
* Utility class for json serializer/deserializer.
* Used by &id:oatpp::parser::json::mapping::Serializer;, &id:oatpp::parser::json::mapping::Deserializer;.
*/
class Utils {
public:
/**
* ERROR_INVALID_ESCAPED_CHAR = "ERROR_INVALID_ESCAPED_CHAR"
*/
static const char* const ERROR_INVALID_ESCAPED_CHAR;
/**
* ERROR_INVALID_SURROGATE_PAIR = "ERROR_INVALID_SURROGATE_PAIR"
*/
static const char* const ERROR_INVALID_SURROGATE_PAIR;
/**
* ERROR_PARSER_QUOTE_EXPECTED = "'\"' - EXPECTED"
*/
static const char* const ERROR_PARSER_QUOTE_EXPECTED;
/**
* ERROR_CODE_INVALID_ESCAPED_CHAR = 1
* ERROR_CODE_INVALID_ESCAPED_CHAR
*/
static constexpr v_int32 ERROR_CODE_INVALID_ESCAPED_CHAR = 1;
/**
* ERROR_CODE_INVALID_SURROGATE_PAIR = 2
* ERROR_CODE_INVALID_SURROGATE_PAIR
*/
static constexpr v_int32 ERROR_CODE_INVALID_SURROGATE_PAIR = 2;
/**
* "'\"' - EXPECTED"
* ERROR_CODE_PARSER_QUOTE_EXPECTED = 3
* '\\' - EXPECTED"
* ERROR_CODE_PARSER_QUOTE_EXPECTED
*/
static constexpr v_int32 ERROR_CODE_PARSER_QUOTE_EXPECTED = 3;
@ -72,19 +61,65 @@ public:
private:
static v_int32 escapeUtf8Char(p_char8 sequence, p_char8 buffer);
static v_int32 calcEscapedStringSize(p_char8 data, v_int32 size, v_int32& safeSize);
static v_int32 calcUnescapedStringSize(p_char8 data, v_int32 size, const char* & error, v_int32& errorPosition);
static v_int32 calcUnescapedStringSize(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition);
static void unescapeStringToBuffer(p_char8 data, v_int32 size, p_char8 resultData);
static p_char8 preparseString(ParsingCaret& caret, v_int32& size);
public:
/**
* if(copyAsOwnData == false && escapedString == initialString) then result string will point to initial data
* Escape string as for json standard. <br>
* *Note:* if(copyAsOwnData == false && escapedString == initialString) then result string will point to initial data.
* @param data - pointer to string to escape.
* @param size - data size.
* @param copyAsOwnData - see &id:oatpp::base::StrBuffer::StrBuffer;.
* @return - &id:oatpp::String;.
*/
static String escapeString(p_char8 data, v_int32 size, bool copyAsOwnData = true);
static String unescapeString(p_char8 data, v_int32 size, const char* & error, v_int32& errorPosition);
static std::string unescapeStringToStdString(p_char8 data, v_int32 size,
const char* & error, v_int32& errorPosition);
/**
* Unescape string as for json standard.
* @param data - pointer to string to unescape.
* @param size - data size.
* @param errorCode - out parameter. Error code <br>
* *One of:*<br>
* <ul>
* <li>&l:Utils::ERROR_CODE_INVALID_ESCAPED_CHAR;</li>
* <li>&l:Utils::ERROR_CODE_INVALID_SURROGATE_PAIR;</li>
* <li>&l:Utils::ERROR_CODE_PARSER_QUOTE_EXPECTED;</li>
* </ul>
* @param errorPosition - out parameter. Error position in data.
* @return - &id:oatpp::String;.
*/
static String unescapeString(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition);
/**
* Same as &l:Utils::unescapeString (); but return `std::string`.
* @param data - pointer to string to unescape.
* @param size - data size.
* @param errorCode - out parameter. Error code <br>
* *One of:*<br>
* <ul>
* <li>&l:Utils::ERROR_CODE_INVALID_ESCAPED_CHAR;</li>
* <li>&l:Utils::ERROR_CODE_INVALID_SURROGATE_PAIR;</li>
* <li>&l:Utils::ERROR_CODE_PARSER_QUOTE_EXPECTED;</li>
* </ul>
* @param errorPosition - out parameter. Error position in data.
* @return - &id:oatpp::String;.
*/
static std::string unescapeStringToStdString(p_char8 data, v_int32 size, v_int32& errorCode, v_int32& errorPosition);
/**
* Parse string enclosed in `"<string>"`.
* @param caret - &id:oatpp::parser::Caret;.
* @return - &id:oatpp::String;.
*/
static String parseString(ParsingCaret& caret);
/**
* Parse string enclosed in `"<string>"`.
* @param caret - &id:oatpp::parser::Caret;.
* @return - `std::string`.
*/
static std::string parseStringToStdString(ParsingCaret& caret);
};

View File

@ -36,7 +36,11 @@
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace parser { namespace json { namespace mapping {
/**
* Json deserializer.
* Deserializes json to oatpp DTO object. See [Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/).
*/
class Deserializer {
public:
typedef oatpp::data::mapping::type::Type Type;
@ -58,17 +62,31 @@ private:
typedef oatpp::data::mapping::type::ListMap<String, AbstractObjectWrapper> AbstractListMap;
public:
/**
* Deserializer config.
*/
class Config : public oatpp::base::Countable {
public:
/**
* Constructor.
*/
Config()
{}
public:
/**
* Create shared Config.
* @return - `std::shared_ptr` to Config.
*/
static std::shared_ptr<Config> createShared(){
return std::make_shared<Config>();
}
/**
* Do not fail if unknown field is found in json.
* "unknown field" is the one which is not present in DTO object class.
*/
bool allowUnknownFields = true;
};
@ -151,7 +169,14 @@ private:
const std::shared_ptr<Config>& config);
public:
/**
* Deserialize json to oatpp DTO object.
* @param caret - &id:oatpp::parser::Caret;.
* @param config - &l:Deserializer::Config;.
* @param type - &id:oatpp::data::mapping::type::Type;.
* @return - &id:oatpp::data::mapping::type::AbstractObjectWrapper; containing deserialized object.
*/
static AbstractObjectWrapper deserialize(oatpp::parser::Caret& caret,
const std::shared_ptr<Config>& config,
const Type* const type) {

View File

@ -24,3 +24,28 @@
#include "ObjectMapper.hpp"
namespace oatpp { namespace parser { namespace json { namespace mapping {
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer::Config>& pSerializerConfig,
const std::shared_ptr<Deserializer::Config>& pDeserializerConfig)
: oatpp::data::mapping::ObjectMapper(getMapperInfo())
, serializerConfig(pSerializerConfig)
, deserializerConfig(pDeserializerConfig)
{}
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<Serializer::Config>& serializerConfig,
const std::shared_ptr<Deserializer::Config>& deserializerConfig){
return std::make_shared<ObjectMapper>(serializerConfig, deserializerConfig);
}
void ObjectMapper::write(const std::shared_ptr<oatpp::data::stream::OutputStream>& stream,
const oatpp::data::mapping::type::AbstractObjectWrapper& variant) const {
Serializer::serialize(stream, variant, serializerConfig);
}
oatpp::data::mapping::type::AbstractObjectWrapper ObjectMapper::read(oatpp::parser::Caret& caret,
const oatpp::data::mapping::type::Type* const type) const {
return Deserializer::deserialize(caret, deserializerConfig, type);
}
}}}}

View File

@ -31,7 +31,12 @@
#include "oatpp/core/data/mapping/ObjectMapper.hpp"
namespace oatpp { namespace parser { namespace json { namespace mapping {
/**
* Json ObjectMapper. Serialized/Deserializes oatpp DTO objects to/from JSON.
* See [Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/). <br>
* Extends &id:oatpp::base::Countable;, &id:oatpp::data::mapping::ObjectMapper;.
*/
class ObjectMapper : public oatpp::base::Countable, public oatpp::data::mapping::ObjectMapper {
private:
static Info& getMapperInfo() {
@ -39,32 +44,50 @@ private:
return info;
}
public:
ObjectMapper(const std::shared_ptr<Serializer::Config>& pSerializerConfig,
const std::shared_ptr<Deserializer::Config>& pDeserializerConfig)
: oatpp::data::mapping::ObjectMapper(getMapperInfo())
, serializerConfig(pSerializerConfig)
, deserializerConfig(pDeserializerConfig)
{}
/**
* Constructor.
* @param pSerializerConfig - &id:oatpp::parser::json::mapping::Serializer::Config;.
* @param pDeserializerConfig - &id:oatpp::parser::json::mapping::Deserializer::Config;.
*/
ObjectMapper(const std::shared_ptr<Serializer::Config>& pSerializerConfig = Serializer::Config::createShared(),
const std::shared_ptr<Deserializer::Config>& pDeserializerConfig = Deserializer::Config::createShared());
public:
/**
* Create shared ObjectMapper.
* @param serializerConfig - &id:oatpp::parser::json::mapping::Serializer::Config;.
* @param deserializerConfig - &id:oatpp::parser::json::mapping::Deserializer::Config;.
* @return - `std::shared_ptr` to ObjectMapper.
*/
static std::shared_ptr<ObjectMapper>
createShared(const std::shared_ptr<Serializer::Config>& serializerConfig = Serializer::Config::createShared(),
const std::shared_ptr<Deserializer::Config>& deserializerConfig = Deserializer::Config::createShared()){
return std::make_shared<ObjectMapper>(serializerConfig, deserializerConfig);
}
const std::shared_ptr<Deserializer::Config>& deserializerConfig = Deserializer::Config::createShared());
/**
* Implementation of &id:oatpp::data::mapping::ObjectMapper::write;.
* @param stream - stream to write serializerd data to &id:oatpp::data::stream::OutputStream;.
* @param variant - object to serialize &id:oatpp::data::mapping::type::AbstractObjectWrapper;.
*/
void write(const std::shared_ptr<oatpp::data::stream::OutputStream>& stream,
const oatpp::data::mapping::type::AbstractObjectWrapper& variant) const override {
Serializer::serialize(stream, variant, serializerConfig);
}
oatpp::data::mapping::type::AbstractObjectWrapper
read(oatpp::parser::Caret& caret,
const oatpp::data::mapping::type::Type* const type) const override {
return Deserializer::deserialize(caret, deserializerConfig, type);
}
const oatpp::data::mapping::type::AbstractObjectWrapper& variant) const override;
/**
* Implementation of &id:oatpp::data::mapping::ObjectMapper::read;.
* @param caret - &id:oatpp::parser::Caret;.
* @param type - type of resultant object &id:oatpp::data::mapping::type::Type;.
* @return - &id:oatpp::data::mapping::type::AbstractObjectWrapper; holding resultant object.
*/
oatpp::data::mapping::type::AbstractObjectWrapper read(oatpp::parser::Caret& caret,
const oatpp::data::mapping::type::Type* const type) const override;
/**
* Serializer config.
*/
std::shared_ptr<Serializer::Config> serializerConfig;
/**
* Deserializer config.
*/
std::shared_ptr<Deserializer::Config> deserializerConfig;
};

View File

@ -38,7 +38,11 @@
#include "oatpp/core/Types.hpp"
namespace oatpp { namespace parser { namespace json { namespace mapping {
/**
* Json Serializer.
* Serializes oatpp DTO object to json. See [Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/).
*/
class Serializer {
public:
typedef oatpp::data::mapping::type::Type Type;
@ -56,18 +60,37 @@ public:
typedef oatpp::data::mapping::type::ListMap<String, AbstractObjectWrapper> AbstractFieldsMap;
public:
/**
* Serializer config.
*/
class Config : public oatpp::base::Countable {
public:
/**
* Constructor.
*/
Config()
{}
public:
/**
* Create shared config.
* @return - `std::shared_ptr` to Config.
*/
static std::shared_ptr<Config> createShared(){
return std::make_shared<Config>();
}
/**
* Include fields with value == nullptr into serialized json.
*/
bool includeNullFields = true;
/**
* If `true` - insert string `"<unknown-type>"` in json field value in case unknown field found.
* Fail if `false`.
* Known types for this serializer are:<br>
* (String, Int8, Int16, Int32, Int64, Float32, Float64, Boolean, DTOs, List, Fields).
*/
bool throwOnUnknownTypes = true;
};
@ -93,7 +116,16 @@ private:
static void writeValue(oatpp::data::stream::OutputStream* stream, const AbstractObjectWrapper& polymorph, const std::shared_ptr<Config>& config);
public:
/**
* Serialize DTO object to stream.
* @param stream - stream to write serialized object to. &id:oatpp::data::stream::OutputStream;. <br>
* **WARNING** Serializer currently does't check call results of &id:oatpp::data::stream::OutputStream::write;.
* Meaning that Serializer does not ensures that all data has been transferred successfully. <br>
* **USE** output stream with guarantee that all data being successfully written. Like &id:oatpp::data::stream::ChunkedBuffer;.
* @param polymorph - DTO object to serialize.
* @param config - &l:Serializer::Config;.
*/
static void serialize(const std::shared_ptr<oatpp::data::stream::OutputStream>& stream,
const oatpp::data::mapping::type::AbstractObjectWrapper& polymorph,
const std::shared_ptr<Config>& config){

View File

@ -112,8 +112,8 @@ void ApiClient::addPathQueryParams(oatpp::data::stream::OutputStream* stream,
}
oatpp::web::protocol::http::Protocol::Headers ApiClient::convertParamsMap(const std::shared_ptr<StringToParamMap>& params) {
oatpp::web::protocol::http::Protocol::Headers result;
oatpp::web::protocol::http::Headers ApiClient::convertParamsMap(const std::shared_ptr<StringToParamMap>& params) {
oatpp::web::protocol::http::Headers result;
if(params) {
auto curr = params->getFirstEntry();
@ -124,6 +124,64 @@ oatpp::web::protocol::http::Protocol::Headers ApiClient::convertParamsMap(const
}
return result;
}
oatpp::String ApiClient::formatPath(const PathPattern& pathPattern,
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams)
{
oatpp::data::stream::ChunkedBuffer stream;
formatPath(&stream, pathPattern, pathParams);
if(queryParams) {
addPathQueryParams(&stream, queryParams);
}
return stream.toString();
}
std::shared_ptr<RequestExecutor::ConnectionHandle> ApiClient::getConnection() {
return m_requestExecutor->getConnection();
}
oatpp::async::Action ApiClient::getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, RequestExecutor::AsyncConnectionCallback callback) {
return m_requestExecutor->getConnectionAsync(parentCoroutine, callback);
}
std::shared_ptr<ApiClient::Response> ApiClient::executeRequest(const oatpp::String& method,
const PathPattern& pathPattern,
const std::shared_ptr<StringToParamMap>& headers,
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams,
const std::shared_ptr<RequestExecutor::Body>& body,
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle) {
return m_requestExecutor->execute(method,
formatPath(pathPattern, pathParams, queryParams),
convertParamsMap(headers),
body,
connectionHandle);
}
oatpp::async::Action ApiClient::executeRequestAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback,
const oatpp::String& method,
const PathPattern& pathPattern,
const std::shared_ptr<StringToParamMap>& headers,
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams,
const std::shared_ptr<RequestExecutor::Body>& body,
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle) {
return m_requestExecutor->executeAsync(parentCoroutine,
callback,
method,
formatPath(pathPattern, pathParams, queryParams),
convertParamsMap(headers),
body,
connectionHandle);
}
}}}

View File

@ -50,7 +50,10 @@
#include <unordered_map>
namespace oatpp { namespace web { namespace client {
/**
* ApiClient class provides convenient Retrofit-like interface over the oatpp::web::client::RequestExecutor.
*/
class ApiClient : public oatpp::base::Countable {
public:
static constexpr const char* const TAG = "Client";
@ -67,18 +70,56 @@ private:
oatpp::String
> StringToStringMap;
public:
/**
* Convenience typedef for &id:oatpp::web::protocol::http::Status;.
*/
typedef oatpp::web::protocol::http::Status Status;
/**
* Convenience typedef for &id:oatpp::web::protocol::http::Header;.
*/
typedef oatpp::web::protocol::http::Header Header;
public:
/**
* Convenience typedef for &id:oatpp::data::mapping::type::String;.
*/
typedef oatpp::data::mapping::type::String String;
/**
* Convenience typedef for &id:oatpp::data::mapping::type::Int32;.
*/
typedef oatpp::data::mapping::type::Int32 Int32;
/**
* Convenience typedef for &id:oatpp::data::mapping::type::Int64;.
*/
typedef oatpp::data::mapping::type::Int64 Int64;
/**
* Convenience typedef for &id:oatpp::data::mapping::type::Float32;.
*/
typedef oatpp::data::mapping::type::Float32 Float32;
/**
* Convenience typedef for &id:oatpp::data::mapping::type::Float64;.
*/
typedef oatpp::data::mapping::type::Float64 Float64;
/**
* Convenience typedef for &id:oatpp::data::mapping::type::Boolean;.
*/
typedef oatpp::data::mapping::type::Boolean Boolean;
public:
/**
* Convenience typedef for &id:oatpp::web::protocol::http::incoming::Response;.
*/
typedef oatpp::web::protocol::http::incoming::Response Response;
public:
/**
* Convenience typedef for &id:oatpp::web::client::RequestExecutor::AsyncCallback;.
*/
typedef RequestExecutor::AsyncCallback AsyncCallback;
protected:
@ -106,7 +147,7 @@ private:
void addPathQueryParams(oatpp::data::stream::OutputStream* stream,
const std::shared_ptr<StringToParamMap>& params);
oatpp::web::protocol::http::Protocol::Headers convertParamsMap(const std::shared_ptr<StringToParamMap>& params);
oatpp::web::protocol::http::Headers convertParamsMap(const std::shared_ptr<StringToParamMap>& params);
protected:
@ -134,42 +175,33 @@ public:
protected:
virtual oatpp::String formatPath(const PathPattern& pathPattern,
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams) {
oatpp::data::stream::ChunkedBuffer stream;
formatPath(&stream, pathPattern, pathParams);
if(queryParams) {
addPathQueryParams(&stream, queryParams);
}
return stream.toString();
}
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams);
public:
virtual std::shared_ptr<RequestExecutor::ConnectionHandle> getConnection() {
return m_requestExecutor->getConnection();
}
virtual oatpp::async::Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, RequestExecutor::AsyncConnectionCallback callback) {
return m_requestExecutor->getConnectionAsync(parentCoroutine, callback);
}
/**
* Call &id:oatpp::web::client::RequestExecutor::getConnection;.
* @return - &id:oatpp::web::client::RequestExecutor::ConnectionHandle;.
*/
virtual std::shared_ptr<RequestExecutor::ConnectionHandle> getConnection();
/**
* Call &id:oatpp::web::client::RequestExecutor::getConnectionAsync;.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - function pointer to asynchronous callback.
* @return - &id:oatpp::async::Action;.
*/
virtual oatpp::async::Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, RequestExecutor::AsyncConnectionCallback callback);
virtual std::shared_ptr<Response> executeRequest(const oatpp::String& method,
const PathPattern& pathPattern,
const std::shared_ptr<StringToParamMap>& headers,
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams,
const std::shared_ptr<RequestExecutor::Body>& body,
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle = nullptr) {
return m_requestExecutor->execute(method,
formatPath(pathPattern, pathParams, queryParams),
convertParamsMap(headers),
body,
connectionHandle);
}
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle = nullptr);
virtual oatpp::async::Action executeRequestAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback,
@ -179,17 +211,7 @@ public:
const std::shared_ptr<StringToParamMap>& pathParams,
const std::shared_ptr<StringToParamMap>& queryParams,
const std::shared_ptr<RequestExecutor::Body>& body,
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle = nullptr) {
return m_requestExecutor->executeAsync(parentCoroutine,
callback,
method,
formatPath(pathPattern, pathParams, queryParams),
convertParamsMap(headers),
body,
connectionHandle);
}
const std::shared_ptr<RequestExecutor::ConnectionHandle>& connectionHandle = nullptr);
};

View File

@ -40,7 +40,20 @@
#include <unistd.h>
namespace oatpp { namespace web { namespace client {
HttpRequestExecutor::HttpRequestExecutor(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder)
: m_connectionProvider(connectionProvider)
, m_bodyDecoder(bodyDecoder)
{}
std::shared_ptr<HttpRequestExecutor>
HttpRequestExecutor::createShared(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder)
{
return std::make_shared<HttpRequestExecutor>(connectionProvider, bodyDecoder);
}
std::shared_ptr<HttpRequestExecutor::ConnectionHandle> HttpRequestExecutor::getConnection() {
auto connection = m_connectionProvider->getConnection();
if(!connection){

View File

@ -31,7 +31,10 @@
#include "oatpp/network/ConnectionProvider.hpp"
namespace oatpp { namespace web { namespace client {
/**
* Default implementation of &id:oatpp::web::client::RequestExecutor; for making http request.
*/
class HttpRequestExecutor : public oatpp::base::Countable, public RequestExecutor {
private:
typedef oatpp::web::protocol::http::Header Header;
@ -39,42 +42,90 @@ protected:
std::shared_ptr<oatpp::network::ClientConnectionProvider> m_connectionProvider;
std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder> m_bodyDecoder;
public:
/**
* Connection handle for &l:HttpRequestExecutor; <br>
* For more details see &id:oatpp::web::client::RequestExecutor::ConnectionHandle;.
*/
class HttpConnectionHandle : public ConnectionHandle {
public:
/**
* Constructor.
* @param stream - &id:oatpp::network::ConnectionProvider::IOStream;.
*/
HttpConnectionHandle(const std::shared_ptr<oatpp::network::ConnectionProvider::IOStream>& stream)
: connection(stream)
{}
/**
* Connection.
*/
std::shared_ptr<oatpp::network::ConnectionProvider::IOStream> connection;
};
public:
/**
* Constructor.
* @param connectionProvider - &id:oatpp::network::ClientConnectionProvider;.
* @param bodyDecoder - &id:oatpp::web::protocol::http::incoming::BodyDecoder;.
*/
HttpRequestExecutor(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder =
std::make_shared<oatpp::web::protocol::http::incoming::SimpleBodyDecoder>())
: m_connectionProvider(connectionProvider)
, m_bodyDecoder(bodyDecoder)
{}
std::make_shared<oatpp::web::protocol::http::incoming::SimpleBodyDecoder>());
public:
/**
* Create shared HttpRequestExecutor.
* @param connectionProvider - &id:oatpp::network::ClientConnectionProvider;.
* @param bodyDecoder - &id:oatpp::web::protocol::http::incoming::BodyDecoder;.
* @return - `std::shared_ptr` to `HttpRequestExecutor`.
*/
static std::shared_ptr<HttpRequestExecutor>
createShared(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider,
const std::shared_ptr<const oatpp::web::protocol::http::incoming::BodyDecoder>& bodyDecoder =
std::make_shared<oatpp::web::protocol::http::incoming::SimpleBodyDecoder>()){
return std::make_shared<HttpRequestExecutor>(connectionProvider, bodyDecoder);
}
std::shared_ptr<ConnectionHandle> getConnection() override;
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, AsyncConnectionCallback callback) override;
std::make_shared<oatpp::web::protocol::http::incoming::SimpleBodyDecoder>());
/**
* throws RequestExecutionError
* Get &id:oatpp::web::client::RequestExecutor::ConnectionHandle;
* @return - ConnectionHandle which is &l:HttpRequestExecutor::HttpConnectionHandle;.
*/
std::shared_ptr<ConnectionHandle> getConnection() override;
/**
* Same as &l:HttpRequestExecutor::getConnection (); but async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - function pointer to asynchronous callback.
* @return - &id:oatpp::async::Action;
*/
Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, AsyncConnectionCallback callback) override;
/**
* Execute http request.
* @param method - method ex: ["GET", "POST", "PUT", etc.].
* @param path - path to resource.
* @param headers - headers map &id:oatpp::web::client::RequestExecutor::Headers;.
* @param body - `std::shared_ptr` to &id:oatpp::web::client::RequestExecutor::Body; object.
* @param connectionHandle - ConnectionHandle obtain in call to &l:HttpRequestExecutor::getConnection ();.
* @return - &id:oatpp::web::protocol::http::incoming::Response;.
* @throws - &id:oatpp::web::client::RequestExecutor::RequestExecutionError;
*/
std::shared_ptr<Response> execute(const String& method,
const String& path,
const Headers& headers,
const std::shared_ptr<Body>& body,
const std::shared_ptr<ConnectionHandle>& connectionHandle = nullptr) override;
/**
* Same as &l:HttpRequestExecutor::execute (); but Async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - function pointer to asynchronous callback.
* @param method - method ex: ["GET", "POST", "PUT", etc.].
* @param path - path to resource.
* @param headers - headers map &id:oatpp::web::client::RequestExecutor::Headers;.
* @param body - `std::shared_ptr` to &id:oatpp::web::client::RequestExecutor::Body; object.
* @param connectionHandle - ConnectionHandle obtain in call to &l:HttpRequestExecutor::getConnection ();.
* @return - &id:oatpp::async::Action;.
*/
Action executeAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback,
const String& method,

View File

@ -23,3 +23,26 @@
***************************************************************************/
#include "RequestExecutor.hpp"
namespace oatpp { namespace web { namespace client {
RequestExecutor::RequestExecutionError::RequestExecutionError(v_int32 errorCode, const char* message, v_int32 readErrorCode)
: std::runtime_error(message)
, m_errorCode(errorCode)
, m_message(message)
, m_readErrorCode(readErrorCode)
{}
v_int32 RequestExecutor::RequestExecutionError::getErrorCode() const {
return m_errorCode;
}
const char* RequestExecutor::RequestExecutionError::getMessage() const {
return m_message;
}
v_int32 RequestExecutor::RequestExecutionError::getReadErrorCode() const {
return m_readErrorCode;
}
}}}

View File

@ -30,19 +30,41 @@
#include "oatpp/web/protocol/http/Http.hpp"
namespace oatpp { namespace web { namespace client {
/**
* Abstract RequestExecutor.
* RequestExecutor is class responsible for making remote requests.
*/
class RequestExecutor {
public:
/**
* Convenience typedef for &id:oatpp::String;.
*/
typedef oatpp::String String;
/**
* Convenience typedef for &id:oatpp::async::Action;.
*/
typedef oatpp::async::Action Action;
public:
typedef oatpp::web::protocol::http::Protocol::Headers Headers;
/**
* Convenience typedef for &id:oatpp::web::protocol::http::Headers;.
*/
typedef oatpp::web::protocol::http::Headers Headers;
/**
* Convenience typedef for &id:oatpp::web::protocol::http::incoming::Response;.
*/
typedef oatpp::web::protocol::http::incoming::Response Response;
/**
* Convenience typedef for &id:oatpp::web::protocol::http::outgoing::Body;.
*/
typedef oatpp::web::protocol::http::outgoing::Body Body;
public:
/**
* ConnectionHandle is always specific to a RequestExecutor
* ConnectionHandle is always specific to a RequestExecutor.
* You can't pass ConnectionHandle retrieved by one RequestExecutor implementation
* to another
*/
@ -55,65 +77,116 @@ public:
typedef Action (oatpp::async::AbstractCoroutine::*AsyncCallback)(const std::shared_ptr<Response>&);
typedef Action (oatpp::async::AbstractCoroutine::*AsyncConnectionCallback)(const std::shared_ptr<ConnectionHandle>&);
public:
/**
* Class representing Request Execution Error.
*/
class RequestExecutionError : public std::runtime_error {
public:
/**
* Error code for "can't connect" error.
*/
constexpr static const v_int32 ERROR_CODE_CANT_CONNECT = 1;
/**
* Error code for "can't parse starting line" error.
*/
constexpr static const v_int32 ERROR_CODE_CANT_PARSE_STARTING_LINE = 2;
/**
* Error code for "can't parse headers" error.
*/
constexpr static const v_int32 ERROR_CODE_CANT_PARSE_HEADERS = 3;
/**
* Error code for "can't read response" error.
*/
constexpr static const v_int32 ERROR_CODE_CANT_READ_RESPONSE = 4;
/**
* Error code for "no response" error.
*/
constexpr static const v_int32 ERROR_CODE_NO_RESPONSE = 5;
private:
v_int32 m_errorCode;
const char* m_message;
v_int32 m_readErrorCode;
public:
RequestExecutionError(v_int32 errorCode, const char* message, v_int32 readErrorCode = 0)
:std::runtime_error(message)
, m_errorCode(errorCode)
, m_message(message)
, m_readErrorCode(readErrorCode)
{}
v_int32 getErrorCode() const {
return m_errorCode;
}
const char* getMessage() const {
return m_message;
}
/**
* Constructor.
* @param errorCode - error code.
* @param message - error message.
* @param readErrorCode - io error code.
*/
RequestExecutionError(v_int32 errorCode, const char* message, v_int32 readErrorCode = 0);
/**
* Get error code.
* @return - error code.
*/
v_int32 getErrorCode() const;
/**
* Get error message.
* @return - error message.
*/
const char* getMessage() const;
/**
* This value is valid if errorCode == ERROR_CODE_CANT_READ_RESPONSE
* This value is valid if errorCode == &l:RequestExecutor::RequestExecutionError::ERROR_CODE_CANT_READ_RESPONSE; <br>
* For more information about the read error you get check out:
* - oatpp::data::stream::IOStream for possible error codes
* - implementation of Connection provided by your ConnectionProvider for implementation-specific behaviour
* <ul>
* <li>&id:oatpp::data::stream::IOStream; for possible error codes.</li>
* <li>Implementation-specific behaviour of corresponding Connection and ConnectionProvider.</li>
* </ul>
*/
v_int32 getReadErrorCode() const {
return m_readErrorCode;
}
v_int32 getReadErrorCode() const;
};
public:
/**
* Obtain ConnectionHandle which then can be passed to execute()
* Obtain &l:RequestExecutor::ConnectionHandle; which then can be passed to &l:RequestExecutor::execute ();.
* @return std::shared_ptr to &l:RequestExecutor::ConnectionHandle;.
*/
virtual std::shared_ptr<ConnectionHandle> getConnection() = 0;
/**
* Same as getConnection but Async
* Same as &l:RequestExecutor::getConnection (); but Async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - function pointer to asynchronous callback.
* @return - &id:oatpp::async::Action;.
*/
virtual Action getConnectionAsync(oatpp::async::AbstractCoroutine* parentCoroutine, AsyncConnectionCallback callback) = 0;
/**
* Execute request.
* @param method - method ex: ["GET", "POST", "PUT", etc.].
* @param path - path to resource.
* @param headers - headers map &l:RequestExecutor::Headers;.
* @param body - `std::shared_ptr` to &l:RequestExecutor::Body; object.
* @param connectionHandle - &l:RequestExecutor::ConnectionHandle;
* @return - &id:oatpp::web::protocol::http::incoming::Response;.
*/
virtual std::shared_ptr<Response> execute(const String& method,
const String& path,
const Headers& headers,
const std::shared_ptr<Body>& body,
const std::shared_ptr<ConnectionHandle>& connectionHandle = nullptr) = 0;
/**
* Same as &l:RequestExecutor::execute (); but Async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - function pointer to asynchronous callback.
* @param method - method ex: ["GET", "POST", "PUT", etc.].
* @param path - path to resource.
* @param headers - headers map &l:RequestExecutor::Headers;.
* @param body - `std::shared_ptr` to &l:RequestExecutor::Body; object.
* @param connectionHandle - &l:RequestExecutor::ConnectionHandle;
* @return - &id:oatpp::async::Action;.
*/
virtual Action executeAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback,
const String& method,

View File

@ -28,35 +28,75 @@
#include "oatpp/core/data/IODefinitions.hpp"
namespace oatpp { namespace web { namespace protocol {
/**
* Communication Error
*/
class CommunicationError : public std::runtime_error {
private:
oatpp::data::v_io_size m_ioStatus;
oatpp::String m_message;
public:
/**
* Constructor.
* @param ioStatus - I/O error. See &id:oatpp::data::v_io_size;.
* @param message - error message.
*/
CommunicationError(oatpp::data::v_io_size ioStatus, const oatpp::String& message);
/**
* Get I/O error. See &id:oatpp::data::v_io_size;.
* @return &id:oatpp::data::v_io_size;.
*/
oatpp::data::v_io_size getIOStatus();
/**
* Get error message.
* @return - error message.
*/
oatpp::String& getMessage();
};
/**
* Protocol Error template.
* @tparam Status - arbitrary data type.
*/
template<class Status>
class ProtocolError : public CommunicationError {
public:
/**
* Protocol Error Info.
*/
struct Info {
/**
* Default Constructor.
*/
Info()
: ioStatus(0)
{}
/**
* Constructor.
* @param pIOStatus - I/O level error. See &id:oatpp::data::v_io_size;.
* @param pStatus - configurable arbitrary data type.
*/
Info(oatpp::data::v_io_size pIOStatus, const Status& pStatus)
: ioStatus(pIOStatus)
, status(pStatus)
{}
/**
* Get I/O level error.
*/
oatpp::data::v_io_size ioStatus;
/**
* Configurable arbitrary data type.
*/
Status status;
};
@ -64,12 +104,21 @@ public:
private:
Info m_info;
public:
/**
* Constructor.
* @param info - &l:ProtocolError::Info ;.
* @param message - error message.
*/
ProtocolError(const Info& info, const oatpp::String& message)
: CommunicationError(info.ioStatus, message)
, m_info(info)
{}
/**
* Get error info.
* @return - error info.
*/
Info getInfo() {
return m_info;
}

View File

@ -236,7 +236,7 @@ ContentRange ContentRange::parse(const oatpp::String& str) {
return parse(caret);
}
oatpp::data::share::StringKeyLabelCI_FAST Protocol::parseHeaderNameLabel(const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::data::share::StringKeyLabelCI_FAST Parser::parseHeaderNameLabel(const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret) {
p_char8 data = caret.getData();
for(v_int32 i = caret.getPosition(); i < caret.getDataSize(); i++) {
@ -251,7 +251,7 @@ oatpp::data::share::StringKeyLabelCI_FAST Protocol::parseHeaderNameLabel(const s
return oatpp::data::share::StringKeyLabelCI_FAST(nullptr, nullptr, 0);
}
void Protocol::parseRequestStartingLine(RequestStartingLine& line,
void Parser::parseRequestStartingLine(RequestStartingLine& line,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error) {
@ -285,7 +285,7 @@ void Protocol::parseRequestStartingLine(RequestStartingLine& line,
}
void Protocol::parseResponseStartingLine(ResponseStartingLine& line,
void Parser::parseResponseStartingLine(ResponseStartingLine& line,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error) {
@ -312,7 +312,7 @@ void Protocol::parseResponseStartingLine(ResponseStartingLine& line,
}
void Protocol::parseOneHeader(Headers& headers,
void Parser::parseOneHeader(Headers& headers,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error) {
@ -335,7 +335,7 @@ void Protocol::parseOneHeader(Headers& headers,
}
}
void Protocol::parseHeaders(Headers& headers,
void Parser::parseHeaders(Headers& headers,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error) {

View File

@ -38,88 +38,349 @@
#include <unordered_map>
namespace oatpp { namespace web { namespace protocol { namespace http {
/**
* Http status.
*/
class Status{
public:
/**
* Continue.
*/
static const Status CODE_100;// Continue
/**
* Switching Protocols.
*/
static const Status CODE_101;// Switching
/**
* Processing.
*/
static const Status CODE_102;// Processing
/**
* OK.
*/
static const Status CODE_200;// OK
/**
* Created.
*/
static const Status CODE_201;// Created
/**
* Accepted.
*/
static const Status CODE_202;// Accepted
/**
* Non-Authoritative Information.
*/
static const Status CODE_203;// Non-Authoritative Information
/**
* No Content.
*/
static const Status CODE_204;// No Content
/**
* Reset Content.
*/
static const Status CODE_205;// Reset Content
/**
* Partial Content.
*/
static const Status CODE_206;// Partial Content
/**
* Multi-Status.
*/
static const Status CODE_207;// Multi-Status
/**
* IM Used.
*/
static const Status CODE_226;// IM Used
/**
* Multiple Choices.
*/
static const Status CODE_300;// Multiple Choices
/**
* Moved Permanently.
*/
static const Status CODE_301;// Moved Permanently
/**
* Moved Temporarily.
*/
static const Status CODE_302;// Moved Temporarily
/**
* See Other.
*/
static const Status CODE_303;// See Other
/**
* Not Modified.
*/
static const Status CODE_304;// Not Modified
/**
* Use Proxy.
*/
static const Status CODE_305;// Use Proxy
/**
* Reserved.
*/
static const Status CODE_306;// Reserved
/**
* Temporary Redirect.
*/
static const Status CODE_307;// Temporary Redirect
/**
* Bad Request.
*/
static const Status CODE_400;// Bad Request
/**
* Unauthorized.
*/
static const Status CODE_401;// Unauthorized
/**
* Payment Required.
*/
static const Status CODE_402;// Payment Required
/**
* Forbidden.
*/
static const Status CODE_403;// Forbidden
/**
* Not Found.
*/
static const Status CODE_404;// Not Found
/**
* Method Not Allowed.
*/
static const Status CODE_405;// Method Not Allowed
/**
* Not Acceptable.
*/
static const Status CODE_406;// Not Acceptable
/**
* Proxy Authentication Required.
*/
static const Status CODE_407;// Proxy Authentication Required
/**
* Request Timeout.
*/
static const Status CODE_408;// Request Timeout
/**
* Conflict.
*/
static const Status CODE_409;// Conflict
/**
* Gone
*/
static const Status CODE_410;// Gone
/**
* Length Required.
*/
static const Status CODE_411;// Length Required
/**
* Precondition Failed.
*/
static const Status CODE_412;// Precondition Failed
/**
* Request Entity Too Large.
*/
static const Status CODE_413;// Request Entity Too Large
/**
* Request-URI Too Large.
*/
static const Status CODE_414;// Request-URI Too Large
/**
* Unsupported Media Type.
*/
static const Status CODE_415;// Unsupported Media Type
/**
* Requested Range Not Satisfiable.
*/
static const Status CODE_416;// Requested Range Not Satisfiable
/**
* Expectation Failed.
*/
static const Status CODE_417;// Expectation Failed
/**
* Unprocessable Entity.
*/
static const Status CODE_422;// Unprocessable Entity
/**
* Locked.
*/
static const Status CODE_423;// Locked
/**
* Failed Dependency.
*/
static const Status CODE_424;// Failed Dependency
/**
* Unordered Collection.
*/
static const Status CODE_425;// Unordered Collection
/**
* Upgrade Required.
*/
static const Status CODE_426;// Upgrade Required
/**
* Precondition Required.
*/
static const Status CODE_428;// Precondition Required
/**
* Too Many Requests.
*/
static const Status CODE_429;// Too Many Requests
/**
* Request Header Fields Too Large.
*/
static const Status CODE_431;// Request Header Fields Too Large
/**
* Requested host unavailable.
*/
static const Status CODE_434;// Requested host unavailable
/**
* Close connection withot sending headers.
*/
static const Status CODE_444;// Close connection withot sending headers
/**
* Retry With.
*/
static const Status CODE_449;// Retry With
/**
* Unavailable For Legal Reasons.
*/
static const Status CODE_451;// Unavailable For Legal Reasons
/**
* Internal Server Error.
*/
static const Status CODE_500;// Internal Server Error
/**
* Not Implemented.
*/
static const Status CODE_501;// Not Implemented
/**
* Bad Gateway.
*/
static const Status CODE_502;// Bad Gateway
/**
* Service Unavailable.
*/
static const Status CODE_503;// Service Unavailable
/**
* Gateway Timeout.
*/
static const Status CODE_504;// Gateway Timeout
/**
* HTTP Version Not Supported.
*/
static const Status CODE_505;// HTTP Version Not Supported
/**
* Variant Also Negotiates.
*/
static const Status CODE_506;// Variant Also Negotiates
/**
* Insufficient Storage.
*/
static const Status CODE_507;// Insufficient Storage
/**
* Loop Detected.
*/
static const Status CODE_508;// Loop Detected
/**
* Bandwidth Limit Exceeded.
*/
static const Status CODE_509;// Bandwidth Limit Exceeded
/**
* Not Extended.
*/
static const Status CODE_510;// Not Extended
/**
* Network Authentication Required.
*/
static const Status CODE_511;// Network Authentication Required
/**
* Constructor.
*/
Status()
: code(0)
, description(nullptr)
{}
/**
* Constructor.
* @param pCode - status code.
* @param pDesc - description.
*/
Status(v_int32 pCode, const char* pDesc)
: code(pCode)
, description(pDesc)
{}
/**
* Status code.
*/
v_int32 code;
/**
* Description.
*/
const char* description;
bool operator==(const Status& other) const {
@ -131,25 +392,51 @@ public:
}
};
/**
* HttpError extends &id:oatpp::web::protocol::ProtocolError;<&l:Status;>.
*/
class HttpError : public protocol::ProtocolError<Status> {
public:
/**
* Constructor.
* @param info
* @param message
*/
HttpError(const Info& info, const oatpp::String& message)
: protocol::ProtocolError<Status>(info, message)
{}
/**
* Constructor.
* @param status
* @param message
*/
HttpError(const Status& status, const oatpp::String& message)
: protocol::ProtocolError<Status>(Info(0, status), message)
{}
};
/**
* Throw &l:HttpError; if assertion failed.
* @param COND - boolean statement. If evaluates to false - throw error.
* @param STATUS - &l:Status;.
* @param MESSAGE - String message.
*/
#define OATPP_ASSERT_HTTP(COND, STATUS, MESSAGE) \
if(!(COND)) { throw oatpp::web::protocol::http::HttpError(STATUS, MESSAGE); }
/**
* Collection of HTTP Header constants.
*/
class Header {
public:
/**
* Possible values for headers.
*/
class Value {
public:
static const char* const CONNECTION_CLOSE;
@ -247,43 +534,118 @@ public:
static ContentRange parse(const oatpp::String& str);
};
/**
* Struct representing HTTP request starting line.
* Example request starting line: `GET /path/to/resource/ HTTP/1.1`.
*/
struct RequestStartingLine {
/**
* Method as &id:oatpp::data::share::StringKeyLabel;.
*/
oatpp::data::share::StringKeyLabel method; // GET, POST ...
/**
* Path as &id:oatpp::data::share::StringKeyLabel;.
*/
oatpp::data::share::StringKeyLabel path;
/**
* Protocol as &id:oatpp::data::share::StringKeyLabel;.
*/
oatpp::data::share::StringKeyLabel protocol;
};
/**
* Struct representing HTTP response starting line.
* Example response starting line: `HTTP/1.1 200 OK`.
*/
struct ResponseStartingLine {
/**
* Protocol as &id:oatpp::data::share::StringKeyLabel;.
*/
oatpp::data::share::StringKeyLabel protocol;
/**
* Status code as v_int32.
*/
v_int32 statusCode;
/**
* Description as &id:oatpp::data::share::StringKeyLabel;.
*/
oatpp::data::share::StringKeyLabel description;
};
class Protocol {
public:
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
typedef std::unordered_map<oatpp::data::share::StringKeyLabel, oatpp::data::share::StringKeyLabel> QueryParams;
/**
* Typedef for headers map. Headers map key is case-insensitive.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabelCI_FAST; and &id:oatpp::data::share::StringKeyLabel;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabelCI_FAST, oatpp::data::share::StringKeyLabel> Headers;
/**
* Typedef for query parameters map.
* `std::unordered_map` of &id:oatpp::data::share::StringKeyLabel; and &id:oatpp::data::share::StringKeyLabel;.
*/
typedef std::unordered_map<oatpp::data::share::StringKeyLabel, oatpp::data::share::StringKeyLabel> QueryParams;
/**
* Oatpp Http parser.
*/
class Parser {
private:
static oatpp::data::share::StringKeyLabelCI_FAST parseHeaderNameLabel(const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret);
public:
/**
* Parse &l:RequestStartingLine;.
* @param line - &l:RequestStartingLine;. Values will be set to line's fields.
* @param headersText - `std::shared_ptr` to &id:oatpp::base::StrBuffer; needed as a "memory handle" for
* &l:RequestStartingLine; fields. See &id:oatpp::data::share::MemoryLabel;.
* @param caret - &id:oatpp::parser::Caret;.
* @param error - out parameter &l:Status;.
*/
static void parseRequestStartingLine(RequestStartingLine& line,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error);
/**
* Parse &l:ResponseStartingLine;.
* @param line - &l:ResponseStartingLine;. Values will be set to line's fields.
* @param headersText - `std::shared_ptr` to &id:oatpp::base::StrBuffer; needed as a "memory handle" for
* &l:ResponseStartingLine; fields. See &id:oatpp::data::share::MemoryLabel;.
* @param caret - &id:oatpp::parser::Caret;.
* @param error - out parameter &l:Status;.
*/
static void parseResponseStartingLine(ResponseStartingLine& line,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error);
/**
* Parse one header line. Example of the header line:
* `"Content-Type: application/json\r\n"`.
* @param headers - &l:Headers; map to put parsed header to.
* @param headersText - `std::shared_ptr` to &id:oatpp::base::StrBuffer; needed as a "memory handle" for
* &l:Headers; values. See &id:oatpp::data::share::MemoryLabel;.
* @param caret - &id:oatpp::parser::Caret;.
* @param error - out parameter &l:Status;.
*/
static void parseOneHeader(Headers& headers,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,
Status& error);
/**
* Parse HTTP headers to &l:Headers; map.
* @param headers - &l:Headers; map to put parsed headers to.
* @param headersText - `std::shared_ptr` to &id:oatpp::base::StrBuffer; needed as a "memory handle" for
* &l:Headers; values. See &id:oatpp::data::share::MemoryLabel;.
* @param caret - &id:oatpp::parser::Caret;.
* @param error - out parameter &l:Status;.
*/
static void parseHeaders(Headers& headers,
const std::shared_ptr<oatpp::base::StrBuffer>& headersText,
oatpp::parser::Caret& caret,

View File

@ -29,7 +29,7 @@
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
BodyDecoder::ToStringDecoder::ToStringDecoder(const BodyDecoder* decoder,
const Protocol::Headers& headers,
const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream)
: m_decoder(decoder)
, m_headers(headers)

View File

@ -30,20 +30,26 @@
#include "oatpp/core/async/Coroutine.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
/**
* Abstract BodyDecoder.
* Body Decoder is responsible to decode body of incoming request.
* For example if you receive chunked-encoded body, you have to decode it in order to get "plain" body.
* You may extend this class in order to customize body-decoding process.
*/
class BodyDecoder {
private:
class ToStringDecoder : public oatpp::async::CoroutineWithResult<ToStringDecoder, oatpp::String> {
private:
const BodyDecoder* m_decoder;
Protocol::Headers m_headers;
Headers m_headers;
std::shared_ptr<oatpp::data::stream::InputStream> m_bodyStream;
std::shared_ptr<oatpp::data::stream::ChunkedBuffer> m_chunkedBuffer;
public:
ToStringDecoder(const BodyDecoder* decoder,
const Protocol::Headers& headers,
const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream);
Action act() override;
@ -55,14 +61,14 @@ private:
class ToDtoDecoder : public oatpp::async::CoroutineWithResult<ToDtoDecoder<Type>, typename Type::ObjectWrapper> {
private:
const BodyDecoder* m_decoder;
Protocol::Headers m_headers;
Headers m_headers;
std::shared_ptr<oatpp::data::stream::InputStream> m_bodyStream;
std::shared_ptr<oatpp::data::mapping::ObjectMapper> m_objectMapper;
std::shared_ptr<oatpp::data::stream::ChunkedBuffer> m_chunkedBuffer = oatpp::data::stream::ChunkedBuffer::createShared();
public:
ToDtoDecoder(const BodyDecoder* decoder,
Protocol::Headers& headers,
Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& objectMapper)
: m_decoder(decoder)
@ -88,43 +94,92 @@ private:
};
public:
virtual void decode(const Protocol::Headers& headers,
/**
* Implement this method! Decode bodyStream and write decoded data to toStream.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @param toStream - `std::shared_ptr` to &id:oatpp::data::stream::OutputStream;.
*/
virtual void decode(const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::stream::OutputStream>& toStream) const = 0;
/**
* Implement this method! Same as &l:BodyDecoder::decode (); but Async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param actionOnReturn - &id:oatpp::async::Action; to do when decoding finished.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @param toStream - `std::shared_ptr` to &id:oatpp::data::stream::OutputStream;.
* @return - &id:oatpp::async::Action;.
*/
virtual oatpp::async::Action decodeAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
const oatpp::async::Action& actionOnReturn,
const Protocol::Headers& headers,
const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::stream::OutputStream>& toStream) const = 0;
oatpp::String decodeToString(const Protocol::Headers& headers,
/**
* Read body stream and decode it to string.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @return - &oatpp::String;.
*/
oatpp::String decodeToString(const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream) const {
auto chunkedBuffer = oatpp::data::stream::ChunkedBuffer::createShared();
decode(headers, bodyStream, chunkedBuffer);
return chunkedBuffer->toString();
}
/**
* Read body stream, decode, and deserialize it as DTO Object (see [Data Transfer Object (DTO)](https://oatpp.io/docs/components/dto/)).
* @tparam Type - DTO object type.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @param objectMapper - `std::shared_ptr` to &id:oatpp::data::mapping::ObjectMapper;.
* @return - deserialized DTO object.
*/
template<class Type>
typename Type::ObjectWrapper decodeToDto(const Protocol::Headers& headers,
typename Type::ObjectWrapper decodeToDto(const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& objectMapper) const {
return objectMapper->readFromString<Type>(decodeToString(headers, bodyStream));
}
/**
* Same as &l:BodyDecoder::decodeToString (); but Async.
* @tparam ParentCoroutineType - caller coroutine type.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - pointer to callback function.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @return - &id:oatpp::async::Action;.
*/
template<typename ParentCoroutineType>
oatpp::async::Action decodeToStringAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
oatpp::async::Action (ParentCoroutineType::*callback)(const oatpp::String&),
const Protocol::Headers& headers,
const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream) const {
return parentCoroutine->startCoroutineForResult<ToStringDecoder>(callback, this, headers, bodyStream);
}
/**
* Same as &l:BodyDecoder::decodeToDto (); but Async.
* @tparam DtoType - DTO object type.
* @tparam ParentCoroutineType - caller coroutine type.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - pointer to callback function.
* @param headers - Headers map. &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - `std::shared_ptr` to &id:oatpp::data::stream::InputStream;.
* @param objectMapper - `std::shared_ptr` to &id:oatpp::data::mapping::ObjectMapper;.
* @return - &id:oatpp::async::Action;.
*/
template<class DtoType, typename ParentCoroutineType>
oatpp::async::Action decodeToDtoAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
oatpp::async::Action (ParentCoroutineType::*callback)(const typename DtoType::ObjectWrapper&),
const Protocol::Headers& headers,
const Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& objectMapper) const {
return parentCoroutine->startCoroutineForResult<ToDtoDecoder<DtoType>>(callback, this, headers, bodyStream, objectMapper);

View File

@ -28,7 +28,7 @@ namespace oatpp { namespace web { namespace protocol { namespace http { namespac
Request::Request(const http::RequestStartingLine& startingLine,
const url::mapping::Pattern::MatchMap& pathVariables,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder)
: m_startingLine(startingLine)
@ -41,7 +41,7 @@ Request::Request(const http::RequestStartingLine& startingLine,
std::shared_ptr<Request> Request::createShared(const http::RequestStartingLine& startingLine,
const url::mapping::Pattern::MatchMap& pathVariables,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder) {
return Shared_Incoming_Request_Pool::allocateShared(startingLine, pathVariables, headers, bodyStream, bodyDecoder);
@ -55,11 +55,11 @@ const url::mapping::Pattern::MatchMap& Request::getPathVariables() const {
return m_pathVariables;
}
const http::Protocol::Headers& Request::getHeaders() const {
const http::Headers& Request::getHeaders() const {
return m_headers;
}
const http::Protocol::QueryParams& Request::getQueryParameters() const {
const http::QueryParams& Request::getQueryParameters() const {
if(!m_queryParamsParsed) {
m_queryParams = oatpp::network::Url::Parser::labelQueryParams(m_pathVariables.getTail());
m_queryParamsParsed = true;

View File

@ -33,7 +33,7 @@
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
/**
* Class http::incoming::Request AKA IncomingRequest represents client's incoming request
* Class http::incoming::Request AKA IncomingRequest represents client's incoming request.
*/
class Request : public oatpp::base::Countable {
public:
@ -43,7 +43,7 @@ private:
http::RequestStartingLine m_startingLine;
url::mapping::Pattern::MatchMap m_pathVariables;
http::Protocol::Headers m_headers;
http::Headers m_headers;
std::shared_ptr<oatpp::data::stream::InputStream> m_bodyStream;
/*
@ -53,20 +53,20 @@ private:
std::shared_ptr<const http::incoming::BodyDecoder> m_bodyDecoder;
mutable bool m_queryParamsParsed; // used for lazy parsing of QueryParams
mutable http::Protocol::QueryParams m_queryParams;
mutable http::QueryParams m_queryParams;
public:
Request(const http::RequestStartingLine& startingLine,
const url::mapping::Pattern::MatchMap& pathVariables,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder);
public:
static std::shared_ptr<Request> createShared(const http::RequestStartingLine& startingLine,
const url::mapping::Pattern::MatchMap& pathVariables,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder);
@ -76,7 +76,7 @@ public:
* Please note: lazy parsing of query parameters is not thread-safe!
* @return map<key, value> for "&key=value"
*/
const http::Protocol::QueryParams& getQueryParameters() const;
const http::QueryParams& getQueryParameters() const;
/**
* Get query parameter value by name
@ -86,7 +86,7 @@ public:
oatpp::String getQueryParameter(const oatpp::data::share::StringKeyLabel& name) const;
/**
*
* Get query parameter value by name with defaultValue
* @param name
* @param defaultValue
* @return query parameter value or defaultValue if no such parameter found
@ -100,8 +100,8 @@ public:
const http::RequestStartingLine& getStartingLine() const;
/**
* Get path variables according to path-pattern.
* Ex. given request path="/sum/19/1" for path-pattern="/sum/{a}/{b}"
* Get path variables according to path-pattern. <br>
* Ex. given request path="/sum/19/1" for path-pattern="/sum/{a}/{b}" <br>
* getPathVariables().getVariable("a") == 19, getPathVariables().getVariable("b") == 1.
*
* @return url MatchMap
@ -112,7 +112,7 @@ public:
* Get request's headers map
* @return Headers map
*/
const http::Protocol::Headers& getHeaders() const;
const http::Headers& getHeaders() const;
/**
* Get request's body stream

View File

@ -84,9 +84,9 @@ RequestHeadersReader::Result RequestHeadersReader::readHeaders(const std::shared
auto headersText = buffer.toString();
oatpp::parser::Caret caret (headersText);
http::Status status;
http::Protocol::parseRequestStartingLine(result.startingLine, headersText.getPtr(), caret, status);
http::Parser::parseRequestStartingLine(result.startingLine, headersText.getPtr(), caret, status);
if(status.code == 0) {
http::Protocol::parseHeaders(result.headers, headersText.getPtr(), caret, status);
http::Parser::parseHeaders(result.headers, headersText.getPtr(), caret, status);
}
}
@ -161,9 +161,9 @@ RequestHeadersReader::Action RequestHeadersReader::readHeadersAsync(oatpp::async
auto headersText = m_bufferStream.toString();
oatpp::parser::Caret caret (headersText);
http::Status status;
http::Protocol::parseRequestStartingLine(m_result.startingLine, headersText.getPtr(), caret, status);
http::Parser::parseRequestStartingLine(m_result.startingLine, headersText.getPtr(), caret, status);
if(status.code == 0) {
http::Protocol::parseHeaders(m_result.headers, headersText.getPtr(), caret, status);
http::Parser::parseHeaders(m_result.headers, headersText.getPtr(), caret, status);
if(status.code == 0) {
return _return(m_result);
} else {

View File

@ -29,18 +29,42 @@
#include "oatpp/core/async/Coroutine.hpp"
namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming {
/**
* Helper class to read http headers of incoming request from stream.
*/
class RequestHeadersReader {
public:
/**
* Convenience typedef for &id:oatpp::async::Action;.
*/
typedef oatpp::async::Action Action;
private:
static constexpr v_int32 SECTION_END = ('\r' << 24) | ('\n' << 16) | ('\r' << 8) | ('\n');
public:
/**
* Result of headers reading and parsing.
*/
struct Result {
/**
* &id:oatpp::web::protocol::http::RequestStartingLine;.
*/
http::RequestStartingLine startingLine;
http::Protocol::Headers headers;
/**
* &id:oatpp::web::protocol::http::Headers;.
*/
http::Headers headers;
/**
* This value represents starting position in buffer used to read data from stream for the last read operation.
*/
v_int32 bufferPosStart;
/**
* This value represents end position in buffer used to read data from stream for the last read operation.
*/
v_int32 bufferPosEnd;
};
@ -55,14 +79,34 @@ private:
v_int32 m_bufferSize;
v_int32 m_maxHeadersSize;
public:
/**
* Constructor.
* @param buffer - buffer to use to read data from stream.
* @param bufferSize - buffer size.
* @param maxHeadersSize - maximum allowed size in bytes of http headers section.
*/
RequestHeadersReader(void* buffer, v_int32 bufferSize, v_int32 maxHeadersSize)
: m_buffer((p_char8) buffer)
, m_bufferSize(bufferSize)
, m_maxHeadersSize(maxHeadersSize)
{}
/**
* Read and parse http headers from stream.
* @param connection - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
* @param error - out parameter &id:oatpp::web::protocol::ProtocolError::Info;.
* @return - &l:RequestHeadersReader::Result;.
*/
Result readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection, http::HttpError::Info& error);
/**
* Read and parse http headers from stream in asynchronous manner.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - pointer to callback function.
* @param connection - `std::shared_ptr` to &id:oatpp::data::stream::IOStream;.
* @return - &id:oatpp::async::Action;.
*/
Action readHeadersAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
AsyncCallback callback,
const std::shared_ptr<oatpp::data::stream::IOStream>& connection);

View File

@ -28,7 +28,7 @@ namespace oatpp { namespace web { namespace protocol { namespace http { namespac
Response::Response(v_int32 statusCode,
const oatpp::String& statusDescription,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder)
: m_statusCode(statusCode)
@ -40,7 +40,7 @@ Response::Response(v_int32 statusCode,
std::shared_ptr<Response> Response::createShared(v_int32 statusCode,
const oatpp::String& statusDescription,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder) {
return Shared_Incoming_Response_Pool::allocateShared(statusCode, statusDescription, headers, bodyStream, bodyDecoder);
@ -54,7 +54,7 @@ oatpp::String Response::getStatusDescription() const {
return m_statusDescription;
}
const http::Protocol::Headers& Response::getHeaders() const {
const http::Headers& Response::getHeaders() const {
return m_headers;
}

View File

@ -40,10 +40,10 @@ public:
private:
v_int32 m_statusCode;
oatpp::String m_statusDescription;
http::Protocol::Headers m_headers;
http::Headers m_headers;
std::shared_ptr<oatpp::data::stream::InputStream> m_bodyStream;
/**
/*
* Response should be preconfigured with default BodyDecoder.
* Entity that created response object is responsible for providing correct BodyDecoder.
* Custom BodyDecoder can be set on demand
@ -53,50 +53,125 @@ private:
std::shared_ptr<oatpp::data::stream::IOStream> m_connection;
public:
/**
* Constructor.
* @param statusCode - http status code.
* @param statusDescription - http status description.
* @param headers - &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - &id:oatpp::data::stream::InputStream;.
* @param bodyDecoder - &id:oatpp::web::protocol::http::incoming::BodyDecoder;.
*/
Response(v_int32 statusCode,
const oatpp::String& statusDescription,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder);
public:
/**
* Create shared Response.
* @param statusCode - http status code.
* @param statusDescription - http status description.
* @param headers - &id:oatpp::web::protocol::http::Headers;.
* @param bodyStream - &id:oatpp::data::stream::InputStream;.
* @param bodyDecoder - &id:oatpp::web::protocol::http::incoming::BodyDecoder;.
* @return - `std::shared_ptr` to Response.
*/
static std::shared_ptr<Response> createShared(v_int32 statusCode,
const oatpp::String& statusDescription,
const http::Protocol::Headers& headers,
const http::Headers& headers,
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder);
/**
* Get http status code.
* @return - http status code.
*/
v_int32 getStatusCode() const;
/**
* Get http status description.
* @return - http status description.
*/
oatpp::String getStatusDescription() const;
const http::Protocol::Headers& getHeaders() const;
/**
* Get response http headers as &id:oatpp::web::protocol::http::Headers;.
* @return - response http headers as &id:oatpp::web::protocol::http::Headers;.
*/
const http::Headers& getHeaders() const;
/**
* Get raw body stream.
* @return - raw body stream as &id:oatpp::data::stream::InputStream;.
*/
std::shared_ptr<oatpp::data::stream::InputStream> getBodyStream() const;
/**
* Get body decoder configured for this response.
* @return - &id:oatpp::web::protocol::http::incoming::BodyDecoder;.
*/
std::shared_ptr<const http::incoming::BodyDecoder> getBodyDecoder() const;
/**
* Decode and transfer body to toStream.
* Use case example - stream huge body directly to file using relatively small buffer.
* @param toStream - &id:oatpp::data::stream::OutputStream;.
*/
void streamBody(const std::shared_ptr<oatpp::data::stream::OutputStream>& toStream) const;
/**
* Decode and read body to &id:oatpp::String;.
* @return - &id:oatpp::String;.
*/
oatpp::String readBodyToString() const;
/**
* Read body stream, decode, and deserialize it as DTO Object (see [Data Transfer Object (DTO)](https://oatpp.io/docs/components/dto/)).
* @tparam Type - DTO object type.
* @param objectMapper - `std::shared_ptr` to &id:oatpp::data::mapping::ObjectMapper;.
* @return - deserialized DTO object.
*/
template<class Type>
typename Type::ObjectWrapper readBodyToDto(const std::shared_ptr<oatpp::data::mapping::ObjectMapper>& objectMapper) const {
return m_bodyDecoder->decodeToDto<Type>(m_headers, m_bodyStream, objectMapper);
}
// Async
/**
* Same as &l:Response::readBodyToDto (); but Async.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param actionOnReturn - &id:oatpp::async::Action; to do when decoding finished.
* @param toStream - `std::shared_ptr` to &id:oatpp::data::stream::OutputStream;.
* @return - &id:oatpp::async::Action;.
*/
oatpp::async::Action streamBodyAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
const oatpp::async::Action& actionOnReturn,
const std::shared_ptr<oatpp::data::stream::OutputStream>& toStream) const;
/**
* Same as &l:Response::readBodyToString (); but Async.
* @tparam ParentCoroutineType - caller coroutine type.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - pointer to callback function.
* @return - &id:oatpp::async::Action;.
*/
template<typename ParentCoroutineType>
oatpp::async::Action readBodyToStringAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
oatpp::async::Action (ParentCoroutineType::*callback)(const oatpp::String&)) const {
return m_bodyDecoder->decodeToStringAsync(parentCoroutine, callback, m_headers, m_bodyStream);
}
/**
* Same as &l:Response::readBodyToDto (); but Async.
* @tparam DtoType - DTO object type.
* @tparam ParentCoroutineType - caller coroutine type.
* @param parentCoroutine - caller coroutine as &id:oatpp::async::AbstractCoroutine;*.
* @param callback - pointer to callback function.
* @param objectMapper - `std::shared_ptr` to &id:oatpp::data::mapping::ObjectMapper;.
* @return - &id:oatpp::async::Action;.
*/
template<class DtoType, typename ParentCoroutineType>
oatpp::async::Action readBodyToDtoAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
oatpp::async::Action (ParentCoroutineType::*callback)(const typename DtoType::ObjectWrapper&),

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