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,16 +63,13 @@ 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() qCritical() << "Stream error(" << status.code() << "):" << status.message();
<< "):" << status.message();
} }
if (status.code() if (status.code() == QtGrpc::StatusCode::Unauthenticated) {
== QtGrpc::StatusCode::Unauthenticated) {
emit authFailed(); emit authFailed();
} else if (status.code() != QtGrpc::StatusCode::Ok) { } else if (status.code() != QtGrpc::StatusCode::Ok) {
emit networkError(status.message()); emit networkError(status.message());
@ -80,8 +77,8 @@ void SimpleChatEngine::login(const QString &name, const QString &password)
} else { } else {
setState(Disconnected); setState(Disconnected);
} }
disconnect(*finishedConnection); },
}); Qt::SingleShotConnection);
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
&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:: if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, errorCallback)
checkReceivedStatus(jsEngine, status,
errorCallback)
&& successCallback.isCallable()) { && successCallback.isCallable()) {
successCallback.call(); successCallback.call();
} }
QObject::disconnect(*finishConnection); },
}); Qt::SingleShotConnection);
} }
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, if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, errorCallback))
errorCallback))
impl(jsEngine, operation.get(), successCallback, errorCallback); impl(jsEngine, operation.get(), successCallback, errorCallback);
},
QObject::disconnect(*finishConnection); Qt::SingleShotConnection);
});
} }
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", Client::printRpcResult("UnaryCall", mTimer.nsecsElapsed(), writes);
mTimer.nsecsElapsed(),
writes);
mLoop.quit(); mLoop.quit();
} }
} else { } else {
qDebug() << "FAILED: " << status; qDebug() << "FAILED: " << status;
mLoop.quit(); mLoop.quit();
} }
QObject::disconnect(*connection); },
}); Qt::SingleShotConnection);
} }
void QtGrpcClientBenchmark::serverStreaming() void QtGrpcClientBenchmark::serverStreaming()