boost_redis 1.4.2
A redis client library
connector.hpp
1/* Copyright (c) 2018-2022 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_CONNECTOR_HPP
8#define BOOST_REDIS_CONNECTOR_HPP
9
10#include <boost/redis/detail/helper.hpp>
11#include <boost/redis/error.hpp>
12#include <boost/asio/compose.hpp>
13#include <boost/asio/connect.hpp>
14#include <boost/asio/coroutine.hpp>
15#include <boost/asio/experimental/parallel_group.hpp>
16#include <boost/asio/ip/tcp.hpp>
17#include <boost/asio/steady_timer.hpp>
18#include <string>
19#include <chrono>
20
21namespace boost::redis::detail
22{
23
24template <class Connector, class Stream>
25struct connect_op {
26 Connector* ctor_ = nullptr;
27 Stream* stream = nullptr;
28 asio::ip::tcp::resolver::results_type const* res_ = nullptr;
29 asio::coroutine coro{};
30
31 template <class Self>
32 void operator()( Self& self
33 , std::array<std::size_t, 2> const& order = {}
34 , system::error_code const& ec1 = {}
35 , asio::ip::tcp::endpoint const& ep= {}
36 , system::error_code const& ec2 = {})
37 {
38 BOOST_ASIO_CORO_REENTER (coro)
39 {
40 ctor_->timer_.expires_after(ctor_->timeout_);
41
42 BOOST_ASIO_CORO_YIELD
43 asio::experimental::make_parallel_group(
44 [this](auto token)
45 {
46 auto f = [](system::error_code const&, auto const&) { return true; };
47 return asio::async_connect(*stream, *res_, f, token);
48 },
49 [this](auto token) { return ctor_->timer_.async_wait(token);}
50 ).async_wait(
51 asio::experimental::wait_for_one(),
52 std::move(self));
53
54 if (is_cancelled(self)) {
55 self.complete(asio::error::operation_aborted);
56 return;
57 }
58
59 switch (order[0]) {
60 case 0: {
61 ctor_->endpoint_ = ep;
62 self.complete(ec1);
63 } break;
64 case 1:
65 {
66 if (ec2) {
67 self.complete(ec2);
68 } else {
69 self.complete(error::connect_timeout);
70 }
71 } break;
72
73 default: BOOST_ASSERT(false);
74 }
75 }
76 }
77};
78
79template <class Executor>
80class connector {
81public:
82 using timer_type =
83 asio::basic_waitable_timer<
84 std::chrono::steady_clock,
85 asio::wait_traits<std::chrono::steady_clock>,
86 Executor>;
87
88 connector(Executor ex)
89 : timer_{ex}
90 {}
91
92 void set_config(config const& cfg)
93 { timeout_ = cfg.connect_timeout; }
94
95 template <class Stream, class CompletionToken>
96 auto
97 async_connect(
98 Stream& stream,
99 asio::ip::tcp::resolver::results_type const& res,
100 CompletionToken&& token)
101 {
102 return asio::async_compose
103 < CompletionToken
104 , void(system::error_code)
105 >(connect_op<connector, Stream>{this, &stream, &res}, token, timer_);
106 }
107
108 std::size_t cancel(operation op)
109 {
110 switch (op) {
112 case operation::all:
113 timer_.cancel();
114 break;
115 default: /* ignore */;
116 }
117
118 return 0;
119 }
120
121 auto const& endpoint() const noexcept { return endpoint_;}
122
123private:
124 template <class, class> friend struct connect_op;
125
126 timer_type timer_;
127 std::chrono::steady_clock::duration timeout_ = std::chrono::seconds{2};
128 asio::ip::tcp::endpoint endpoint_;
129};
130
131} // boost::redis::detail
132
133#endif // BOOST_REDIS_CONNECTOR_HPP
operation
Connection operations that can be cancelled.
Definition: operation.hpp:18
@ connect_timeout
Connect timeout.
@ all
Refers to all operations.
@ connect
Connect operation.