Prefer the usage of SingleShotConnection

Currently we're doing something manually, which, since Qt6 is a
dedicated feature. Use that instead for less error-prone disconnections
for our single-shot signals.

Lets not re-invent the wheel for something that has been (potentially
faster rather then slower) invented for this exact usecase.

We will promote the usage of Qt::SingleShotConnection, so as good
teachers we should be using it as well.

Pick-to: 6.8
Change-Id: I3b2b9f176f06d91b4d0946a38c53a4c2614c8a01
Reviewed-by:  Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
Dennis Oberst 2024-08-08 11:26:41 +02:00
parent c29f3291b6
commit 19fca04537
5 changed files with 67 additions and 81 deletions

View File

@ -63,25 +63,22 @@ void SimpleChatEngine::login(const QString &name, const QString &password)
// ![1] // ![1]
auto stream = m_client->messageList(qtgrpc::examples::chat::None()); auto stream = m_client->messageList(qtgrpc::examples::chat::None());
auto streamPtr = stream.get(); auto streamPtr = stream.get();
auto finishedConnection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*finishedConnection = QObject::connect(streamPtr, &QGrpcServerStream::finished, this, streamPtr, &QGrpcServerStream::finished, this,
[this, finishedConnection, [this, stream = std::move(stream)](const QGrpcStatus &status) {
stream = std::move(stream)](const QGrpcStatus &status) { if (!status.isOk()) {
if (!status.isOk()) { qCritical() << "Stream error(" << status.code() << "):" << status.message();
qCritical() << "Stream error(" << status.code() }
<< "):" << status.message(); if (status.code() == QtGrpc::StatusCode::Unauthenticated) {
} emit authFailed();
if (status.code() } else if (status.code() != QtGrpc::StatusCode::Ok) {
== QtGrpc::StatusCode::Unauthenticated) { emit networkError(status.message());
emit authFailed(); setState(Disconnected);
} else if (status.code() != QtGrpc::StatusCode::Ok) { } else {
emit networkError(status.message()); setState(Disconnected);
setState(Disconnected); }
} else { },
setState(Disconnected); Qt::SingleShotConnection);
}
disconnect(*finishedConnection);
});
QObject::connect(streamPtr, &QGrpcServerStream::messageReceived, this, QObject::connect(streamPtr, &QGrpcServerStream::messageReceived, this,
[this, name, password, stream = streamPtr]() { [this, name, password, stream = streamPtr]() {

View File

@ -144,13 +144,13 @@ void QGrpcClientBasePrivate::addStream(QGrpcOperation *grpcStream)
activeStreams.remove(grpcStream); activeStreams.remove(grpcStream);
}); });
auto finishedConnection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*finishedConnection = QObject::connect(grpcStream, &QGrpcOperation::finished, q, grpcStream, &QGrpcOperation::finished, q,
[this, grpcStream, finishedConnection] { [this, grpcStream] {
Q_ASSERT(activeStreams.contains(grpcStream)); Q_ASSERT(activeStreams.contains(grpcStream));
activeStreams.remove(grpcStream); activeStreams.remove(grpcStream);
QObject::disconnect(*finishedConnection); },
}); Qt::SingleShotConnection);
const auto it = activeStreams.insert(grpcStream); const auto it = activeStreams.insert(grpcStream);
Q_ASSERT(it.second); Q_ASSERT(it.second);
} }

View File

