dimanche 8 août 2021

note: candidate: 'RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::

I have written a RESTClient using boost::beast. This is a refacotred version of the example given in the boost::beast website.

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>

namespace http = boost::beast::http;
namespace asio = boost::asio;
namespace beast = boost::beast;
using tcp = boost::asio::ip::tcp;
using HttpRequest = http::request<http::string_body>;
using HttpResponse = http::response<http::string_body>;

using ResponseCallback = std::function<void(bool success, const std::string& message)>;

class RestClient : public std::enable_shared_from_this<RestClient>
{
public:
    explicit RestClient(asio::io_context& ioc)
        : m_resolver(ioc)
        , m_socket(ioc)
    {

    }

    void doHttpGet(const ResponseCallback &callback, std::string &host, std::string& port, std::string& target, int version)
    {
        CreateGetRequest(host, target, version);

        std::cout << "calling async_resolve:" << std::endl;
        m_resolver.async_resolve(host, port, [this, callback](beast::error_code ec, const tcp::resolver::results_type& results) {
            this->onResolve(callback, ec, results);
        });
    }

    void CreateGetRequest(std::string &host, std::string &target, int version)
    {
        m_httpRequest.version(version);
        m_httpRequest.method(http::verb::get);
        m_httpRequest.target(target);
        m_httpRequest.set(http::field::host, host);
        m_httpRequest.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
    }

    void
    onResolve(const ResponseCallback& callback, boost::system::error_code ec, const tcp::resolver::results_type& results)
    {
        if(ec) {
            callback(false, ec.message());
        }
        std::cout << "calling async_connect:" << std::endl;
        auto self = shared_from_this();
        asio::async_connect(m_socket, results, [callback, self](boost::system::error_code ec){
            self->onConnect(callback, ec);
        });
    }

    void onConnect(const ResponseCallback& callback, boost::system::error_code ec)
    {
        if(ec) {
            callback(false, ec.message());
            return;
        }
        std::cout << "calling async_write:" << std::endl;
        auto self = shared_from_this();
        http::async_write(m_socket, m_httpRequest, [callback, self](boost::system::error_code ec, std::size_t bytes_transferred){
            self->onWrite(callback, ec, bytes_transferred);
        });
    }

    void
    onWrite(const ResponseCallback& callback, boost::system::error_code ec, std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec) {
            callback(false, ec.message());
            return;
        }
        std::cout << "calling async_read:" << std::endl;
        auto self = shared_from_this();
        http::async_read(m_socket, m_buffer, m_httpResponse, [callback, self](boost::system::error_code ec, std::size_t bytes_transferred){
            self->onRead(callback, ec, bytes_transferred);
        });
    }

    void
    onRead(const ResponseCallback& callback, boost::system::error_code ec, std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec) {
            callback(false, ec.message());
            return;
        }
        std::cout << m_httpResponse << std::endl;

        std::cout << "calling shutdown:" << std::endl;
        m_socket.shutdown(tcp::socket::shutdown_both, ec);

        if(ec && ec != boost::system::errc::not_connected) {
            callback(false, ec.message());
            return;
        }

        if(m_httpResponse.result() != http::status::ok){
            callback(false, std::string(m_httpResponse.reason()));
            return;
        }else
        {
            callback(true, m_httpResponse.body());
        }
    }
private:
    tcp::resolver m_resolver;
    tcp::socket m_socket;
    beast::flat_buffer m_buffer; // (Must persist between reads)
    HttpRequest m_httpRequest;
    HttpResponse m_httpResponse;
};



int main(int argc, char** argv)
{

    bool callbackSuccess = false;
    std::string callbackMessage;
    ResponseCallback responseCb = [&callbackSuccess, &callbackMessage](bool success, const std::string& message) {
        callbackSuccess = success;
        callbackMessage = message;
    };

    // Check command line arguments.
    if(argc != 4 && argc != 5)
    {
        std::cerr <<
                  "Usage: http-client-async <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
                  "Example:\n" <<
                  "    http-client-async www.example.com 80 /\n" <<
                  "    http-client-async www.example.com 80 / 1.0\n";
        return EXIT_FAILURE;
    }
    std::string host = argv[1];
    std::string port = argv[2];
    std::string target = argv[3];
    int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;

    // The io_context is required for all I/O
    asio::io_context ioc;

    // Launch the asynchronous operation
    std::make_shared<RestClient>(ioc)->doHttpGet(responseCb, host, port, target, version);

    // Run the I/O service. The call will return when
    // the get operation is complete.
    ioc.run();

    std::cout << "CallBack Message : " << callbackMessage << std::endl;

    return EXIT_SUCCESS;
}

When I compile the above program, I get the following error.

