Traits

List of types that must be defined be Traits

  • timer_manager_t defines the logic of how timeouts are managed;
  • logger_t defines logger that is used by RESTinio to track its inner logic;
  • request_handler_t defines a function-like type to be used as request handler;
  • strand_t - defines a class that is used by connection as a wrapper for its callback-handlers running on asio::io_context thread(s) in order to guarantee serialized callbacks invocation (see asio doc). Actually, there are two options for the strand type: asio::strand<asio::executor> and asio::executor. The first is a real strand that guarantees serialized invocation and the second one is simply a default executor to eliminate unnecessary overhead when running asio::io_context on a single thread;
  • stream_socket_t is a customization point that tells restinio what type of socket used for connections. This parameter allows restinio to support TLS connection (see TLS support).

timer_manager_t

timer_manager_t - defines a timeout controller logic. It must define two nested types. The first one is timer_guard_t with the following interface:

class timer_guard_t
{
  public:
    // Schedule a checking of timed out operations
    // after the time interval specified by timer-manager.
    void schedule(
      // Weak pointer to object to check timed out ops.
      // tcp_connection_ctx_weak_handle_t = std::weak_ptr< tcp_connection_ctx_base_t >
      tcp_connection_ctx_weak_handle_t weak_handle );

    // Cancel timeout guard if any.
    void cancel();
};

To understand the ground idea behind timer managers it is needed to clarify on tcp_connection_ctx_base_t a weak pointer of which is passed to timer_guard_t::schedule(). A class tcp_connection_ctx_base_t has a virtual method:

// Check timeouts for all activities.
virtual void check_timeout(
  // A handle to itself (eliminates one shared_ptr instantiation).
  std::shared_ptr< tcp_connection_ctx_base_t > & self ) = 0;

Internal classes that inherit from tcp_connection_ctx_base_t implement this method to initiate a check whether there are a timed out operations. So timer_guard_t::schedule() timer guard must simply store a weak pointer to tcp_connection_ctx_base_t somewhere and try to invoke check_timeout() after some period of time that is specified by timer manager. Here is an example of how to try to invoke check_timeout():

// restinio::tcp_connection_ctx_weak_handle_t weak_handle;

if( auto h = weak_handle.lock() )
{
  // If here then  h is a shared pointer to an exiting object.
  h->check_timeout( h );
}

Suppose timer manager sets a time period for checking to 1 second, so each second a context object of a given connection will check if any timeout happened. Between two sequential checks, connection context object may change the actual operation that is tracked for timeout many times.

A timer_guard_t::cancel() method must cancel scheduled check of a given timer_guard.

An instance of timer_guard_t is stored in each connection managed by RESTinio and to create it timer_manager_t must define the following method:

class timer_manager_t
{
  public:
    // ...

    // struct/class  timer_guard_t{ ... };
    // or
    // using timer_guard_t = ...;

    // Create guard for connection.
    timer_guard_t create_timer_guard();
    // ...
};

The second type nested in timer_manager_t must be factory_t, that must implement create(asio::io_context&) method:

struct factory_t
{
  /* Extra parameters for creating timer manager */

  auto create( asio::io_context & io_context ) const
  {
    return std::make_shared< timer_manager_t >( /* params */ );
  }
};

Nested factory type is needed for holding parameters of a timer manager that come from settings. Timer manager itself might need a reference to asio::io_context on which server runs, and it is not available on the level of settings object. So the creation of timer instance is done in two steps. The first step - the factory is created in server settings and stores params that are needed for creating timer manager. The second step - when the server is instantiated (hence asio::io_context is known) a timer manager is created using the factory.

RESTinio comes with a set of ready-to-use timer_manager_t implementation:

  • null_timer_manager_t – noop timer guards, they produce timer guards that do nothing (when no control needed). See restinio/null_timer_manager.hpp;
  • asio_timer_manager_t – timer guards implemented with asio timers. See restinio/asio_timer_manager.hpp;
  • so5::so_timer_manager_t – timer guards implemented with SObjectizer timers. See restinio/so5/so_timer_manager.hpp. Note that restinio/so5/so_timer_manager.hpp header file is not included by restinio/all.hpp, so it needs to be included separately.

logger_t

logger_t - defines a logger implementation. It must support the following interface:

class null_logger_t
{
  public:
    template< typename Msg_Builder >
    void trace( Msg_Builder && mb );

    template< typename Msg_Builder >
    void info( Msg_Builder && mb );

    template< typename Msg_Builder >
    void warn( Msg_Builder && mb );

    template< typename Msg_Builder >
    void error( Msg_Builder && mb );
};

Msg_Builder is lambda that returns a message to log out. This approach allows a compiler to optimize logging when it is possible, see null_logger_t.

For implementation example see ostream_logger_t.

request_handler_t

request_handler_t - is a key type for request handling process. It must be a function-object with the following invocation interface:

restinio::request_handling_status_t
handler( restinio::request_handle_t req );

See Request handler for more details.

strand_t

strand_t provides serialized callback invocation for events of a specific connection. There are two option for strand_t: asio::strand<asio::executor> or asio::executor.

By default asio::strand<asio::executor> is used, it guarantees serialized chain of callback invocation. But if asio::io_context runs on a single thread there is no need to use asio::strand because there is no way to run callbacks in parallel. So in such cases, it is enough to use asio::executor directly and eliminate the overhead of asio::strand.

stream_socket_t

stream_socket_t allows to customize underlying socket type, so it possible to create https server using identical interface (see TLS support).