| 56 | } // namespace |
| 57 | |
| 58 | AsioTransport::AsioTransport(const std::string& host, |
| 59 | const unsigned short port, |
| 60 | std::chrono::milliseconds timeout) |
| 61 | : owned_ctx_{std::make_unique<asio::io_context>()}, ctx_{owned_ctx_.get()}, |
| 62 | socket_{*ctx_}, timeout_{timeout} { |
| 63 | // NOTE: connect failure here must NOT throw -- it must leave the socket |
| 64 | // closed and disconnected_ set, matching the old Qt-based TcpTransport, |
| 65 | // which never checked its wait-for-connected result and let the app |
| 66 | // self-quit on the first loop() tick via should_quit_on_disconnect. |
| 67 | // Throwing here would escape MainWindow's ctor and crash the process |
| 68 | // instead. |
| 69 | asio::ip::tcp::resolver resolver{*ctx_}; |
| 70 | asio::error_code ec; |
| 71 | const auto endpoints = resolver.resolve(host, std::to_string(port), ec); |
| 72 | if (ec) { |
| 73 | disconnected_ = true; |
| 74 | return; |
| 75 | } |
| 76 | |
| 77 | bool done = false; |
| 78 | asio::error_code op_ec; |
| 79 | asio::async_connect(socket_, |
| 80 | endpoints, |
| 81 | [&op_ec, &done](const asio::error_code& e, |
| 82 | const asio::ip::tcp::endpoint&) { |
| 83 | op_ec = e; |
| 84 | done = true; |
| 85 | }); |
| 86 | if (run_until(*ctx_, socket_, done, timeout_) || op_ec) { |
| 87 | disconnected_ = true; |
| 88 | asio::error_code close_ec; |
| 89 | socket_.close(close_ec); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | AsioTransport::AsioTransport(asio::io_context& ctx, |
| 94 | asio::ip::tcp::socket&& sock, |
nothing calls this directly
no test coverage detected