diff options
author | Øystein Heskestad <oystein.heskestad@qt.io> | 2021-05-07 15:23:38 +0200 |
---|---|---|
committer | Øystein Heskestad <oystein.heskestad@qt.io> | 2021-05-20 14:25:42 +0200 |
commit | a7199de7d90f48ce3d95cae795bd9209c39516ce (patch) | |
tree | 5d5a1d2afe05b0e47926bc8d7c16a87d0f6632f9 /src/webchannel | |
parent | d076ebe19669cc78227a63b67da444282e767608 (diff) |
Handle per-transport client idle status
[ChangeLog][QMetaObjectPublisher] Handle per-transport client idle status
Task-number: QTBUG-92927
Change-Id: I5a06261e6dddb0fc0fae9f73b280c61cf5a2b52d
Reviewed-by: Arno Rehn <a.rehn@menlosystems.com>
Diffstat (limited to 'src/webchannel')
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 70 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher_p.h | 39 |
2 files changed, 85 insertions, 24 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index be49b66..f478ede 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -202,7 +202,6 @@ void QWebChannelPropertyChangeNotifier::notify( QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel) : QObject(webChannel), webChannel(webChannel), - clientIsIdle(false), blockUpdates(false), propertyUpdatesInitialized(false), propertyUpdateIntervalTime(50), @@ -319,17 +318,17 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWeb return data; } -void QMetaObjectPublisher::setClientIsIdle(bool isIdle) +void QMetaObjectPublisher::setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport) { - if (clientIsIdle == isIdle) { - return; - } - clientIsIdle = isIdle; - if (!isIdle && timer.isActive()) { - timer.stop(); - } else { - startPropertyUpdateTimer(); - } + transportState[transport].clientIsIdle = isIdle; + if (isIdle) + sendEnqueuedPropertyUpdates(transport); +} + +bool QMetaObjectPublisher::isClientIdle(QWebChannelAbstractTransport *transport) +{ + auto found = transportState.find(transport); + return found != transportState.end() && found.value().clientIsIdle; } QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport) @@ -395,7 +394,7 @@ void QMetaObjectPublisher::initializePropertyUpdates(QObject *const object, cons void QMetaObjectPublisher::sendPendingPropertyUpdates() { - if (blockUpdates || !clientIsIdle || pendingPropertyUpdates.isEmpty()) { + if (blockUpdates) { return; } @@ -450,18 +449,19 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates() // data does not contain specific updates if (!data.isEmpty()) { - setClientIsIdle(false); - message[KEY_DATA] = data; - broadcastMessage(message); + enqueueBroadcastMessage(message); } // send every property update which is not supposed to be broadcasted const QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator suend = specificUpdates.constEnd(); for (QHash<QWebChannelAbstractTransport*, QJsonArray>::const_iterator it = specificUpdates.constBegin(); it != suend; ++it) { message[KEY_DATA] = it.value(); - it.key()->sendMessage(message); + enqueueMessage(message, it.key()); } + + for (auto state = transportState.begin(); state != transportState.end(); ++state) + sendEnqueuedPropertyUpdates(state.key()); } QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const QMetaMethod &method, @@ -621,7 +621,7 @@ void QMetaObjectPublisher::propertyValueChanged(const QObject *object, const int void QMetaObjectPublisher::startPropertyUpdateTimer(bool forceRestart) { - if (!clientIsIdle || blockUpdates) + if (blockUpdates) return; if (propertyUpdateIntervalTime >= 0) { if (forceRestart || !timer.isActive()) @@ -949,6 +949,40 @@ void QMetaObjectPublisher::broadcastMessage(const QJsonObject &message) const } } +void QMetaObjectPublisher::enqueueBroadcastMessage(const QJsonObject &message) +{ + if (webChannel->d_func()->transports.isEmpty()) { + qWarning("QWebChannel is not connected to any transports, cannot send message: %s", + QJsonDocument(message).toJson().constData()); + return; + } + + for (auto *transport : webChannel->d_func()->transports) { + auto &state = transportState[transport]; + state.queuedMessages.append(message); + } +} + +void QMetaObjectPublisher::enqueueMessage(const QJsonObject &message, + QWebChannelAbstractTransport *transport) +{ + auto &state = transportState[transport]; + state.queuedMessages.append(message); +} + +void QMetaObjectPublisher::sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport) +{ + auto found = transportState.find(transport); + if (found != transportState.end() && found.value().clientIsIdle + && !found.value().queuedMessages.isEmpty()) { + for (auto message : found.value().queuedMessages) { + transport->sendMessage(message); + } + found.value().queuedMessages.clear(); + found.value().clientIsIdle = false; + } +} + void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport) { if (!webChannel->d_func()->transports.contains(transport)) { @@ -963,7 +997,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel const MessageType type = toType(message.value(KEY_TYPE)); if (type == TypeIdle) { - setClientIsIdle(true); + setClientIsIdle(true, transport); } else if (type == TypeInit) { if (!message.contains(KEY_ID)) { qWarning("JSON message object is missing the id property: %s", diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index f6ec01e..60a855f 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -59,6 +59,7 @@ #include <QBasicTimer> #include <QPointer> #include <QJsonObject> +#include <QQueue> #include <unordered_map> @@ -130,16 +131,35 @@ public: void broadcastMessage(const QJsonObject &message) const; /** + * Enqueue the given @p message to all known transports. + */ + void enqueueBroadcastMessage(const QJsonObject &message); + + /** + * Enqueue the given @p message to @p transport. + */ + void enqueueMessage(const QJsonObject &message, QWebChannelAbstractTransport *transport); + + /** + * If client for given @p transport is idle, send queued messaged to @p transport and then mark + * the client as not idle. + */ + void sendEnqueuedPropertyUpdates(QWebChannelAbstractTransport *transport); + + /** * Serialize the QMetaObject of @p object and return it in JSON form. */ QJsonObject classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport); /** - * Set the client to idle or busy, based on the value of @p isIdle. - * - * When the value changed, start/stop the property update timer accordingly. + * Set the client to idle or busy for a single @p transport, based on the value of @p isIdle. */ - void setClientIsIdle(bool isIdle); + void setClientIsIdle(bool isIdle, QWebChannelAbstractTransport *transport); + + /** + * Check that client is idle for @p transport. + */ + bool isClientIdle(QWebChannelAbstractTransport *transport); /** * Initialize clients by sending them the class information of the registered objects. @@ -322,8 +342,15 @@ private: std::unordered_map<const QThread*, SignalHandler<QMetaObjectPublisher>> signalHandlers; SignalHandler<QMetaObjectPublisher> *signalHandlerFor(const QObject *object); - // true when the client is idle, false otherwise - bool clientIsIdle; + struct TransportState + { + TransportState() : clientIsIdle(false) { } + // true when the client is idle, false otherwise + bool clientIsIdle; + // messages to send + QQueue<QJsonObject> queuedMessages; + }; + QHash<QWebChannelAbstractTransport *, TransportState> transportState; // true when no property updates should be sent, false otherwise bool blockUpdates; |