RESTinio
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.
27  ok,
28  //! The scheduling of the actual processing failed. Note, that
29  //! there is no additional information about the failure.
30  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]]
48 inline constexpr schedule_result_t
49 ok() 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]]
71 inline constexpr schedule_result_t
72 failure() noexcept { return schedule_result_t::failure; }
73 
74 // Just a forward declaration.
75 template< typename Extra_Data_Factory = no_extra_data_factory_t >
76 class async_handling_controller_t;
77 
78 /*!
79  * @brief Short alias for unique_ptr to async_handling_controller.
80  *
81  * @since v.0.7.0
82  */
83 template< typename Extra_Data_Factory = no_extra_data_factory_t >
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  */
92 template< typename Extra_Data_Factory = no_extra_data_factory_t >
94  std::function<
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  */
118 template< typename Extra_Data_Factory = no_extra_data_factory_t >
119 using on_next_result_t = std::variant<
122  >;
123 
124 // Just a forward declaration.
125 template< typename Extra_Data_Factory >
126 void
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  */
144 template< typename Extra_Data_Factory /*= no_extra_data_factory_t*/ >
145 class async_handling_controller_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 
152 public:
153  //! Short alias for request_handle type.
154  using actual_request_handle_t =
155  generic_request_handle_t< typename Extra_Data_Factory::data_t >;
156 
157  //! Short alias for async_request_scheduler type.
158  using actual_async_request_scheduler_t =
159  generic_async_request_scheduler_t< typename Extra_Data_Factory::data_t >;
160 
161  //! Short alias for the result type of %on_next method.
162  using actual_on_next_result_t =
163  on_next_result_t< Extra_Data_Factory >;
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 
189 private:
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 
205 namespace 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  */
218 template< typename Request_Handle >
219 void
220 make_not_implemented_response( const Request_Handle & req )
221 {
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  */
235 template< typename Request_Handle >
236 void
237 make_internal_server_error_response( const Request_Handle & req )
238 {
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  */
253 template< 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  {
268  case schedule_result_t::ok:
269  /* nothing to do */
270  // It's assumed that handler will call next() when it'll be
271  // appropriate.
272  break;
273 
276  break;
277  }
278  }
279 
280  void
282  const no_more_schedulers_t & ) const
283  {
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  */
325 template< typename Extra_Data_Factory >
326 void
328 {
329  std::visit(
331  controller->on_next() );
332 }
333 
334 } /* namespace restinio::async_chain */
Helper type to be used as handler of variant values in std::visit.
Definition: common.hpp:254
virtual const actual_request_handle_t & request_handle() const noexcept=0
Get reference to the source request.
void operator()(const generic_async_request_scheduler_t< Extra_Data_Factory > &handler) const
Definition: common.hpp:259
constexpr schedule_result_t ok() noexcept
Helper function to be used if scheduling was successful.
Definition: common.hpp:49
void operator()(const no_more_schedulers_t &) const
Definition: common.hpp:281
The scheduling of the actual processing was successful.
constexpr schedule_result_t failure() noexcept
Helper function to be used if scheduling failed.
Definition: common.hpp:72
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
Special type to be used as an indicator that there are no more schedulers in an async chain...
Definition: common.hpp:106
The scheduling of the actual processing failed. Note, that there is no additional information about t...
void make_not_implemented_response(const Request_Handle &req)
Helper to make a negative response with "Not Implemented" status.
Definition: common.hpp:220
schedule_result_t
Type for return value of a scheduler in a chain.
Definition: common.hpp:24
friend void next(unique_async_handling_controller_t< Extra_Data_Factory_For_Next > controller)
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
virtual actual_on_next_result_t on_next()=0
Command to try find a next scheduler to be invoked.
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
unique_async_handling_controller_t< Extra_Data_Factory > & m_controller
Definition: common.hpp:256