2024-07-14 20:39:33 +00:00
|
|
|
// Copyright (C) 2024 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
|
|
|
|
|
|
#include <QtGrpcQuick/qqmlgrpcfunctionalhandlers.h>
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
namespace QtGrpcQuickFunctional {
|
|
|
|
|
2024-08-24 12:31:17 +00:00
|
|
|
void handleDeserializationError(QJSEngine *jsEngine, const QJSValue &errorCallback)
|
2024-07-26 17:24:18 +00:00
|
|
|
{
|
|
|
|
if (!errorCallback.isCallable())
|
|
|
|
return;
|
|
|
|
using StatusCode = QtGrpc::StatusCode;
|
2024-08-24 12:31:17 +00:00
|
|
|
const auto status = QGrpcStatus{ StatusCode::InvalidArgument,
|
|
|
|
"Unable to deserialize return value" };
|
2024-07-26 17:24:18 +00:00
|
|
|
errorCallback.call(QJSValueList{ jsEngine->toScriptValue(status) });
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkReceivedStatus(QJSEngine *jsEngine, const QGrpcStatus &status,
|
|
|
|
const QJSValue &errorCallback)
|
|
|
|
{
|
|
|
|
Q_ASSERT(jsEngine != nullptr);
|
|
|
|
|
|
|
|
if (status.isOk())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (errorCallback.isCallable())
|
|
|
|
errorCallback.call(QJSValueList{ jsEngine->toScriptValue(status) });
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-07-14 20:39:33 +00:00
|
|
|
void connectMultipleReceiveOperationFinished(QJSEngine *jsEngine,
|
Migrate to std::unique_ptr return value for all RPCs
The use of shared pointers has potential risk of storing the
QGrpcOperation children forever and leaking in user code. The problem
is clearly in the lambda connections that we encourage to use in the
docs and examples:
auto stream = testStream(...);
QObject::connect(stream.get(), &QGrpcOperation::finished,
ctx, [ctx, stream]{...});
The above code will hold the 'stream' forever, unless user will make
the explicit disconnect in the lambda.
By using std::unique_ptr we partially solve this, or at least convince
user to solve this. When user creates lambda he knows the 'stream'
lifetime and most probably should consider that after the move, lambda
is owning the QGrpcOperation, so the need of disconnect is more clear
in this case:
auto stream = testStream(...);
auto *streamPtr = stream.get();
QObject::connect(streamPtr, &QGrpcOperation::finished,
ctx, [ctx, stream = std::move(stream)]{...});
The code becomes a bit more complicated, but it points explicitly to
the potential risk. Also it disallows to make this trick to multiple
lambdas at the same time.
Of course using the lambda context to control the QGrpcOperation
lifetime in this case is not necessary. But even if users will decide
to manage the QGrpcOperation lifetime differently, the use of
std::unique_ptr will clearly point to the ownership.
[ChangeLog][Grpc] All generated RPC methods now return std::unique_ptr
instead of std::shared_ptr. This change explicitly defines that caller
takes the ownership of the returned pointers.
Pick-to: 6.8
Change-Id: I271b91454f0c1b12b77127a7e025fa493367e279
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2024-08-28 15:15:33 +00:00
|
|
|
std::unique_ptr<QGrpcOperation> &&operation,
|
2024-07-14 20:39:33 +00:00
|
|
|
const QJSValue &successCallback,
|
|
|
|
const QJSValue &errorCallback)
|
|
|
|
{
|
Migrate to std::unique_ptr return value for all RPCs
The use of shared pointers has potential risk of storing the
QGrpcOperation children forever and leaking in user code. The problem
is clearly in the lambda connections that we encourage to use in the
docs and examples:
auto stream = testStream(...);
QObject::connect(stream.get(), &QGrpcOperation::finished,
ctx, [ctx, stream]{...});
The above code will hold the 'stream' forever, unless user will make
the explicit disconnect in the lambda.
By using std::unique_ptr we partially solve this, or at least convince
user to solve this. When user creates lambda he knows the 'stream'
lifetime and most probably should consider that after the move, lambda
is owning the QGrpcOperation, so the need of disconnect is more clear
in this case:
auto stream = testStream(...);
auto *streamPtr = stream.get();
QObject::connect(streamPtr, &QGrpcOperation::finished,
ctx, [ctx, stream = std::move(stream)]{...});
The code becomes a bit more complicated, but it points explicitly to
the potential risk. Also it disallows to make this trick to multiple
lambdas at the same time.
Of course using the lambda context to control the QGrpcOperation
lifetime in this case is not necessary. But even if users will decide
to manage the QGrpcOperation lifetime differently, the use of
std::unique_ptr will clearly point to the ownership.
[ChangeLog][Grpc] All generated RPC methods now return std::unique_ptr
instead of std::shared_ptr. This change explicitly defines that caller
takes the ownership of the returned pointers.
Pick-to: 6.8
Change-Id: I271b91454f0c1b12b77127a7e025fa493367e279
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2024-08-28 15:15:33 +00:00
|
|
|
auto *operationPtr = operation.get();
|
|
|
|
QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operationPtr);
|
2024-07-14 20:39:33 +00:00
|
|
|
|
|
|
|
auto finishConnection = std::make_shared<QMetaObject::Connection>();
|
Migrate to std::unique_ptr return value for all RPCs
The use of shared pointers has potential risk of storing the
QGrpcOperation children forever and leaking in user code. The problem
is clearly in the lambda connections that we encourage to use in the
docs and examples:
auto stream = testStream(...);
QObject::connect(stream.get(), &QGrpcOperation::finished,
ctx, [ctx, stream]{...});
The above code will hold the 'stream' forever, unless user will make
the explicit disconnect in the lambda.
By using std::unique_ptr we partially solve this, or at least convince
user to solve this. When user creates lambda he knows the 'stream'
lifetime and most probably should consider that after the move, lambda
is owning the QGrpcOperation, so the need of disconnect is more clear
in this case:
auto stream = testStream(...);
auto *streamPtr = stream.get();
QObject::connect(streamPtr, &QGrpcOperation::finished,
ctx, [ctx, stream = std::move(stream)]{...});
The code becomes a bit more complicated, but it points explicitly to
the potential risk. Also it disallows to make this trick to multiple
lambdas at the same time.
Of course using the lambda context to control the QGrpcOperation
lifetime in this case is not necessary. But even if users will decide
to manage the QGrpcOperation lifetime differently, the use of
std::unique_ptr will clearly point to the ownership.
[ChangeLog][Grpc] All generated RPC methods now return std::unique_ptr
instead of std::shared_ptr. This change explicitly defines that caller
takes the ownership of the returned pointers.
Pick-to: 6.8
Change-Id: I271b91454f0c1b12b77127a7e025fa493367e279
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2024-08-28 15:15:33 +00:00
|
|
|
*finishConnection = QObject::connect(operationPtr, &QGrpcOperation::finished, jsEngine,
|
2024-07-14 20:39:33 +00:00
|
|
|
[successCallback, errorCallback, jsEngine,
|
|
|
|
finishConnection,
|
Migrate to std::unique_ptr return value for all RPCs
The use of shared pointers has potential risk of storing the
QGrpcOperation children forever and leaking in user code. The problem
is clearly in the lambda connections that we encourage to use in the
docs and examples:
auto stream = testStream(...);
QObject::connect(stream.get(), &QGrpcOperation::finished,
ctx, [ctx, stream]{...});
The above code will hold the 'stream' forever, unless user will make
the explicit disconnect in the lambda.
By using std::unique_ptr we partially solve this, or at least convince
user to solve this. When user creates lambda he knows the 'stream'
lifetime and most probably should consider that after the move, lambda
is owning the QGrpcOperation, so the need of disconnect is more clear
in this case:
auto stream = testStream(...);
auto *streamPtr = stream.get();
QObject::connect(streamPtr, &QGrpcOperation::finished,
ctx, [ctx, stream = std::move(stream)]{...});
The code becomes a bit more complicated, but it points explicitly to
the potential risk. Also it disallows to make this trick to multiple
lambdas at the same time.
Of course using the lambda context to control the QGrpcOperation
lifetime in this case is not necessary. But even if users will decide
to manage the QGrpcOperation lifetime differently, the use of
std::unique_ptr will clearly point to the ownership.
[ChangeLog][Grpc] All generated RPC methods now return std::unique_ptr
instead of std::shared_ptr. This change explicitly defines that caller
takes the ownership of the returned pointers.
Pick-to: 6.8
Change-Id: I271b91454f0c1b12b77127a7e025fa493367e279
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
2024-08-28 15:15:33 +00:00
|
|
|
operation = std::move(operation)](const QGrpcStatus
|
|
|
|
&status) {
|
2024-07-14 20:39:33 +00:00
|
|
|
// We take 'operation' by copy so that its lifetime
|
|
|
|
// is extended until this lambda is destroyed.
|
2024-07-26 17:24:18 +00:00
|
|
|
if (QtGrpcQuickFunctional::
|
|
|
|
checkReceivedStatus(jsEngine, status,
|
|
|
|
errorCallback)
|
|
|
|
&& successCallback.isCallable()) {
|
|
|
|
successCallback.call();
|
2024-07-14 20:39:33 +00:00
|
|
|
}
|
|
|
|
QObject::disconnect(*finishConnection);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-24 12:31:17 +00:00
|
|
|
void handleReceivedMessageImpl(QJSEngine *jsEngine, std::optional<QJSValue> message,
|
|
|
|
const QJSValue &successCallback, const QJSValue &errorCallback)
|
2024-07-26 17:24:18 +00:00
|
|
|
{
|
|
|
|
if (!successCallback.isCallable())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (message)
|
|
|
|
successCallback.call(QJSValueList{ *message });
|
|
|
|
else
|
2024-08-24 12:31:17 +00:00
|
|
|
QtGrpcQuickFunctional::handleDeserializationError(jsEngine, errorCallback);
|
2024-07-26 17:24:18 +00:00
|
|
|
}
|
|
|
|
|
2024-07-14 20:39:33 +00:00
|
|
|
} // namespace QtGrpcQuickFunctional
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|