RESTinio
Loading...
Searching...
No Matches
common.hpp
Go to the documentation of this file.
1/*!
2 * @file
3 * @brief Common stuff for different types of async handlers chains.
4 * @since v.0.7.0
5 */
6
7#pragma once
8
9#include <restinio/request_handler.hpp>
10
12{
13
14/*!
15 * @brief Type for return value of a scheduler in a chain.
16 *
17 * A scheduler should schedule the actual processing of a request and should
18 * tell whether this scheduling was successful or not. If it was successful,
19 * schedule_result_t::ok must be returned, otherwise the
20 * schedule_result_t::failure must be returned.
21 *
22 * @since v.0.7.0
23 */
25{
26 //! The scheduling of the actual processing was successful.
28 //! The scheduling of the actual processing failed. Note, that
29 //! there is no additional information about the failure.
31};
32
33/*!
34 * @brief Helper function to be used if scheduling was successful.
35 *
36 * Usage example:
37 * @code
38 * restinio::async_chain::growable_size_chain_t<>::builder_t builder;
39 * builder.add([this](auto controller) {
40 * ... // Actual scheduling.
41 * return restinio::async_chain::ok();
42 * });
43 * @endcode
44 *
45 * @since v.0.7.0
46 */
47[[nodiscard]]
48inline constexpr schedule_result_t
49ok() noexcept { return schedule_result_t::ok; }
50
51/*!
52 * @brief Helper function to be used if scheduling failed.
53 *
54 * Usage example:
55 * @code
56 * restinio::async_chain::growable_size_chain_t<>::builder_t builder;
57 * builder.add([this](auto controller) {
58 * try {
59 * ... // Actual scheduling.
60 * return restinio::async_chain::ok(); // OK, no problems.
61 * }
62 * catch( ... ) {
63 * return restinio::async_chain::failure();
64 * }
65 * });
66 * @endcode
67 *
68 * @since v.0.7.0
69 */
70[[nodiscard]]
71inline constexpr schedule_result_t
72failure() noexcept { return schedule_result_t::failure; }
73
74// Just a forward declaration.
75template< typename Extra_Data_Factory = no_extra_data_factory_t >
77
78/*!
79 * @brief Short alias for unique_ptr to async_handling_controller.
80 *
81 * @since v.0.7.0
82 */
86
87/*!
88 * @brief Short alias for a type of a scheduler to be used in async chains.
89 *
90 * @since v.0.7.0
91 */
96 >;
97
98/*!
99 * @brief Special type to be used as an indicator that there are no more
100 * schedulers in an async chain.
101 *
102 * This type will be used in on_next_result_t variant.
103 *
104 * @since v.0.7.0
105 */
107
108/*!
109 * @brief Special type to be used as result of async_handling_controller's
110 * on_next method.
111 *
112 * The async_handling_controller_t::on_next may return an actual scheduler to
113 * be called or (if there are no more handlers left) a special no_more_handler
114 * value. This is described by on_next_result_t variant type.
115 *
116 * @since v.0.7.0
117 */
118template< typename Extra_Data_Factory = no_extra_data_factory_t >
122 >;
123
124// Just a forward declaration.
125template< typename Extra_Data_Factory >
126void
127next( unique_async_handling_controller_t< Extra_Data_Factory > controller );
128
129/*!
130 * @brief Interface of a controller of an async chan.
131 *
132 * All actual controllers have to implement this interface.
133 *
134 * It's assumed that implementation of that interface won't be thread
135 * safe. It means that methods like request_handle() and on_next() must
136 * not be called in parallel.
137 *
138 * @tparam Extra_Data_Factory Type of factory for creation of extra data
139 * objects for every incoming request. Should be no_extra_data_factory_t
140 * if extra data for incoming requests is not needed.
141 *
142 * @since v.0.7.0
143 */
144template< typename Extra_Data_Factory /*= no_extra_data_factory_t*/ >
146{
147 // The next() function should call on_next() method.
148 template< typename Extra_Data_Factory_For_Next >
149 friend void
150 next( unique_async_handling_controller_t< Extra_Data_Factory_For_Next > controller );
151
152public:
153 //! Short alias for request_handle type.
156
157 //! Short alias for async_request_scheduler type.
160
161 //! Short alias for the result type of %on_next method.
164
165 virtual ~async_handling_controller_t() = default;
166
167 /*!
168 * @brief Get reference to the source request.
169 *
170 * Usage example:
171 * @code
172 * restinio::async_chain::schedule_result_t my_handler(
173 * restinio::async_chain::unique_async_handling_controller_t<> controller )
174 * {
175 * // Get access to the source request.
176 * const auto req = controller->request_handle();
177 * if( restinio::http_method_get() == req->header().method() )
178 * {
179 * ...
180 * }
181 * return restinio::async_chain::ok();
182 * }
183 * @endcode
184 */
185 [[nodiscard]]
186 virtual const actual_request_handle_t &
187 request_handle() const noexcept = 0;
188
189private:
190 /*!
191 * @brief Command to try find a next scheduler to be invoked.
192 *
193 * Implementation of async_handling_controller_t should switch to the
194 * next scheduler in the chain and return the scheduler to be called next.
195 * If there are no such schedulers, no_more_schedulers_t must be returned.
196 *
197 * @note
198 * This method is intended to be called by next() function.
199 */
200 [[nodiscard]]
202 on_next() = 0;
203};
204
205namespace impl
206{
207
208/*!
209 * @brief Helper to make a negative response with "Not Implemented" status.
210 *
211 * This helper will be used if there is no more schedulers to call, but
212 * the request is still not handled.
213 *
214 * @tparam Request_Handle Type of request handle that holds the source request.
215 *
216 * @since v.0.7.0
217 */
218template< typename Request_Handle >
219void
220make_not_implemented_response( const Request_Handle & req )
221{
222 req->create_response( status_not_found() ).done();
223}
224
225/*!
226 * @brief Helper to make a negative response with "Internal Server Error" status.
227 *
228 * This helper will be used if the current scheduler returns
229 * schedule_result_t::failure.
230 *
231 * @tparam Request_Handle Type of request handle that holds the source request.
232 *
233 * @since v.0.7.0
234 */
235template< typename Request_Handle >
236void
237make_internal_server_error_response( const Request_Handle & req )
238{
239 req->create_response( status_internal_server_error() ).done();
240}
241
242/*!
243 * @brief Helper type to be used as handler of variant values in std::visit.
244 *
245 * If there is the next async scheduler to be called it will be called.
246 * If it returns schedule_result_t::failure, then negative response will
247 * be generated and processing will be stopped.
248 *
249 * If no_more_schedulers_t is here, then negative response will be generated.
250 *
251 * @since v.0.7.0
252 */
253template< typename Extra_Data_Factory >
255{
257
258 void
260 const generic_async_request_scheduler_t< Extra_Data_Factory > & handler ) const
261 {
262 // We have to store request_handle before further processing because
263 // m_controller becomes empty after passing to the `handler`.
264 const auto req = m_controller->request_handle();
265 const auto schedule_result = handler( std::move(m_controller) );
266 switch( schedule_result )
267 {
269 /* nothing to do */
270 // It's assumed that handler will call next() when it'll be
271 // appropriate.
272 break;
273
275 make_internal_server_error_response( req );
276 break;
277 }
278 }
279
280 void
282 const no_more_schedulers_t & ) const
283 {
284 make_not_implemented_response( m_controller->request_handle() );
285 }
286};
287
288} /* namespace impl */
289
290/*!
291 * @brief Command to try to switch to the next handler in an async chain.
292 *
293 * If an intermediate handler in an async chain doesn't complete processing
294 * of the request it should call next() function to activate the next
295 * handler in the chain.
296 *
297 * If there are no more handlers in the chain the processing of the request
298 * will be finished just inside the next() call by generating negative
299 * response.
300 *
301 * @note
302 * The handler must not call next() if it generates the response for the
303 * request:
304 * @code
305 * void actual_processor(restinio::async_chain::unique_async_handling_controller_t<> controller) {
306 * const auto req = controller->request_handle();
307 * if(request_can_be_handled(req)) {
308 * processing_of_the_request(req);
309 * req->create_response(...)
310 * ...
311 * .done(); // Request processing completed.
312 * }
313 * else {
314 * // This handler can't complete processing of the request.
315 * // Have to switch to the next handler.
316 * next(std::move(controller));
317 * }
318 *
319 * // NOTE: it's not safe to use `controller` here!
320 * }
321 * @endcode
322 *
323 * @since v.0.7.0
324 */
325template< typename Extra_Data_Factory >
326void
327next( unique_async_handling_controller_t< Extra_Data_Factory > controller )
328{
329 std::visit(
330 impl::on_next_result_visitor_t< Extra_Data_Factory >{ controller },
331 controller->on_next() );
332}
333
334} /* namespace restinio::async_chain */
Interface of a controller of an async chan.
Definition common.hpp:146
virtual actual_on_next_result_t on_next()=0
Command to try find a next scheduler to be invoked.
virtual const actual_request_handle_t & request_handle() const noexcept=0
Get reference to the source request.
void make_internal_server_error_response(const Request_Handle &req)
Helper to make a negative response with "Internal Server Error" status.
Definition common.hpp:237
void make_not_implemented_response(const Request_Handle &req)
Helper to make a negative response with "Not Implemented" status.
Definition common.hpp:220
constexpr schedule_result_t ok() noexcept
Helper function to be used if scheduling was successful.
Definition common.hpp:49
void next(unique_async_handling_controller_t< Extra_Data_Factory > controller)
Command to try to switch to the next handler in an async chain.
Definition common.hpp:327
constexpr schedule_result_t failure() noexcept
Helper function to be used if scheduling failed.
Definition common.hpp:72
schedule_result_t
Type for return value of a scheduler in a chain.
Definition common.hpp:25
@ failure
The scheduling of the actual processing failed. Note, that there is no additional information about t...
Definition common.hpp:30
@ ok
The scheduling of the actual processing was successful.
Definition common.hpp:27
http_status_line_t status_internal_server_error()
http_status_line_t status_not_found()
Helper type to be used as handler of variant values in std::visit.
Definition common.hpp:255
void operator()(const no_more_schedulers_t &) const
Definition common.hpp:281
void operator()(const generic_async_request_scheduler_t< Extra_Data_Factory > &handler) const
Definition common.hpp:259
unique_async_handling_controller_t< Extra_Data_Factory > & m_controller
Definition common.hpp:256
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.