2022-10-20 11:49:27 +00:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
|
|
|
|
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
|
|
|
|
2023-08-06 20:07:05 +00:00
|
|
|
#include "qgrpcoperation.h"
|
|
|
|
|
|
|
|
|
|
#include "qtgrpcglobal_p.h"
|
|
|
|
|
#include "qgrpcchanneloperation.h"
|
2022-10-20 11:49:27 +00:00
|
|
|
|
2023-09-05 10:39:18 +00:00
|
|
|
#include <QtCore/QAtomicInteger>
|
2023-02-08 14:46:54 +00:00
|
|
|
#include <QtCore/private/qobject_p.h>
|
2023-09-05 10:39:18 +00:00
|
|
|
#include <QtCore/qpointer.h>
|
|
|
|
|
#include <QtCore/qeventloop.h>
|
2023-02-08 14:46:54 +00:00
|
|
|
|
2022-10-20 11:49:27 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
2023-08-06 20:07:05 +00:00
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
|
|
2022-10-20 11:49:27 +00:00
|
|
|
/*!
|
2022-12-16 08:55:22 +00:00
|
|
|
\class QGrpcOperation
|
2023-03-10 09:49:15 +00:00
|
|
|
\inmodule QtGrpc
|
2022-12-16 08:55:22 +00:00
|
|
|
\brief The QGrpcOperation class implements common logic to
|
2023-08-06 20:07:05 +00:00
|
|
|
handle the gRPC communication from the client side.
|
2022-12-08 12:53:08 +00:00
|
|
|
*/
|
2022-10-20 11:49:27 +00:00
|
|
|
|
|
|
|
|
/*!
|
2024-01-14 18:39:01 +00:00
|
|
|
\fn template <typename T> T QGrpcOperation::read() const
|
2022-10-20 11:49:27 +00:00
|
|
|
|
2023-08-06 20:07:05 +00:00
|
|
|
Reads message from raw byte array stored in QGrpcOperation.
|
2022-12-08 12:53:08 +00:00
|
|
|
|
2023-08-06 20:07:05 +00:00
|
|
|
Returns a deserialized message or, on failure, a default-constructed
|
|
|
|
|
message.
|
|
|
|
|
If deserialization is not successful the \l QGrpcOperation::errorOccurred
|
|
|
|
|
signal is emitted.
|
2022-12-08 12:53:08 +00:00
|
|
|
*/
|
2022-10-20 11:49:27 +00:00
|
|
|
|
|
|
|
|
/*!
|
2023-01-27 19:49:36 +00:00
|
|
|
\fn void QGrpcOperation::finished()
|
2022-12-08 12:53:08 +00:00
|
|
|
|
|
|
|
|
This signal indicates the end of communication for this call.
|
|
|
|
|
|
2023-09-05 10:39:18 +00:00
|
|
|
If this signal is emitted by the stream then this stream is successfully
|
2022-12-08 12:53:08 +00:00
|
|
|
closed either by client or server.
|
|
|
|
|
*/
|
2022-10-20 11:49:27 +00:00
|
|
|
|
|
|
|
|
/*!
|
2023-08-06 15:13:23 +00:00
|
|
|
\fn void QGrpcOperation::errorOccurred(const QGrpcStatus &status) const
|
2022-10-20 11:49:27 +00:00
|
|
|
|
2022-12-08 12:53:08 +00:00
|
|
|
This signal indicates the error occurred during serialization.
|
|
|
|
|
|
|
|
|
|
This signal is emitted when error with \a status occurs in channel
|
|
|
|
|
or during serialization.
|
2024-01-14 19:22:07 +00:00
|
|
|
|
|
|
|
|
\sa QAbstractGrpcClient::errorOccurred
|
2022-12-08 12:53:08 +00:00
|
|
|
*/
|
2022-10-20 11:49:27 +00:00
|
|
|
|
2023-02-08 14:46:54 +00:00
|
|
|
class QGrpcOperationPrivate : public QObjectPrivate
|
|
|
|
|
{
|
|
|
|
|
Q_DECLARE_PUBLIC(QGrpcOperation)
|
|
|
|
|
public:
|
2023-09-05 10:39:18 +00:00
|
|
|
QGrpcOperationPrivate(std::shared_ptr<QGrpcChannelOperation> _channelOperation)
|
|
|
|
|
: channelOperation(std::move(_channelOperation))
|
2023-04-21 10:01:26 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 14:46:54 +00:00
|
|
|
QByteArray data;
|
2023-08-06 20:07:05 +00:00
|
|
|
std::shared_ptr<QGrpcChannelOperation> channelOperation;
|
2023-09-05 10:39:18 +00:00
|
|
|
QAtomicInteger<bool> isFinished{ false };
|
2023-02-08 14:46:54 +00:00
|
|
|
};
|
|
|
|
|
|
2023-09-05 10:39:18 +00:00
|
|
|
QGrpcOperation::QGrpcOperation(std::shared_ptr<QGrpcChannelOperation> channelOperation)
|
|
|
|
|
: QObject(*new QGrpcOperationPrivate(std::move(channelOperation)))
|
2022-10-20 11:49:27 +00:00
|
|
|
{
|
2023-08-06 20:07:05 +00:00
|
|
|
[[maybe_unused]] bool valid =
|
|
|
|
|
QObject::connect(d_func()->channelOperation.get(), &QGrpcChannelOperation::dataReady,
|
|
|
|
|
this, [this](const QByteArray &data) {
|
|
|
|
|
Q_D(QGrpcOperation);
|
|
|
|
|
d->data = data;
|
|
|
|
|
});
|
|
|
|
|
Q_ASSERT_X(valid, "QGrpcOperation::QGrpcOperation",
|
|
|
|
|
"Unable to make connection to the 'dataReady' signal");
|
|
|
|
|
|
|
|
|
|
valid = QObject::connect(d_func()->channelOperation.get(),
|
|
|
|
|
&QGrpcChannelOperation::errorOccurred, this,
|
2023-09-05 10:39:18 +00:00
|
|
|
[this](const auto &status) {
|
|
|
|
|
d_func()->isFinished.storeRelaxed(true);
|
|
|
|
|
emit this->errorOccurred(status);
|
|
|
|
|
});
|
2023-08-06 20:07:05 +00:00
|
|
|
Q_ASSERT_X(valid, "QGrpcOperation::QGrpcOperation",
|
|
|
|
|
"Unable to make connection to the 'errorOccurred' signal");
|
|
|
|
|
|
|
|
|
|
valid = QObject::connect(d_func()->channelOperation.get(), &QGrpcChannelOperation::finished,
|
2023-09-05 10:39:18 +00:00
|
|
|
this, [this]() {
|
|
|
|
|
d_func()->isFinished.storeRelaxed(true);
|
|
|
|
|
emit this->finished();
|
|
|
|
|
});
|
2023-08-06 20:07:05 +00:00
|
|
|
Q_ASSERT_X(valid, "QGrpcOperation::QGrpcOperation",
|
|
|
|
|
"Unable to make connection to the 'finished' signal");
|
2022-10-20 11:49:27 +00:00
|
|
|
}
|
|
|
|
|
|
2022-12-09 12:03:04 +00:00
|
|
|
QGrpcOperation::~QGrpcOperation() = default;
|
|
|
|
|
|
2023-02-08 14:46:54 +00:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
Getter of the data received from the channel.
|
|
|
|
|
*/
|
|
|
|
|
QByteArray QGrpcOperation::data() const
|
|
|
|
|
{
|
|
|
|
|
return d_func()->data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 14:39:05 +00:00
|
|
|
/*!
|
2023-08-06 20:07:05 +00:00
|
|
|
Getter of the metadata received from the channel. For the HTTP2 channels it
|
|
|
|
|
usually contains the HTTP headers received from the server.
|
2023-05-17 14:39:05 +00:00
|
|
|
*/
|
2023-08-06 20:07:05 +00:00
|
|
|
QGrpcMetadata QGrpcOperation::metadata() const
|
2023-05-17 14:39:05 +00:00
|
|
|
{
|
2023-08-06 20:07:05 +00:00
|
|
|
return d_func()->channelOperation->serverMetadata();
|
2023-05-17 14:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-13 16:07:11 +00:00
|
|
|
/*!
|
|
|
|
|
Getter of the method that this operation was intialized with.
|
|
|
|
|
*/
|
|
|
|
|
QLatin1StringView QGrpcOperation::method() const
|
|
|
|
|
{
|
|
|
|
|
return d_func()->channelOperation->method();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 14:39:05 +00:00
|
|
|
/*!
|
2023-08-06 20:07:05 +00:00
|
|
|
\internal
|
|
|
|
|
Returns a pointer to the assigned channel-side QGrpcChannelOperation.
|
2023-05-17 14:39:05 +00:00
|
|
|
*/
|
2023-08-06 20:07:05 +00:00
|
|
|
const QGrpcChannelOperation *QGrpcOperation::channelOperation() const
|
2023-05-17 14:39:05 +00:00
|
|
|
{
|
2023-08-06 20:07:05 +00:00
|
|
|
return d_func()->channelOperation.get();
|
2023-05-17 14:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-08 14:46:54 +00:00
|
|
|
/*!
|
|
|
|
|
\internal
|
2023-04-21 10:01:26 +00:00
|
|
|
Getter of the serializer that QGrpcOperation was constructed with.
|
2023-02-08 14:46:54 +00:00
|
|
|
*/
|
2023-09-05 10:39:18 +00:00
|
|
|
std::shared_ptr<const QAbstractProtobufSerializer> QGrpcOperation::serializer() const
|
2023-02-08 14:46:54 +00:00
|
|
|
{
|
2023-09-05 10:39:18 +00:00
|
|
|
return d_func()->channelOperation->serializer();
|
2022-10-20 11:49:27 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-06 20:07:05 +00:00
|
|
|
void QGrpcOperation::cancel()
|
|
|
|
|
{
|
2023-09-05 10:39:18 +00:00
|
|
|
d_func()->isFinished.storeRelaxed(true);
|
2023-08-06 20:07:05 +00:00
|
|
|
emit d_func()->channelOperation->cancelled();
|
|
|
|
|
emit errorOccurred({ QGrpcStatus::Cancelled, "Operation is cancelled by client"_L1 });
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-05 10:39:18 +00:00
|
|
|
/*!
|
|
|
|
|
Returns true when QGrpcOperation finished its workflow,
|
|
|
|
|
meaning it was finished, canceled, or error occurred, otherwise returns false.
|
|
|
|
|
*/
|
|
|
|
|
bool QGrpcOperation::isFinished() const
|
|
|
|
|
{
|
|
|
|
|
return d_func()->isFinished.loadRelaxed();
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-06 15:13:23 +00:00
|
|
|
QGrpcStatus QGrpcOperation::deserializationError() const
|
|
|
|
|
{
|
|
|
|
|
QGrpcStatus status;
|
2023-09-05 10:39:18 +00:00
|
|
|
switch (serializer()->deserializationError()) {
|
2023-08-06 15:13:23 +00:00
|
|
|
case QAbstractProtobufSerializer::InvalidHeaderError: {
|
|
|
|
|
const QLatin1StringView errStr("Response deserialization failed: invalid field found.");
|
|
|
|
|
status = { QGrpcStatus::InvalidArgument, errStr };
|
|
|
|
|
qGrpcWarning() << errStr;
|
|
|
|
|
emit errorOccurred(status);
|
|
|
|
|
} break;
|
|
|
|
|
case QAbstractProtobufSerializer::NoDeserializerError: {
|
|
|
|
|
const QLatin1StringView errStr("No deserializer was found for a given type.");
|
|
|
|
|
status = { QGrpcStatus::InvalidArgument, errStr };
|
|
|
|
|
qGrpcWarning() << errStr;
|
|
|
|
|
emit errorOccurred(status);
|
|
|
|
|
} break;
|
|
|
|
|
case QAbstractProtobufSerializer::UnexpectedEndOfStreamError: {
|
|
|
|
|
const QLatin1StringView errStr("Invalid size of received buffer.");
|
|
|
|
|
status = { QGrpcStatus::OutOfRange, errStr };
|
|
|
|
|
qGrpcWarning() << errStr;
|
|
|
|
|
emit errorOccurred(status);
|
|
|
|
|
} break;
|
|
|
|
|
case QAbstractProtobufSerializer::NoError:
|
|
|
|
|
Q_FALLTHROUGH();
|
|
|
|
|
default:
|
|
|
|
|
const QLatin1StringView errStr("Deserializing failed, but no error was set.");
|
|
|
|
|
status = { QGrpcStatus::InvalidArgument, errStr };
|
|
|
|
|
qGrpcWarning() << errStr;
|
|
|
|
|
emit errorOccurred(status);
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-20 11:49:27 +00:00
|
|
|
QT_END_NAMESPACE
|
2022-12-09 12:03:04 +00:00
|
|
|
|
|
|
|
|
#include "moc_qgrpcoperation.cpp"
|