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);
  • http_method_mapper_t is a mapper from integer codes of HTTP methods from http_parser library to RESTinio’s http_method_id_t instances;
  • connection_state_listener_t is a customization point that tells RESTInio what type of connection state listener should be used (see Connection state listener).
  • ip_blocker_t is a customization point that tells RESTInio what type of IP-blocker should be used (see IP-blocker).
  • extra_data_factory_t defines what extra-data should be incorporated into a request object (see Extra-data in request object).

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() )
{
  // Now 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/core.hpp, so it needs to be included separately.

If the timer_manager requires initial parameters then such parameters can be specified by using timer_manager method in settings:

restinio::run(
   restinio::on_this_thread()
      // Settings tuning starts here.
      .port(8080)
      .address("localhost")
      .timer_manager(... /* Parameters for the timer manager */)
      .request_handler(...)
      // Settings tuning is completed.
   );

The list of parameters to be passed to timer_manager method depends on the type of the timer_manager. For example, the standard asio_timer_manager_t accepts just one parameter: duration of now tick of the timer:

restinio::run(
   restinio::on_this_thread()
      // Settings tuning starts here.
      .port(8080)
      .address("localhost")
      // Change the default one-second timer interval to more precise one.
      .timer_manager(std::chrono::milliseconds{250})
      .request_handler(...)
      // Settings tuning is completed.
   );

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:

template<typename User_Data>
restinio::request_handling_status_t
handler( restinio::generic_request_handle_t<User_Data> 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).

http_method_mapper_t

Since v.0.5.0 RESTinio allows to used customized versions of http_parser libraries. It means that a customized http_parser can support some additional HTTP methods. For example, someone can fork http_parser and add support for ENCODE and DECODE custom methods to that fork. Type http_method_mapper_t allows to bring the support of that custom methods to RESTinio.

A user-supplied http_method_mapper_t type should contain one static and public method from_nodejs with the following signature:

static restinio::http_method_id_t
from_nodejs( int http_parser_code ) noexcept;

Method from_nodejs will be called when RESTinio receives HTTP method code from http_parser. Value returned this method will be stored in http_request_header_t object associated with the corresponding request.

By default http_method_mapper_t is just a typedef for restinio::default_http_methods_t type. A user have to define its http_method_mapper_t only if a customized http_parser is used and that parser introduces new non-standard HTTP methods.

An example of customization of RESTinio to use non-standard HTTP methods can look like that:

// Definitions of new HTTP methods.
constexpr const restinio::http_method_id_t http_encode{HTTP_ENCODE, "ENCODE"};
constexpr const restinio::http_method_id_t http_decode{HTTP_DECODE, "DECODE"};

// Definition of custom http_method_mapper.
struct my_http_method_mapper {
   inline static constexpr restinio::http_method_id_t
   from_nodejs(int code) noexcept {
      switch(code) {
         case HTTP_ENCODE: return http_encode;
         case HTTP_DECODE: return http_decode;
         default: return restinio::default_http_methods_t::from_nodejs(code);
      }
   }
};

connection_state_listener_t

This type allows to specify what type of connection state listener should be used for RESTinio’s server. By default the value restinio::connection_state::noop_listener_t is used. See Connection state listener for more details.

ip_blocker_t

This type allows to specify what type of IP-blocker should be used for RESTinio’s server. By default the value restinio::ip_blocker::noop_ip_blocker_t is used. See IP-blocker for more details.

extra_data_factory_t

If a user wants to incorporate some extra-data into a request object then he/she have to define own extra-data-factory type and specify the name of that type as extra_data_factory_t inside Traits. See Extra-data in request object for more details.