mirror of https://github.com/qt/qtgrpc.git
React on QQmlGrpcMetadata::dataChanged in QQmlGrpcChannelOptions
It's necessary not only to set the inner metadata when the setMetadata is called, but also when QQmlGrpcMetadata::data is changed. Otherwise the internal metadata value will not be in sync. As drive-by change, fix the usage of channel options in QGrpcHttp2Channel. Instead of storing the options duplicate in QGrpcHttp2Channel, use the QAbstractGrpcHttp2Channel copy. Make QAbstractGrpcHttp2Channel::channelOptions public. TODO: QGrpcHttp2Channel doesn't consider the changes of ssl configuration and serialization format when updating the channelOptions, but it should react respectively or disallow setting those at runtime. Pick-to: 6.8 Change-Id: I40cf8476679f83a2925d77bcd1d89f043a0b6e67 Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
This commit is contained in:
parent
4d1653d6f6
commit
6cf8e05703
|
|
@ -34,6 +34,9 @@ public:
|
||||||
[[nodiscard]] virtual std::shared_ptr<QAbstractProtobufSerializer>
|
[[nodiscard]] virtual std::shared_ptr<QAbstractProtobufSerializer>
|
||||||
serializer() const noexcept = 0;
|
serializer() const noexcept = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] const QGrpcChannelOptions &channelOptions() const & noexcept;
|
||||||
|
void channelOptions() && = delete;
|
||||||
|
|
||||||
void setChannelOptions(const QGrpcChannelOptions &options) noexcept;
|
void setChannelOptions(const QGrpcChannelOptions &options) noexcept;
|
||||||
void setChannelOptions(QGrpcChannelOptions &&options) noexcept;
|
void setChannelOptions(QGrpcChannelOptions &&options) noexcept;
|
||||||
|
|
||||||
|
|
@ -47,9 +50,6 @@ protected:
|
||||||
virtual void clientStream(std::shared_ptr<QGrpcOperationContext> operationContext) = 0;
|
virtual void clientStream(std::shared_ptr<QGrpcOperationContext> operationContext) = 0;
|
||||||
virtual void bidiStream(std::shared_ptr<QGrpcOperationContext> operationContext) = 0;
|
virtual void bidiStream(std::shared_ptr<QGrpcOperationContext> operationContext) = 0;
|
||||||
|
|
||||||
[[nodiscard]] const QGrpcChannelOptions &channelOptions() const & noexcept;
|
|
||||||
void channelOptions() && = delete;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<QGrpcCallReply> call(QLatin1StringView method, QLatin1StringView service,
|
std::shared_ptr<QGrpcCallReply> call(QLatin1StringView method, QLatin1StringView service,
|
||||||
QByteArrayView arg,
|
QByteArrayView arg,
|
||||||
|
|
|
||||||
|
|
@ -159,14 +159,14 @@ class QGrpcHttp2ChannelPrivate : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QGrpcHttp2ChannelPrivate(const QUrl &uri, const QGrpcChannelOptions &options);
|
explicit QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Channel *q);
|
||||||
~QGrpcHttp2ChannelPrivate() override;
|
~QGrpcHttp2ChannelPrivate() override;
|
||||||
|
|
||||||
void processOperation(const std::shared_ptr<QGrpcOperationContext> &operationContext,
|
void processOperation(const std::shared_ptr<QGrpcOperationContext> &operationContext,
|
||||||
bool endStream = false);
|
bool endStream = false);
|
||||||
std::shared_ptr<QAbstractProtobufSerializer> serializer;
|
std::shared_ptr<QAbstractProtobufSerializer> serializer;
|
||||||
QUrl hostUri;
|
QUrl hostUri;
|
||||||
QGrpcChannelOptions channelOptions;
|
QGrpcHttp2Channel *q_ptr = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY_MOVE(QGrpcHttp2ChannelPrivate)
|
Q_DISABLE_COPY_MOVE(QGrpcHttp2ChannelPrivate)
|
||||||
|
|
@ -394,8 +394,8 @@ void QGrpcHttp2ChannelPrivate::Http2Handler::attachStream(QHttp2Stream *stream_)
|
||||||
std::optional<std::chrono::milliseconds> deadline;
|
std::optional<std::chrono::milliseconds> deadline;
|
||||||
if (channelOpPtr->callOptions().deadlineTimeout())
|
if (channelOpPtr->callOptions().deadlineTimeout())
|
||||||
deadline = channelOpPtr->callOptions().deadlineTimeout();
|
deadline = channelOpPtr->callOptions().deadlineTimeout();
|
||||||
else if (parentChannel->channelOptions.deadlineTimeout())
|
else if (parentChannel->q_ptr->channelOptions().deadlineTimeout())
|
||||||
deadline = parentChannel->channelOptions.deadlineTimeout();
|
deadline = parentChannel->q_ptr->channelOptions().deadlineTimeout();
|
||||||
if (deadline) {
|
if (deadline) {
|
||||||
// We have an active stream and a deadline. It's time to start the timer.
|
// We have an active stream and a deadline. It's time to start the timer.
|
||||||
QObject::connect(&m_deadlineTimer, &QTimer::timeout, this,
|
QObject::connect(&m_deadlineTimer, &QTimer::timeout, this,
|
||||||
|
|
@ -428,7 +428,7 @@ void QGrpcHttp2ChannelPrivate::Http2Handler::prepareInitialRequest(QGrpcOperatio
|
||||||
QGrpcHttp2ChannelPrivate
|
QGrpcHttp2ChannelPrivate
|
||||||
*channel)
|
*channel)
|
||||||
{
|
{
|
||||||
auto &channelOptions = channel->channelOptions;
|
const auto &channelOptions = channel->q_ptr->channelOptions();
|
||||||
QByteArray service{ operationContext->service().data(), operationContext->service().size() };
|
QByteArray service{ operationContext->service().data(), operationContext->service().size() };
|
||||||
QByteArray method{ operationContext->method().data(), operationContext->method().size() };
|
QByteArray method{ operationContext->method().data(), operationContext->method().size() };
|
||||||
m_initialHeaders = HPack::HttpHeader{
|
m_initialHeaders = HPack::HttpHeader{
|
||||||
|
|
@ -585,10 +585,10 @@ void QGrpcHttp2ChannelPrivate::Http2Handler::onDeadlineTimeout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri,
|
QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri, QGrpcHttp2Channel *q)
|
||||||
const QGrpcChannelOptions &options)
|
: hostUri(uri), q_ptr(q)
|
||||||
: hostUri(uri), channelOptions(options)
|
|
||||||
{
|
{
|
||||||
|
auto channelOptions = q_ptr->channelOptions();
|
||||||
auto formatSuffix = channelOptions.serializationFormat().suffix();
|
auto formatSuffix = channelOptions.serializationFormat().suffix();
|
||||||
const QByteArray defaultContentType = DefaultContentType.toByteArray();
|
const QByteArray defaultContentType = DefaultContentType.toByteArray();
|
||||||
const QByteArray contentTypeFromOptions = !formatSuffix.isEmpty()
|
const QByteArray contentTypeFromOptions = !formatSuffix.isEmpty()
|
||||||
|
|
@ -608,6 +608,7 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri,
|
||||||
<< it.value() << ". Using protobuf format as the default one.";
|
<< it.value() << ". Using protobuf format as the default one.";
|
||||||
channelOptions.setSerializationFormat(SerializationFormat::Default);
|
channelOptions.setSerializationFormat(SerializationFormat::Default);
|
||||||
}
|
}
|
||||||
|
q_ptr->setChannelOptions(channelOptions);
|
||||||
} else if (it.value() != contentTypeFromOptions) {
|
} else if (it.value() != contentTypeFromOptions) {
|
||||||
warnAboutFormatConflict = true;
|
warnAboutFormatConflict = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -652,13 +653,13 @@ QGrpcHttp2ChannelPrivate::QGrpcHttp2ChannelPrivate(const QUrl &uri,
|
||||||
};
|
};
|
||||||
} else
|
} else
|
||||||
#if QT_CONFIG(ssl)
|
#if QT_CONFIG(ssl)
|
||||||
if (hostUri.scheme() == "https"_L1 || options.sslConfiguration()) {
|
if (hostUri.scheme() == "https"_L1 || channelOptions.sslConfiguration()) {
|
||||||
auto *sslSocket = initSocket<QSslSocket>();
|
auto *sslSocket = initSocket<QSslSocket>();
|
||||||
if (hostUri.port() < 0) {
|
if (hostUri.port() < 0) {
|
||||||
hostUri.setPort(443);
|
hostUri.setPort(443);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto userSslConfig = options.sslConfiguration(); userSslConfig) {
|
if (const auto userSslConfig = channelOptions.sslConfiguration(); userSslConfig) {
|
||||||
sslSocket->setSslConfiguration(*userSslConfig);
|
sslSocket->setSslConfiguration(*userSslConfig);
|
||||||
} else {
|
} else {
|
||||||
static const QByteArray h2NexProtocol = "h2"_ba;
|
static const QByteArray h2NexProtocol = "h2"_ba;
|
||||||
|
|
@ -824,8 +825,7 @@ void QGrpcHttp2ChannelPrivate::deleteHandler(Http2Handler *handler)
|
||||||
Constructs QGrpcHttp2Channel with \a hostUri.
|
Constructs QGrpcHttp2Channel with \a hostUri.
|
||||||
*/
|
*/
|
||||||
QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri)
|
QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri)
|
||||||
: QAbstractGrpcChannel(),
|
: QAbstractGrpcChannel(), d_ptr(std::make_unique<QGrpcHttp2ChannelPrivate>(hostUri, this))
|
||||||
d_ptr(std::make_unique<QGrpcHttp2ChannelPrivate>(hostUri, QGrpcChannelOptions{}))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -834,7 +834,7 @@ QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri)
|
||||||
*/
|
*/
|
||||||
QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri, const QGrpcChannelOptions &options)
|
QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri, const QGrpcChannelOptions &options)
|
||||||
: QAbstractGrpcChannel(options),
|
: QAbstractGrpcChannel(options),
|
||||||
d_ptr(std::make_unique<QGrpcHttp2ChannelPrivate>(hostUri, options))
|
d_ptr(std::make_unique<QGrpcHttp2ChannelPrivate>(hostUri, this))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,7 +892,7 @@ void QGrpcHttp2Channel::bidiStream(std::shared_ptr<QGrpcOperationContext> operat
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<QAbstractProtobufSerializer> QGrpcHttp2Channel::serializer() const noexcept
|
std::shared_ptr<QAbstractProtobufSerializer> QGrpcHttp2Channel::serializer() const noexcept
|
||||||
{
|
{
|
||||||
return d_ptr->channelOptions.serializationFormat().serializer();
|
return channelOptions().serializationFormat().serializer();
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public:
|
||||||
#if QT_CONFIG(ssl)
|
#if QT_CONFIG(ssl)
|
||||||
QQmlSslConfiguration configuration;
|
QQmlSslConfiguration configuration;
|
||||||
#endif // QT_CONFIG(ssl)
|
#endif // QT_CONFIG(ssl)
|
||||||
|
QMetaObject::Connection metadataUpdateConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
QQmlGrpcChannelOptionsPrivate::QQmlGrpcChannelOptionsPrivate() : QObjectPrivate()
|
QQmlGrpcChannelOptionsPrivate::QQmlGrpcChannelOptionsPrivate() : QObjectPrivate()
|
||||||
|
|
@ -68,12 +69,22 @@ void QQmlGrpcChannelOptions::setMetadata(QQmlGrpcMetadata *value)
|
||||||
{
|
{
|
||||||
Q_D(QQmlGrpcChannelOptions);
|
Q_D(QQmlGrpcChannelOptions);
|
||||||
if (d->metadata != value) {
|
if (d->metadata != value) {
|
||||||
|
if (d->metadataUpdateConnection) {
|
||||||
|
disconnect(d->metadataUpdateConnection);
|
||||||
|
d->metadataUpdateConnection = {};
|
||||||
|
}
|
||||||
|
|
||||||
d->metadata = value;
|
d->metadata = value;
|
||||||
if (d->metadata)
|
if (d->metadata) {
|
||||||
d->options.setMetadata(d->metadata->metadata());
|
const auto updateMetadata = [this]() {
|
||||||
else
|
Q_D(QQmlGrpcChannelOptions);
|
||||||
d->options.setMetadata({});
|
d->options.setMetadata(d->metadata->metadata());
|
||||||
emit metadataChanged();
|
emit metadataChanged();
|
||||||
|
};
|
||||||
|
d->metadataUpdateConnection = connect(d->metadata, &QQmlGrpcMetadata::dataChanged, this,
|
||||||
|
updateMetadata);
|
||||||
|
updateMetadata();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,10 @@ Item {
|
||||||
return Qt.createQmlObject("import QtQuick; import QtGrpc; GrpcHttp2Channel { \
|
return Qt.createQmlObject("import QtQuick; import QtGrpc; GrpcHttp2Channel { \
|
||||||
hostUri: \"http://localhost:50051\"; \
|
hostUri: \"http://localhost:50051\"; \
|
||||||
options: GrpcChannelOptions { \
|
options: GrpcChannelOptions { \
|
||||||
deadlineTimeout: { 2000 } } }", root)
|
deadlineTimeout: { 2000 } \
|
||||||
|
metadata: GrpcMetadata {
|
||||||
|
data: ({ \"common-meta-data\": \"test-channel-metadata\" }) \
|
||||||
|
}}}", root)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGrpcChannelWithDeadlineItem() {
|
function createGrpcChannelWithDeadlineItem() {
|
||||||
|
|
@ -149,13 +152,16 @@ Item {
|
||||||
var missingHeaders = Array()
|
var missingHeaders = Array()
|
||||||
missingHeaders.push("user-name")
|
missingHeaders.push("user-name")
|
||||||
missingHeaders.push("user-password")
|
missingHeaders.push("user-password")
|
||||||
|
missingHeaders.push("common-meta-data")
|
||||||
|
|
||||||
for (var i = 0; i < unaryCallWithOptions.result.valuesData.length; i++) {
|
for (var i = 0; i < unaryCallWithOptions.result.valuesData.length; i++) {
|
||||||
var md = unaryCallWithOptions.result.valuesData[i]
|
var md = unaryCallWithOptions.result.valuesData[i]
|
||||||
if (md.key == "user-name" && md.value == "localhost")
|
if (md.key === "user-name" && md.value === "localhost")
|
||||||
removeElementFromArray(missingHeaders, "user-name")
|
removeElementFromArray(missingHeaders, "user-name")
|
||||||
if (md.key == "user-password" && md.value == "qwerty")
|
if (md.key === "user-password" && md.value === "qwerty")
|
||||||
removeElementFromArray(missingHeaders, "user-password")
|
removeElementFromArray(missingHeaders, "user-password")
|
||||||
|
if (md.key === "common-meta-data" && md.value === "test-channel-metadata")
|
||||||
|
removeElementFromArray(missingHeaders, "common-meta-data")
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(missingHeaders.length === 0,
|
verify(missingHeaders.length === 0,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue