boost_redis 1.4.2
A redis client library
resolver.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_RESOLVER_HPP
8#define BOOST_REDIS_RESOLVER_HPP
9
10#include <boost/redis/config.hpp>
11#include <boost/redis/detail/helper.hpp>
12#include <boost/redis/error.hpp>
13#include <boost/asio/compose.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 Resolver>
25struct resolve_op {
26 Resolver* resv_ = nullptr;
27 asio::coroutine coro{};
28
29 template <class Self>
30 void operator()( Self& self
31 , std::array<std::size_t, 2> order = {}
32 , system::error_code ec1 = {}
33 , asio::ip::tcp::resolver::results_type res = {}
34 , system::error_code ec2 = {})
35 {
36 BOOST_ASIO_CORO_REENTER (coro)
37 {
38 resv_->timer_.expires_after(resv_->timeout_);
39
40 BOOST_ASIO_CORO_YIELD
41 asio::experimental::make_parallel_group(
42 [this](auto token)
43 {
44 return resv_->resv_.async_resolve(resv_->addr_.host, resv_->addr_.port, token);
45 },
46 [this](auto token) { return resv_->timer_.async_wait(token);}
47 ).async_wait(
48 asio::experimental::wait_for_one(),
49 std::move(self));
50
51 if (is_cancelled(self)) {
52 self.complete(asio::error::operation_aborted);
53 return;
54 }
55
56 switch (order[0]) {
57 case 0: {
58 // Resolver completed first.
59 resv_->results_ = res;
60 self.complete(ec1);
61 } break;
62
63 case 1: {
64 if (ec2) {
65 // Timer completed first with error, perhaps a
66 // cancellation going on.
67 self.complete(ec2);
68 } else {
69 // Timer completed first without an error, this is a
70 // resolve timeout.
71 self.complete(error::resolve_timeout);
72 }
73 } break;
74
75 default: BOOST_ASSERT(false);
76 }
77 }
78 }
79};
80
81template <class Executor>
82class resolver {
83public:
84 using timer_type =
85 asio::basic_waitable_timer<
86 std::chrono::steady_clock,
87 asio::wait_traits<std::chrono::steady_clock>,
88 Executor>;
89
90 resolver(Executor ex) : resv_{ex} , timer_{ex} {}
91
92 template <class CompletionToken>
93 auto async_resolve(CompletionToken&& token)
94 {
95 return asio::async_compose
96 < CompletionToken
97 , void(system::error_code)
98 >(resolve_op<resolver>{this}, token, resv_);
99 }
100
101 std::size_t cancel(operation op)
102 {
103 switch (op) {
105 case operation::all:
106 resv_.cancel();
107 timer_.cancel();
108 break;
109 default: /* ignore */;
110 }
111
112 return 0;
113 }
114
115 auto const& results() const noexcept
116 { return results_;}
117
118 void set_config(config const& cfg)
119 {
120 addr_ = cfg.addr;
121 timeout_ = cfg.resolve_timeout;
122 }
123
124private:
125 using resolver_type = asio::ip::basic_resolver<asio::ip::tcp, Executor>;
126 template <class> friend struct resolve_op;
127
128 resolver_type resv_;
129 timer_type timer_;
130 address addr_;
131 std::chrono::steady_clock::duration timeout_;
132 asio::ip::tcp::resolver::results_type results_;
133};
134
135} // boost::redis::detail
136
137#endif // BOOST_REDIS_RESOLVER_HPP
operation
Connection operations that can be cancelled.
Definition: operation.hpp:18
@ resolve_timeout
Resolve timeout.
@ resolve
Resolve operation.
@ all
Refers to all operations.