我有一个进入异步功能的信号。 我需要将此添加到另一个与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并创建信号等待功能? 添加计时器?