RESTinio
Loading...
Searching...
No Matches
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
13namespace 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 */
176template<
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.
192 typename async_handling_controller_t< Extra_Data_Factory >::actual_request_handle_t;
193
194 //! Short alias for the result of controller's on_next method.
196 typename async_handling_controller_t< Extra_Data_Factory >::actual_on_next_result_t;
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 */
217 std::size_t m_current{};
218
219 public:
220 //! Initializing constructor.
223 const schedulers_array_t & schedulers )
224 : m_request{ request }
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)]
267 ( unique_controller_t controller ) -> schedule_result_t
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
276public:
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 */
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
299 store_to( 0u, std::forward<Schedulers>(schedulers)... );
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]]
310 operator()( const actual_request_handle_t & req ) const
311 {
312 unique_controller_t controller =
313 std::make_unique< actual_controller_t >(
314 req,
315 m_schedulers );
316 next( std::move(controller) );
317
318 return request_accepted();
319 }
320};
321
322} /* namespace restinio::async_chain */
Interface of a controller of an async chan.
Definition common.hpp:146
std::size_t m_current
Index of the current scheduler to be used.
const actual_request_handle_t & request_handle() const noexcept override
Get reference to the source request.
actual_controller_t(actual_request_handle_t request, const schedulers_array_t &schedulers)
Initializing constructor.
const actual_request_handle_t m_request
The source request.
actual_on_next_result_t on_next() override
Command to try find a next scheduler to be invoked.
A holder of fixed-size chain of asynchronous handlers.
schedulers_array_t m_schedulers
The array of schedulers.
fixed_size_chain_t(Schedulers &&...schedulers)
Initializing constructor.
request_handling_status_t operator()(const actual_request_handle_t &req) const
typename async_handling_controller_t< Extra_Data_Factory >::actual_on_next_result_t actual_on_next_result_t
Short alias for the result of controller's on_next method.
typename async_handling_controller_t< Extra_Data_Factory >::actual_request_handle_t actual_request_handle_t
Short alias to a smart pointer to the source request.
void store_to(std::size_t index, Head &&head, Tail &&...tail)
Helper method to initialize the array of schedulers.
constexpr request_handling_status_t request_accepted() noexcept
request_handling_status_t
Request handling status.
Special type to be used as an indicator that there are no more schedulers in an async chain.
Definition common.hpp:106
The default extra-data-factory to be used in server's traits if a user doesn't specify own one.