Loading...
Searching...
No Matches
resp3_handshaker.hpp
1/* Copyright (c) 2018-2024 Marcelo Zimbres Silva (mzimbres@gmail.com)
2 *
3 * Distributed under the Boost Software License, Version 1.0. (See
4 * accompanying file LICENSE.txt)
5 */
6
7#ifndef BOOST_REDIS_RUNNER_HPP
8#define BOOST_REDIS_RUNNER_HPP
9
10#include <boost/redis/config.hpp>
11#include <boost/redis/detail/connection_logger.hpp>
12#include <boost/redis/error.hpp>
13#include <boost/redis/operation.hpp>
14#include <boost/redis/request.hpp>
15#include <boost/redis/response.hpp>
16
17#include <boost/asio/compose.hpp>
18#include <boost/asio/coroutine.hpp>
19
20#include <string>
21
22namespace boost::redis::detail {
23
24void push_hello(config const& cfg, request& req);
25
26// TODO: Can we avoid this whole function whose only purpose is to
27// check for an error in the hello response and complete with an error
28// so that the parallel group that starts it can exit?
29template <class Handshaker, class Connection>
30struct hello_op {
31 Handshaker* handshaker_ = nullptr;
32 Connection* conn_ = nullptr;
33 asio::coroutine coro_{};
34
35 template <class Self>
36 void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
37 {
38 BOOST_ASIO_CORO_REENTER(coro_)
39 {
40 handshaker_->add_hello();
41
42 BOOST_ASIO_CORO_YIELD
43 conn_->async_exec(
44 handshaker_->hello_req_,
45 any_adapter(handshaker_->hello_resp_),
46 std::move(self));
47 conn_->logger_.on_hello(ec, handshaker_->hello_resp_);
48
49 if (ec) {
50 conn_->cancel(operation::run);
51 self.complete(ec);
52 return;
53 }
54
55 if (handshaker_->has_error_in_response()) {
56 conn_->cancel(operation::run);
57 self.complete(error::resp3_hello);
58 return;
59 }
60
61 self.complete({});
62 }
63 }
64};
65
66template <class Executor>
67class resp3_handshaker {
68public:
69 void set_config(config const& cfg) { cfg_ = cfg; }
70
71 template <class Connection, class CompletionToken>
72 auto async_hello(Connection& conn, CompletionToken token)
73 {
74 return asio::async_compose<CompletionToken, void(system::error_code)>(
75 hello_op<resp3_handshaker, Connection>{this, &conn},
76 token,
77 conn);
78 }
79
80private:
81 template <class, class> friend struct hello_op;
82
83 void add_hello()
84 {
85 hello_req_.clear();
86 if (hello_resp_.has_value())
87 hello_resp_.value().clear();
88 push_hello(cfg_, hello_req_);
89 }
90
91 bool has_error_in_response() const noexcept
92 {
93 if (!hello_resp_.has_value())
94 return true;
95
96 auto f = [](auto const& e) {
97 switch (e.data_type) {
99 case resp3::type::blob_error: return true;
100 default: return false;
101 }
102 };
103
104 return std::any_of(std::cbegin(hello_resp_.value()), std::cend(hello_resp_.value()), f);
105 }
106
107 request hello_req_;
108 generic_response hello_resp_;
109 config cfg_;
110};
111
112} // namespace boost::redis::detail
113
114#endif // BOOST_REDIS_RUNNER_HPP
void clear()
Clears the request preserving allocated memory.
Definition request.hpp:104
adapter::result< std::vector< resp3::node > > generic_response
A generic response to a request.
Definition response.hpp:35
@ resp3_hello
Resp3 hello command error.
@ run
Refers to connection::async_run operations.