diff options
12 files changed, 166 insertions, 28 deletions
diff --git a/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.cpp b/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.cpp index 3f20ec9..e266407 100644 --- a/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.cpp +++ b/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.cpp @@ -57,7 +57,7 @@ ProcessingService::ProcessingService() setLastMessage(QStringLiteral("Service online.")); } -int ProcessingService::process(const QString & data) +QVariant ProcessingService::process(const QString & data) { setLastMessage(QStringLiteral("Processed data \'%1\'").arg(data)); return data.length(); diff --git a/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.h b/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.h index 8c7f6b2..1f65e82 100644 --- a/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.h +++ b/examples/ivicore/qface-ivi-remote/server_qtro/processingservice.h @@ -60,7 +60,7 @@ class ProcessingService : public ProcessingServiceSimpleSource public: ProcessingService(); - int process(const QString & data) override; + QVariant process(const QString & data) override; }; //! [0] #endif // PROCESSINGSERVICE_H diff --git a/src/tools/ivigenerator/common/interface.rep.tpl b/src/tools/ivigenerator/common/interface.rep.tpl index 7297971..46dcc02 100644 --- a/src/tools/ivigenerator/common/interface.rep.tpl +++ b/src/tools/ivigenerator/common/interface.rep.tpl @@ -56,6 +56,8 @@ {{inc}} {% endfor %} +POD {{interface}}PendingResult(quint64 id, bool failed) + class {{class}} { {% for property in interface.properties %} @@ -82,9 +84,10 @@ class {{class}} {% endif %} {% for operation in interface.operations %} - SLOT({{operation|return_type}} {{operation}}({{ivi.join_params(operation, zoned = interface_zoned)}})) + SLOT(QVariant {{operation}}({{ivi.join_params(operation, zoned = interface_zoned)}})) {% endfor %} + SIGNAL(pendingResultAvailable(quint64 id, bool isSuccess, const QVariant &value)) {% for signal in interface.signals %} SIGNAL({{signal}}({{ivi.join_params(signal, zoned = interface_zoned)}})) {% endfor %} diff --git a/src/tools/ivigenerator/templates_backend_qtro/backend.cpp.tpl b/src/tools/ivigenerator/templates_backend_qtro/backend.cpp.tpl index a2a5e5f..9d4fddf 100644 --- a/src/tools/ivigenerator/templates_backend_qtro/backend.cpp.tpl +++ b/src/tools/ivigenerator/templates_backend_qtro/backend.cpp.tpl @@ -48,6 +48,8 @@ #include <QSettings> #include "{{module.module_name|lower}}module.h" +Q_LOGGING_CATEGORY(qLcRO{{interface}}, "{{module|qml_type|lower}}.{{interface|lower}}backend.remoteobjects", QtInfoMsg) + {% for property in interface.properties %} {% if property.type.is_model %} {% include "pagingmodel.cpp.tpl" %} @@ -245,22 +247,40 @@ QStringList {{class}}::availableZones() const {% endif %} {% set function_parameters = function_parameters + 'zone' %} {% endif%} -{% if not operation.type.is_void %} - QRemoteObjectPendingReply<{{operation|return_type}}> reply = m_replica->{{operation}}({{function_parameters}}); + qCDebug(qLcRO{{interface}}) << "{{operation}} called"; + QRemoteObjectPendingReply<QVariant> reply = m_replica->{{operation}}({{function_parameters}}); auto watcher = new QRemoteObjectPendingCallWatcher(reply); connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, [this, iviReply](QRemoteObjectPendingCallWatcher *self) mutable { if (self->error() == QRemoteObjectPendingCallWatcher::NoError) { - iviReply.setSuccess(self->returnValue().value<{{operation|return_type}}>()); +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) + QVariant value = self->returnValue(); +#else + QVariant value = self->returnValue().value<QVariant>(); +#endif + if (value.canConvert<{{interface}}PendingResult>()) { + {{interface}}PendingResult result = value.value<{{interface}}PendingResult>(); + if (result.failed()) { + qCDebug(qLcRO{{interface}}) << "Pending Result with id:" << result.id() << "failed"; + iviReply.setFailed(); + } else { + qCDebug(qLcRO{{interface}}) << "Result not available yet. Waiting for id:" << result.id(); + m_pendingReplies.insert(result.id(), iviReply); + } + } else { +{% if operation.type.is_void %} + qCDebug(qLcRO{{interface}}) << "Got the value right away: void"; + iviReply.setSuccess(); +{% else %} + qCDebug(qLcRO{{interface}}) << "Got the value right away:" << value.value<{{operation|return_type}}>(); + iviReply.setSuccess(value.value<{{operation|return_type}}>()); +{% endif %} + } } else { iviReply.setFailed(); emit errorChanged(QIviAbstractFeature::InvalidOperation, QStringLiteral("{{class}}, remote call of method {{operation}} failed")); } self->deleteLater(); }); -{% else %} - m_replica->{{operation}}({{function_parameters}}); - iviReply.setSuccess(); -{% endif %} return iviReply; } @@ -268,6 +288,7 @@ QStringList {{class}}::availableZones() const void {{class}}::setupConnections() { + connect(m_replica.data(), &{{interface}}Replica::pendingResultAvailable, this, &{{class}}::onPendingResultAvailable); {% if interface_zoned %} connect(m_replica.data(), &QRemoteObjectReplica::initialized, this, &{{class}}::syncZones); {% else %} @@ -318,6 +339,22 @@ void {{class}}::onNodeError(QRemoteObjectNode::ErrorCode code) emit errorChanged(QIviAbstractFeature::Unknown, "QRemoteObjectNode error, code: " + code); } +void {{class}}::onPendingResultAvailable(quint64 id, bool isSuccess, const QVariant &value) +{ + qCDebug(qLcRO{{interface}}) << "pending result available" << id; + if (!m_pendingReplies.contains(id)) { + qCDebug(qLcRO{{interface}}) << "Received a result for an unexpected id:" << id << ". Ignoring!"; + return; + } + + QIviPendingReplyBase iviReply = m_pendingReplies.take(id); + + if (isSuccess) + iviReply.setSuccess(value); + else + iviReply.setFailed(); +} + {% if interface_zoned %} void {{class}}::onZoneSyncDone() { diff --git a/src/tools/ivigenerator/templates_backend_qtro/backend.h.tpl b/src/tools/ivigenerator/templates_backend_qtro/backend.h.tpl index c0ebb61..04a0642 100644 --- a/src/tools/ivigenerator/templates_backend_qtro/backend.h.tpl +++ b/src/tools/ivigenerator/templates_backend_qtro/backend.h.tpl @@ -131,6 +131,7 @@ protected Q_SLOTS: void onReplicaStateChanged(QRemoteObjectReplica::State newState, QRemoteObjectReplica::State oldState); void onNodeError(QRemoteObjectNode::ErrorCode code); + void onPendingResultAvailable(quint64 id, bool isSuccess, const QVariant &value); {% if interface_zoned %} void syncZones(); void onZoneSyncDone(); @@ -142,6 +143,7 @@ protected: QSharedPointer<{{interface}}Replica> m_replica; QRemoteObjectNode* m_node= nullptr; QUrl m_url; + QHash<quint64, QIviPendingReplyBase> m_pendingReplies; {% for property in interface.properties %} {% if property.type.is_model %} QIviPagingModelInterface *m_{{property}}; diff --git a/tests/auto/core/ivigenerator/org.example.echo.qtro.qface b/tests/auto/core/ivigenerator/org.example.echo.qtro.qface index edbcd24..82f7f82 100644 --- a/tests/auto/core/ivigenerator/org.example.echo.qtro.qface +++ b/tests/auto/core/ivigenerator/org.example.echo.qtro.qface @@ -34,6 +34,8 @@ interface Echo { Combo getCombo(); void voidSlot(); void voidSlot2(int param); + void timer(int interval); + signal anotherChanged(AnotherStruct another); signal foobar(string foo); signal somethingHappened(); @@ -103,6 +105,7 @@ interface EchoZoned { string id(); var varMethod(); Combo getCombo(); + string timer(int interval); signal anotherChanged(AnotherStruct another); signal foobar(string foo); diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.cpp b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.cpp index 57e4782..c3edac1 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.cpp +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.cpp @@ -28,6 +28,7 @@ ****************************************************************************/ #include "echoservice.h" +#include <QTimer> EchoService::EchoService() : m_testCombo(Contact(QStringLiteral("Antti"), 34, true, QVariant()), EchoModule::Friday) @@ -41,30 +42,42 @@ void EchoService::setLastMessage(QString lastMessage) EchoSimpleSource::setLastMessage(lastMessage); } -QString EchoService::echo(const QString &msg) +QVariant EchoService::echo(const QString &msg) { emit echoSlotCalled(msg); return msg; } -QString EchoService::id() +QVariant EchoService::id() { emit idSlotCalled(); return m_testId; } -Combo EchoService::getCombo() +QVariant EchoService::getCombo() { emit getComboSlotCalled(); - return m_testCombo; + return QVariant::fromValue(m_testCombo); } -void EchoService::voidSlot() +QVariant EchoService::voidSlot() { emit voidSlotCalled(); + return QVariant(); } -void EchoService::voidSlot2(int param) +QVariant EchoService::voidSlot2(int param) { emit voidSlot2Called(param); + return QVariant(); +} + +QVariant EchoService::timer(int interval) +{ + static quint64 counter = 0; + EchoPendingResult pendingResult(counter++, false); + QTimer::singleShot(interval, this, [this, pendingResult](){ + emit pendingResultAvailable(pendingResult.id(), true, QVariant()); + }); + return QVariant::fromValue(pendingResult); } diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.h b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.h index ad3eba1..2bdbf54 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.h +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echoservice.h @@ -45,11 +45,12 @@ public: virtual void setLastMessage(QString lastMessage) override; public Q_SLOTS: - virtual QString echo(const QString &msg) override; - virtual QString id() override; - virtual Combo getCombo() override; - virtual void voidSlot() override; - virtual void voidSlot2(int param) override; + virtual QVariant echo(const QString &msg) override; + virtual QVariant id() override; + virtual QVariant getCombo() override; + virtual QVariant voidSlot() override; + virtual QVariant voidSlot2(int param) override; + virtual QVariant timer(int interval) override; Q_SIGNALS: void echoSlotCalled(const QString &msg); diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.cpp b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.cpp index f7c5862..8476f35 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.cpp +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.cpp @@ -28,6 +28,8 @@ #include "echozonedservice.h" +#include <QTimer> + #define SET_VALUE(m_VALUE, VALUE, CHANGED_SIGNAL) \ if (m_zoneHash.value(zone).m_VALUE == VALUE) \ return; \ @@ -207,13 +209,13 @@ QStringList EchoZonedService::availableZones() return keys; } -QString EchoZonedService::echo(const QString &msg, const QString &zone) +QVariant EchoZonedService::echo(const QString &msg, const QString &zone) { emit echoSlotCalled(msg, zone); return msg; } -QString EchoZonedService::id(const QString &zone) +QVariant EchoZonedService::id(const QString &zone) { emit idSlotCalled(zone); return m_testId; @@ -225,8 +227,18 @@ QVariant EchoZonedService::varMethod(const QString &zone) return QVariant("FOOOO"); } -Combo EchoZonedService::getCombo(const QString &zone) +QVariant EchoZonedService::getCombo(const QString &zone) { emit getComboSlotCalled(zone); - return m_testCombo; + return QVariant::fromValue(m_testCombo); +} + +QVariant EchoZonedService::timer(int interval, const QString &zone) +{ + static quint64 counter = 0; + EchoZonedPendingResult pendingResult(counter++, false); + QTimer::singleShot(interval, this, [this, pendingResult, zone](){ + emit pendingResultAvailable(pendingResult.id(), true, zone); + }); + return QVariant::fromValue(pendingResult); } diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.h b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.h index acdb5f5..6bfb567 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.h +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/echozonedservice.h @@ -70,10 +70,11 @@ public slots: qreal UPPERCASEPROPERTY(const QString &zone) override; void setUPPERCASEPROPERTY(qreal UPPERCASEPROPERTY, const QString &zone) override; QStringList availableZones() override; - QString echo(const QString &msg, const QString &zone) override; - QString id(const QString &zone) override; + QVariant echo(const QString &msg, const QString &zone) override; + QVariant id(const QString &zone) override; QVariant varMethod(const QString &zone) override; - Combo getCombo(const QString &zone) override; + QVariant getCombo(const QString &zone) override; + QVariant timer(int interval, const QString &zone) override; Q_SIGNALS: void echoSlotCalled(const QString &msg, const QString& zone); diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.cpp b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.cpp index c1f520a..33508d7 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.cpp +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.cpp @@ -801,6 +801,71 @@ void EchoQtroTest::testMultipleSlotCalls() QCOMPARE(echoZonedSpy[0][1].toString(), frontLeftZone); } +void EchoQtroTest::testAsyncSlotResults() +{ + Server server; + server.start(); + + Echo client; + QSignalSpy initSpy(&client, SIGNAL(isInitializedChanged(bool))); + QVERIFY(initSpy.isValid()); + QVERIFY(client.startAutoDiscovery() == QIviAbstractFeature::ProductionBackendLoaded); + + //wait until the client has connected and initial values are set + initSpy.wait(1000); + QCOMPARE(initSpy.count(), 1); + QVERIFY(client.isInitialized()); + + // test the timer() function which uses a pendingReply on the server side to return the + // function when the timer is finished. + QIviPendingReply<void> reply = client.timer(1000); + QIviPendingReply<void> reply2 = client.timer(500); + QSignalSpy echoReplySpy(reply.watcher(), SIGNAL(replySuccess())); + QSignalSpy echoReplySpy2(reply2.watcher(), SIGNAL(replySuccess())); + + //Wait for the second reply to return first. Verify the other reply is not yet ready. + echoReplySpy2.wait(); + QCOMPARE(echoReplySpy2.count(), 1); + QCOMPARE(echoReplySpy.count(), 0); + + //Wait for the first reply and verify both replies were sent. + echoReplySpy.wait(); + QCOMPARE(echoReplySpy2.count(), 1); + QCOMPARE(echoReplySpy.count(), 1); + + EchoZoned zonedClient; + QSignalSpy zonedInitSpy(&zonedClient, SIGNAL(isInitializedChanged(bool))); + QVERIFY(zonedInitSpy.isValid()); + QVERIFY(zonedClient.startAutoDiscovery() == QIviAbstractFeature::ProductionBackendLoaded); + + //wait until the client has connected and initial values are set + zonedInitSpy.wait(1000); + QCOMPARE(zonedInitSpy.count(), 1); + QVERIFY(zonedClient.isInitialized()); + + EchoZoned *zone = qobject_cast<EchoZoned*>(zonedClient.zoneAt(frontLeftZone)); + QVERIFY(zone); + + // test the timer() function which uses a pendingReply on the server side to return the + // function when the timer is finished. + QIviPendingReply<QString> zonedReply = zonedClient.timer(1000); + QIviPendingReply<QString> zonedReply2 = zone->timer(500); + QSignalSpy zonedEchoReplySpy(zonedReply.watcher(), SIGNAL(replySuccess())); + QSignalSpy zonedEchoReplySpy2(zonedReply2.watcher(), SIGNAL(replySuccess())); + + //Wait for the second reply to return first. Verify the other reply is not yet ready. + zonedEchoReplySpy2.wait(); + QCOMPARE(zonedEchoReplySpy2.count(), 1); + QCOMPARE(zonedEchoReplySpy.count(), 0); + QCOMPARE(zonedReply2.value(), frontLeftZone); + + //Wait for the first reply and verify both replies were sent. + zonedEchoReplySpy.wait(); + QCOMPARE(zonedEchoReplySpy2.count(), 1); + QCOMPARE(zonedEchoReplySpy.count(), 1); + QCOMPARE(zonedReply.value(), QString()); +} + void EchoQtroTest::testSignals() { Server server; diff --git a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.h b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.h index 84aabcd..5ff3da4 100644 --- a/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.h +++ b/tests/auto/core/ivigenerator/projects/org-example-echo-qtro/server_qtro_test/tst_echoqtro.h @@ -52,6 +52,7 @@ private slots: void testSlots(); void testZonedSlots(); void testMultipleSlotCalls(); + void testAsyncSlotResults(); void testSignals(); void testModel(); }; |