Commit b752131e authored by Wouter's avatar Wouter

Make RPC calls asynchronous (using QFuture results)

parent 081b88ca
......@@ -117,10 +117,14 @@ Config::Config(QObject* parent): QObject(parent)
m_globalTypeHeaderMap.insert("QList", "QtCore/QList");
m_globalTypeHeaderMap.insert("QSet", "QtCore/QSet");
m_globalTypeHeaderMap.insert("QSharedPointer", "QtCore/QSharedPointer");
m_globalTypeHeaderMap.insert("QFuture", "QtCore/QFuture");
// TODO Add more
// Generated by default templates
m_localTypeHeaderMap.insert("AbstractWrapper", "abstractwrapper.h");
m_localTypeHeaderMap.insert("RpcFutureInterface", "rpcfutureinterface.h");
// Default (Qt) type mappings
m_jsonTypeMap.insert("string", "QString");
......@@ -134,6 +138,8 @@ Config::Config(QObject* parent): QObject(parent)
// From default templates
m_headerDependencies.insert("class", "QObject");
m_headerDependencies.insert("class", "QVariantMap");
m_headerDependencies.insert("class", "QFuture");
m_headerDependencies.insert("class", "RpcFutureInterface");
m_headerDependencies.insert("array", "QList");
m_headerDependencies.insert("array", "QVariant");
m_headerDependencies.insert("wrapper", "AbstractWrapper");
......
......@@ -628,6 +628,7 @@ RpcMethod* Introspector::introspectMethod(const QString& id, const QVariantMap&
}
RpcMethod *method = new RpcMethod(makeIdentifier(id), id, containerClass);
method->setVirtual(true); // TODO make configurable?
if (data.contains("description")) {
method->setDocumentation(data.value("description").toString());
}
......
......@@ -79,7 +79,7 @@ public:
{% if not class.rpcMethods|length_is:0 %}
protected:
virtual QVariant doCall(const QString& methodName, const QVariantMap& parameters) = 0;
virtual void doCall(const QString& methodName, const QVariantMap& parameters, RpcFutureInterfaceBase* futureInterface) = 0;
{% endif %}
public:
......
......@@ -87,7 +87,7 @@
{% case "RpcMethod" %}
{% if not member.isInline %}{% if not member.isPureVirtual %}
{{ member.returnType.signature }} {{ class.fullName }}::{{ member.name }}({% for param in member.parameters %}{% if not forloop.first %}, {% endif %}{{ param.type.signature }} {{ param.name }}{% endfor %}){% if member.isConst %} const{% endif %} {
{% ifequal member.returnType.type.fullName "void" %}void{% else %}QFuture<{{ member.returnType.signature }}>{% endifequal %} {{ class.fullName }}::{{ member.name }}({% for param in member.parameters %}{% if not forloop.first %}, {% endif %}{{ param.type.signature }} {{ param.name }}{% endfor %}){% if member.isConst %} const{% endif %} {
QVariantMap _rpcParameters;
{% for param in member.parameters %}
// {{ param.type.type.metaType }}
......@@ -105,18 +105,19 @@
{% endswitch %}
{% endfor %}
{% switch member.returnType.type.metaType %}
{% default %}
QVariantMap resultMap = doCall("{{ member.originalName }}", _rpcParameters).toMap();
return {{ member.returnType.type.className }}::fromVariant(resultMap);
{% case "type" %}
{% ifequal member.returnType.type.fullName "void" %}
doCall("{{ member.originalName }}", _rpcParameters);
{% else %}
QVariant result = doCall("{{ member.originalName }}", _rpcParameters);
return result.value<{{ member.returnType.type.fullName }}>();
{% endifequal %}
{% endswitch %}
{% ifequal member.returnType.type.fullName "void" %}
doCall("{{ member.originalName }}", _rpcParameters, NULL);
{% else %}
{% switch member.returnType.type.metaType %}
{% default %}
RpcFutureInterface<{{ member.returnType.signature }}>* result = new RpcFutureInterface<{{ member.returnType.signature }}>(&{{ member.returnType.type.className }}::fromVariant, QFutureInterfaceBase::Running);
{% case "type" %}
RpcFutureInterface<{{ member.returnType.signature }}>* result = new RpcFutureInterface<{{ member.returnType.signature }}>(0, QFutureInterfaceBase::Running);
{% endswitch %}
doCall("{{ member.originalName }}", _rpcParameters, result);
return result->future();
{% endifequal %}
}
{% endif %}{% endif %}{# inline, pureVirtual #}
......
......@@ -25,12 +25,20 @@
*/
{% if member.isExplicit %}explicit {% endif %}{{ member.name }}(const QVariantMap &data{% for param in member.parameters %}, {{ param.type.signature }} {{ param.name }}{% if param.defaultValue %} = {{ param.defaultValue }}{% endif %}{% endfor %});
{% endfilter %}
{% case "Method" "RpcMethod" "Notification" %}
{% case "Method" "Notification" %}
{% filter indent:0 %}
{% if member.isInline %}inline {% endif %}{% if member.isStatic %}static {% endif %}{% if member.isVirtual %}virtual {% endif %}{{ member.returnType.signature }} {{ member.name }}({% for param in member.parameters %}{% if not forloop.first %}, {% endif %}{{ param.type.signature }} {{ param.name }}{% if param.defaultValue %} = {{ param.defaultValue }}{% endif %}{% endfor %}){% if member.isConst %} const{% endif %}{% if member.isPureVirtual %} = 0{% endif %}{% if member.isInline %} {
{{ member.body }}
}{% endif %};
{% endfilter %}
{% case "RpcMethod" %}
{% filter indent:0 %}
{% if member.isInline %}inline {% endif %}{% if member.isStatic %}static {% endif %}{% if member.isVirtual %}virtual {% endif %}{% ifequal member.returnType.type.fullName "void" %}void{% else %}QFuture<{{ member.returnType.signature }}>{% endifequal %} {{ member.name }}({% for param in member.parameters %}{% if not forloop.first %}, {% endif %}{{ param.type.signature }} {{ param.name }}{% if param.defaultValue %} = {{ param.defaultValue }}{% endif %}{% endfor %}){% if member.isConst %} const{% endif %}{% if member.isPureVirtual %} = 0{% endif %}{% if member.isInline %} {
{{ member.body }}
}{% endif %};
{% endfilter %}
{% case "Field" "Property" %}
{% filter indent:0 %}
{{ member.type.signature }} {{ member.name }};
......
{% extends "header.template" %}
{% block guardopen %}
#ifndef {{ project.namespace|upper }}_RPCFUTUREINTERFACE_H
#define {{ project.namespace|upper }}_RPCFUTUREINTERFACE_H
{% endblock %}
{% block includes %}
#include <QtCore/QVariant>
#include <QtCore/QFutureInterface>
{% endblock %}
{% block namespace %}
namespace {{ project.namespace }} {
class RpcFutureInterfaceBase
{
public:
RpcFutureInterfaceBase()
{
}
virtual ~RpcFutureInterfaceBase()
{
}
virtual void reportCalled() = 0;
virtual void reportVariantResult(const QVariant& result, int index = -1) = 0;
virtual void reportAborted() = 0;
virtual void reportTimeout() = 0;
};
template<class T>
class RpcFutureInterface: public RpcFutureInterfaceBase
{
public:
typedef T (*VariantConversion)(const QVariant&, bool*);
explicit RpcFutureInterface(VariantConversion conversionFunc = 0, QFutureInterfaceBase::State initialState = QFutureInterfaceBase::NoState)
: RpcFutureInterfaceBase()
, m_futureInterface(initialState)
, m_convert(conversionFunc)
{
}
RpcFutureInterface(const RpcFutureInterface &other)
: RpcFutureInterfaceBase()
, m_futureInterface(other.m_futureInterface)
, m_convert(other.m_convert)
{
}
virtual ~RpcFutureInterface()
{
qDebug() << "Destroy the future";
}
QFuture<T> future()
{
return m_futureInterface.future();
}
virtual void reportCalled()
{
m_futureInterface.reportStarted();
}
virtual void reportVariantResult(const QVariant& result, int index = -1)
{
if (m_convert) {
m_futureInterface.reportResult((*m_convert)(result, 0), index);
}
else {
m_futureInterface.reportResult(result.value<T>(), index);
}
m_futureInterface.reportFinished();
}
virtual void reportAborted()
{
m_futureInterface.reportCanceled();
}
virtual void reportTimeout()
{
m_futureInterface.reportCanceled();
}
private:
QFutureInterface<T> m_futureInterface;
VariantConversion m_convert;
};
}
{% endblock %}
{% block metasystem %}
Q_DECLARE_METATYPE({{ project.namespace }}::RpcFutureInterfaceBase*)
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment