You're trying to make a composed operation. There's no logical need for the promise1, and whether or not the composed operation would be consumed using a promise should be up to the caller.
You can use async_compose to create the composed operation (as @LucasL's answer shows, albeit un-idiomatically passing it a hardcoded completion token), but I'd prefer a more lightweight approach. Consider the co_composed initiator or asio::deferred:
template <typename Token = asio::deferred_t>
auto asyncConnect(tcp::resolver::results_type eps, Token&& token = {}) {
auto op = asio::async_connect( //
underlyingSocket(), std::move(eps),
asio::deferred([this](error_code ec, tcp::endpoint) {
return asio::deferred
.when(ec.failed() || !isSSL())
.then(asio::deferred.values(ec))
.otherwise(stream().async_handshake(SslStream::client));
}));
return std::move(op)(std::forward<Token>(token));
}
This initiation function can be used with any completion token, so e.g.
w.asyncConnect(eps, [](auto ec) { std::cout << "Connect: " << ec.message() << std::endl; });
Or, indeed in a coro:
co_await w.asyncConnect(eps);
Or, if you wanted a promise:
auto p = w.asyncConnect(eps, asio::experimental::use_promise);
Or, basically anything you wanted.
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/experimental/promise.hpp>
#include <boost/asio/experimental/use_promise.hpp>
#include <boost/asio/ssl.hpp>
#include <iostream>
#include <random>
using error_code = boost::system::error_code;
using namespace std::chrono_literals;
namespace asio = boost::asio;
using asio::ip::tcp;
class SocketWrapper {
private:
using SslStream = asio::ssl::stream<tcp::socket>;
public:
SocketWrapper(asio::any_io_executor ex) : s_{ex, ctx_} {}
template <typename Token = asio::deferred_t>
auto asyncConnect(tcp::resolver::results_type eps, Token&& token = {}) {
auto op = asio::async_connect( //
underlyingSocket(), std::move(eps), asio::deferred([this](error_code ec, tcp::endpoint) {
return asio::deferred
.when(ec.failed() || !isSSL())
.then(asio::deferred.values(ec))
.otherwise(stream().async_handshake(SslStream::client));
}));
return std::move(op)(std::forward<Token>(token));
}
private:
bool isSSL() const { return true; }
tcp::socket const& underlyingSocket() const { return s_.next_layer(); }
tcp::socket& underlyingSocket() { return s_.next_layer(); }
SslStream const& stream() const { return s_; }
SslStream& stream() { return s_; }
asio::ssl::context ctx_{asio::ssl::context::tlsv13};
SslStream s_;
};
int main(int argc, char** argv) {
asio::thread_pool ioc(1);
SocketWrapper w(ioc.get_executor());
auto eps = tcp::resolver{ioc}.resolve("localhost", "8989");
auto select = argc > 1 ? atoi(argv[1]) : std::random_device{}();
switch (select % 4) {
case 0:
std::cout << "Straight callback" << std::endl;
w.asyncConnect(eps, [](error_code ec) { std::cout << "Callback: " << ec.message() << std::endl; });
break;
case 1:
std::cout << "Coro await" << std::endl;
co_spawn(ioc, [&] -> asio::awaitable<void> {
co_await w.asyncConnect(eps);
std::cout << "Coro connected" << std::endl;
co_return;
},
asio::detached);
break;
case 2:
std::cout << "Coro await with promise" << std::endl;
co_spawn(ioc, [&] -> asio::awaitable<void> {
auto p = w.asyncConnect(eps, asio::experimental::use_promise);
std::cout << "Doing some other time consuming stuff as well" << std::endl;
co_await p(asio::deferred);
std::cout << "Coro with promise connected" << std::endl;
co_return;
},
asio::detached);
break;
case 3: {
std::cout << "Custom completion token with adaptors" << std::endl;
auto f = w.asyncConnect(eps, asio::as_tuple(asio::use_future));
if (f.wait_for(20ms) == std::future_status::ready) {
auto [ec] = f.get();
std::cout << "Future resolved within 20ms: " << ec.message() << std::endl;
}
break;
}
};
ioc.join();
}
Printing e.g.:
+ ./build/sotest 0
Straight callback
Callback: Success
+ ./build/sotest 1
Coro await
Coro connected
+ ./build/sotest 2
Coro await with promise
Doing some other time consuming stuff as well
Coro with promise connected
+ ./build/sotest 3
Custom completion token with adaptors
Future resolved within 20ms: Success