RESTinio

sample/async_handling_with_sobjectizer/main.cpp
#include <restinio/all.hpp>
#include <so_5/all.hpp>
#include <random>
#if !defined(SO_5_VERSION) || SO_5_VERSION < SO_5_VERSION_MAKE(6ull, 0ull, 0ull)
decltype(auto) from_all()
{
return so_5::from_all();
}
#else
decltype(auto) from_all()
{
return so_5::from_all().handle_all();
}
#endif
#if !defined(SO_5_VERSION) || SO_5_VERSION < SO_5_VERSION_MAKE(7ull, 0ull, 0ull)
template< typename Handler >
decltype(auto) read_case( so_5::mchain_t chain, Handler && handler )
{
return so_5::case_( std::move(chain), std::forward<Handler>(handler) );
}
#else
template< typename Handler >
decltype(auto) read_case( so_5::mchain_t chain, Handler && handler )
{
return so_5::receive_case( std::move(chain), std::forward<Handler>(handler) );
}
#endif
// Message for transfer requests from RESTinio's thread to processing thread.
struct handle_request
{
restinio::request_handle_t m_req;
};
// Message for delaying actual requests processing.
struct timeout_elapsed
{
restinio::request_handle_t m_req;
std::chrono::milliseconds m_pause;
};
void processing_thread_func(const so_5::mchain_t& req_ch)
{
// The stuff necessary for random pause generation.
std::random_device rd;
std::mt19937 generator{rd()};
std::uniform_int_distribution<> pause_generator{350, 3500};
// The channel for delayed timeout_elapsed messages.
auto delayed_ch = so_5::create_mchain(req_ch->environment());
// This flag will be set to 'true' when some of channels will be closed.
bool stop = false;
select(
from_all()
// If some channel become closed we should set out 'stop' flag.
.on_close([&stop](const auto &) { stop = true; })
// A predicate for stopping select() function.
.stop_on([&stop]{ return stop; }),
// Read and handle handle_request messages from req_ch.
read_case(req_ch,
[&](const handle_request& cmd) {
// Generate a random pause for processing of that request.
const std::chrono::milliseconds pause{pause_generator(generator)};
// Delay processing of that request by using delayed message.
so_5::send_delayed<timeout_elapsed>(delayed_ch,
// This the pause for send_delayed.
pause,
// The further arguments are going to timeout_elapsed's
// constructor.
cmd.m_req,
pause);
}),
// Read and handle timeout_elapsed messages from delayed_ch.
read_case(delayed_ch,
[](const timeout_elapsed& cmd) {
// Now we can create an actual response to the request.
cmd.m_req->create_response()
.set_body("Hello, World! (pause:"
+ std::to_string(cmd.m_pause.count())
+ "ms)")
.done();
})
);
}
int main()
{
// Launching SObjectizer on a separate thread.
// There is no need to start and shutdown SObjectize:
// the wrapped_env_t instance does it automatically.
so_5::wrapped_env_t sobj;
// Thread object for processing thread.
std::thread processing_thread;
// This thread should be automatically joined at exit
// (this is necessary for exception safety).
auto processing_thread_joiner = so_5::auto_join(processing_thread);
// A channel for sending requests from RESTinio's thread to
// separate processing thread.
auto req_ch = so_5::create_mchain(sobj);
// This channel should be automatically closed at scope exit
// (this is necessary for exception safety).
auto ch_closer = so_5::auto_close_drop_content(req_ch);
// Now we can start processing thread.
// If some exception will be thrown somewhere later the thread
// will be automatically stopped and joined.
processing_thread = std::thread{
processing_thread_func, req_ch
};
// Traits for our simple server.
struct traits_t : public restinio::default_traits_t
{
using logger_t = restinio::shared_ostream_logger_t;
};
restinio::run(
restinio::on_this_thread<traits_t>()
.port(8080)
.address("localhost")
.request_handler([req_ch](auto req) {
// Handle only HTTP GET requests for the root.
if(restinio::http_method_get() == req->header().method() &&
"/" == req->header().path())
{
// Request will be delegated to the actual processing.
so_5::send<handle_request>(req_ch, req);
return restinio::request_accepted();
}
else
return restinio::request_rejected();
})
.cleanup_func([&] {
// Processing thread needs to be closed.
// It is better to do it manually because there can
// be requests waiting in req_ch.
so_5::close_drop_content(req_ch);
}));
return 0;
}
all.hpp
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
nonstd::sv_lite::to_string
std::basic_string< CharT, Traits > to_string(basic_string_view< CharT, Traits > v)
Definition: string_view.hpp:1508
restinio::request_rejected
RESTINIO_NODISCARD constexpr request_handling_status_t request_rejected() noexcept
Definition: common_types.hpp:53
restinio::shared_ostream_logger_t
ostream_logger_t< std::mutex > shared_ostream_logger_t
Definition: ostream_logger.hpp:103
restinio::run
void run(asio_ns::io_context &ioctx, run_on_this_thread_settings_t< Traits > &&settings)
Helper function for running http server until ctrl+c is hit.
Definition: http_server_run.hpp:216
restinio::request_handle_t
std::shared_ptr< request_t > request_handle_t
An alias for handle for incoming request without additional extra-data.
Definition: request_handler.hpp:463
restinio::traits_t
Definition: traits.hpp:147