aboutsummaryrefslogtreecommitdiffstats
path: root/src/webchannel
diff options
context:
space:
mode:
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
commita7199de7d90f48ce3d95cae795bd9209c39516ce (patch)
tree5d5a1d2afe05b0e47926bc8d7c16a87d0f6632f9 /src/webchannel
parentd076ebe19669cc78227a63b67da444282e767608 (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.cpp70
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h39
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;