In file included from /usr/include/boost/asio/impl/execution_context.hpp:18,
                 from /usr/include/boost/asio/execution_context.hpp:408,
                 from /usr/include/boost/asio/detail/scheduler.hpp:21,
                 from /usr/include/boost/asio/system_context.hpp:19,
                 from /usr/include/boost/asio/impl/system_executor.hpp:22,
                 from /usr/include/boost/asio/system_executor.hpp:129,
                 from /usr/include/boost/asio/associated_executor.hpp:21,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:15,
                 from /usr/include/boost/beast/core/bind_handler.hpp:15,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:1:
/usr/include/boost/asio/impl/connect.hpp: In instantiation of 'typename boost::asio::async_result<typename std::decay<WriteHandler>::type, void(boost::system::error_code, typename Protocol::endpoint)>::return_type boost::asio::async_connect(boost::asio::basic_socket<Protocol>&, const EndpointSequence&, RangeConnectHandler&&, typename std::enable_if<boost::asio::is_endpoint_sequence<EndpointSequence>::value>::type*) [with Protocol = boost::asio::ip::tcp; EndpointSequence = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; RangeConnectHandler = RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>; typename boost::asio::async_result<typename std::decay<WriteHandler>::type, void(boost::system::error_code, typename Protocol::endpoint)>::return_type = void; typename Protocol::endpoint = boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>; typename std::decay<WriteHandler>::type = std::decay<RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)> >::type; typename std::enable_if<boost::asio::is_endpoint_sequence<EndpointSequence>::value>::type = void]':
/cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:58:28:   required from here
/usr/include/boost/asio/impl/connect.hpp:707:3: error: static assertion failed: RangeConnectHandler type requirements not met
  707 |   BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/asio/impl/connect.hpp:707:3: note: '(sizeof (boost::asio::detail::two_arg_handler_test<RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)> >(boost::asio::detail::rvref() [with T = RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>](), 0, 0)) == 1)' evaluates to false
/usr/include/boost/asio/impl/connect.hpp:707:3: error: no match for call to '(RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>) (const boost::system::error_code&, const boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>&)'
  707 |   BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:58:48: note: candidate: 'RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>'
   58 |         asio::async_connect(m_socket, results, [callback, self](boost::system::error_code ec){
      |                                                ^
/cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:58:48: note:   candidate expects 1 argument, 2 provided
In file included from /usr/include/boost/asio/detail/handler_type_requirements.hpp:53,
                 from /usr/include/boost/asio/impl/execution_context.hpp:18,
                 from /usr/include/boost/asio/execution_context.hpp:408,
                 from /usr/include/boost/asio/detail/scheduler.hpp:21,
                 from /usr/include/boost/asio/system_context.hpp:19,
                 from /usr/include/boost/asio/impl/system_executor.hpp:22,
                 from /usr/include/boost/asio/system_executor.hpp:129,
                 from /usr/include/boost/asio/associated_executor.hpp:21,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:15,
                 from /usr/include/boost/beast/core/bind_handler.hpp:15,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:1:
/usr/include/boost/asio/async_result.hpp:156:12: error: 'boost::asio::async_completion<CompletionToken, Signature>::async_completion(CompletionToken&) [with CompletionToken = RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>; Signature = void(boost::system::error_code, boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>)]', declared using local type 'RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>', is used but never defined [-fpermissive]
  156 |   explicit async_completion(CompletionToken& token)
      |            ^~~~~~~~~~~~~~~~
In file included from /usr/include/boost/asio/connect.hpp:1059,
                 from /cygdrive/c/Users/karthik/Documents/Workspace/cpluspluspen/boostbeast/RESTClient/RestClient.cpp:4:
/usr/include/boost/asio/impl/connect.hpp:304:5: error: 'boost::asio::detail::range_connect_op<Protocol, EndpointSequence, ConnectCondition, RangeConnectHandler>::range_connect_op(boost::asio::basic_socket<Protocol>&, const EndpointSequence&, const ConnectCondition&, RangeConnectHandler&) [with Protocol = boost::asio::ip::tcp; EndpointSequence = boost::asio::ip::basic_resolver_results<boost::asio::ip::tcp>; ConnectCondition = boost::asio::detail::default_connect_condition; RangeConnectHandler = RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>]', declared using local type 'RestClient::onResolve(const ResponseCallback&, boost::system::error_code, const results_type&)::<lambda(boost::system::error_code)>', is used but never defined [-fpermissive]
  304 |     range_connect_op(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& sock,
      |     ^~~~~~~~~~~~~~~~
make[3]: *** [boostbeast/RESTClient/CMakeFiles/rest_client.dir/build.make:82: boostbeast/RESTClient/CMakeFiles/rest_client.dir/RestClient.cpp.o] Error 1
make[2]: *** [CMakeFiles/Makefile2:2766: boostbeast/RESTClient/CMakeFiles/rest_client.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:2773: boostbeast/RESTClient/CMakeFiles/rest_client.dir/rule] Error 2
make: *** [Makefile:1000: rest_client] Error 2

I can't understand what exactly is wrong with the error message. Can someone please explain. I am using cygwin on Windows 10 and CLion.

Aucun commentaire:

Enregistrer un commentaire