@ -360,18 +360,17 @@ void Http2Handler::attachStream(QHttp2Stream *stream_)
}); });
Q_ASSERT(parentChannel != nullptr); Q_ASSERT(parentChannel != nullptr);
auto errorConnection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*errorConnection = QObject::connect(
m_stream.get(), &QHttp2Stream::errorOccurred, parentChannel, m_stream.get(), &QHttp2Stream::errorOccurred, parentChannel,
[parentChannel, errorConnection, this](quint32 http2ErrorCode, const QString &errorString) { [parentChannel, this](quint32 http2ErrorCode, const QString &errorString) {
if (!m_operation.expired()) { if (!m_operation.expired()) {
auto channelOp = m_operation.lock(); auto channelOp = m_operation.lock();
emit channelOp->finished(QGrpcStatus{ http2ErrorToStatusCode(http2ErrorCode), emit channelOp->finished(QGrpcStatus{ http2ErrorToStatusCode(http2ErrorCode),
errorString }); errorString });
} }
parentChannel->deleteHandler(this); parentChannel->deleteHandler(this);
QObject::disconnect(*errorConnection); },
}); Qt::SingleShotConnection);
QObject::connect(m_stream.get(), &QHttp2Stream::dataReceived, channelOpPtr, QObject::connect(m_stream.get(), &QHttp2Stream::dataReceived, channelOpPtr,
[channelOpPtr, parentChannel, this](const QByteArray &data, bool endStream) { [channelOpPtr, parentChannel, this](const QByteArray &data, bool endStream) {

View File

@ -38,22 +38,18 @@ void connectMultipleReceiveOperationFinished(QJSEngine *jsEngine,
auto *operationPtr = operation.get(); auto *operationPtr = operation.get();
QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operationPtr); QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operationPtr);
auto finishConnection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*finishConnection = QObject::connect(operationPtr, &QGrpcOperation::finished, jsEngine, operationPtr, &QGrpcOperation::finished, jsEngine,
[successCallback, errorCallback, jsEngine, [successCallback, errorCallback, jsEngine,
finishConnection, operation = std::move(operation)](const QGrpcStatus &status) {
operation = std::move(operation)](const QGrpcStatus // We take 'operation' by copy so that its lifetime
&status) { // is extended until this lambda is destroyed.
// We take 'operation' by copy so that its lifetime if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, errorCallback)
// is extended until this lambda is destroyed. && successCallback.isCallable()) {
if (QtGrpcQuickFunctional:: successCallback.call();
checkReceivedStatus(jsEngine, status, }
errorCallback) },
&& successCallback.isCallable()) { Qt::SingleShotConnection);
successCallback.call();
}
QObject::disconnect(*finishConnection);
});
} }
void handleReceivedMessageImpl(QJSEngine *jsEngine, std::optional<QJSValue> message, void handleReceivedMessageImpl(QJSEngine *jsEngine, std::optional<QJSValue> message,
@ -77,19 +73,16 @@ void Private::connectSingleReceiveOperationFinishedImpl(QJSEngine *jsEngine,
auto *operationPtr = operation.get(); auto *operationPtr = operation.get();
QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operationPtr); QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operationPtr);
auto finishConnection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*finishConnection = QObject:: operationPtr, &QGrpcCallReply::finished, jsEngine,
connect(operationPtr, &QGrpcCallReply::finished, jsEngine, [jsEngine, successCallback, errorCallback, impl,
[jsEngine, successCallback, errorCallback, finishConnection, impl, operation = std::move(operation)](const QGrpcStatus &status) {
operation = std::move(operation)](const QGrpcStatus &status) { // We take 'operation' by copy so that its lifetime
// We take 'operation' by copy so that its lifetime // is extended until this lambda is destroyed.
// is extended until this lambda is destroyed. if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, errorCallback))
if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, impl(jsEngine, operation.get(), successCallback, errorCallback);
errorCallback)) },
impl(jsEngine, operation.get(), successCallback, errorCallback); Qt::SingleShotConnection);
QObject::disconnect(*finishConnection);
});
} }
void Private::makeServerStreamConnectionsImpl(QJSEngine *jsEngine, void Private::makeServerStreamConnectionsImpl(QJSEngine *jsEngine,

View File

@ -66,27 +66,24 @@ void QtGrpcClientBenchmark::unaryCallHelper(qt::bench::UnaryCallRequest &request
auto reply = mClient.UnaryCall(request); auto reply = mClient.UnaryCall(request);
auto *replyPtr = reply.get(); auto *replyPtr = reply.get();
auto connection = std::make_shared<QMetaObject::Connection>(); QObject::connect(
*connection = QObject::connect(replyPtr, &QGrpcCallReply::finished, &mClient, replyPtr, &QGrpcCallReply::finished, &mClient,
[connection, reply = std::move(reply), this, &request, [reply = std::move(reply), this, &request, &writes](const QGrpcStatus &status) {
&writes](const QGrpcStatus &status) { if (writes == 0)
if (writes == 0) mTimer.start();
mTimer.start(); if (status.isOk()) {
if (status.isOk()) { if (++writes < mCalls) {
if (++writes < mCalls) { unaryCallHelper(request, writes);
unaryCallHelper(request, writes); } else {
} else { Client::printRpcResult("UnaryCall", mTimer.nsecsElapsed(), writes);
Client::printRpcResult("UnaryCall", mLoop.quit();
mTimer.nsecsElapsed(), }
writes); } else {
mLoop.quit(); qDebug() << "FAILED: " << status;
} mLoop.quit();
} else { }
qDebug() << "FAILED: " << status; },
mLoop.quit(); Qt::SingleShotConnection);
}
QObject::disconnect(*connection);
});
} }
void QtGrpcClientBenchmark::serverStreaming() void QtGrpcClientBenchmark::serverStreaming()