RESTinio
fixed_size.hpp
Go to the documentation of this file.
1 /*!
2  * @file
3  * @brief Chain of async handlers of the fixed size.
4  * @since v.0.7.0
5  */
6 
7 #pragma once
8 
9 #include <restinio/async_chain/common.hpp>
10 
11 #include <array>
12 
13 namespace restinio::async_chain
14 {
15 
16 /*!
17  * @brief A holder of fixed-size chain of asynchronous handlers.
18  *
19  * @note
20  * An instance of that type is intended to be filled with actual schedulers
21  * at the creation time. After that new schedulers can't be added to the chain,
22  * and old handlers can't be removed from the chain.
23  *
24  * Usage example for the case when there is no extra-data in a request object
25  * (please note that this is simplified example without actual asynchronous code,
26  * all schedulers work as synchronous handlers):
27  * @code
28  * struct my_traits : public restinio::default_traits_t {
29  * using request_handler_t = restinio::async_chain::fixed_size_chain_t<3>;
30  * };
31  *
32  * // The first handler in the chain.
33  * restinio::async_chain::schedule_result_t headers_checker(
34  * restinio::async_chain::unique_async_handling_controller_t<> controller )
35  * {
36  * ... // Checks values of HTTP-fields and rejects invalid requests.
37  *
38  * // Activation of the next handler.
39  * next( std::move(controller) );
40  *
41  * return restinio::async_chain::ok();
42  * }
43  *
44  * // The second handler in the chain.
45  * restinio::async_chain::schedule_result_t authentificator(
46  * restinio::async_chain::unique_async_handling_controller_t<> controller )
47  * {
48  * ... // Checks user's credentials and rejects requests from
49  * // non-authentificated users.
50  *
51  * // Activation of the next handler.
52  * next( std::move(controller) );
53  *
54  * return restinio::async_chain::ok();
55  * }
56  *
57  * // The last handler in the chain.
58  * restinio::async_chain::schedule_result_t actual_handler(
59  * restinio::async_chain::unique_async_handling_controller_t<> controller )
60  * {
61  * ... // Actual processing.
62  *
63  * return restinio::async_chain::ok();
64  * }
65  *
66  * restinio::run(
67  * on_thread_pool<my_traits>(16)
68  * .address(...)
69  * .port(...)
70  * .request_handler(
71  * // Just enumerate all handlers.
72  * headers_checker,
73  * authentificator,
74  * actual_handler )
75  * );
76  * @endcode
77  *
78  * An instance of `fixed_size_chain_t` can also be created manually and
79  * passed to server's settings by `unique_ptr`:
80  * @code
81  * auto chain = std::make_unique<restinio::async_chain::fixed_size_chain_t<3>>(
82  * headers_checker, authentificator, actual_handler);
83  * ...
84  * restinio::run(
85  * on_thread_pool<my_traits>(16)
86  * .address(...)
87  * .port(...)
88  * .request_handler(std::move(chain))
89  * );
90  * @endcode
91  *
92  * Usage example for the case when some extra-data is incorporated into
93  * a request object
94  * (please note that this is simplified example without actual asynchronous code,
95  * all schedulers work as synchronous handlers):
96  * @code
97  * struct my_extra_data_factory {
98  * // A data formed by checker of HTTP-fields.
99  * struct request_specific_fields_t {...};
100  *
101  * // A data formed by user-authentificator.
102  * struct user_info_t {...};
103  *
104  * // A data to be incorporated into a request object.
105  * using data_t = std::tuple<request_specific_fields_t, user_info_t>;
106  *
107  * void make_within(restinio::extra_data_buffer_t<data_t> buf) {
108  * new(buf.get()) data_t{};
109  * }
110  * };
111  *
112  * struct my_traits : public restinio::default_traits_t {
113  * using extra_data_factory_t = my_extra_data_factory;
114  * using request_handler_t = restinio::async_chain::fixed_size_chain_t<
115  * 3,
116  * extra_data_factory>;
117  * };
118  *
119  * using my_unique_controller_t =
120  * restinio::async_chain::unique_async_handling_controller_t<my_extra_data_factory>;
121  * using my_request_handle_t = my_unique_controller_t::actual_request_handle_t;
122  *
123  * // The first handler in the chain.
124  * restinio::async_chain::schedule_result_t headers_checker(
125  * my_unique_controller_t controller )
126  * {
127  * const my_request_handle_t req = acceptor->request_handle();
128  * ... // Checks values of HTTP-fields and rejects invalid requests.
129  * ...
130  * next( std::move(controller) );
131  * return restinio::async_chain::ok();
132  * }
133  *
134  * // The second handler in the chain.
135  * restinio::async_chain::schedule_result_t authentificator(
136  * my_unique_controller_t controller )
137  * {
138  * const my_request_handle_t req = acceptor->request_handle();
139  * ... // Checks user's credentials and rejects requests from
140  * // non-authentificated users.
141  * ...
142  * next( std::move(controller) );
143  * return restinio::async_chain::ok();
144  * }
145  *
146  * // The last handler in the chain.
147  * restinio::async_chain::schedule_result_t actual_handler(
148  * my_unique_controller_t controller )
149  * {
150  * const my_request_handle_t req = acceptor->request_handle();
151  * auto & field_values = std::get<my_extra_data_factory::request_specific_fields_t>(req->extra_data());
152  * auto & user_info = std::get<my_extra_data_factory::user_info_t>(req->extra_data());
153  * ... // Actual processing.
154  * return restinio::async_chain::ok();
155  * }
156  *
157  * restinio::run(
158  * on_thread_pool<my_traits>(16)
159  * .address(...)
160  * .port(...)
161  * .request_handler(
162  * // Just enumerate all handlers.
163  * headers_checker,
164  * authentificator,
165  * actual_handler )
166  * );
167  * @endcode
168  *
169  * @tparam Size The exact number of schedulers in the chain.
170  *
171  * @tparam Extra_Data_Factory The type of extra-data-factory specified in
172  * the server's traits.
173  *
174  * @since v.0.7.0
175  */
176 template<
177  std::size_t Size,
178  typename Extra_Data_Factory = no_extra_data_factory_t >
180 {
181  //! Short alias for unique controller type.
183 
184  //! Short alias for a request handler.
186 
187  //! Short alias for an array of request handlers.
189 
190  //! Short alias to a smart pointer to the source request.
193 
194  //! Short alias for the result of controller's on_next method.
197 
198  /*!
199  * @brief Actual implementation of the controller interface.
200  *
201  * @note
202  * Object of this type holds a copy of the source array of schedulers.
203  */
204  class actual_controller_t final
205  : public async_handling_controller_t< Extra_Data_Factory >
206  {
207  //! The source request.
209  //! Request handlers.
211  //! Index of the current scheduler to be used.
212  /*!
213  * @note
214  * May be equal to or greater than m_schedulers.size() in the case
215  * when all handlers are already processed.
216  */
218 
219  public:
220  //! Initializing constructor.
222  actual_request_handle_t request,
223  const schedulers_array_t & schedulers )
224  : m_request{ request }
225  , m_schedulers{ schedulers }
226  {}
227 
228  [[nodiscard]]
230  request_handle() const noexcept override { return m_request; }
231 
232  private:
233  [[nodiscard]]
235  on_next() override
236  {
237  const auto index_to_use = m_current;
238  ++m_current;
239 
240  if( index_to_use >= m_schedulers.size() )
241  {
242  return { no_more_schedulers_t{} };
243  }
244  else
245  {
246  return { m_schedulers[ index_to_use ] };
247  }
248  }
249  };
250 
251  //! The array of schedulers.
252  /*!
253  * @note
254  * It's initialized in the constructor and then never changed.
255  */
257 
258  //! Helper method to initialize the array of schedulers.
259  template<
260  typename Head,
261  typename... Tail >
262  void
263  store_to( std::size_t index, Head && head, Tail && ...tail )
264  {
265  m_schedulers[ index ] =
266  [scheduler = std::move(head)]
268  {
269  return scheduler( std::move(controller) );
270  };
271 
272  if constexpr( 0u != sizeof...(tail) )
273  store_to( index + 1u, std::forward<Tail>(tail)... );
274  }
275 
276 public:
277  /*!
278  * @attention
279  * The default constructor is disabled. It's because a chain should
280  * be initialized by handlers at the creation time. Because of that
281  * fixed_size_chain_t isn't a DefaultConstructible type.
282  */
283  fixed_size_chain_t() = delete;
284 
285  /*!
286  * @brief Initializing constructor.
287  *
288  * @note
289  * The number of parameters should match the value of @a Size
290  * template parameter.
291  */
292  template< typename... Schedulers >
293  fixed_size_chain_t( Schedulers && ...schedulers )
294  {
295  static_assert( Size == sizeof...(schedulers),
296  "Wrong number of parameters for the constructor of "
297  "fixed_size_chain_t<Size>. Exact `Size` parameters expected" );
298 
300  }
301 
302  /*!
303  * Initiates execution of the first scheduler in the chain.
304  *
305  * @note
306  * Always returns request_handling_status_t::accepted.
307  */
308  [[nodiscard]]
311  {
314  req,
315  m_schedulers );
316  next( std::move(controller) );
317 
318  return request_accepted();
319  }
320 };
321 
322 } /* namespace restinio::async_chain */
const actual_request_handle_t m_request
The source request.
Definition: fixed_size.hpp:208
request_handling_status_t operator()(const actual_request_handle_t &req) const
Definition: fixed_size.hpp:310
fixed_size_chain_t(Schedulers &&...schedulers)
Initializing constructor.
Definition: fixed_size.hpp:293
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, std::optional< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in std::optional<Value_Type> if parameter exis...
Definition: value_or.hpp:64
actual_on_next_result_t on_next() override
Command to try find a next scheduler to be invoked.
Definition: fixed_size.hpp:235
A holder of fixed-size chain of asynchronous handlers.
Definition: fixed_size.hpp:179
std::size_t m_current
Index of the current scheduler to be used.
Definition: fixed_size.hpp:217
actual_controller_t(actual_request_handle_t request, const schedulers_array_t &schedulers)
Initializing constructor.
Definition: fixed_size.hpp:221
void store_to(std::size_t index, Head &&head, Tail &&...tail)
Helper method to initialize the array of schedulers.
Definition: fixed_size.hpp:263
const actual_request_handle_t & request_handle() const noexcept override
Get reference to the source request.
Definition: fixed_size.hpp:230
schedulers_array_t m_schedulers
The array of schedulers.
Definition: fixed_size.hpp:256