从异步函数获取信号

时间:2018-09-26 12:12:22

标签: c++ qt boost boost-asio

我有一个进入异步功能的信号。 我需要将此添加到另一个与ui(QML)交互的函数中 ui必须随此信号而改变。

UI端: 我使用rootContext()实例化我的c ++类

engine.rootContext()->setContextProperty("http", &request);

进入qml组件,我使用一个简单的事件:

onClicked:{
        http.start_request("mydomain", "443", "/login", 11, "POST", "username=" + login.text + "&password=" + password.text)
    }

要捕获后端发出的信号,我使用连接处理程序:

    Connections{
    target: http
    onLogin: console.log("ok")
    onWrongpassword: console.log("Wrong Password")
    onWronglogin: console.log("Unknow user")
}

后端: 得到回应后会发出信号:

void request::start_request(QString host, QString port, QString target, unsigned int version, QString method, QString body)
{
boost::asio::io_context ioc;
ssl::context ctx{ssl::context::sslv23_client};

const char* std_host = host.toStdString().c_str();
const char* std_port = port.toStdString().c_str();
const char* std_target = target.toStdString().c_str();
const char* std_method = method.toStdString().c_str();
const char* std_body = body.toStdString().c_str();

std::make_shared<request>(ioc, ctx)->run(std_host, std_port, std_target, version, std_method, std_body );

ioc.run();
}

void request::run(char const* host, char const* port, char const* target, unsigned int version, QString method, QString body)
{
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
{
    boost::system::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
    std::cerr << ec.message() << "\n";
    respond = "test" ;
    return;
}

// Set up an HTTP GET request message
http::verb method_verb;
boost::string_view method_strview ;
method_strview = method.toStdString();
method_verb = boost::beast::http::string_to_verb(method_strview);
req.version(version);
req.method(method_verb);
req.target(target);
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(http::field::content_type, "application/x-www-form-urlencoded");
req.body() = body.toStdString() ;
req.prepare_payload();

// Look up the domain name

resolver.async_resolve(host, port, std::bind(&request::on_resolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
 }

void request::on_resolve(boost::system::error_code ec, tcp::resolver::results_type results)
{
if(ec){
    //return fail(ec, "resolve");
    respond = "test" ;
}
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(stream.next_layer(), results.begin(), results.end(), std::bind( &request::on_connect, shared_from_this(), std::placeholders::_1));
 }

void request::on_connect(boost::system::error_code ec)
{
if(ec){
    //return fail(ec, "connect");
     respond = ec.message();
    }

// Perform the SSL handshake
stream.async_handshake(ssl::stream_base::client, std::bind(&request::on_handshake, shared_from_this(), std::placeholders::_1));
}

void request::on_handshake(boost::system::error_code ec)
{
if(ec){
    return fail(ec, "handshake");
}

// Send the HTTP request to the remote host
http::async_write(stream, req, std::bind(&request::on_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}

void request::on_write(boost::system::error_code ec, std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);

if(ec)
    return fail(ec, "write");

// Receive the HTTP response
http::async_read(stream, buffer, res, std::bind(&request::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
 }

 void request::on_read(boost::system::error_code ec, std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);

if(ec)
    return fail(ec, "read");

//TODO : Improve to get the user infos
pt::ptree root;
std::stringstream stringstream;
stringstream << res.body();
pt::read_json(stringstream, root);

switch(res.result_int())
{
case 200: {
    emit login();  <== THIS SIGNAL
    std::cout<<res.result_int()<<std::endl;
          }
    break;
case 401:{
    if (root.get<std::string>("message") ==  "wrong username"){
        std::cout<<"Unknow User"<<std::endl;
        emit wronglogin();
        }
    if (root.get<std::string>("message") ==  "wrong password"){
        std::cout<<"Wrong password"<<std::endl;
        emit wrongpassword();
        }
    }
    break;
default: std::cout<<"Undefined"<<std::endl;
}

// Gracefully close the stream
stream.async_shutdown(std::bind(&request::on_shutdown, shared_from_this(), std::placeholders::_1));
}

void request::on_shutdown(boost::system::error_code ec)
{
if(ec == boost::asio::error::eof)
{
    ec.assign(0, ec.category());
}
if(ec)
  return fail(ec, "shutdown");

// If we get here then the connection is closed gracefully
}

信号永远不会被QML组件捕获。 如果我从request :: start_request()发出信号,则可以捕获该信号。

那么我该怎么做呢? 使用Future来同步请求request :: on_read()finih吗? 添加升压信号2并创建信号等待功能? 添加计时器?

0 个答案:

没有答案