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/request.hpp>
12#include <boost/redis/response.hpp>
13#include <boost/redis/error.hpp>
14#include <boost/redis/logger.hpp>
15#include <boost/redis/operation.hpp>
16#include <boost/asio/compose.hpp>
17#include <boost/asio/coroutine.hpp>
18//#include <boost/asio/ip/tcp.hpp>
19#include <string>
20#include <memory>
21#include <chrono>
22
23namespace boost::redis::detail
24{
25
26void push_hello(config const& cfg, request& req);
27
28// TODO: Can we avoid this whole function whose only purpose is to
29// check for an error in the hello response and complete with an error
30// so that the parallel group that starts it can exit?
31template <class Handshaker, class Connection, class Logger>
32struct hello_op {
33 Handshaker* handshaker_ = nullptr;
34 Connection* conn_ = nullptr;
35 Logger logger_;
36 asio::coroutine coro_{};
37
38 template <class Self>
39 void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
40 {
41 BOOST_ASIO_CORO_REENTER (coro_)
42 {
43 handshaker_->add_hello();
44
45 BOOST_ASIO_CORO_YIELD
46 conn_->async_exec(handshaker_->hello_req_, any_adapter(handshaker_->hello_resp_), std::move(self));
47 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)
70 { cfg_ = cfg; }
71
72 template <class Connection, class Logger, class CompletionToken>
73 auto async_hello(Connection& conn, Logger l, CompletionToken token)
74 {
75 return asio::async_compose
76 < CompletionToken
77 , void(system::error_code)
78 >(hello_op<resp3_handshaker, Connection, Logger>{this, &conn, l}, token, conn);
79 }
80
81private:
82 template <class, class, class> friend struct hello_op;
83
84 void add_hello()
85 {
86 hello_req_.clear();
87 if (hello_resp_.has_value())
88 hello_resp_.value().clear();
89 push_hello(cfg_, hello_req_);
90 }
91
92 bool has_error_in_response() const noexcept
93 {
94 if (!hello_resp_.has_value())
95 return true;
96
97 auto f = [](auto const& e)
98 {
99 switch (e.data_type) {
101 case resp3::type::blob_error: return true;
102 default: return false;
103 }
104 };
105
106 return std::any_of(std::cbegin(hello_resp_.value()), std::cend(hello_resp_.value()), f);
107 }
108
109 request hello_req_;
110 generic_response hello_resp_;
111 config cfg_;
112};
113
114} // boost::redis::detail
115
116#endif // BOOST_REDIS_RUNNER_HPP
void clear()
Clears the request preserving allocated memory.
Definition request.hpp:102
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.