/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com) * * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE.txt) */ #ifndef BOOST_REDIS_CONNECTOR_HPP #define BOOST_REDIS_CONNECTOR_HPP #include #include #include #include #include #include #include #include #include #include namespace boost::redis::detail { template struct connect_op { Connector* ctor_ = nullptr; Stream* stream = nullptr; asio::ip::tcp::resolver::results_type const* res_ = nullptr; asio::coroutine coro{}; template void operator()( Self& self , std::array const& order = {} , system::error_code const& ec1 = {} , asio::ip::tcp::endpoint const& ep= {} , system::error_code const& ec2 = {}) { BOOST_ASIO_CORO_REENTER (coro) { ctor_->timer_.expires_after(ctor_->timeout_); BOOST_ASIO_CORO_YIELD asio::experimental::make_parallel_group( [this](auto token) { auto f = [](system::error_code const&, auto const&) { return true; }; return asio::async_connect(*stream, *res_, f, token); }, [this](auto token) { return ctor_->timer_.async_wait(token);} ).async_wait( asio::experimental::wait_for_one(), std::move(self)); if (is_cancelled(self)) { self.complete(asio::error::operation_aborted); return; } switch (order[0]) { case 0: { ctor_->endpoint_ = ep; self.complete(ec1); } break; case 1: { if (ec2) { self.complete(ec2); } else { self.complete(error::connect_timeout); } } break; default: BOOST_ASSERT(false); } } } }; template class connector { public: using timer_type = asio::basic_waitable_timer< std::chrono::steady_clock, asio::wait_traits, Executor>; connector(Executor ex) : timer_{ex} {} void set_config(config const& cfg) { timeout_ = cfg.connect_timeout; } template auto async_connect( Stream& stream, asio::ip::tcp::resolver::results_type const& res, CompletionToken&& token) { return asio::async_compose < CompletionToken , void(system::error_code) >(connect_op{this, &stream, &res}, token, timer_); } std::size_t cancel(operation op) { switch (op) { case operation::connect: case operation::all: timer_.cancel(); break; default: /* ignore */; } return 0; } auto const& endpoint() const noexcept { return endpoint_;} private: template friend struct connect_op; timer_type timer_; std::chrono::steady_clock::duration timeout_ = std::chrono::seconds{2}; asio::ip::tcp::endpoint endpoint_; }; } // boost::redis::detail #endif // BOOST_REDIS_CONNECTOR_HPP