diff --git a/codegen/facelift/facelift-codegen.py b/codegen/facelift/facelift-codegen.py index 612c2ab5..26b55e22 100755 --- a/codegen/facelift/facelift-codegen.py +++ b/codegen/facelift/facelift-codegen.py @@ -139,21 +139,23 @@ def referencedTypes(self): insertUniqueType(param, types) return types -def appendTypeIfStructure(symbol, list): +def appendTypeIfStructureAndUnique(symbol, unique_list): type = symbol.type.nested if symbol.type.nested else symbol.type - if type.is_struct: - list.append(type) + if type.is_struct and type.name not in (t.name for t in unique_list): + unique_list.append(type) def referencedStructureTypes(self): interfaces = [] for property in self.properties: - appendTypeIfStructure(property, interfaces) + appendTypeIfStructureAndUnique(property, interfaces) for m in self.operations: for param in m.parameters: - appendTypeIfStructure(param, interfaces) + appendTypeIfStructureAndUnique(param, interfaces) + if m.hasReturnValue: + appendTypeIfStructureAndUnique(m.type, interfaces) for m in self.signals: for param in m.parameters: - appendTypeIfStructure(param, interfaces) + appendTypeIfStructureAndUnique(param, interfaces) return interfaces def appendTypeIfInterface(symbol, list): @@ -201,6 +203,9 @@ def isQMLImplementationEnabled(self): def isSerializable(self): return True if self.tags.get('serializable') else generateAll +def toByteArrayOverDBus(self): + return True if self.tags.get('toByteArrayOverDBus') else generateAll + def isQObjectWrapperEnabled(self): return True if self.tags.get('qml-component') else False @@ -299,6 +304,7 @@ def cppMethodArgumentType(self): setattr(qface.idl.domain.Struct, 'verifyStruct', property(verifyStruct)) setattr(qface.idl.domain.Struct, 'isSerializable', property(isSerializable)) +setattr(qface.idl.domain.Struct, 'toByteArrayOverDBus', property(toByteArrayOverDBus)) setattr(qface.idl.domain.Struct, 'isQObjectWrapperEnabled', property(isQObjectWrapperEnabled)) setattr(qface.idl.domain.Struct, 'isQObjectWrapperDeprecated', property(isQObjectWrapperDeprecated)) diff --git a/codegen/facelift/templates/IPCCommon.template.h b/codegen/facelift/templates/IPCCommon.template.h index 9266e859..1f42ce09 100644 --- a/codegen/facelift/templates/IPCCommon.template.h +++ b/codegen/facelift/templates/IPCCommon.template.h @@ -45,25 +45,12 @@ class {{interfaceName}}IPCCommon {{operation.name}}, {% endfor %} {% for property in interface.properties %} - {% if (not property.readonly) %} - set{{property.name}}, - {% endif %} {% if (property.type.is_model) %} {{property.name}}, // model {% endif %} {% endfor %} }; - enum class SignalID { - invalid = static_cast(facelift::CommonSignalID::firstSpecific), - {% for signal in interface.signals %} - {{signal.name}}, - {% endfor %} - {% for property in interface.properties %} - {{property.name}}, - {% endfor %} - }; - }; {{module.namespaceCppClose}} diff --git a/codegen/facelift/templates/IPCDBusProxyAdapter.template.cpp b/codegen/facelift/templates/IPCDBusProxyAdapter.template.cpp index 2d88467c..d4fe5fc9 100644 --- a/codegen/facelift/templates/IPCDBusProxyAdapter.template.cpp +++ b/codegen/facelift/templates/IPCDBusProxyAdapter.template.cpp @@ -34,4 +34,6 @@ ****************************************************************************/ {% set baseClass = "::facelift::dbus::DBusIPCProxy<" + interfaceName + ">" %} {% set proxyTypeNameSuffix = "IPCDBusProxy" %} +{% set proxyType = "DBus" %} + {% include "IPCProxyAdapter.template.cpp" %} diff --git a/codegen/facelift/templates/IPCDBusProxyAdapter.template.h b/codegen/facelift/templates/IPCDBusProxyAdapter.template.h index 41ec8d1f..33e0f75f 100644 --- a/codegen/facelift/templates/IPCDBusProxyAdapter.template.h +++ b/codegen/facelift/templates/IPCDBusProxyAdapter.template.h @@ -34,6 +34,7 @@ ****************************************************************************/ {% set baseClass = "::facelift::dbus::DBusIPCProxy<" + interfaceName + ">" %} {% set proxyTypeNameSuffix = "IPCDBusProxy" %} +{% set proxyType = "DBus" %} #include "DBusIPCProxy.h" diff --git a/codegen/facelift/templates/IPCDBusServiceAdapter.template.cpp b/codegen/facelift/templates/IPCDBusServiceAdapter.template.cpp index edea8dfe..b2fd93c9 100644 --- a/codegen/facelift/templates/IPCDBusServiceAdapter.template.cpp +++ b/codegen/facelift/templates/IPCDBusServiceAdapter.template.cpp @@ -34,5 +34,6 @@ ****************************************************************************/ {% set baseClass = "::facelift::dbus::IPCDBusServiceAdapter<" + interfaceName + ">" %} {% set proxyTypeNameSuffix = "IPCDBusAdapter" %} +{% set proxyType = "DBus" %} {% include "IPCServiceAdapter.template.cpp" %} diff --git a/codegen/facelift/templates/IPCDBusServiceAdapter.template.h b/codegen/facelift/templates/IPCDBusServiceAdapter.template.h index b5800895..bd079463 100644 --- a/codegen/facelift/templates/IPCDBusServiceAdapter.template.h +++ b/codegen/facelift/templates/IPCDBusServiceAdapter.template.h @@ -42,6 +42,7 @@ #include "IPCDBusServiceAdapter.h" #include "IPCAdapterModelPropertyHandler.h" #include "DBusManager.h" +#include "FaceliftDBusMarshaller.h" #include "{{module.fullyQualifiedPath}}/{{interfaceName}}.h" #include "{{module.fullyQualifiedPath}}/{{interfaceName}}QMLAdapter.h" @@ -65,7 +66,6 @@ class {{className}}: public {{baseClass}} using ServiceType = {{interfaceName}}; using BaseType = {{baseClass}}; using ThisType = {{className}}; - using SignalID = {{interface}}IPCCommon::SignalID; using MethodID = {{interface}}IPCCommon::MethodID; {{className}}(QObject* parent = nullptr) : @@ -85,7 +85,13 @@ class {{className}}: public {{baseClass}} void connectSignals() override; - void serializePropertyValues(OutputIPCMessage& msg, bool isCompleteSnapshot) override; + QVariantMap dirtyProperties(); + + QVariantMap marshalProperties() override; + + QVariant marshalProperty(const QString& propertyName) override; + + void setProperty(const QString& propertyName, const QVariant& value) override; {% for event in interface.signals %} void {{event}}( @@ -94,7 +100,7 @@ class {{className}}: public {{baseClass}} {{ comma() }}{{parameter.interfaceCppType}} {{parameter.name}} {%- endfor -%} ) { - sendSignal(SignalID::{{event}} + sendSignal(QLatin1String("{{event}}") {%- for parameter in event.parameters -%} , {{parameter.name}} {%- endfor -%} ); @@ -105,14 +111,9 @@ class {{className}}: public {{baseClass}} {% for property in interface.properties %} {% if property.type.is_model %} ::facelift::IPCAdapterModelPropertyHandler m_{{property.name}}Handler; - {% elif property.type.is_interface %} - QString m_previous{{property.name}}ObjectPath; {% else %} {{property.interfaceCppType}} m_previous{{property.name}} {}; {% endif %} - {% if property.type.is_interface %} - InterfacePropertyIPCAdapterHandler<{{property.cppType}}, {{property.cppType}}{{proxyTypeNameSuffix}}> m_{{property.name}}; - {% endif %} {% endfor %} }; diff --git a/codegen/facelift/templates/IPCProxyAdapter.template.cpp b/codegen/facelift/templates/IPCProxyAdapter.template.cpp index e7d50b71..73c3aedf 100644 --- a/codegen/facelift/templates/IPCProxyAdapter.template.cpp +++ b/codegen/facelift/templates/IPCProxyAdapter.template.cpp @@ -36,14 +36,10 @@ {% set className = interfaceName + proxyTypeNameSuffix %} #include "{{className}}.h" - {{module.namespaceCppOpen}} {{className}}::{{className}}(QObject *parent) : BaseType(parent) {% for property in interface.properties %} - {% if property.type.is_interface %} - , m_{{property.name}}Proxy(*this) - {% endif %} {% if property.type.is_model %} , m_{{property.name}}(*this) {% endif %} @@ -55,36 +51,34 @@ {% endif %} } -void {{className}}::deserializePropertyValues(InputIPCMessage &msg, bool isCompleteSnapshot) +void {{className}}::unmarshalProperties(const QVariantMap& values) { {% for property in interface.properties %} - {% if property.type.is_interface %} bool emit_{{property.name}}ChangeSignal = false; - QString {{property.name}}_objectPath; - if (deserializeOptionalValue(msg, {{property.name}}_objectPath, isCompleteSnapshot)) - { - m_{{property.name}}Proxy.update({{property.name}}_objectPath); - m_{{property.name}} = m_{{property.name}}Proxy.getValue(); - emit_{{property.name}}ChangeSignal = true; - } + if (values.contains(QLatin1String("{{property.name}}"))) { + {% if property.type.is_interface %} + const {{property.interfaceCppType}} previous_{{property.name}}_Value = m_{{property.name}}; + m_{{property.name}} = castFromQVariant<{{property.interfaceCppType}}>(values[QLatin1String("{{property.name}}")]); + emit_{{property.name}}ChangeSignal = ((previous_{{property.name}}_Value != m_{{property.name}})); {% elif property.type.is_model %} - bool emit_{{property.name}}ChangeSignal = false; - if (isCompleteSnapshot) { - int {{property.name}}Size; - deserializeValue(msg, {{property.name}}Size); + int {{property.name}}Size = castFromQVariant(values[QLatin1String("{{property.name}}")]); m_{{property.name}}.beginResetModel(); m_{{property.name}}.reset({{property.name}}Size, std::bind(&ThisType::{{property.name}}Data, this, std::placeholders::_1)); m_{{property.name}}.endResetModel(); emit_{{property.name}}ChangeSignal = true; - } {% else %} - const auto previous_{{property.name}}_Value = m_{{property.name}}; - deserializeOptionalValue(msg, m_{{property.name}}, isCompleteSnapshot); - bool emit_{{property.name}}ChangeSignal = isCompleteSnapshot && ((previous_{{property.name}}_Value != m_{{property.name}})); + const auto previous_{{property.name}}_Value = m_{{property.name}}; + m_{{property.name}} = castFromQVariant<{{property.interfaceCppType}}>(values[QLatin1String("{{property.name}}")]); + emit_{{property.name}}ChangeSignal = ((previous_{{property.name}}_Value != m_{{property.name}})); {% endif %} + } {% endfor %} - - bool emit_ReadyChangeSignal = deserializeReadyValue(msg, isCompleteSnapshot) && isCompleteSnapshot; + bool emit_ReadyChangeSignal = false; + if (values.contains(QLatin1String("ready"))) { + bool previousIsReady = this->ready(); + m_serviceReady = castFromQVariant(values[QLatin1String("ready")]); + emit_ReadyChangeSignal = (previousIsReady != m_serviceReady); + } {% for property in interface.properties %} if (emit_{{property.name}}ChangeSignal) @@ -93,39 +87,63 @@ void {{className}}::deserializePropertyValues(InputIPCMessage &msg, bool isCompl if (emit_ReadyChangeSignal) emit readyChanged(); - } -void {{className}}::deserializeSignal(InputIPCMessage &msg) +void {{className}}::handleSignals(InputIPCMessage& msg) { - SignalID member; - deserializeValue(msg, member); - + Q_UNUSED(msg) {% for event in interface.signals %} - if (member == SignalID::{{event}}) - { + if (msg.member() == QLatin1String("{{event}}")) { + QListIterator argumentsIterator(msg.arguments()); {% for parameter in event.parameters %} {{parameter.interfaceCppType}} param_{{parameter.name}}; - deserializeValue(msg, param_{{parameter.name}}); + param_{{parameter.name}} = (argumentsIterator.hasNext() ? castFromQVariant<{{parameter.interfaceCppType}}>(argumentsIterator.next()):{% if not parameter.type.is_interface %}{{parameter.interfaceCppType}}(){% else %}nullptr{% endif %}); {% endfor %} emit {{event}}( {%- set comma = joiner(", ") -%} {%- for parameter in event.parameters -%} {{ comma() }}param_{{parameter.name}} {%- endfor -%} ); - } else + } {% endfor %} + + {% if interface.hasModelProperty %} + this->onModelUpdateEvent(msg); + {% endif %} +} +{% if proxyType and proxyType == "DBus" %} +const QList& {{className}}::getSignals() const +{ + static QList allSignals{ + {% for event in interface.signals %} + "{{event}}", + {% endfor %} + {% if interface.hasModelProperty %} + facelift::IPCCommon::MODEL_DATA_CHANGED_MESSAGE_NAME, + facelift::IPCCommon::MODEL_INSERT_MESSAGE_NAME, + facelift::IPCCommon::MODEL_REMOVE_MESSAGE_NAME, + facelift::IPCCommon::MODEL_MOVE_MESSAGE_NAME, + facelift::IPCCommon::MODEL_RESET_MESSAGE_NAME, + {% endif %} + }; + + return allSignals; +} +{% endif %} +{% if interface.hasModelProperty %} +void {{className}}::onModelUpdateEvent(const InputIPCMessage& msg) +{ + QListIterator argumentsIterator(msg.arguments()); + const QString& modelPropertyName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); {% for property in interface.properties %} - if (member == SignalID::{{property.name}}) { {% if property.type.is_model %} + if (modelPropertyName == QLatin1String("{{property.name}}")) { m_{{property.name}}.handleSignal(msg); - {% else %} - emit {{property.name}}Changed(); + } {% endif %} - } else {% endfor %} - BaseType::deserializeCommonSignal(static_cast(member), this); } +{% endif %} {% for property in interface.properties %} @@ -134,7 +152,7 @@ void {{className}}::deserializeSignal(InputIPCMessage &msg) void {{className}}::set{{property}}({{property.cppMethodArgumentType}} newValue) { {% if (not property.type.is_interface) %} - ipc()->sendSetterCall(memberID(MethodID::set{{property.name}}, "set{{property.name}}"), newValue); + ipc()->sendSetterCall(QLatin1String("{{property.name}}"), newValue); {% else %} Q_ASSERT(false); // Writable interface properties are unsupported {% endif %} @@ -168,12 +186,11 @@ void {{className}}::{{operation.name}}( {%- endfor -%} ){% if operation.is_const %} const{% endif %} { {% if (operation.hasReturnValue) %} - {{operation.interfaceCppType}} returnValue; - ipc()->sendMethodCallWithReturn(memberID(MethodID::{{operation.name}}, "{{operation.name}}"), returnValue + QList args = ipc()->sendMethodCallWithReturn(memberID(MethodID::{{operation.name}}, "{{operation.name}}") {%- for parameter in operation.parameters -%} , {{parameter.name}} {%- endfor -%} ); - return returnValue; + return (!args.isEmpty() ? castFromQVariant<{{operation.interfaceCppType}}>(args.first()):{% if not (operation.type.is_interface) %}{{operation.cppType}}(){% else %}nullptr{% endif %}); {% else %} ipc()->sendMethodCall(memberID(MethodID::{{operation.name}}, "{{operation.name}}") {%- for parameter in operation.parameters -%} diff --git a/codegen/facelift/templates/IPCProxyAdapter.template.h b/codegen/facelift/templates/IPCProxyAdapter.template.h index b7d0a793..662fd570 100644 --- a/codegen/facelift/templates/IPCProxyAdapter.template.h +++ b/codegen/facelift/templates/IPCProxyAdapter.template.h @@ -58,7 +58,6 @@ class {{className}} : public {{baseClass}} using ThisType = {{className}}; using BaseType = {{baseClass}}; - using SignalID = {{interface}}IPCCommon::SignalID; using MethodID = {{interface}}IPCCommon::MethodID; // override the default QMLAdapter type to add the IPC related properties @@ -66,7 +65,7 @@ class {{className}} : public {{baseClass}} {{className}}(QObject *parent = nullptr); - void deserializePropertyValues(InputIPCMessage &msg, bool isCompleteSnapshot) override; + void unmarshalProperties(const QVariantMap& values) override; {% if interface.hasModelProperty %} void setServiceRegistered(bool isRegistered) override @@ -83,7 +82,11 @@ class {{className}} : public {{baseClass}} {% endif %} - void deserializeSignal(InputIPCMessage &msg) override; + void handleSignals(InputIPCMessage& msg) override; + + {% if proxyType and proxyType == "DBus" %} + const QList& getSignals() const override; + {% endif %} {% for operation in interface.operations %} @@ -120,7 +123,6 @@ class {{className}} : public {{baseClass}} } {% elif property.type.is_list %} - const {{property.interfaceCppType}}& {{property}}() const override { return m_{{property.name}}; @@ -148,15 +150,22 @@ class {{className}} : public {{baseClass}} {% endif %} {% endfor %} + {% if interface.hasModelProperty %} + void onModelUpdateEvent(const InputIPCMessage& msg); + + Q_SIGNAL void ModelUpdateEventDataChanged(const InputIPCMessage& msg); + Q_SIGNAL void ModelUpdateEventInsert(const InputIPCMessage& msg); + Q_SIGNAL void ModelUpdateEventRemove(const InputIPCMessage& msg); + Q_SIGNAL void ModelUpdateEventMove(const InputIPCMessage& msg); + Q_SIGNAL void ModelUpdateEventReset(const InputIPCMessage& msg); + {% endif %} private: {% for property in interface.properties %} - {% if property.type.is_interface %} - InterfacePropertyIPCProxyHandler<{{property.cppType}}{{proxyTypeNameSuffix}}> m_{{property.name}}Proxy; - {% endif %} {% if property.type.is_model %} facelift::IPCProxyModelProperty m_{{property.name}}; {% endif %} {% endfor %} + }; diff --git a/codegen/facelift/templates/IPCServiceAdapter.template.cpp b/codegen/facelift/templates/IPCServiceAdapter.template.cpp index 068ed434..836691fd 100644 --- a/codegen/facelift/templates/IPCServiceAdapter.template.cpp +++ b/codegen/facelift/templates/IPCServiceAdapter.template.cpp @@ -35,9 +35,10 @@ {% set className = interfaceName + proxyTypeNameSuffix %} +#include "ipc-common.h" +#include "DBusSignatureHelper.h" #include "{{className}}.h" - {{module.namespaceCppOpen}} facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessage &requestMessage, @@ -45,7 +46,7 @@ facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessa { Q_UNUSED(replyMessage); // Since we do not always have return values Q_UNUSED(requestMessage); - + QListIterator argumentsIterator(requestMessage.arguments()); const auto &member = requestMessage.member(); Q_UNUSED(member); // In case there are no methods auto theService = service(); @@ -56,8 +57,7 @@ facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessa {% for operation in interface.operations %} if (member == memberID(MethodID::{{operation.name}}, "{{operation.name}}")) { {% for parameter in operation.parameters %} - {{parameter.cppType}} param_{{parameter.name}}; - deserializeValue(requestMessage, param_{{parameter.name}}); + {{parameter.cppType}} param_{{parameter.name}} = (argumentsIterator.hasNext() ? castFromQVariant<{{parameter.cppType}}>(argumentsIterator.next()):{% if not parameter.type.is_interface %}{{parameter.cppType}}(){% else %}nullptr{% endif %}); {% endfor %} {% if operation.isAsync %} theService->{{operation.name}}({% for parameter in operation.parameters %} param_{{parameter.name}}, {%- endfor -%} @@ -75,7 +75,7 @@ facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessa {{ comma() }}param_{{parameter.name}} {%- endfor -%}); {% if operation.hasReturnValue %} - serializeValue(replyMessage, returnValue); + replyMessage << castToQVariant(returnValue); {% endif %} {% endif %} } else @@ -83,18 +83,10 @@ facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessa {% for property in interface.properties %} {% if property.type.is_model %} if (member == memberID(MethodID::{{property.name}}, "{{property.name}}")) { - m_{{property.name}}Handler.handleModelRequest(requestMessage, replyMessage); - } else - {% endif %} - {% if (not property.readonly) %} - if (member == memberID(MethodID::set{{property.name}}, "set{{property.name}}")) { - {% if (not property.type.is_interface) %} - {{property.cppType}} value; - deserializeValue(requestMessage, value); - theService->set{{property.name}}(value); - {% else %} - Q_ASSERT(false); // Writable interface properties are unsupported - {% endif %} + QListIterator argumentsIterator(requestMessage.arguments()); + int first = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): int()); + int last = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): int()); + m_{{property.name}}Handler.handleModelRequest(first, last, replyMessage); } else {% endif %} {% endfor %} @@ -104,49 +96,47 @@ facelift::IPCHandlingResult {{className}}::handleMethodCallMessage(InputIPCMessa return facelift::IPCHandlingResult::OK; } - +{% if proxyType and proxyType == "DBus" %} void {{className}}::appendDBUSIntrospectionData(QTextStream &s) const { - Q_UNUSED(s); // For empty interfaces + Q_UNUSED(s) // For empty interfaces {% for property in interface.properties %} - ::facelift::DBusSignatureHelper::addPropertySignature(s, "{{property.name}}", {{ property.readonly | cppBool }}); + {% if not property.type.is_model %} + facelift::appendPropertySignature(s, "{{property.name}}", typeToSignature<{{property.type.interfaceCppType}}>(), {{ property.readonly | cppBool }}); + {% endif %} {% endfor %} - {% for operation in interface.operations %} + facelift::appendReadyProperty(s); - { - std::array argumentNames = { { - {%- for parameter in operation.parameters -%} - "{{parameter}}", - {%- endfor -%} - } }; - ::facelift::DBusSignatureHelper::addMethodSignature< - {%- set comma = joiner(", ") -%} - {%- for parameter in operation.parameters -%} - {{ comma() }}{{parameter.cppType}} - {%- endfor -%} - >(s, "{{operation.name}}", argumentNames); + {% for operation in interface.operations %} + facelift::appendDBusMethodSignature(s, "{{operation.name}}", std::list>{ + {%- set comma = joiner(", ") -%} + {% for parameter in operation.parameters %} + {{ comma() }}{"{{parameter.name}}", typeToSignature<{{parameter.type.interfaceCppType}}>()} + {% endfor %} } + {% if operation.hasReturnValue %} + , typeToSignature<{{operation.interfaceCppType}}>() + {% endif %} + ); {% endfor %} // signals {% for signal in interface.signals %} { - std::array argumentNames = { { - {%- for parameter in signal.parameters -%} - "{{parameter}}", - {%- endfor -%} - }}; - ::facelift::DBusSignatureHelper::addSignalSignature< - {%- set comma = joiner(", ") -%} - {%- for parameter in signal.parameters -%} - {{ comma() }}{{parameter.interfaceCppType}} - {%- endfor -%} - >(s, "{{signal.name}}", argumentNames); + facelift::appendDBusSignalSignature(s, "{{signal.name}}", std::list>{ + {%- set comma = joiner(", ") -%} + {% for parameter in signal.parameters %} + {{ comma() }}{"{{parameter.name}}", typeToSignature<{{parameter.type.interfaceCppType}}>()} + {% endfor %} + }); } - {% endfor %} -} + {% if interface.hasModelProperty %} + facelift::appendDBusModelSignals(s); + {% endif %} +} +{% endif %} void {{className}}::connectSignals() { auto theService = service(); @@ -154,54 +144,103 @@ void {{className}}::connectSignals() {% for property in interface.properties %} {% if property.type.is_model %} - m_{{property.name}}Handler.connectModel(SignalID::{{property.name}}, theService->{{property.name}}()); - {% elif property.type.is_interface %} + m_{{property.name}}Handler.connectModel(QLatin1String("{{property.name}}"), theService->{{property.name}}()); {% else %} m_previous{{property.name}} = theService->{{property.name}}(); {% endif %} {% endfor %} + m_previousReadyState = theService->ready(); // Properties {% for property in interface.properties %} - {% if property.type.is_interface %} - m_{{property.name}}.update(this, theService->{{property.name}}()); + {% if (not property.type.is_model) %} QObject::connect(theService, &ServiceType::{{property.name}}Changed, this, [this, theService] () { - m_{{property.name}}.update(this, theService->{{property.name}}()); + this->sendPropertiesChanged(dirtyProperties()); }); {% endif %} - QObject::connect(theService, &ServiceType::{{property.name}}Changed, this, [this] () { - this->sendSignal(SignalID::{{property.name}}); - }); {% endfor %} + QObject::connect(theService, &ServiceType::readyChanged, this, [this, theService] () { + this->sendPropertiesChanged(dirtyProperties()); + }); + // Signals {% for signal in interface.signals %} QObject::connect(theService, &ServiceType::{{signal}}, this, &ThisType::{{signal}}); {% endfor %} } -void {{className}}::serializePropertyValues(OutputIPCMessage& msg, bool isCompleteSnapshot) +QVariantMap {{className}}::dirtyProperties() +{ + QMap ret; + auto theService = service(); + Q_UNUSED(theService); + {% for property in interface.properties %} + {% if not property.type.is_model %} + if (m_previous{{property.name}} != theService->{{property.name}}()) { + ret[QLatin1String("{{property.name}}")] = castToQVariant(theService->{{property.name}}()); + m_previous{{property.name}} = theService->{{property.name}}(); + } + {% endif %} + {% endfor %} + if (m_previousReadyState != theService->ready()) { + ret[QLatin1String("ready")] = castToQVariant(theService->ready()); + m_previousReadyState = theService->ready(); + } + return ret; +} + +QVariantMap {{className}}::marshalProperties() { + QVariantMap ret; auto theService = service(); {#% if (not interface.properties) %#} Q_UNUSED(theService); {#% endif %#} {% for property in interface.properties %} - {% if property.type.is_interface %} + {% if property.type.is_model %} + ret[QLatin1String("{{property.name}}")] = castToQVariant(theService->{{property.name}}().size()); + {% else %} + ret[QLatin1String("{{property.name}}")] = castToQVariant(theService->{{property.name}}()); + {% endif %} + {% endfor %} + ret[QLatin1String("ready")] = castToQVariant(theService->ready()); + return ret; +} - serializeOptionalValue(msg, m_{{property.name}}.objectPath(), m_previous{{property.name}}ObjectPath, isCompleteSnapshot); +QVariant {{className}}::marshalProperty(const QString& propertyName) +{ + {% for property in interface.properties %} + if (propertyName == QLatin1String("{{property.name}}")) { + {% if property.type.is_model %} - {% elif property.type.is_model %} - if (isCompleteSnapshot) { - serializeValue(msg, theService->{{property.name}}().size()); - } {% else %} - serializeOptionalValue(msg, theService->{{property.name}}(), m_previous{{property.name}}, isCompleteSnapshot); + return castToQVariant(service()->{{property.name}}()); {% endif %} + } {% endfor %} + if (propertyName == QLatin1String("ready")) { + return castToQVariant(service()->ready()); + } +return QVariant(); +} - BaseType::serializePropertyValues(msg, isCompleteSnapshot); +void {{className}}::setProperty(const QString& propertyName, const QVariant& value) +{ + Q_UNUSED(propertyName) + Q_UNUSED(value) + {% for property in interface.properties %} + if (propertyName == QLatin1String("{{property.name}}")) { + {% if property.type.is_interface %} + Q_ASSERT(false); // Writable interface properties are unsupported + {% elif property.type.is_model %} + + {% elif (not property.readonly) %} + service()->set{{property.name}}(castFromQVariant<{{property.cppType}}>(value)); + {% endif %} + } + {% endfor %} } {{module.namespaceCppClose}} diff --git a/codegen/facelift/templates/IPCServiceAdapter.template.h b/codegen/facelift/templates/IPCServiceAdapter.template.h index 4b1b0442..07744034 100644 --- a/codegen/facelift/templates/IPCServiceAdapter.template.h +++ b/codegen/facelift/templates/IPCServiceAdapter.template.h @@ -62,7 +62,6 @@ class {{className}}: public {{baseClass}} using ServiceType = {{interfaceName}}; using BaseType = {{baseClass}}; using ThisType = {{className}}; - using SignalID = {{interface}}IPCCommon::SignalID; using MethodID = {{interface}}IPCCommon::MethodID; {{className}}(QObject* parent = nullptr) : BaseType(parent) @@ -73,15 +72,21 @@ class {{className}}: public {{baseClass}} {% endfor %} { } - + {% if proxyType and proxyType == "DBus" %} void appendDBUSIntrospectionData(QTextStream &s) const override; - + {% endif %} ::facelift::IPCHandlingResult handleMethodCallMessage(InputIPCMessage &requestMessage, OutputIPCMessage &replyMessage) override; void connectSignals() override; - void serializePropertyValues(OutputIPCMessage& msg, bool isCompleteSnapshot) override; + QVariantMap dirtyProperties(); + + QVariantMap marshalProperties() override; + + QVariant marshalProperty(const QString& propertyName) override; + + void setProperty(const QString& propertyName, const QVariant& value) override; {% for event in interface.signals %} void {{event}}( @@ -90,7 +95,7 @@ class {{className}}: public {{baseClass}} {{ comma() }}{{parameter.interfaceCppType}} {{parameter.name}} {%- endfor -%} ) { - sendSignal(SignalID::{{event}} + sendSignal(QLatin1String("{{event}}") {%- for parameter in event.parameters -%} , {{parameter.name}} {%- endfor -%} ); @@ -101,15 +106,11 @@ class {{className}}: public {{baseClass}} {% for property in interface.properties %} {% if property.type.is_model %} ::facelift::IPCAdapterModelPropertyHandler m_{{property.name}}Handler; - {% elif property.type.is_interface %} - QString m_previous{{property.name}}ObjectPath; {% else %} {{property.interfaceCppType}} m_previous{{property.name}} {}; {% endif %} - {% if property.type.is_interface %} - InterfacePropertyIPCAdapterHandler<{{property.cppType}}, {{property.cppType}}{{proxyTypeNameSuffix}}> m_{{property.name}}; - {% endif %} {% endfor %} + bool m_previousReadyState = false; }; {{module.namespaceCppClose}} diff --git a/codegen/facelift/templates/Service.template.h b/codegen/facelift/templates/Service.template.h index 05e6ce65..88d503c2 100644 --- a/codegen/facelift/templates/Service.template.h +++ b/codegen/facelift/templates/Service.template.h @@ -122,9 +122,6 @@ class {{interfaceName}} : public facelift::InterfaceBase { return facelift::ServicePropertyInterface(this, &ThisType::{{property}}, &ThisType::{{property}}Changed); } - {% if (not property.readonly) %} - virtual void set{{property}}( {{property.cppMethodArgumentType}} newValue) = 0; - {% endif %} {% else %} using PropertyType_{{property}} = {{property.interfaceCppType}}; virtual const {{property.interfaceCppType}}& {{property}}() const = 0; diff --git a/codegen/facelift/templates/Struct.template.cpp b/codegen/facelift/templates/Struct.template.cpp index 7fc2dbd2..75649dcf 100644 --- a/codegen/facelift/templates/Struct.template.cpp +++ b/codegen/facelift/templates/Struct.template.cpp @@ -95,6 +95,12 @@ void {{struct.name}}::deserialize(const QByteArray &array) {% endif %} +{% if struct.toByteArrayOverDBus %} +bool {{struct.name}}::toByteArrayOverDBus() +{ + return true; +} +{% endif %} const {{struct}}::FieldNames {{struct}}::FIELD_NAMES = { { {%- for field in struct.fields -%} @@ -126,5 +132,4 @@ QString {{struct.name}}::toString() const return toStringWithFields(CLASS_ID, FIELD_NAMES); } - {{module.namespaceCppClose}} diff --git a/codegen/facelift/templates/Struct.template.h b/codegen/facelift/templates/Struct.template.h index cc69a14c..6a1375f5 100644 --- a/codegen/facelift/templates/Struct.template.h +++ b/codegen/facelift/templates/Struct.template.h @@ -96,6 +96,10 @@ class {{struct.name}} : public facelift::Structure< {% endif %} + {% if struct.toByteArrayOverDBus %} + static bool toByteArrayOverDBus(); + {% endif %} + QString toString() const; {% for field in struct.fields %} @@ -126,7 +130,6 @@ class {{struct.name}} : public facelift::Structure< {% endfor -%} }; - {{module.namespaceCppClose}} inline QTextStream &operator <<(QTextStream &outStream, const {{struct.fullyQualifiedCppType}} &f) @@ -144,8 +147,10 @@ inline QDebug operator<< (QDebug d, const {{struct.fullyQualifiedCppType}} &f) return d; } +typedef QMap QMapOf{{struct.fullyQualifiedCppType|replace("::","")}}; + Q_DECLARE_METATYPE(QList<{{struct.fullyQualifiedCppType}}>) // Needed for list properties -//Q_DECLARE_METATYPE(QMap) // TODO: Needed for map properties? +Q_DECLARE_METATYPE(QMapOf{{struct.fullyQualifiedCppType|replace("::","")}}) Q_DECLARE_METATYPE({{struct.fullyQualifiedCppType}}) diff --git a/doc/page-annotations.h b/doc/page-annotations.h index 34f50d2c..03a6f8ee 100644 --- a/doc/page-annotations.h +++ b/doc/page-annotations.h @@ -39,6 +39,7 @@ The following annotations can be used in structure definitions: |Annotation | Description | Supported over IPC | |-------------------------------|-------------------------------------------------------------|--------------------| +|\@toByteArrayOverDBus: true | Serialize the whole structure as one byte array over IPC reducing structure signature only to DBUS Type ARRAY OF BYTE | Yes | |\@serializable: true | Adds serialization/deserialization capability to the structure | Yes | |\@qml-component: true | Enables the creation and registration of a creatable QML component for the corresponding structure | Yes | diff --git a/src/ipc/dbus/CMakeLists.txt b/src/ipc/dbus/CMakeLists.txt index 1897e1b0..1adb68b0 100644 --- a/src/ipc/dbus/CMakeLists.txt +++ b/src/ipc/dbus/CMakeLists.txt @@ -17,6 +17,7 @@ if(Qt5DBus_FOUND) DBusIPCProxyBinder.cpp DBusManager.cpp HEADERS + DBusIPCCommon.h DBusObjectRegistry.h DBusIPCProxyBinder.h IPCDBusServiceAdapterBase.h @@ -26,6 +27,7 @@ if(Qt5DBus_FOUND) DBusManager.h DBusManagerInterface.h DBusIPCProxy.h + FaceliftDBusMarshaller.h IPCDBusServiceAdapter.h SOURCES_GLOB_RECURSE ${GENERATED_FILE_PATH}/ipc/*.cpp diff --git a/src/ipc/dbus/DBusIPCCommon.h b/src/ipc/dbus/DBusIPCCommon.h index 44f02927..ff990ae1 100644 --- a/src/ipc/dbus/DBusIPCCommon.h +++ b/src/ipc/dbus/DBusIPCCommon.h @@ -35,13 +35,14 @@ namespace dbus { using namespace facelift; struct DBusIPCCommon { - static constexpr const char *GET_PROPERTIES_MESSAGE_NAME = "GetAllProperties"; + static constexpr const char *DEFAULT_SERVICE_NAME = "facelift.registry"; + static constexpr const char *GET_ALL_PROPERTIES_MESSAGE_NAME = "GetAll"; + static constexpr const char *GET_PROPERTY_MESSAGE_NAME = "Get"; + static constexpr const char *SET_PROPERTY_MESSAGE_NAME = "Set"; static constexpr const char *PROPERTIES_CHANGED_SIGNAL_NAME = "PropertiesChanged"; - static constexpr const char *SIGNAL_TRIGGERED_SIGNAL_NAME = "SignalTriggered"; - static constexpr const char *SET_PROPERTY_MESSAGE_NAME = "SetProperty"; - static constexpr const char *INTROSPECTABLE_INTERFACE_NAME = "org.freedesktop.DBus.Introspectable"; static constexpr const char *PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; - static constexpr const char *DEFAULT_SERVICE_NAME = "facelift.registry"; + static constexpr const char *INTROSPECTABLE_INTERFACE_NAME = "org.freedesktop.DBus.Introspectable"; + static constexpr const int FACELIFT_DBUS_MAXIMUM_SIGNATURE_LENGTH = 255; }; } diff --git a/src/ipc/dbus/DBusIPCMessage.cpp b/src/ipc/dbus/DBusIPCMessage.cpp index cd7b6056..f259afa4 100644 --- a/src/ipc/dbus/DBusIPCMessage.cpp +++ b/src/ipc/dbus/DBusIPCMessage.cpp @@ -67,6 +67,17 @@ DBusIPCMessage::DBusIPCMessage(const QString &path, const QString &interface, co m_message = QDBusMessage::createSignal(path, interface, signal); } +QList DBusIPCMessage::arguments() const +{ + return m_message.arguments(); +} + +DBusIPCMessage &DBusIPCMessage::operator<<(const QVariant &arg) +{ + m_message << arg; + return *this; +} + QString DBusIPCMessage::member() const { return m_message.member(); @@ -99,9 +110,9 @@ DBusIPCMessage DBusIPCMessage::createReply() return DBusIPCMessage(m_message.createReply()); } -DBusIPCMessage DBusIPCMessage::createErrorReply(const QString &msg, const QString &member) +DBusIPCMessage DBusIPCMessage::createErrorReply(const QString &name, const QString &msg) { - return DBusIPCMessage(m_message.createErrorReply(msg, member)); + return DBusIPCMessage(m_message.createErrorReply(name, msg)); } QString DBusIPCMessage::signature() const @@ -119,28 +130,7 @@ bool DBusIPCMessage::isErrorMessage() const return (m_message.type() == QDBusMessage::ErrorMessage); } -OutputPayLoad &DBusIPCMessage::outputPayLoad() -{ - if (m_outputPayload == nullptr) { - m_outputPayload = std::make_unique(m_payload); - } - return *m_outputPayload; -} - -InputPayLoad &DBusIPCMessage::inputPayLoad() -{ - if (m_inputPayload == nullptr) { - m_payload = m_message.arguments()[0].value(); - m_inputPayload = std::make_unique(m_payload); - } - return *m_inputPayload; -} - QDBusMessage& DBusIPCMessage::outputMessage() { - if (m_outputPayload) { - m_message << m_outputPayload->getContent(); - m_outputPayload.reset(); - } return m_message; } diff --git a/src/ipc/dbus/DBusIPCMessage.h b/src/ipc/dbus/DBusIPCMessage.h index d3b5f136..9f269bf0 100644 --- a/src/ipc/dbus/DBusIPCMessage.h +++ b/src/ipc/dbus/DBusIPCMessage.h @@ -54,20 +54,17 @@ class DBusIPCMessage QString member() const; QString toString() const; + QList arguments() const; + DBusIPCMessage &operator<<(const QVariant &arg); DBusIPCMessage createReply(); - DBusIPCMessage createErrorReply(const QString &msg, const QString &member); + DBusIPCMessage createErrorReply(const QString &name, const QString &msg); QString signature() const; bool isReplyMessage() const; bool isErrorMessage() const; - OutputPayLoad &outputPayLoad(); - InputPayLoad &inputPayLoad(); QDBusMessage& outputMessage(); private: QDBusMessage m_message; - QByteArray m_payload; - std::unique_ptr m_outputPayload; - std::unique_ptr m_inputPayload; }; } // end namespace dbus diff --git a/src/ipc/dbus/DBusIPCProxy.h b/src/ipc/dbus/DBusIPCProxy.h index 770c07e6..a2ad6674 100644 --- a/src/ipc/dbus/DBusIPCProxy.h +++ b/src/ipc/dbus/DBusIPCProxy.h @@ -72,42 +72,6 @@ class DBusIPCProxy : public IPCProxyBase, protected DBusRequestHa return memberName; } - template - void serializeValue(DBusIPCMessage &msg, const Type &v) - { - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg, IPCTypeRegisterHandler::convertToSerializedType(v, *this)); - } - - template - void deserializeValue(DBusIPCMessage &msg, Type &v) - { - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); - } - - template - bool deserializeOptionalValue(DBusIPCMessage &msg, Type &value, bool isCompleteSnapshot) - { - bool b = true; - if (!isCompleteSnapshot) { - msg.inputPayLoad().readNextParameter(b); - } - if (b) { - this->deserializeValue(msg, value); - } - return b; - } - - bool deserializeReadyValue(DBusIPCMessage &msg, bool isCompleteSnapshot) - { - bool previousIsReady = this->ready(); - deserializeOptionalValue(msg, this->m_serviceReady, isCompleteSnapshot); - return (this->ready() != previousIsReady); - } - void setServiceRegistered(bool isRegistered) override { bool oldReady = this->ready(); @@ -135,6 +99,11 @@ class DBusIPCProxy : public IPCProxyBase, protected DBusRequestHa m_ipcBinder.connectToServer(); } + template + T castFromQVariant(const QVariant& value) { + return m_ipcBinder.castFromQVariant(value); + } + protected: bool m_serviceRegistered = false; private: diff --git a/src/ipc/dbus/DBusIPCProxyBinder.cpp b/src/ipc/dbus/DBusIPCProxyBinder.cpp index 636fbb0b..87ed3e42 100644 --- a/src/ipc/dbus/DBusIPCProxyBinder.cpp +++ b/src/ipc/dbus/DBusIPCProxyBinder.cpp @@ -32,7 +32,6 @@ #include "DBusIPCProxyBinder.h" #include "DBusManagerInterface.h" #include "DBusRequestHandler.h" -#include "DBusIPCCommon.h" #include "DBusObjectRegistry.h" namespace facelift { @@ -60,25 +59,23 @@ void DBusIPCProxyBinder::setInterfaceName(const QString &name) checkInit(); } -void DBusIPCProxyBinder::onServerNotAvailableError(const char *methodName) const +void DBusIPCProxyBinder::onServerNotAvailableError(const QString &propertyName) const { qCCritical(LogIpc, "Error message received when calling method '%s' on service at path '%s'. " "This likely indicates that the server you are trying to access is not available yet", - qPrintable(methodName), qPrintable(objectPath())); + qPrintable(propertyName), qPrintable(objectPath())); } void DBusIPCProxyBinder::onPropertiesChanged(const QDBusMessage &dbusMessage) { DBusIPCMessage msg(dbusMessage); - m_serviceObject->deserializePropertyValues(msg, false); -} - -void DBusIPCProxyBinder::onSignalTriggered(const QDBusMessage &dbusMessage) -{ - DBusIPCMessage msg(dbusMessage); - m_serviceObject->deserializePropertyValues(msg, false); - m_serviceObject->deserializeSignal(msg); + QListIterator argumentsIterator(msg.arguments()); + QString interfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (interfaceName == m_interfaceName) { + QVariantMap dirtyProperties = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QVariantMap()); + m_serviceObject->unmarshalProperties(dirtyProperties); + } } void DBusIPCProxyBinder::setHandler(DBusRequestHandler *handler) @@ -90,11 +87,12 @@ void DBusIPCProxyBinder::setHandler(DBusRequestHandler *handler) void DBusIPCProxyBinder::requestPropertyValues() { - DBusIPCMessage msg(serviceName(), objectPath(), interfaceName(), DBusIPCCommon::GET_PROPERTIES_MESSAGE_NAME); - + DBusIPCMessage msg(serviceName(), objectPath(), DBusIPCCommon::PROPERTIES_INTERFACE_NAME, DBusIPCCommon::GET_ALL_PROPERTIES_MESSAGE_NAME); + msg << QVariant::fromValue(interfaceName()); auto replyHandler = [this](DBusIPCMessage &replyMessage) { if (replyMessage.isReplyMessage()) { - m_serviceObject->deserializePropertyValues(replyMessage, true); + QVariantMap values = (!replyMessage.arguments().isEmpty() ? castFromQVariant(replyMessage.arguments().first()): QVariantMap()); + m_serviceObject->unmarshalProperties(values); m_serviceObject->setServiceRegistered(true); } else { qCDebug(LogIpc) << "Service not yet available : " << objectPath(); @@ -115,16 +113,16 @@ void DBusIPCProxyBinder::onServiceNameKnown() auto& connection = m_dbusManager.connection(); auto successPropertyChangeSignal = connection.connect(m_serviceName, - objectPath(), m_interfaceName, DBusIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME, this, + objectPath(), DBusIPCCommon::PROPERTIES_INTERFACE_NAME, DBusIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME, this, SLOT(onPropertiesChanged(const QDBusMessage&))); Q_UNUSED(successPropertyChangeSignal); // TODO: check - auto successSignalTriggeredSignal = connection.connect(m_serviceName, - objectPath(), m_interfaceName, DBusIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME, this, - SLOT(onSignalTriggered(const QDBusMessage&))); - - Q_UNUSED(successSignalTriggeredSignal); // TODO: check + for (const QString& signalEntry: m_serviceObject->getSignals()) { + auto signalConnected = connection.connect(m_serviceName, + objectPath(), m_interfaceName, signalEntry, this, SLOT(handleGenericSignals(const QDBusMessage&))); + Q_UNUSED(signalConnected) // TODO: check + } m_busWatcher.addWatchedService(m_serviceName); m_busWatcher.setConnection(connection); @@ -155,12 +153,13 @@ void DBusIPCProxyBinder::checkRegistry() auto& connection = m_dbusManager.connection(); connection.disconnect(m_serviceName, - objectPath(), m_interfaceName, DBusIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME, this, + objectPath(), DBusIPCCommon::PROPERTIES_INTERFACE_NAME, DBusIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME, this, SLOT(onPropertiesChanged(const QDBusMessage&))); - connection.disconnect(m_serviceName, - objectPath(), m_interfaceName, DBusIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME, this, - SLOT(onSignalTriggered(const QDBusMessage&))); + for (const QString& signalEntry: m_serviceObject->getSignals()) { + connection.disconnect(m_serviceName, + objectPath(), interfaceName(), signalEntry, this, SLOT(handleGenericSignals(const QDBusMessage&))); + } setServiceAvailable(false); m_serviceName.clear(); @@ -168,6 +167,12 @@ void DBusIPCProxyBinder::checkRegistry() } } +void DBusIPCProxyBinder::handleGenericSignals(const QDBusMessage& msg) +{ + DBusIPCMessage dbusMsg(msg); + m_serviceObject->handleSignals(dbusMsg); +} + void DBusIPCProxyBinder::asyncCall(DBusIPCMessage &message, const QObject *context, std::function callback) { auto& connection = m_dbusManager.connection(); diff --git a/src/ipc/dbus/DBusIPCProxyBinder.h b/src/ipc/dbus/DBusIPCProxyBinder.h index 3a718f77..4bfde867 100644 --- a/src/ipc/dbus/DBusIPCProxyBinder.h +++ b/src/ipc/dbus/DBusIPCProxyBinder.h @@ -30,11 +30,15 @@ #pragma once +#include #include #include "IPCProxyBinderBase.h" #include "DBusIPCMessage.h" -#include "ipc-serialization.h" +#include "DBusIPCCommon.h" +#include "FaceliftUtils.h" +#include "FaceliftDBusMarshaller.h" #include "DBusManagerInterface.h" +#include "IPCServiceAdapterBase.h" class QDBusMessage; @@ -66,7 +70,7 @@ class DBusIPCProxyBinder : public IPCProxyBinderBase Q_SLOT void onPropertiesChanged(const QDBusMessage &dbusMessage); - Q_SLOT void onSignalTriggered(const QDBusMessage &dbusMessage); + Q_SLOT void handleGenericSignals(const QDBusMessage &msg); void bindToIPC() override; @@ -85,34 +89,129 @@ class DBusIPCProxyBinder : public IPCProxyBinderBase void asyncCall(DBusIPCMessage &message, const QObject *context, std::function callback); - template - void serializeValue(DBusIPCMessage &msg, const Type &v); - - template - void deserializeValue(DBusIPCMessage &msg, Type &v); - - void onServerNotAvailableError(const char *methodName) const; + void onServerNotAvailableError(const QString &propertyName) const; template - void sendSetterCall(const char *methodName, const PropertyType &value); + void sendSetterCall(const QString& property, const PropertyType &value); template - DBusIPCMessage sendMethodCall(const char *methodName, const Args & ... args) const; + DBusIPCMessage sendMethodCall(const char *methodName, Args && ... args) const; template - void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args); + void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args); template - void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args); + void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args); - template - void sendMethodCallWithReturn(const char *methodName, ReturnType &returnValue, const Args & ... args) const; + template + QList sendMethodCallWithReturn(const char *methodName, Args && ... args) const; void setHandler(DBusRequestHandler *handler); + template + T castFromQVariant(const QVariant& value) { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType());}); + return castFromQVariantSpecialized(HelperType(), value); + } + + template + QVariant castToQVariant(const T& value) const { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType());}); + return castToQVariantSpecialized(HelperType(), value); + } + private: void checkRegistry(); + template::value && !std::is_enum::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return qdbus_cast(value); + } + + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + return qdbus_cast(value); // workaround to use QList since its signature matches the QStringList + } + + template::value && std::is_enum::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return static_cast(qdbus_cast(value)); + } + + template::value && std::is_enum::value, int> = 0> + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QList ret; + QList tmp = qdbus_cast>(value); + std::transform(tmp.begin(), tmp.end(), std::back_inserter(ret), [](const int entry){return static_cast(entry);}); + return ret; + } + + template::value && std::is_enum::value, int> = 0> + QMap castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QMap ret; + QMap tmp = qdbus_cast>(value); + for (const QString& key: tmp.keys()) { + ret[key] = static_cast(tmp[key]); + } + return ret; + } + + template::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return getOrCreateSubProxy::type::IPCDBusProxyType>(qdbus_cast(value)); + } + + template::value, int> = 0> + QMap castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QMap ret; + auto objectPaths = qdbus_cast>(value); + for (const QString& key: objectPaths.keys()) { + ret[key] = getOrCreateSubProxy::type::IPCDBusProxyType>(objectPaths[key]); + } + return ret; + } + + template::value, int> = 0> + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QList ret; + auto objectPaths = qdbus_cast(value); + for (const QString& objectPath: objectPaths) { + ret.append(getOrCreateSubProxy::type::IPCDBusProxyType>(objectPath)); + } + return ret; + } + + template::value && !std::is_enum::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType, const T& value) const { + return QVariant::fromValue(value); + } + + QVariant castToQVariantSpecialized(HelperType>, const QList& value) const { + return QVariant::fromValue(QStringList(value)); // workaround to use QList since its signature matches the QStringList + } + + template::value && std::is_enum::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType, const T& value) const { + return QVariant::fromValue(static_cast(value)); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QList& value) const { + QList ret; + std::transform(value.begin(), value.end(), std::back_inserter(ret), [](const T entry){return static_cast(entry);}); + return QVariant::fromValue(ret); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QMap& value) const { + QMap ret; + for (const QString& key: value.keys()) { + ret[key] = static_cast(value[key]); + } + return QVariant::fromValue(ret); + } + QString m_interfaceName; QDBusServiceWatcher m_busWatcher; DBusRequestHandler *m_serviceObject = nullptr; @@ -121,29 +220,14 @@ class DBusIPCProxyBinder : public IPCProxyBinderBase }; -template -inline void DBusIPCProxyBinder::serializeValue(DBusIPCMessage &msg, const Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg.outputPayLoad(), IPCTypeRegisterHandler::convertToSerializedType(v, *this)); -} - -template -inline void DBusIPCProxyBinder::deserializeValue(DBusIPCMessage &msg, Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); -} - - template -inline DBusIPCMessage DBusIPCProxyBinder::sendMethodCall(const char *methodName, const Args & ... args) const +inline DBusIPCMessage DBusIPCProxyBinder::sendMethodCall(const char *methodName, Args && ... args) const { DBusIPCMessage msg(m_serviceName, objectPath(), m_interfaceName, methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << castToQVariant(std::forward(args))), 0)... + }; auto replyMessage = this->call(msg); if (replyMessage.isErrorMessage()) { onServerNotAvailableError(methodName); @@ -152,15 +236,19 @@ inline DBusIPCMessage DBusIPCProxyBinder::sendMethodCall(const char *methodName, } template -inline void DBusIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args) +inline void DBusIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args) { DBusIPCMessage msg(m_serviceName, objectPath(), m_interfaceName, methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << castToQVariant(std::forward(args))), 0)... + }; asyncCall(msg, this, [this, answer](DBusIPCMessage &msg) { ReturnType returnValue; if (msg.isReplyMessage()) { - deserializeValue(msg, returnValue); + if (!msg.arguments().isEmpty()) { + returnValue = castFromQVariant(msg.arguments().first()); + } answer(returnValue); } else { qCWarning(LogIpc) << "Error received" << msg.toString(); @@ -169,43 +257,46 @@ inline void DBusIPCProxyBinder::sendAsyncMethodCall(const char *methodName, face } template -inline void DBusIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args) +inline void DBusIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args) { DBusIPCMessage msg(m_serviceName, objectPath(), m_interfaceName, methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << castToQVariant(std::forward(args))), 0)... + }; asyncCall(msg, this, [answer](DBusIPCMessage &msg) { - Q_UNUSED(msg); + Q_UNUSED(msg) answer(); }); } -template -inline void DBusIPCProxyBinder::sendMethodCallWithReturn(const char *methodName, ReturnType &returnValue, const Args & ... args) const +template +inline QList DBusIPCProxyBinder::sendMethodCallWithReturn(const char *methodName, Args && ... args) const { DBusIPCMessage msg = sendMethodCall(methodName, args ...); + QList ret; if (msg.isReplyMessage()) { - const_cast(this)->deserializeValue(msg, returnValue); - } else { - assignDefaultValue(returnValue); + ret = msg.arguments(); } + return ret; } - template -inline void DBusIPCProxyBinder::sendSetterCall(const char *methodName, const PropertyType &value) +inline void DBusIPCProxyBinder::sendSetterCall(const QString &property, const PropertyType &value) { - DBusIPCMessage msg(m_serviceName, objectPath(), m_interfaceName, methodName); - serializeValue(msg, value); + DBusIPCMessage msg(m_serviceName, objectPath(), DBusIPCCommon::PROPERTIES_INTERFACE_NAME, DBusIPCCommon::SET_PROPERTY_MESSAGE_NAME); + msg << QVariant::fromValue(m_interfaceName); + msg << castToQVariant(property); + msg << QVariant::fromValue(QDBusVariant(castToQVariant(value))); if (isSynchronous()) { auto replyMessage = call(msg); if (replyMessage.isErrorMessage()) { - onServerNotAvailableError(methodName); + onServerNotAvailableError(property); } } else { - asyncCall(msg, this, [this, methodName](const DBusIPCMessage &replyMessage) { + asyncCall(msg, this, [this, property](const DBusIPCMessage &replyMessage) { if (replyMessage.isErrorMessage()) { - onServerNotAvailableError(methodName); + onServerNotAvailableError(property); } }); } diff --git a/src/ipc/dbus/DBusManager.cpp b/src/ipc/dbus/DBusManager.cpp index 2a8189a1..2f6dcb77 100644 --- a/src/ipc/dbus/DBusManager.cpp +++ b/src/ipc/dbus/DBusManager.cpp @@ -44,6 +44,14 @@ DBusManager::DBusManager() : m_busConnection(QDBusConnection::sessionBus()) DBusManager &DBusManager::instance() { + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>(); + static auto i = new DBusManager(); // TODO solve memory leak return *i; } diff --git a/src/ipc/dbus/DBusRequestHandler.h b/src/ipc/dbus/DBusRequestHandler.h index 425a2e42..d5c116ce 100644 --- a/src/ipc/dbus/DBusRequestHandler.h +++ b/src/ipc/dbus/DBusRequestHandler.h @@ -39,8 +39,9 @@ class DBusRequestHandler { public: - virtual void deserializePropertyValues(DBusIPCMessage &msg, bool isCompleteSnapshot) = 0; - virtual void deserializeSignal(DBusIPCMessage &msg) = 0; + virtual void unmarshalProperties(const QVariantMap& properties) = 0; + virtual void handleSignals(DBusIPCMessage& msg) = 0; + virtual const QList& getSignals() const = 0; virtual void setServiceRegistered(bool isRegistered) = 0; virtual ~DBusRequestHandler() = default; diff --git a/src/ipc/dbus/FaceliftDBusMarshaller.h b/src/ipc/dbus/FaceliftDBusMarshaller.h new file mode 100644 index 00000000..14507ce9 --- /dev/null +++ b/src/ipc/dbus/FaceliftDBusMarshaller.h @@ -0,0 +1,269 @@ +/********************************************************************** +** +** Copyright (C) 2018 Luxoft Sweden AB +** +** This file is part of the FaceLift project +** +** Permission is hereby granted, free of charge, to any person +** obtaining a copy of this software and associated documentation files +** (the "Software"), to deal in the Software without restriction, +** including without limitation the rights to use, copy, modify, merge, +** publish, distribute, sublicense, and/or sell copies of the Software, +** and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** SPDX-License-Identifier: MIT +** +**********************************************************************/ + +#pragma once + +#include +#include // std::once_flag +#include "FaceliftUtils.h" +#include "StructureBase.h" +#include "DBusIPCCommon.h" + +template struct HelperType { }; + +template::value && !std::is_enum::value, int> = 0> +void registerDBusType(HelperType) +{ + // DO NOTHIG FOR BUILTIN TYPES +} + +template::value && std::is_enum::value, int> = 0> +void registerDBusType(HelperType) +{ + // Can't register an enum to have basic DBus types (int) in QtDBus -> Bug ticket QTBUG-86867 + // workaround is to handle in castToQVariant the conversion + //qDBusRegisterMetaType(); +} + +template::value, int> = 0> +void registerDBusType(HelperType) +{ + qDBusRegisterMetaType(); + Q_ASSERT_X(strlen(QDBusMetaType::typeToSignature(qMetaTypeId())) < facelift::dbus::DBusIPCCommon::FACELIFT_DBUS_MAXIMUM_SIGNATURE_LENGTH, "Signature overflow", + "Struct's signature exceeds dbus limit, annonate @toByteArrayOverDBus to switch to byte array stream of the struct over dbus, better yet rethink your structure!"); +} +template::value, int> = 0> +void registerDBusType(HelperType>) +{ + qDBusRegisterMetaType(); + qDBusRegisterMetaType>(); + Q_ASSERT_X(strlen(QDBusMetaType::typeToSignature(qMetaTypeId>())) < facelift::dbus::DBusIPCCommon::FACELIFT_DBUS_MAXIMUM_SIGNATURE_LENGTH, "Signature overflow", + "Struct's signature exceeds dbus limit, annonate @toByteArrayOverDBus to switch to byte array stream of the struct over dbus, better yet rethink your structure!"); +} + +template::value, int> = 0> +void registerDBusType(HelperType>) +{ + qDBusRegisterMetaType(); + qDBusRegisterMetaType>(); + Q_ASSERT_X(strlen(QDBusMetaType::typeToSignature(qMetaTypeId>())) < facelift::dbus::DBusIPCCommon::FACELIFT_DBUS_MAXIMUM_SIGNATURE_LENGTH, "Signature overflow", + "Struct's signature exceeds dbus limit, annonate @toByteArrayOverDBus to switch to byte array stream of the struct over dbus, better yet rethink your structure!"); +} + +struct ToQDBusArgument +{ + ToQDBusArgument(QDBusArgument& argument): m_argument(argument) + {} + template + void operator()(T &&value) + { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType::type>());}); + m_argument << value; + } + // Can't register an enum to have basic DBus types (int) in QtDBus -> Bug ticket QTBUG-86867 + // workaround to convert enum to int + template::type>::value, int> = 0> + void operator()(const QList &value) + { + QList tmp; + std::transform(value.begin(), value.end(), std::back_inserter(tmp), [](const T entry){return static_cast(entry);}); + m_argument << tmp; + } + template::type>::value, int> = 0> + void operator()(const QMap &value) + { + QMap tmp; + for (const QString key: value.keys()) { + tmp[key] = static_cast(value[key]); + } + m_argument << tmp; + } + QDBusArgument m_argument; +}; + +struct FromQDBusArgument +{ + FromQDBusArgument(const QDBusArgument& argument): m_argument(argument) + {} + template + void operator()(T &&value) + { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType::type>());}); + m_argument >> value; + } + // Can't register an enum to have basic DBus types (int) in QtDBus -> Bug ticket QTBUG-86867 + // workaround to convert enum to int + template::type>::value, int> = 0> + void operator()(const QList &value) + { + QList tmp; + m_argument >> tmp; + std::transform(tmp.begin(), tmp.end(), std::back_inserter(value), [](const int entry){return static_cast(entry);}); + } + template::type>::value, int> = 0> + void operator()(const QMap &value) + { + QMap tmp; + m_argument >> tmp; + for (const QString& key: tmp.keys()) { + value[key] = static_cast(tmp[key]); + } + } + const QDBusArgument& m_argument; +}; + +struct FromQDataStream +{ + FromQDataStream(QDataStream& dataStream): m_dataStream(dataStream) + {} + template + void operator()(T &&value) + { + m_dataStream >> value; + } + QDataStream& m_dataStream; +}; + +struct ToQDataStream +{ + ToQDataStream(QDataStream& dataStream): m_dataStream(dataStream) + {} + template + void operator()(T &&value) + { + m_dataStream << value; + } + QDataStream& m_dataStream; +}; + +template +class ToByteArrayOverDBus +{ +private: + typedef char YesType[1]; + typedef char NoType[2]; + + template static YesType& test( decltype(&C::toByteArrayOverDBus) ) ; + template static NoType& test(...); +public: + enum { value = sizeof(test(0)) == sizeof(YesType) }; +}; + + +template::value, int> = 0> +inline QDataStream& operator<<(QDataStream &dataStream, const T& source) +{ + dataStream << static_cast(source); + return dataStream; +} + +template::value, int> = 0> +inline const QDataStream& operator>>(QDataStream &dataStream, T &source) +{ + int value; + dataStream >> value; + source = static_cast(value); + return dataStream; +} + +template::value, int> = 0> +inline QDataStream& operator<<( QDataStream& dataStream, const T &structure) +{ + facelift::for_each_in_tuple_const(structure.asTuple(), ToQDataStream(dataStream)); + return dataStream; +} + +template::value, int> = 0> +inline QDataStream& operator>>( QDataStream& dataStream, T &structure) +{ + facelift::for_each_in_tuple(structure.asTuple(), FromQDataStream(dataStream)); + return dataStream; +} + +// not neccessary if Qt allows defining Enum as INT +template::value, int> = 0> +inline QDBusArgument& operator<<(QDBusArgument &argument, const T& source) +{ + argument << static_cast(source); + return argument; +} + +template::value, int> = 0> +inline const QDBusArgument& operator>>(const QDBusArgument &argument, T &source) +{ + int tmp; + argument >> tmp; + source = static_cast(tmp); + return argument; +} + +template::value && !ToByteArrayOverDBus::value, int> = 0> +inline QDBusArgument &operator<<(QDBusArgument &argument, const T &structure) +{ + argument.beginStructure(); + facelift::for_each_in_tuple_const(structure.asTuple(), ToQDBusArgument(argument)); + argument.endStructure(); + return argument; +} + +template::value && ToByteArrayOverDBus::value, int> = 0> +inline QDBusArgument &operator<<(QDBusArgument &argument, const T &structure) +{ + argument.beginStructure(); + QByteArray byteArray; + QDataStream dataStream(&byteArray, QIODevice::WriteOnly); + dataStream << structure; + argument << byteArray; + argument.endStructure(); + return argument; +} + +template::value && !ToByteArrayOverDBus::value, int> = 0> +inline const QDBusArgument &operator>>(const QDBusArgument &argument, T &structure) +{ + argument.beginStructure(); + facelift::for_each_in_tuple(structure.asTuple(), FromQDBusArgument(argument)); + argument.endStructure(); + return argument; +} + +template::value && ToByteArrayOverDBus::value, int> = 0> +inline const QDBusArgument &operator>>(const QDBusArgument &argument, T &structure) +{ + argument.beginStructure(); + QByteArray byteArray; + QDataStream dataStream(&byteArray, QIODevice::ReadOnly); + argument >> byteArray; + dataStream >> structure; + argument.endStructure(); + return argument; +} diff --git a/src/ipc/dbus/IPCDBusServiceAdapter.h b/src/ipc/dbus/IPCDBusServiceAdapter.h index 25397059..66ec0da2 100644 --- a/src/ipc/dbus/IPCDBusServiceAdapter.h +++ b/src/ipc/dbus/IPCDBusServiceAdapter.h @@ -85,7 +85,61 @@ class IPCDBusServiceAdapter : public IPCDBusServiceAdapterBase registerService(objectPath, static_cast(serverObject)); } + template + const char* typeToSignature() const + { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType());}); + return typeToSignatureSpecialized(HelperType()); + } protected: + + template::value && !std::is_enum::value, int> = 0> + const char* typeToSignatureSpecialized(HelperType) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId()); + } + + template::value && std::is_enum::value, int> = 0> + const char* typeToSignatureSpecialized(HelperType) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId()); + } + + template::value, int> = 0> + inline const char* typeToSignatureSpecialized(HelperType) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId()); + } + + inline const char* typeToSignatureSpecialized(HelperType>) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId()); + } + + template::value, int> = 0> + inline const char* typeToSignatureSpecialized(HelperType>) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId()); + } + + template::value, int> = 0> + inline const char* typeToSignatureSpecialized(HelperType>) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId>()); + } + + template::value, int> = 0> + inline const char* typeToSignatureSpecialized(HelperType>) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId>()); + } + + template::value, int> = 0> + inline const char* typeToSignatureSpecialized(HelperType>) const + { + return QDBusMetaType::typeToSignature(qMetaTypeId>()); + } QPointer m_service; }; diff --git a/src/ipc/dbus/IPCDBusServiceAdapterBase.cpp b/src/ipc/dbus/IPCDBusServiceAdapterBase.cpp index bd3e21ed..6e65a310 100644 --- a/src/ipc/dbus/IPCDBusServiceAdapterBase.cpp +++ b/src/ipc/dbus/IPCDBusServiceAdapterBase.cpp @@ -51,78 +51,85 @@ #include "DBusIPCProxy.h" #include "DBusObjectRegistry.h" -#include "DBusIPCCommon.h" #include "IPCDBusServiceAdapterBase.h" namespace facelift { namespace dbus { -constexpr const char *DBusIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME; - -void IPCDBusServiceAdapterBase::initOutgoingSignalMessage() { - m_pendingOutgoingMessage = std::make_unique(objectPath(), interfaceName(), DBusIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME); - - // Send property value updates before the signal itself so that they are set before the signal is triggered on the client side. - this->serializePropertyValues(*m_pendingOutgoingMessage, false); -} - -void IPCDBusServiceAdapterBase::serializePropertyValues(DBusIPCMessage &msg, bool isCompleteSnapshot) -{ - Q_ASSERT(service()); - serializeOptionalValue(msg, service()->ready(), m_previousReadyState, isCompleteSnapshot); -} - -void IPCDBusServiceAdapterBase::flush() -{ - if (m_pendingOutgoingMessage) { - this->send(*m_pendingOutgoingMessage); - m_pendingOutgoingMessage.reset(); - } -} - bool IPCDBusServiceAdapterBase::handleMessage(const QDBusMessage &dbusMsg) { DBusIPCMessage requestMessage(dbusMsg); - DBusIPCMessage replyMessage = requestMessage.createReply(); + bool retVal = false; qCDebug(LogIpc) << "Handling incoming message: " << requestMessage.toString(); if (dbusMsg.interface() == DBusIPCCommon::INTROSPECTABLE_INTERFACE_NAME) { - // TODO + // is handled via the QDBusVirtualObject } else if (dbusMsg.interface() == DBusIPCCommon::PROPERTIES_INTERFACE_NAME) { - // TODO - } else { - if (service()) { - bool sendReply = true; - if (requestMessage.member() == DBusIPCCommon::GET_PROPERTIES_MESSAGE_NAME) { - if (!m_signalsConnected) { - m_signalsConnected = true; - QObject::connect(service(), &InterfaceBase::readyChanged, this, [this]() { - this->sendSignal(CommonSignalID::readyChanged); - }); - qCDebug(LogIpc) << "Enabling IPCDBusServiceAdapter for" << this->service(); - connectSignals(); + if (!m_signalsConnected) { + m_signalsConnected = true; + qCDebug(LogIpc) << "Enabling IPCDBusServiceAdapter for" << this->service(); + connectSignals(); + } + if (dbusMsg.member() == DBusIPCCommon::GET_ALL_PROPERTIES_MESSAGE_NAME) { + QListIterator argumentsIterator(dbusMsg.arguments()); + auto msgInterfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (msgInterfaceName == interfaceName()) { + QVariantMap ret = marshalProperties(); + QMap convertedToDBusVariant; + for (const QString& key: ret.keys()) { + convertedToDBusVariant[key] = QDBusVariant(ret[key]); } - serializePropertyValues(replyMessage, true); - } else { - auto handlingResult = handleMethodCallMessage(requestMessage, replyMessage); - if (handlingResult == IPCHandlingResult::INVALID) { - replyMessage = requestMessage.createErrorReply("Invalid arguments", "TODO"); - } else if (handlingResult == IPCHandlingResult::OK_ASYNC) { - sendReply = false; + replyMessage << QVariant::fromValue(convertedToDBusVariant); + send(replyMessage); + retVal = true; + } + } + else if (dbusMsg.member() == DBusIPCCommon::GET_PROPERTY_MESSAGE_NAME) { + QListIterator argumentsIterator(dbusMsg.arguments()); + auto msgInterfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (msgInterfaceName == interfaceName()) { + auto propertyName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + QVariant value = marshalProperty(propertyName); + if (value.isValid()) { + replyMessage << QVariant::fromValue(QDBusVariant(value)); + send(replyMessage); + retVal = true; } } + } + else if (dbusMsg.member() == DBusIPCCommon::SET_PROPERTY_MESSAGE_NAME) { + QListIterator argumentsIterator(requestMessage.arguments()); + auto msgInterfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (msgInterfaceName == interfaceName()) { + QString propertyName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (argumentsIterator.hasNext()) { + setProperty(propertyName, qdbus_cast(argumentsIterator.next()).variant()); + retVal = true; + } + } + send(replyMessage); + } + } else if (dbusMsg.interface() == interfaceName()) { + if (service()) { + bool sendReply = true; + auto handlingResult = handleMethodCallMessage(requestMessage, replyMessage); + if (handlingResult == IPCHandlingResult::INVALID) { + replyMessage = requestMessage.createErrorReply("Invalid arguments", "TODO"); + } else if (handlingResult == IPCHandlingResult::OK_ASYNC) { + sendReply = false; + } if (sendReply) { send(replyMessage); } - return true; + retVal = true; } else { qCWarning(LogIpc) << "DBus request received for object which has been destroyed" << this; } } - return false; + return retVal; } IPCDBusServiceAdapterBase::IPCDBusServiceAdapterBase(DBusManagerInterface& dbusManager, QObject *parent) : diff --git a/src/ipc/dbus/IPCDBusServiceAdapterBase.h b/src/ipc/dbus/IPCDBusServiceAdapterBase.h index b60687d2..d7004b1b 100644 --- a/src/ipc/dbus/IPCDBusServiceAdapterBase.h +++ b/src/ipc/dbus/IPCDBusServiceAdapterBase.h @@ -31,11 +31,14 @@ #pragma once #include +#include #include "IPCServiceAdapterBase.h" #include "DBusIPCMessage.h" +#include "DBusIPCCommon.h" #include "ipc-common.h" -#include "ipc-serialization.h" +#include "FaceliftUtils.h" #include "DBusManagerInterface.h" +#include "FaceliftDBusMarshaller.h" namespace facelift { @@ -81,18 +84,10 @@ class IPCDBusServiceAdapterBase : public IPCServiceAdapterBase bool handleMessage(const QDBusMessage &dbusMsg); - void flush(); + inline void sendPropertiesChanged(const QVariantMap& dirtyProperties); - template - void serializeValue(DBusIPCMessage &msg, const Type &v); - - template - void deserializeValue(DBusIPCMessage &msg, Type &v); - - void initOutgoingSignalMessage(); - - template - void sendSignal(MemberID signalID, const Args & ... args); + template + void sendSignal(const QString& signalName, Args && ... args); template void sendAsyncCallAnswer(DBusIPCMessage &replyMessage, const ReturnType returnValue); @@ -103,17 +98,15 @@ class IPCDBusServiceAdapterBase : public IPCServiceAdapterBase virtual IPCHandlingResult handleMethodCallMessage(DBusIPCMessage &requestMessage, DBusIPCMessage &replyMessage) = 0; - virtual void serializePropertyValues(DBusIPCMessage &msg, bool isCompleteSnapshot); + virtual QVariantMap marshalProperties() = 0; - void registerService() override; + virtual QVariant marshalProperty(const QString& propertyName) = 0; - void unregisterService() override; + virtual void setProperty(const QString& propertyName, const QVariant& value) = 0; - template - void serializeOptionalValue(DBusIPCMessage &msg, const Type ¤tValue, Type &previousValue, bool isCompleteSnapshot); + void registerService() override; - template - void serializeOptionalValue(DBusIPCMessage &msg, const Type ¤tValue, bool isCompleteSnapshot); + void unregisterService() override; virtual void appendDBUSIntrospectionData(QTextStream &s) const = 0; @@ -127,8 +120,21 @@ class IPCDBusServiceAdapterBase : public IPCServiceAdapterBase return memberName; } + template + T castFromQVariant(const QVariant& value) { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType());}); + return castFromQVariantSpecialized(HelperType(), value); + } + + template + QVariant castToQVariant(const T& value) { + static std::once_flag registerFlag; + std::call_once(registerFlag, [](){registerDBusType(HelperType());}); + return castToQVariantSpecialized(HelperType(), value); + } + protected: - std::unique_ptr m_pendingOutgoingMessage; DBusVirtualObject m_dbusVirtualObject; QString m_introspectionData; @@ -139,65 +145,125 @@ class IPCDBusServiceAdapterBase : public IPCServiceAdapterBase bool m_alreadyInitialized = false; DBusManagerInterface& m_dbusManager; -}; +private: + template::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return qdbus_cast(value); + } -template -inline void IPCDBusServiceAdapterBase::serializeValue(DBusIPCMessage &msg, const Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg.outputPayLoad(), IPCTypeRegisterHandler::convertToSerializedType(v, *this)); -} + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + return qdbus_cast(value); // workaround to use QList since its signature matches the QStringList + } -template -inline void IPCDBusServiceAdapterBase::deserializeValue(DBusIPCMessage &msg, Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); -} + template::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return static_cast(qdbus_cast(value)); + } -template -inline void IPCDBusServiceAdapterBase::sendSignal(MemberID signalID, const Args & ... args) -{ - if (m_pendingOutgoingMessage == nullptr) { - initOutgoingSignalMessage(); - auto argTuple = std::make_tuple(signalID, args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(m_pendingOutgoingMessage->outputPayLoad(), *this)); - flush(); + template::value, int> = 0> + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QList tmp = qdbus_cast>(value); + QList ret; + std::transform(tmp.begin(), tmp.end(), std::back_inserter(ret), [](const int entry){return static_cast(entry);}); + return ret; } -} -template -inline void IPCDBusServiceAdapterBase::sendAsyncCallAnswer(DBusIPCMessage &replyMessage, const ReturnType returnValue) + template::value, int> = 0> + QMap castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QMap ret; + QMap tmp = qdbus_cast>(value); + for (const QString& key: tmp.keys()) { + ret[key] = static_cast(tmp[key]); + } + return ret; + } + + template::value && !std::is_enum::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType, const T& value) { + return QVariant::fromValue(value); + } + + template::value && std::is_enum::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType, const T& value) { + return QVariant::fromValue(static_cast(value)); + } + + QVariant castToQVariantSpecialized(HelperType>, const QList& value) { + return QVariant::fromValue(QStringList(value)); // workaround to use QList since its signature matches the QStringList + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType, const T& value) { + QString objectPath; + if (value != nullptr) { + objectPath = getOrCreateAdapter::type::IPCDBusAdapterType>(value)->objectPath(); + } + return QVariant::fromValue(objectPath); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QList& value) { + QStringList objectPathes; + for (T service: value) { + objectPathes.append(getOrCreateAdapter::type::IPCDBusAdapterType>(service)->objectPath()); + } + return QVariant::fromValue(objectPathes); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QMap& value) { + QMap objectPathesMap; + for (const QString& key: value.keys()) { + objectPathesMap[key] = getOrCreateAdapter::type::IPCDBusAdapterType>(value[key])->objectPath(); + } + return QVariant::fromValue(objectPathesMap); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QList& value) { + QList ret; + std::transform(value.begin(), value.end(), std::back_inserter(ret), [](const T& entry){return static_cast(entry);}); + return QVariant::fromValue(ret); + } + + template::value, int> = 0> + QVariant castToQVariantSpecialized(HelperType>, const QMap& value) { + QMap ret; + for (const QString& key: value.keys()) { + ret[key] = static_cast(value[key]); + } + return QVariant::fromValue(ret); + } +}; + +inline void IPCDBusServiceAdapterBase::sendPropertiesChanged(const QVariantMap &dirtyProperties) { - serializeValue(replyMessage, returnValue); - send(replyMessage); + DBusIPCMessage reply(objectPath(), DBusIPCCommon::PROPERTIES_INTERFACE_NAME, DBusIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME); + reply << interfaceName(); + QMap convertedToDBusVariant; + for (const QString& key: dirtyProperties.keys()) { + convertedToDBusVariant[key] = QDBusVariant(dirtyProperties[key]); + } + reply << QVariant::fromValue(convertedToDBusVariant); + this->send(reply); } -template -inline void IPCDBusServiceAdapterBase::serializeOptionalValue(DBusIPCMessage &msg, const Type ¤tValue, Type &previousValue, bool isCompleteSnapshot) +template +inline void IPCDBusServiceAdapterBase::sendSignal(const QString& signalName, Args && ... args) { - if (isCompleteSnapshot) { - serializeValue(msg, currentValue); - } else { - if (previousValue == currentValue) { - msg.outputPayLoad().writeSimple(false); - } else { - msg.outputPayLoad().writeSimple(true); - serializeValue(msg, currentValue); - previousValue = currentValue; - } - } + DBusIPCMessage signal(objectPath(), interfaceName(), signalName); + using expander = int[]; + (void)expander{0, + (void(signal << castToQVariant(std::forward(args))), 0)... + }; + this->send(signal); } -template -inline void IPCDBusServiceAdapterBase::serializeOptionalValue(DBusIPCMessage &msg, const Type ¤tValue, bool isCompleteSnapshot) +template +inline void IPCDBusServiceAdapterBase::sendAsyncCallAnswer(DBusIPCMessage &replyMessage, const ReturnType returnValue) { - msg.outputPayLoad().writeSimple(isCompleteSnapshot); - if (isCompleteSnapshot) { - serializeValue(msg, currentValue); - } + replyMessage << castToQVariant(returnValue); + send(replyMessage); } } // end namespace dbus diff --git a/src/ipc/ipc-common/AppendDBUSSignatureFunction.h b/src/ipc/ipc-common/AppendDBUSSignatureFunction.h deleted file mode 100644 index 20bfa801..00000000 --- a/src/ipc/ipc-common/AppendDBUSSignatureFunction.h +++ /dev/null @@ -1,62 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - - -#include - -#include - -#include "FaceliftUtils.h" - -namespace facelift { - -struct AppendDBUSSignatureFunction -{ - AppendDBUSSignatureFunction(QTextStream &s) : - s(s) - { - } - - QTextStream &s; - - template - void operator()(T &&t) - { - Q_UNUSED(t); - typedef typename std::decay::type TupleType; - std::tuple dummyTuple; - appendDBUSTypeSignature(s, dummyTuple); - } -}; - - -} diff --git a/src/ipc/ipc-common/CMakeLists.txt b/src/ipc/ipc-common/CMakeLists.txt index 42413c67..db5e65f1 100644 --- a/src/ipc/ipc-common/CMakeLists.txt +++ b/src/ipc/ipc-common/CMakeLists.txt @@ -1,10 +1,8 @@ - facelift_add_library(FaceliftIPCCommonLib SOURCES ipc-common.cpp - IPCProxyBaseBase.cpp + DBusSignatureHelper.cpp ModuleIPCBase.cpp - ipc-serialization.cpp IPCServiceAdapterBase.cpp NotAvailableImplBase.cpp IPCAdapterFactoryManager.cpp @@ -13,8 +11,6 @@ facelift_add_library(FaceliftIPCCommonLib InterfaceManager.cpp IPCProxyNewBase.cpp NewIPCServiceAdapterBase.cpp - OutputPayLoad.cpp - InputPayLoad.cpp LocalProviderBinderBase.cpp HEADERS InterfaceManager.h @@ -24,28 +20,20 @@ facelift_add_library(FaceliftIPCCommonLib NewIPCServiceAdapterBase.h IPCAttachedPropertyFactory.h HEADERS_NO_MOC - AppendDBUSSignatureFunction.h - ipc-serialization.h DBusSignatureHelper.h IPCProxyBase.h IPCAdapterModelPropertyHandler.h IPCProxyModelProperty.h - IPCProxyBaseBase.h IPCAdapterFactoryManager.h IPCProxyNewBase.h IPCProxy.h - InputPayLoad.h - IPCTypeHandler.h - IPCTypeRegisterHandler.h ModuleIPCBase.h IPCServiceAdapter.h LocalProviderBinderBase.h - OutputPayLoad.h NotAvailableImpl.h NotAvailableImplBase.h Registry.h LocalProviderBinder.h - SerializeParameterFunction.h StaticArrayReference.h ipc-common.h LINK_LIBRARIES FaceliftModelLib FaceliftCommonLib diff --git a/src/ipc/ipc-common/DBusSignatureHelper.cpp b/src/ipc/ipc-common/DBusSignatureHelper.cpp new file mode 100644 index 00000000..325a72fa --- /dev/null +++ b/src/ipc/ipc-common/DBusSignatureHelper.cpp @@ -0,0 +1,92 @@ +/********************************************************************** +** +** Copyright (C) 2020 Luxoft Sweden AB +** +** This file is part of the FaceLift project +** +** Permission is hereby granted, free of charge, to any person +** obtaining a copy of this software and associated documentation files +** (the "Software"), to deal in the Software without restriction, +** including without limitation the rights to use, copy, modify, merge, +** publish, distribute, sublicense, and/or sell copies of the Software, +** and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +** +** SPDX-License-Identifier: MIT +** +**********************************************************************/ + +#include "DBusSignatureHelper.h" +#include "ipc-common.h" + +void facelift::appendPropertySignature(QTextStream& s, const char* propertyName, const char* type, bool readonly) +{ + s << ""; +} + +void facelift::appendReadyProperty(QTextStream& s) +{ + s << ""; +} + +void facelift::appendDBusMethodSignature(QTextStream &s, const char* methodName, const std::list>& inputArgs, const char* outputArgType) +{ + s << ""; + for (const auto& arg: inputArgs) { + s << ""; + } + if (strlen(outputArgType) != 0) { + s << ""; + } + s << ""; +} + +void facelift::appendDBusSignalSignature(QTextStream &s, const char* signalName, const std::list>& args) +{ + s << ""; + for (const auto& arg: args) { + s << ""; + } + s << ""; +} + +void facelift::appendDBusModelSignals(QTextStream &s) +{ + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; +} diff --git a/src/ipc/ipc-common/DBusSignatureHelper.h b/src/ipc/ipc-common/DBusSignatureHelper.h index c8018cdc..619ff06a 100644 --- a/src/ipc/ipc-common/DBusSignatureHelper.h +++ b/src/ipc/ipc-common/DBusSignatureHelper.h @@ -30,106 +30,13 @@ #pragma once -#include "IPCTypeHandler.h" -#include +#include namespace facelift { -class DBusSignatureHelper { - - public: - - template - typename std::enable_if::type - static appendDBUSMethodArgumentsSignature(QTextStream &s, std::tuple &t, const std::array &argNames) - { - Q_UNUSED(s); - Q_UNUSED(t); - Q_UNUSED(argNames); - } - - template - typename std::enable_if < I::type - static appendDBUSMethodArgumentsSignature(QTextStream &s, std::tuple &t, const std::array &argNames) - { - using Type = decltype(std::get(t)); - s << "::writeDBUSSignature(s); - s << "\" direction=\"in\"/>"; - appendDBUSMethodArgumentsSignature(s, t, argNames); - } - - - template - typename std::enable_if::type - static appendDBUSSignalArgumentsSignature(QTextStream &s, std::tuple &t, const std::array &argNames) - { - Q_UNUSED(s); - Q_UNUSED(t); - Q_UNUSED(argNames); - } - - template - typename std::enable_if < I::type - static appendDBUSSignalArgumentsSignature(QTextStream &s, std::tuple &t, const std::array &argNames) - { - using Type = decltype(std::get(t)); - s << "::writeDBUSSignature(s); - s << "\"/>"; - appendDBUSSignalArgumentsSignature(s, t, argNames); - } - - template - typename std::enable_if::type - static appendDBUSTypeSignature(QTextStream &s, std::tuple &t) - { - Q_UNUSED(s); - Q_UNUSED(t); - } - - template - typename std::enable_if < I::type - static appendDBUSTypeSignature(QTextStream &s, std::tuple &t) - { - using Type = decltype(std::get(t)); - IPCTypeHandler::writeDBUSSignature(s); - appendDBUSTypeSignature(s, t); - } - - template - static void addPropertySignature(QTextStream &s, const char *propertyName, bool isReadonly) - { - s << " dummyTuple; - appendDBUSTypeSignature(s, dummyTuple); - s << "\" access=\"" << (isReadonly ? "read" : "readwrite") << "\"/>"; - } - - template - static void addMethodSignature(QTextStream &s, const char *methodName, - const std::array &argNames) - { - s << ""; - std::tuple t; // TODO : get rid of the tuple - appendDBUSMethodArgumentsSignature(s, t, argNames); - s << ""; - } - - template - static void addSignalSignature(QTextStream &s, const char *methodName, - const std::array &argNames) - { - s << ""; - std::tuple t; // TODO : get rid of the tuple - appendDBUSSignalArgumentsSignature(s, t, argNames); - s << ""; - } - -}; - +void appendPropertySignature(QTextStream& s, const char* propertyName, const char* type, bool readonly); +void appendReadyProperty(QTextStream& s); +void appendDBusMethodSignature(QTextStream &s, const char* methodName, const std::list>& inputArgs, const char* outputArgType = ""); +void appendDBusSignalSignature(QTextStream &s, const char* signalName, const std::list>& args); +void appendDBusModelSignals(QTextStream &s); } diff --git a/src/ipc/ipc-common/IPCAdapterModelPropertyHandler.h b/src/ipc/ipc-common/IPCAdapterModelPropertyHandler.h index 432ea783..10ab4feb 100644 --- a/src/ipc/ipc-common/IPCAdapterModelPropertyHandler.h +++ b/src/ipc/ipc-common/IPCAdapterModelPropertyHandler.h @@ -44,26 +44,25 @@ class IPCAdapterModelPropertyHandler { } - template - void connectModel(SignalID signalID, facelift::Model &model) + void connectModel(const QString& modelPropertyName, facelift::Model &model) { m_model = &model; QObject::connect(m_model, static_cast - (&facelift::ModelBase::dataChanged), &m_adapter, [this, signalID] (int first, int last) { + (&facelift::ModelBase::dataChanged), &m_adapter, [this, modelPropertyName] (int first, int last) { QList changedItems; for (int i = first ; i <= last ; i++) { changedItems.append(m_model->elementAt(i)); } - m_adapter.sendSignal(signalID, ModelUpdateEvent::DataChanged, first, changedItems); + m_adapter.sendSignal(IPCCommon::MODEL_DATA_CHANGED_MESSAGE_NAME, modelPropertyName, first, changedItems); }); QObject::connect(m_model, &facelift::ModelBase::beginRemoveElements, &m_adapter, [this] (int first, int last) { m_removeFirst = first; m_removeLast = last; }); - QObject::connect(m_model, &facelift::ModelBase::endRemoveElements, &m_adapter, [this, signalID] () { + QObject::connect(m_model, &facelift::ModelBase::endRemoveElements, &m_adapter, [this, modelPropertyName] () { Q_ASSERT(m_removeFirst != UNDEFINED); Q_ASSERT(m_removeLast != UNDEFINED); - m_adapter.sendSignal(signalID, ModelUpdateEvent::Remove, m_removeFirst, m_removeLast); + m_adapter.sendSignal(IPCCommon::MODEL_REMOVE_MESSAGE_NAME, modelPropertyName, m_removeFirst, m_removeLast); m_removeFirst = UNDEFINED; m_removeLast = UNDEFINED; }); @@ -72,44 +71,39 @@ class IPCAdapterModelPropertyHandler m_moveSourceLastIndex = sourceLastIndex; m_moveDestinationIndex = destinationIndex; }); - QObject::connect(m_model, &facelift::ModelBase::endMoveElements, &m_adapter, [this, signalID] () { + QObject::connect(m_model, &facelift::ModelBase::endMoveElements, &m_adapter, [this, modelPropertyName] () { Q_ASSERT(m_moveSourceFirstIndex != UNDEFINED); Q_ASSERT(m_moveSourceLastIndex != UNDEFINED); Q_ASSERT(m_moveDestinationIndex != UNDEFINED); - m_adapter.sendSignal(signalID, ModelUpdateEvent::Move, m_moveSourceFirstIndex, m_moveSourceLastIndex, m_moveDestinationIndex); + m_adapter.sendSignal(IPCCommon::MODEL_MOVE_MESSAGE_NAME, modelPropertyName, m_moveSourceFirstIndex, m_moveSourceLastIndex, m_moveDestinationIndex); m_moveSourceFirstIndex = UNDEFINED; m_moveSourceLastIndex = UNDEFINED; m_moveDestinationIndex = UNDEFINED; }); - QObject::connect(m_model, &facelift::ModelBase::beginInsertElements, &m_adapter, [this] (int first, int last) { + QObject::connect(m_model, &facelift::ModelBase::beginInsertElements, &m_adapter, [this, modelPropertyName] (int first, int last) { m_insertFirst = first; m_insertLast = last; }); - QObject::connect(m_model, &facelift::ModelBase::endInsertElements, &m_adapter, [this, signalID] () { + QObject::connect(m_model, &facelift::ModelBase::endInsertElements, &m_adapter, [this, modelPropertyName] () { Q_ASSERT(m_insertFirst != UNDEFINED); Q_ASSERT(m_insertLast != UNDEFINED); - m_adapter.sendSignal(signalID, ModelUpdateEvent::Insert, m_insertFirst, m_insertLast); + m_adapter.sendSignal(IPCCommon::MODEL_INSERT_MESSAGE_NAME, modelPropertyName, m_insertFirst, m_insertLast); m_insertFirst = UNDEFINED; m_insertLast = UNDEFINED; }); - QObject::connect(m_model, &facelift::ModelBase::beginResetModel, &m_adapter, [this] () { + QObject::connect(m_model, &facelift::ModelBase::beginResetModel, &m_adapter, [this, modelPropertyName] () { m_resettingModel = true; }); - QObject::connect(m_model, &facelift::ModelBase::endResetModel, &m_adapter, [this, signalID] () { + QObject::connect(m_model, &facelift::ModelBase::endResetModel, &m_adapter, [this, modelPropertyName] () { Q_ASSERT(m_resettingModel); - m_adapter.sendSignal(signalID, ModelUpdateEvent::Reset, m_model->size()); + m_adapter.sendSignal(IPCCommon::MODEL_RESET_MESSAGE_NAME, modelPropertyName, m_model->size()); m_resettingModel = false; }); } - void handleModelRequest(typename IPCAdapterType::InputIPCMessage &requestMessage, typename IPCAdapterType::OutputIPCMessage &replyMessage) + void handleModelRequest(int first, int last, typename IPCAdapterType::OutputIPCMessage &replyMessage) { - std::tuple> requestResult; - int & first = std::get<0>(requestResult); - auto & list = std::get<1>(requestResult); - int last; - m_adapter.deserializeValue(requestMessage, first); - m_adapter.deserializeValue(requestMessage, last); + QList list; // Make sure we do not request items which are out of range first = qMax(first, 0); @@ -119,7 +113,8 @@ class IPCAdapterModelPropertyHandler list.append(m_model->elementAt(i)); } - m_adapter.serializeValue(replyMessage, requestResult); + replyMessage << m_adapter.template castToQVariant(first); + replyMessage << m_adapter.template castToQVariant(list); } private: diff --git a/src/ipc/ipc-common/IPCProxyBase.h b/src/ipc/ipc-common/IPCProxyBase.h index 6e9e80cc..7013e607 100644 --- a/src/ipc/ipc-common/IPCProxyBase.h +++ b/src/ipc/ipc-common/IPCProxyBase.h @@ -31,14 +31,13 @@ #pragma once #include "ipc-common.h" -#include "IPCProxyBaseBase.h" #include "IPCProxyBinderBase.h" namespace facelift { template -class IPCProxyBase : public AdapterType, protected IPCProxyBaseBase +class IPCProxyBase : public AdapterType { public: @@ -67,35 +66,6 @@ class IPCProxyBase : public AdapterType, protected IPCProxyBaseBase return r; } - template - class InterfacePropertyIPCProxyHandler - { - - public: - InterfacePropertyIPCProxyHandler(IPCProxyBase &owner) : m_owner(owner) - { - } - - void update(const QString &objectPath) - { - if (m_proxy && (m_proxy->ipc()->objectPath() != objectPath)) { - m_proxy = nullptr; - } - if (!m_proxy) { - m_proxy = m_owner.m_ipcBinder->template getOrCreateSubProxy(objectPath); - } - } - - ProxyType *getValue() const - { - return m_proxy; - } - - private: - QPointer m_proxy; - IPCProxyBase &m_owner; - }; - protected: bool m_serviceReady = false; IPCProxyBinderBase *m_ipcBinder = nullptr; diff --git a/src/ipc/ipc-common/IPCProxyBaseBase.cpp b/src/ipc/ipc-common/IPCProxyBaseBase.cpp deleted file mode 100644 index b2dbbc9d..00000000 --- a/src/ipc/ipc-common/IPCProxyBaseBase.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, freIPCServiceAdapterBasee of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#include "IPCProxyBase.h" -#include "FaceliftModel.h" - -namespace facelift { - -void IPCProxyBaseBase::deserializeCommonSignal(facelift::CommonSignalID signalID, InterfaceBase* i) -{ - switch (signalID) { - case facelift::CommonSignalID::readyChanged: - emit i->readyChanged(); - break; - default: - qFatal("Unknown signal ID"); - } -} - -} diff --git a/src/ipc/ipc-common/IPCProxyBaseBase.h b/src/ipc/ipc-common/IPCProxyBaseBase.h deleted file mode 100644 index e4c27991..00000000 --- a/src/ipc/ipc-common/IPCProxyBaseBase.h +++ /dev/null @@ -1,45 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, freIPCServiceAdapterBasee of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - -#include "ipc-common.h" - -namespace facelift { - -class IPCProxyBaseBase { - -public: - - void deserializeCommonSignal(facelift::CommonSignalID signalID, InterfaceBase* i); - -}; - -} diff --git a/src/ipc/ipc-common/IPCProxyModelProperty.h b/src/ipc/ipc-common/IPCProxyModelProperty.h index 9e228d42..828b8834 100644 --- a/src/ipc/ipc-common/IPCProxyModelProperty.h +++ b/src/ipc/ipc-common/IPCProxyModelProperty.h @@ -30,6 +30,9 @@ #pragma once #include +#include "FaceliftUtils.h" +#include "ModelProperty.h" +#include "ipc-common.h" namespace facelift { @@ -44,66 +47,56 @@ class IPCProxyModelProperty : public facelift::ModelProperty { } - void handleSignal(typename IPCProxyType::InputIPCMessage &msg) + void handleSignal(const typename IPCProxyType::InputIPCMessage &msg) { - ModelUpdateEvent event; - m_proxy.deserializeValue(msg, event); - switch (event) { + QListIterator argumentsIterator(msg.arguments()); + const QString& modelPropertyName = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): QString()); + Q_ASSERT(!modelPropertyName.isEmpty()); + const QString& messageName = msg.member(); - case ModelUpdateEvent::DataChanged: + if (messageName == IPCCommon::MODEL_DATA_CHANGED_MESSAGE_NAME) { - int first; - QList list; - m_proxy.deserializeValue(msg, first); - m_proxy.deserializeValue(msg, list); + int first = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + QList list = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant>(argumentsIterator.next()): QList()); + int last = first + list.size() - 1; for (int i = first; i <= last; ++i) { m_cache.insert(i, list.at(i - first)); } emit this->dataChanged(first, last); - } break; - - case ModelUpdateEvent::Insert: - { - int first, last; - m_proxy.deserializeValue(msg, first); - m_proxy.deserializeValue(msg, last); + } + else if (messageName == IPCCommon::MODEL_INSERT_MESSAGE_NAME) { + int first = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + int last = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); emit this->beginInsertElements(first, last); clear(); // TODO: insert elements in cache without clear() emit this->endInsertElements(); - } break; - - case ModelUpdateEvent::Remove: + } + else if (messageName == IPCCommon::MODEL_REMOVE_MESSAGE_NAME) { - int first, last; - m_proxy.deserializeValue(msg, first); - m_proxy.deserializeValue(msg, last); + int first = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + int last = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); emit this->beginRemoveElements(first, last); m_cache.clear(); // TODO: remove elements from cache without clear() emit this->endRemoveElements(); - } break; - - case ModelUpdateEvent::Move: - { - int sourceFirstIndex, sourceLastIndex, destinationIndex; - m_proxy.deserializeValue(msg, sourceFirstIndex); - m_proxy.deserializeValue(msg, sourceLastIndex); - m_proxy.deserializeValue(msg, destinationIndex); + } + else if (messageName == IPCCommon::MODEL_MOVE_MESSAGE_NAME) { + int sourceFirstIndex = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + int sourceLastIndex = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + int destinationIndex = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); emit this->beginMoveElements(sourceFirstIndex, sourceLastIndex, destinationIndex); m_cache.clear(); // TODO: move elements in cache without clear() emit this->endMoveElements(); - } break; - - case ModelUpdateEvent::Reset: - { + } + else if (messageName == IPCCommon::MODEL_RESET_MESSAGE_NAME) { emit this->beginResetModel(); - int size; - m_proxy.deserializeValue(msg, size); + int size = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); this->setSize(size); clear(); emit this->endResetModel(); - } break; - + } + else { + qCCritical(LogIpc) << "Unhandled event for model property" << messageName; } } @@ -129,11 +122,10 @@ class IPCProxyModelProperty : public facelift::ModelProperty --last; } - std::tuple> requestResult; - m_proxy.ipc()->sendMethodCallWithReturn(requestMemberID, requestResult, first, last); - - first = std::get<0>(requestResult); - auto &list = std::get<1>(requestResult); + QList args = m_proxy.ipc()->sendMethodCallWithReturn(requestMemberID, first, last); + QListIterator argumentsIterator(args); + first = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + QList list = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant>(argumentsIterator.next()): QList()); last = first + list.size() - 1; for (int i = first; i <= last; ++i) { @@ -181,10 +173,11 @@ class IPCProxyModelProperty : public facelift::ModelProperty } if (first <= last) { - m_proxy.ipc()->sendAsyncMethodCall(requestMemberID, facelift::AsyncAnswer>>(&m_proxy, [this](std::tuple> result) { + m_proxy.ipc()->sendAsyncMethodCall(requestMemberID, facelift::AsyncAnswer>(&m_proxy, [this](QList arguments) { // qCDebug(LogIpc) << "Received model items " << first << "-" << last; - auto & first = std::get<0>(result); - auto & list = std::get<1>(result); + QListIterator argumentsIterator(arguments); + auto first = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant(argumentsIterator.next()): int()); + auto list = (argumentsIterator.hasNext() ? m_proxy.template castFromQVariant>(argumentsIterator.next()): QList()); auto last = first + list.size() - 1; for (int i = first; i <= last; ++i) { auto &newItem = list[i - first]; diff --git a/src/ipc/ipc-common/IPCServiceAdapterBase.h b/src/ipc/ipc-common/IPCServiceAdapterBase.h index b1f51b88..176e0703 100644 --- a/src/ipc/ipc-common/IPCServiceAdapterBase.h +++ b/src/ipc/ipc-common/IPCServiceAdapterBase.h @@ -35,7 +35,6 @@ namespace facelift { - class IPCServiceAdapterBase : public QObject { Q_OBJECT @@ -102,29 +101,6 @@ class IPCServiceAdapterBase : public QObject return serviceAdapter; } - - template - class InterfacePropertyIPCAdapterHandler - { - - public: - void update(IPCServiceAdapterBase *parent, InterfaceType *service) - { - if (m_service != service) { - m_service = service; - m_serviceAdapter = parent->getOrCreateAdapter(service); - } - } - - QString objectPath() const - { - return (m_serviceAdapter ? m_serviceAdapter->objectPath() : ""); - } - - QPointer m_service; - QPointer m_serviceAdapter; - }; - private: QList > m_subAdapters; QString m_objectPath; diff --git a/src/ipc/ipc-common/IPCTypeHandler.h b/src/ipc/ipc-common/IPCTypeHandler.h deleted file mode 100644 index a1159f61..00000000 --- a/src/ipc/ipc-common/IPCTypeHandler.h +++ /dev/null @@ -1,256 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - -#include "ipc-common.h" -#include "ModelProperty.h" -#include "OutputPayLoad.h" -#include "InputPayLoad.h" -#include "AppendDBUSSignatureFunction.h" - -namespace facelift { - -template -struct IPCTypeHandler -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "i"; - } - - static void write(OutputPayLoad &msg, const Type &v) - { - msg.writeSimple(v); - } - - static void read(InputPayLoad &msg, Type &v) - { - msg.readNextParameter(v); - } - -}; - - -template<> -struct IPCTypeHandler -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "d"; - } - - static void write(OutputPayLoad &msg, const double &v) - { - msg.writeSimple(v); - } - - static void read(InputPayLoad &msg, double &v) - { - double d; - msg.readNextParameter(d); - v = d; - } - -}; - - -template<> -struct IPCTypeHandler -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "b"; - } - - static void write(OutputPayLoad &msg, const bool &v) - { - msg.writeSimple(v); - } - - static void read(InputPayLoad &msg, bool &v) - { - msg.readNextParameter(v); - } - -}; - - -template<> -struct IPCTypeHandler -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "s"; - } - - static void write(OutputPayLoad &msg, const QString &v) - { - msg.writeSimple(v); - } - - static void read(InputPayLoad &msg, QString &v) - { - msg.readNextParameter(v); - } - -}; - -template -struct IPCTypeHandler::value>::type> -{ - - static void writeDBUSSignature(QTextStream &s) - { - typename Type::FieldTupleTypes t; // TODO : get rid of that tuple - s << "("; - for_each_in_tuple(t, AppendDBUSSignatureFunction(s)); - s << ")"; - } - - static void write(OutputPayLoad &msg, const Type ¶m) - { - IPCTypeHandler::write(msg, param.asTuple()); - } - - static void read(InputPayLoad &msg, Type ¶m) - { - IPCTypeHandler::read(msg, param.asTuple()); - } - -}; - - -template -struct IPCTypeHandler> -{ - static void write(OutputPayLoad &msg, const std::tuple ¶m) - { - for_each_in_tuple_const(param, StreamWriteFunction(msg)); - } - - static void read(InputPayLoad &msg, std::tuple ¶m) - { - for_each_in_tuple(param, StreamReadFunction(msg)); - } - -}; - - -template -struct IPCTypeHandler::value>::type> -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "i"; - } - - static void write(OutputPayLoad &msg, const Type ¶m) - { - msg.writeSimple(static_cast(param)); - } - - static void read(InputPayLoad &msg, Type ¶m) - { - int i; - msg.readNextParameter(i); - param = static_cast(i); - } -}; - - -template -struct IPCTypeHandler> -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "a"; - IPCTypeHandler::writeDBUSSignature(s); - } - - static void write(OutputPayLoad &msg, const QList &list) - { - int count = list.size(); - msg.writeSimple(count); - for (const auto &e : list) { - IPCTypeHandler::write(msg, e); - } - } - - static void read(InputPayLoad &msg, QList &list) - { - list.clear(); - int count; - msg.readNextParameter(count); - for (int i = 0; i < count; i++) { - ElementType e; - IPCTypeHandler::read(msg, e); - list.append(e); - } - } - -}; - - -template -struct IPCTypeHandler> -{ - static void writeDBUSSignature(QTextStream &s) - { - s << "a{sv}"; // TODO: is it so? - IPCTypeHandler::writeDBUSSignature(s); - } - - static void write(OutputPayLoad &msg, const QMap &map) - { - int count = map.size(); - msg.writeSimple(count); - for (auto i = map.constBegin(); i != map.constEnd(); ++i) { - IPCTypeHandler::write(msg, i.key()); - IPCTypeHandler::write(msg, i.value()); - } - } - - static void read(InputPayLoad &msg, QMap &map) - { - map.clear(); - int count; - msg.readNextParameter(count); - for (int i = 0; i < count; i++) { - QString key; - ElementType value; - IPCTypeHandler::read(msg, key); - IPCTypeHandler::read(msg, value); - map.insert(key, value); - } - } -}; - -} diff --git a/src/ipc/ipc-common/IPCTypeRegisterHandler.h b/src/ipc/ipc-common/IPCTypeRegisterHandler.h deleted file mode 100644 index 105e8d42..00000000 --- a/src/ipc/ipc-common/IPCTypeRegisterHandler.h +++ /dev/null @@ -1,143 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - -#include - -#include "FaceliftModel.h" - -namespace facelift { - -template -struct IPCTypeRegisterHandler -{ - typedef Type SerializedType; - - template - static const Type &convertToSerializedType(const Type &v, OwnerType &adapter) - { - Q_UNUSED(adapter); - return v; - } - - template - static void convertToDeserializedType(Type &v, const SerializedType &serializedValue, OwnerType &adapter) - { - Q_UNUSED(adapter); - v = serializedValue; - } - -}; - - -template -struct IPCTypeRegisterHandler > -{ - typedef QList::SerializedType> SerializedType; - - template - static SerializedType convertToSerializedType(const QList &v, OwnerType &adapter) - { - Q_UNUSED(v); - Q_UNUSED(adapter); - SerializedType convertedValue; - for (const auto &e : v) { - convertedValue.append(IPCTypeRegisterHandler::convertToSerializedType(e, adapter)); - } - return convertedValue; - } - - template - static void convertToDeserializedType(QList &v, const SerializedType &serializedValue, OwnerType &adapter) - { - v.clear(); - for (const auto &e : serializedValue) { - Type c; - IPCTypeRegisterHandler::convertToDeserializedType(c, e, adapter); - v.append(c); - } - } - -}; - - -template -struct IPCTypeRegisterHandler > -{ - typedef QMap::SerializedType> SerializedType; - - template - static SerializedType convertToSerializedType(const QMap &v, OwnerType &adapter) - { - SerializedType convertedValue; - for (const auto &key : v.keys()) { - convertedValue.insert(key, IPCTypeRegisterHandler::convertToSerializedType(v[key], adapter)); - } - return convertedValue; - } - - template - static void convertToDeserializedType(QMap &v, const SerializedType &serializedValue, OwnerType &adapter) - { - v.clear(); - for (const auto &key : serializedValue.keys()) { - Type c; - IPCTypeRegisterHandler::convertToDeserializedType(c, serializedValue[key], adapter); - v.insert(key, c); - } - } - -}; - - -template -struct IPCTypeRegisterHandler::value>::type> -{ - typedef QString SerializedType; - - template - static SerializedType convertToSerializedType(Type *const &v, OwnerType &adapter) - { - using IPCAdapterType = typename OwnerType::template IPCAdapterType; - return adapter.template getOrCreateAdapter< IPCAdapterType >(v)->objectPath(); - } - - template - static void convertToDeserializedType(Type * &v, const SerializedType &serializedValue, OwnerType &owner) - { - using IPCProxyType = typename OwnerType::template IPCProxyType; - v = owner.template getOrCreateSubProxy(serializedValue); - } - -}; - -} - diff --git a/src/ipc/ipc-common/InputPayLoad.cpp b/src/ipc/ipc-common/InputPayLoad.cpp deleted file mode 100644 index eb13413c..00000000 --- a/src/ipc/ipc-common/InputPayLoad.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ -#include "InputPayLoad.h" - -namespace facelift { - -InputPayLoad::InputPayLoad(const QByteArray &payloadArray) : - m_payloadArray(payloadArray), - m_dataStream(m_payloadArray) -{ -} - -InputPayLoad::~InputPayLoad() = default; - - -} diff --git a/src/ipc/ipc-common/InputPayLoad.h b/src/ipc/ipc-common/InputPayLoad.h deleted file mode 100644 index d8a0a035..00000000 --- a/src/ipc/ipc-common/InputPayLoad.h +++ /dev/null @@ -1,63 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ -#pragma once - -#include -#include - -namespace facelift { - -class InputPayLoad -{ - -public: - InputPayLoad(const QByteArray &payloadArray); - - ~InputPayLoad(); - - template - void readNextParameter(Type &v) - { - m_dataStream >> v; - // qCDebug(LogIpc) << "Read from message : " << v; - } - - const QByteArray &getContent() const - { - return m_payloadArray; - } - -private: - const QByteArray& m_payloadArray; - QDataStream m_dataStream; -}; - -} - diff --git a/src/ipc/ipc-common/OutputPayLoad.cpp b/src/ipc/ipc-common/OutputPayLoad.cpp deleted file mode 100644 index f9930d71..00000000 --- a/src/ipc/ipc-common/OutputPayLoad.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ -#include "OutputPayLoad.h" - -namespace facelift { - -OutputPayLoad::OutputPayLoad(QByteArray &payloadArray) : m_payloadArray(payloadArray), m_dataStream(&m_payloadArray, QIODevice::WriteOnly) -{ -} - - -} diff --git a/src/ipc/ipc-common/OutputPayLoad.h b/src/ipc/ipc-common/OutputPayLoad.h deleted file mode 100644 index 443b1d0e..00000000 --- a/src/ipc/ipc-common/OutputPayLoad.h +++ /dev/null @@ -1,63 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ -#pragma once - -#include -#include - -namespace facelift { - -class OutputPayLoad -{ - -public: - OutputPayLoad(QByteArray &payloadArray); - - template - void writeSimple(const Type &v) - { - // qCDebug(LogIpc) << "Writing to message : " << v; - m_dataStream << v; - } - - const QByteArray &getContent() const - { - return m_payloadArray; - } - - -private: - QByteArray& m_payloadArray; - QDataStream m_dataStream; -}; - -} - - diff --git a/src/ipc/ipc-common/SerializeParameterFunction.h b/src/ipc/ipc-common/SerializeParameterFunction.h deleted file mode 100644 index 21d924a0..00000000 --- a/src/ipc/ipc-common/SerializeParameterFunction.h +++ /dev/null @@ -1,61 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - -#include - -#include "OutputPayLoad.h" -#include "IPCTypeHandler.h" -#include "IPCTypeRegisterHandler.h" - -namespace facelift { - -template -struct SerializeParameterFunction -{ - SerializeParameterFunction(OutputPayLoad &msg, const ParentType &parent) : - m_msg(msg), - m_parent(parent) - { - } - - OutputPayLoad &m_msg; - const ParentType &m_parent; - - template - void operator()(const Type &v) - { - IPCTypeHandler::SerializedType>::write(m_msg, - IPCTypeRegisterHandler::convertToSerializedType(v, m_parent)); - } -}; - -} diff --git a/src/ipc/ipc-common/ipc-common.h b/src/ipc/ipc-common/ipc-common.h index 3f336d1f..b52e153e 100644 --- a/src/ipc/ipc-common/ipc-common.h +++ b/src/ipc/ipc-common/ipc-common.h @@ -31,22 +31,12 @@ #pragma once #include - #include "FaceliftModel.h" -#include "InputPayLoad.h" -#include "OutputPayLoad.h" -#include "DBusSignatureHelper.h" -#include "IPCTypeRegisterHandler.h" namespace facelift { Q_DECLARE_LOGGING_CATEGORY(LogIpc) -enum class CommonSignalID { - readyChanged, - firstSpecific -}; - typedef int ASyncRequestID; enum class IPCHandlingResult { @@ -55,19 +45,15 @@ enum class IPCHandlingResult { INVALID, // Message is invalid and could not be handled }; -enum class ModelUpdateEvent { - DataChanged, - Insert, - Remove, - Move, - Reset +struct IPCCommon +{ + static constexpr const char *MODEL_DATA_CHANGED_MESSAGE_NAME = "ModelUpdateEventDataChanged"; + static constexpr const char *MODEL_INSERT_MESSAGE_NAME = "ModelUpdateEventInsert"; + static constexpr const char *MODEL_REMOVE_MESSAGE_NAME = "ModelUpdateEventRemove"; + static constexpr const char *MODEL_MOVE_MESSAGE_NAME = "ModelUpdateEventMove"; + static constexpr const char *MODEL_RESET_MESSAGE_NAME = "ModelUpdateEventReset"; }; -template -inline void assignDefaultValue(Type &v) -{ - v = Type {}; -} } diff --git a/src/ipc/ipc-common/ipc-serialization.h b/src/ipc/ipc-common/ipc-serialization.h deleted file mode 100644 index 413cedeb..00000000 --- a/src/ipc/ipc-common/ipc-serialization.h +++ /dev/null @@ -1,72 +0,0 @@ -/********************************************************************** -** -** Copyright (C) 2020 Luxoft Sweden AB -** -** This file is part of the FaceLift project -** -** Permission is hereby granted, free of charge, to any person -** obtaining a copy of this software and associated documentation files -** (the "Software"), to deal in the Software without restriction, -** including without limitation the rights to use, copy, modify, merge, -** publish, distribute, sublicense, and/or sell copies of the Software, -** and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be -** included in all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -** ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -** SOFTWARE. -** -** SPDX-License-Identifier: MIT -** -**********************************************************************/ - -#pragma once - -#include - -#include "ipc-common.h" -#include "InputPayLoad.h" -#include "OutputPayLoad.h" -#include "Structure.h" -#include "FaceliftUtils.h" -#include "ModelProperty.h" -#include "IPCTypeHandler.h" -#include "SerializeParameterFunction.h" - -namespace facelift { - -template -OutputPayLoad &operator<<(OutputPayLoad &msg, const Type &v) -{ - IPCTypeHandler::write(msg, v); - return msg; -} - - -template -InputPayLoad &operator>>(InputPayLoad &msg, Type &v) -{ - IPCTypeHandler::read(msg, v); - return msg; -} - - -template -InputPayLoad &operator>>(InputPayLoad &msg, Property &property) -{ - Type v; - IPCTypeHandler::read(msg, v); - property.setValue(v); - return msg; -} - - -} diff --git a/src/ipc/local/FaceliftIPCCommon.h b/src/ipc/local/FaceliftIPCCommon.h index 4362aad2..68f32fb1 100644 --- a/src/ipc/local/FaceliftIPCCommon.h +++ b/src/ipc/local/FaceliftIPCCommon.h @@ -36,14 +36,14 @@ namespace local { struct FaceliftIPCCommon { - static constexpr const char *GET_PROPERTIES_MESSAGE_NAME = "GetAllProperties"; - static constexpr const char *PROPERTIES_CHANGED_SIGNAL_NAME = "PropertiesChanged"; - static constexpr const char *SIGNAL_TRIGGERED_SIGNAL_NAME = "SignalTriggered"; - static constexpr const char *SET_PROPERTY_MESSAGE_NAME = "SetProperty"; + static constexpr const char *GET_ALL_PROPERTIES_MESSAGE_NAME = "GetAll"; + static constexpr const char *GET_PROPERTY_MESSAGE_NAME = "Get"; + static constexpr const char *SET_PROPERTY_MESSAGE_NAME = "Set"; + static constexpr const char *PROPERTIES_CHANGED_SIGNAL_NAME = "PropertiesChanged"; + static constexpr const char *PROPERTIES_INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + static constexpr const char *INTROSPECTABLE_INTERFACE_NAME = "org.freedesktop.DBus.Introspectable"; }; -constexpr const char *FaceliftIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME; - } } diff --git a/src/ipc/local/LocalIPC-serialization.h b/src/ipc/local/LocalIPC-serialization.h index 35e55e02..0b2832e0 100644 --- a/src/ipc/local/LocalIPC-serialization.h +++ b/src/ipc/local/LocalIPC-serialization.h @@ -31,55 +31,22 @@ #pragma once #include "LocalIPCMessage.h" -#include "ipc-serialization.h" #include "LocalIPCProxy.h" #include "LocalIPCServiceAdapter.h" +#include "FaceliftIPCCommon.h" namespace facelift { namespace local { - -template -inline void LocalIPCServiceAdapterBase::serializeValue(LocalIPCMessage &msg, const Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg.outputPayLoad(), IPCTypeRegisterHandler::convertToSerializedType(v, *this)); -} - -template -inline void LocalIPCServiceAdapterBase::deserializeValue(LocalIPCMessage &msg, Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); -} - - -template -inline void LocalIPCProxyBinder::serializeValue(LocalIPCMessage &msg, const Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg.outputPayLoad(), IPCTypeRegisterHandler::convertToSerializedType(v, *this)); -} - -template -inline void LocalIPCProxyBinder::deserializeValue(LocalIPCMessage &msg, Type &v) -{ - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); -} - - template -inline LocalIPCMessage LocalIPCProxyBinder::sendMethodCall(const char *methodName, const Args & ... args) const +inline LocalIPCMessage LocalIPCProxyBinder::sendMethodCall(const char *methodName, Args && ... args) const { LocalIPCMessage msg(methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << QVariant::fromValue(std::forward(args))), 0)... + }; auto replyMessage = call(msg); if (replyMessage.isErrorMessage()) { onServerNotAvailableError(methodName); @@ -88,15 +55,17 @@ inline LocalIPCMessage LocalIPCProxyBinder::sendMethodCall(const char *methodNam } template -inline void LocalIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args) +inline void LocalIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args) { LocalIPCMessage msg(methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << QVariant::fromValue(std::forward(args))), 0)... + }; asyncCall(msg, this, [this, answer](LocalIPCMessage &msg) { ReturnType returnValue; if (msg.isReplyMessage()) { - deserializeValue(msg, returnValue); + returnValue = (!msg.arguments().isEmpty() ? qvariant_cast(msg.arguments().first()): ReturnType()); answer(returnValue); } else { qCWarning(LogIpc) << "Error received" << msg.toString(); @@ -105,92 +74,60 @@ inline void LocalIPCProxyBinder::sendAsyncMethodCall(const char *methodName, fac } template -inline void LocalIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args) +inline void LocalIPCProxyBinder::sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args) { LocalIPCMessage msg(methodName); - auto argTuple = std::make_tuple(args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(msg.outputPayLoad(), *this)); + using expander = int[]; + (void)expander{0, + (void(msg << QVariant::fromValue(std::forward(args))), 0)... + }; asyncCall(msg, this, [answer](LocalIPCMessage &msg) { Q_UNUSED(msg); answer(); }); } -template -inline void LocalIPCProxyBinder::sendMethodCallWithReturn(const char *methodName, ReturnType &returnValue, const Args & ... args) const -{ - LocalIPCMessage msg = sendMethodCall(methodName, args ...); - if (msg.isReplyMessage()) { - const_cast(this)->deserializeValue(msg, returnValue); - } else { - assignDefaultValue(returnValue); - } -} - - template -inline void LocalIPCProxyBinder::sendSetterCall(const char *methodName, const PropertyType &value) +inline void LocalIPCProxyBinder::sendSetterCall(const QString& property, const PropertyType &value) { - LocalIPCMessage msg(methodName); - serializeValue(msg, value); + LocalIPCMessage msg(FaceliftIPCCommon::PROPERTIES_INTERFACE_NAME, FaceliftIPCCommon::SET_PROPERTY_MESSAGE_NAME); + msg << QVariant::fromValue(m_interfaceName); + msg << QVariant::fromValue(property); + msg << QVariant::fromValue(QVariant::fromValue(value)); if (isSynchronous()) { auto replyMessage = call(msg); if (replyMessage.isErrorMessage()) { - onServerNotAvailableError(methodName); + onServerNotAvailableError(property); } } else { - asyncCall(msg, this, [this, methodName](const LocalIPCMessage &replyMessage) { + asyncCall(msg, this, [this, property](const LocalIPCMessage &replyMessage) { if (replyMessage.isErrorMessage()) { - onServerNotAvailableError(methodName); + onServerNotAvailableError(property); } }); } } -template -inline void LocalIPCServiceAdapterBase::sendSignal(MemberID signalID, const Args & ... args) +template +inline void LocalIPCServiceAdapterBase::sendSignal(const QString& signalName, Args && ... args) { - if (m_pendingOutgoingMessage == nullptr) { - initOutgoingSignalMessage(); - auto argTuple = std::make_tuple(signalID, args ...); - for_each_in_tuple(argTuple, SerializeParameterFunction(m_pendingOutgoingMessage->outputPayLoad(), *this)); - flush(); - } + LocalIPCMessage signal(signalName); + using expander = int[]; + (void)expander{0, + (void(signal << QVariant::fromValue(std::forward(args))), 0)... + }; + + this->send(signal); } template inline void LocalIPCServiceAdapterBase::sendAsyncCallAnswer(LocalIPCMessage &replyMessage, const ReturnType returnValue) { - serializeValue(replyMessage, returnValue); + replyMessage << QVariant::fromValue(returnValue); sendReply(replyMessage); } -template -inline void LocalIPCServiceAdapterBase::serializeOptionalValue(LocalIPCMessage &msg, const Type ¤tValue, Type &previousValue, - bool isCompleteSnapshot) -{ - if (isCompleteSnapshot) { - serializeValue(msg, currentValue); - } else { - if (previousValue == currentValue) { - msg.outputPayLoad().writeSimple(false); - } else { - msg.outputPayLoad().writeSimple(true); - serializeValue(msg, currentValue); - previousValue = currentValue; - } - } -} - -template -inline void LocalIPCServiceAdapterBase::serializeOptionalValue(LocalIPCMessage &msg, const Type ¤tValue, bool isCompleteSnapshot) -{ - msg.outputPayLoad().writeSimple(isCompleteSnapshot); - if (isCompleteSnapshot) { - serializeValue(msg, currentValue); - } -} } } diff --git a/src/ipc/local/LocalIPCMessage.cpp b/src/ipc/local/LocalIPCMessage.cpp index 411ed953..c36d2740 100644 --- a/src/ipc/local/LocalIPCMessage.cpp +++ b/src/ipc/local/LocalIPCMessage.cpp @@ -45,32 +45,22 @@ QString LocalIPCMessage::toString() const s << "Local IPC message "; s << " member:" << m_data.m_member; - s << m_data.m_payload; + s << m_data.m_arguments; return str; } -OutputPayLoad &LocalIPCMessage::outputPayLoad() -{ - if (m_outputPayload == nullptr) { - m_outputPayload = std::make_unique(m_data.m_payload); - } - return *m_outputPayload; -} - -InputPayLoad &LocalIPCMessage::inputPayLoad() +LocalIPCMessage::LocalIPCMessage() { - if (m_inputPayload == nullptr) { - m_inputPayload = std::make_unique(m_data.m_payload); - } - return *m_inputPayload; } -LocalIPCMessage::LocalIPCMessage() +LocalIPCMessage::LocalIPCMessage(const QString &methodName) { + m_data.m_member = methodName; } -LocalIPCMessage::LocalIPCMessage(const char *methodName) +LocalIPCMessage::LocalIPCMessage(const QString &interface, const char *methodName) { + m_data.m_interface = interface; m_data.m_member = methodName; } @@ -96,6 +86,17 @@ void LocalIPCMessage::copyRequestMessage(const LocalIPCMessage &other) } } +QList LocalIPCMessage::arguments() const +{ + return m_data.m_arguments; +} + +LocalIPCMessage &LocalIPCMessage::operator<<(const QVariant &arg) +{ + m_data.m_arguments.append(arg); + return *this; +} + LocalIPCMessage LocalIPCMessage::createReply() const { LocalIPCMessage reply; diff --git a/src/ipc/local/LocalIPCMessage.h b/src/ipc/local/LocalIPCMessage.h index 168e08d8..66559810 100644 --- a/src/ipc/local/LocalIPCMessage.h +++ b/src/ipc/local/LocalIPCMessage.h @@ -65,7 +65,9 @@ class LocalIPCMessage LocalIPCMessage(); - LocalIPCMessage(const char *methodName); + LocalIPCMessage(const QString& methodName); + + LocalIPCMessage(const QString &interface, const char *methodName); LocalIPCMessage(const LocalIPCMessage &other); @@ -78,6 +80,14 @@ class LocalIPCMessage return m_data.m_member; } + QString interface() const + { + return m_data.m_interface; + } + + QList arguments() const; + + LocalIPCMessage &operator<<(const QVariant &arg); LocalIPCMessage createReply() const; @@ -95,10 +105,6 @@ class LocalIPCMessage return (m_data.m_messageType == MessageType::Error); } - OutputPayLoad &outputPayLoad(); - - InputPayLoad &inputPayLoad(); - void addListener(const QObject *context, ReplyFunction function); void notifyListener(); @@ -106,15 +112,14 @@ class LocalIPCMessage private: struct { + QString m_interface; QString m_member; - QByteArray m_payload; MessageType m_messageType = MessageType::Request; ReplyFunction m_listener; QPointer m_listenerContext; + QList m_arguments; } m_data; - std::unique_ptr m_outputPayload; - std::unique_ptr m_inputPayload; std::unique_ptr m_requestMessage; }; diff --git a/src/ipc/local/LocalIPCProxy.h b/src/ipc/local/LocalIPCProxy.h index bfaf1a7c..06b767b5 100644 --- a/src/ipc/local/LocalIPCProxy.h +++ b/src/ipc/local/LocalIPCProxy.h @@ -69,35 +69,6 @@ class LocalIPCProxy : public IPCProxyBase, protected LocalIPCProx return memberName; } - template - void serializeValue(LocalIPCMessage &msg, const Type &v) - { - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - IPCTypeHandler::write(msg, IPCTypeRegisterHandler::convertToSerializedType(v, *this)); - } - - template - void deserializeValue(LocalIPCMessage &msg, Type &v) - { - typedef typename IPCTypeRegisterHandler::SerializedType SerializedType; - SerializedType serializedValue; - IPCTypeHandler::read(msg.inputPayLoad(), serializedValue); - IPCTypeRegisterHandler::convertToDeserializedType(v, serializedValue, *this); - } - - template - bool deserializeOptionalValue(LocalIPCMessage &msg, Type &value, bool isCompleteSnapshot) - { - bool b = true; - if (!isCompleteSnapshot) { - msg.inputPayLoad().readNextParameter(b); - } - if (b) { - this->deserializeValue(msg, value); - } - return b; - } - void setServiceRegistered(bool isRegistered) override { bool oldReady = this->ready(); @@ -109,13 +80,6 @@ class LocalIPCProxy : public IPCProxyBase, protected LocalIPCProx m_ipcBinder.setServiceAvailable(isRegistered); } - bool deserializeReadyValue(LocalIPCMessage &msg, bool isCompleteSnapshot) - { - bool previousIsReady = this->ready(); - deserializeOptionalValue(msg, this->m_serviceReady, isCompleteSnapshot); - return (this->ready() != previousIsReady); - } - LocalIPCProxyBinder *ipc() { return &m_ipcBinder; @@ -132,7 +96,43 @@ class LocalIPCProxy : public IPCProxyBase, protected LocalIPCProx m_ipcBinder.connectToServer(); } + template + T castFromQVariant(const QVariant& value) { + return castFromQVariantSpecialized(HelperType(), value); + } + private: + template struct HelperType { }; + template::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return qvariant_cast(value); + } + + template::value, int> = 0> + T castFromQVariantSpecialized(HelperType, const QVariant& value) { + return getOrCreateSubProxy::type::IPCLocalProxyType>(qvariant_cast(value)); + } + + template::value, int> = 0> + QMap castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QMap ret; + auto objectPaths = qvariant_cast>(value); + for (const QString& key: objectPaths.keys()) { + ret[key] = getOrCreateSubProxy::type::IPCLocalProxyType>(objectPaths[key]); + } + return ret; + } + + template::value, int> = 0> + QList castFromQVariantSpecialized(HelperType>, const QVariant& value) { + QList ret; + auto objectPaths = qvariant_cast(value); + for (const QString& objectPath: objectPaths) { + ret.append(getOrCreateSubProxy::type::IPCLocalProxyType>(objectPath)); + } + return ret; + } + LocalIPCProxyBinder m_ipcBinder; }; diff --git a/src/ipc/local/LocalIPCProxyBinder.cpp b/src/ipc/local/LocalIPCProxyBinder.cpp index eaff415f..556ffd41 100644 --- a/src/ipc/local/LocalIPCProxyBinder.cpp +++ b/src/ipc/local/LocalIPCProxyBinder.cpp @@ -37,7 +37,6 @@ #include "LocalIPCProxy.h" #include "LocalIPC-serialization.h" #include "LocalIPCRegistry.h" -#include "FaceliftIPCCommon.h" namespace facelift { @@ -60,9 +59,16 @@ void LocalIPCProxyBinder::checkServiceAvailability() } if (!isServiceAvailable()) { m_serviceAdapter = adapter; - m_signalConnection = QObject::connect(adapter, &LocalIPCServiceAdapterBase::messageSent, this, [this] (LocalIPCMessage &message) { - this->onSignalTriggered(message); - }); + m_signalConnection = QObject::connect(adapter, &LocalIPCServiceAdapterBase::messageSent, this, [this](LocalIPCMessage &msg){ + if ((msg.interface() == FaceliftIPCCommon::PROPERTIES_INTERFACE_NAME) && + msg.member() == FaceliftIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME) { + onPropertiesChanged(msg); + } + else if (!msg.member().isEmpty()) { + m_serviceObject->handleSignals(msg); + } + }); + requestPropertyValues(); } } @@ -110,7 +116,7 @@ void LocalIPCProxyBinder::setInterfaceName(const QString &name) checkInit(); } -void LocalIPCProxyBinder::onServerNotAvailableError(const char *methodName) const +void LocalIPCProxyBinder::onServerNotAvailableError(const QString& methodName) const { qCCritical(LogIpc, "Error message received when calling method '%s' on service at path '%s'. " @@ -120,13 +126,12 @@ void LocalIPCProxyBinder::onServerNotAvailableError(const char *methodName) cons void LocalIPCProxyBinder::onPropertiesChanged(LocalIPCMessage &msg) { - m_serviceObject->deserializePropertyValues(msg, false); -} - -void LocalIPCProxyBinder::onSignalTriggered(LocalIPCMessage &msg) -{ - m_serviceObject->deserializePropertyValues(msg, false); - m_serviceObject->deserializeSignal(msg); + QListIterator argumentsIterator(msg.arguments()); + QString interfaceName = (argumentsIterator.hasNext() ? qvariant_cast(argumentsIterator.next()): QString()); + if (interfaceName == m_interfaceName) { + QVariantMap dirtyProperties = (argumentsIterator.hasNext() ? qvariant_cast(argumentsIterator.next()): QVariantMap()); + m_serviceObject->unmarshalProperties(dirtyProperties); + } } LocalIPCMessage LocalIPCProxyBinder::call(LocalIPCMessage &message) const @@ -150,11 +155,13 @@ void LocalIPCProxyBinder::asyncCall(LocalIPCMessage &requestMessage, QObject *co void LocalIPCProxyBinder::requestPropertyValues() { - LocalIPCMessage msg(FaceliftIPCCommon::GET_PROPERTIES_MESSAGE_NAME); + LocalIPCMessage msg(FaceliftIPCCommon::PROPERTIES_INTERFACE_NAME, FaceliftIPCCommon::GET_ALL_PROPERTIES_MESSAGE_NAME); + msg << interfaceName(); auto replyHandler = [this](LocalIPCMessage &replyMessage) { if (replyMessage.isReplyMessage()) { - m_serviceObject->deserializePropertyValues(replyMessage, true); + QVariantMap values = (!replyMessage.arguments().isEmpty() ? qvariant_cast(replyMessage.arguments().first()): QVariantMap()); + m_serviceObject->unmarshalProperties(values); m_serviceObject->setServiceRegistered(true); emit serviceAvailableChanged(); } else { diff --git a/src/ipc/local/LocalIPCProxyBinder.h b/src/ipc/local/LocalIPCProxyBinder.h index 6502e21b..107922a0 100644 --- a/src/ipc/local/LocalIPCProxyBinder.h +++ b/src/ipc/local/LocalIPCProxyBinder.h @@ -61,8 +61,6 @@ class LocalIPCProxyBinder : public IPCProxyBinderBase void onPropertiesChanged(LocalIPCMessage &message); - void onSignalTriggered(LocalIPCMessage &message); - void bindToIPC() override; void setServiceAvailable(bool isRegistered); @@ -75,28 +73,22 @@ class LocalIPCProxyBinder : public IPCProxyBinderBase void requestPropertyValues(); - template - void serializeValue(LocalIPCMessage &msg, const Type &v); - - template - void deserializeValue(LocalIPCMessage &msg, Type &v); - - void onServerNotAvailableError(const char *methodName) const; + void onServerNotAvailableError(const QString &methodName) const; template - void sendSetterCall(const char *methodName, const PropertyType &value); + void sendSetterCall(const QString &property, const PropertyType &value); template - LocalIPCMessage sendMethodCall(const char *methodName, const Args & ... args) const; + LocalIPCMessage sendMethodCall(const char *methodName, Args && ... args) const; template - void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args); + void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args); template - void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, const Args & ... args); + void sendAsyncMethodCall(const char *methodName, facelift::AsyncAnswer answer, Args && ... args); template - void sendMethodCallWithReturn(const char *methodName, ReturnType &returnValue, const Args & ... args) const; + void sendMethodCallWithReturn(const char *methodName, ReturnType &returnValue, Args && ... args) const; LocalIPCMessage call(LocalIPCMessage &message) const; diff --git a/src/ipc/local/LocalIPCRequestHandler.h b/src/ipc/local/LocalIPCRequestHandler.h index 641173b1..166a2ec0 100644 --- a/src/ipc/local/LocalIPCRequestHandler.h +++ b/src/ipc/local/LocalIPCRequestHandler.h @@ -37,7 +37,6 @@ #include "FaceliftModel.h" #include "FaceliftUtils.h" #include "ModelProperty.h" - #include "ipc-common.h" namespace facelift { @@ -55,9 +54,8 @@ class LocalIPCRequestHandler { public: - virtual ~LocalIPCRequestHandler() = default; - virtual void deserializePropertyValues(LocalIPCMessage &msg, bool isCompleteSnapshot) = 0; - virtual void deserializeSignal(LocalIPCMessage &msg) = 0; + virtual void unmarshalProperties(const QVariantMap& properties) = 0; + virtual void handleSignals(LocalIPCMessage& msg) = 0; virtual void setServiceRegistered(bool isRegistered) = 0; }; diff --git a/src/ipc/local/LocalIPCServiceAdapter.h b/src/ipc/local/LocalIPCServiceAdapter.h index 3cc34f41..60e583a2 100644 --- a/src/ipc/local/LocalIPCServiceAdapter.h +++ b/src/ipc/local/LocalIPCServiceAdapter.h @@ -85,6 +85,12 @@ class LocalIPCServiceAdapter : public LocalIPCServiceAdapterBase registerService(objectPath, static_cast(serverObject)); // TODO: get rid of that cast } + template + const char* typeToSignature() const + { + return ""; + } + protected: QPointer m_service; }; diff --git a/src/ipc/local/LocalIPCServiceAdapterBase.cpp b/src/ipc/local/LocalIPCServiceAdapterBase.cpp index 60f8bdc5..80591718 100644 --- a/src/ipc/local/LocalIPCServiceAdapterBase.cpp +++ b/src/ipc/local/LocalIPCServiceAdapterBase.cpp @@ -40,28 +40,6 @@ namespace facelift { namespace local { -void LocalIPCServiceAdapterBase::initOutgoingSignalMessage() -{ - m_pendingOutgoingMessage = std::make_unique(FaceliftIPCCommon::SIGNAL_TRIGGERED_SIGNAL_NAME); - - // Send property value updates before the signal itself so that they are set before the signal is triggered on the client side. - this->serializePropertyValues(*m_pendingOutgoingMessage, false); -} - -void LocalIPCServiceAdapterBase::serializePropertyValues(LocalIPCMessage &msg, bool isCompleteSnapshot) -{ - Q_ASSERT(service()); - serializeOptionalValue(msg, service()->ready(), m_previousReadyState, isCompleteSnapshot); -} - -void LocalIPCServiceAdapterBase::flush() -{ - if (m_pendingOutgoingMessage) { - this->send(*m_pendingOutgoingMessage); - m_pendingOutgoingMessage.reset(); - } -} - IPCHandlingResult LocalIPCServiceAdapterBase::handleMessage(LocalIPCMessage &requestMessage) { LocalIPCMessage replyMessage = requestMessage.createReply(); @@ -71,9 +49,31 @@ IPCHandlingResult LocalIPCServiceAdapterBase::handleMessage(LocalIPCMessage &req auto handlingResult = IPCHandlingResult::OK; bool sendReply = true; - if (requestMessage.member() == FaceliftIPCCommon::GET_PROPERTIES_MESSAGE_NAME) { - serializePropertyValues(replyMessage, true); - } else { + if (requestMessage.interface() == FaceliftIPCCommon::PROPERTIES_INTERFACE_NAME) { + if (requestMessage.member() == FaceliftIPCCommon::GET_ALL_PROPERTIES_MESSAGE_NAME) { + replyMessage << QVariant::fromValue(marshalProperties()); + } + else if (requestMessage.member() == FaceliftIPCCommon::GET_PROPERTY_MESSAGE_NAME) { + QListIterator argumentsIterator(requestMessage.arguments()); + auto msgInterfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + // no need to check interface name in local variant + auto propertyName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + QVariant value = marshalProperty(propertyName); + replyMessage << value; + send(replyMessage); + } + else if (requestMessage.member() == FaceliftIPCCommon::SET_PROPERTY_MESSAGE_NAME) { + QListIterator argumentsIterator(requestMessage.arguments()); + auto msgInterfaceName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (msgInterfaceName == interfaceName()) { + QString propertyName = (argumentsIterator.hasNext() ? castFromQVariant(argumentsIterator.next()): QString()); + if (argumentsIterator.hasNext()) { + setProperty(propertyName, argumentsIterator.next()); + } + } + } + } + else { handlingResult = handleMethodCallMessage(requestMessage, replyMessage); if (handlingResult == IPCHandlingResult::INVALID) { replyMessage = requestMessage.createErrorReply(); @@ -105,12 +105,6 @@ LocalIPCServiceAdapterBase::~LocalIPCServiceAdapterBase() unregisterService(); } -QString LocalIPCServiceAdapterBase::introspect(const QString &path) const -{ - Q_UNUSED(path); - return QString(); -} - void LocalIPCServiceAdapterBase::unregisterService() { if (m_alreadyInitialized) { @@ -126,9 +120,6 @@ void LocalIPCServiceAdapterBase::registerService() m_alreadyInitialized = true; qCDebug(LogIpc) << "Registering local IPC object at " << objectPath(); if (m_alreadyInitialized) { - QObject::connect(service(), &InterfaceBase::readyChanged, this, [this]() { - this->sendSignal(CommonSignalID::readyChanged); - }); connectSignals(); } else { qFatal("Could not register service at object path '%s'", qPrintable(objectPath())); diff --git a/src/ipc/local/LocalIPCServiceAdapterBase.h b/src/ipc/local/LocalIPCServiceAdapterBase.h index f273a1ab..5a45eb5a 100644 --- a/src/ipc/local/LocalIPCServiceAdapterBase.h +++ b/src/ipc/local/LocalIPCServiceAdapterBase.h @@ -32,6 +32,7 @@ #include "LocalIPCMessage.h" #include "IPCServiceAdapterBase.h" +#include "FaceliftIPCCommon.h" namespace facelift { @@ -55,18 +56,10 @@ class LocalIPCServiceAdapterBase : public IPCServiceAdapterBase IPCHandlingResult handleMessage(LocalIPCMessage &message); - void flush(); + inline void sendPropertiesChanged(const QVariantMap &dirtyProperties); - template - void serializeValue(LocalIPCMessage &msg, const Type &v); - - template - void deserializeValue(LocalIPCMessage &msg, Type &v); - - void initOutgoingSignalMessage(); - - template - void sendSignal(MemberID signalID, const Args & ... args); + template + void sendSignal(const QString& signalName, Args && ... args); template void sendAsyncCallAnswer(LocalIPCMessage &replyMessage, const ReturnType returnValue); @@ -75,7 +68,11 @@ class LocalIPCServiceAdapterBase : public IPCServiceAdapterBase virtual IPCHandlingResult handleMethodCallMessage(LocalIPCMessage &requestMessage, LocalIPCMessage &replyMessage) = 0; - virtual void serializePropertyValues(LocalIPCMessage &msg, bool isCompleteSnapshot); + virtual QVariantMap marshalProperties() = 0; + + virtual QVariant marshalProperty(const QString& propertyName) = 0; + + virtual void setProperty(const QString& propertyName, const QVariant& value) = 0; void registerService() override; @@ -87,16 +84,6 @@ class LocalIPCServiceAdapterBase : public IPCServiceAdapterBase void sendReply(LocalIPCMessage &message); - template - void serializeOptionalValue(LocalIPCMessage &msg, const Type ¤tValue, Type &previousValue, bool isCompleteSnapshot); - - template - void serializeOptionalValue(LocalIPCMessage &msg, const Type ¤tValue, bool isCompleteSnapshot); - - virtual void appendDBUSIntrospectionData(QTextStream &s) const = 0; - - QString introspect(const QString &path) const; - template MemberIDType memberID(T member, MemberIDType memberName) const { @@ -105,8 +92,44 @@ class LocalIPCServiceAdapterBase : public IPCServiceAdapterBase return memberName; } + template + T castFromQVariant(const QVariant& value) { + return qvariant_cast(value); + } + + template::value, int> = 0> + QVariant castToQVariant(const T& value) { + return QVariant::fromValue(value); + } + + template::value, int> = 0> + QVariant castToQVariant(const T& value) { + QString objectPath; + if (value != nullptr) { + objectPath = getOrCreateAdapter::type::IPCLocalAdapterType>(value)->objectPath(); + } + return QVariant::fromValue(objectPath); + } + + template::value, int> = 0> + QVariant castToQVariant(const QList& value) { + QStringList objectPathes; + for (T service: value) { + objectPathes.append(getOrCreateAdapter::type::IPCLocalAdapterType>(service)->objectPath()); + } + return QVariant::fromValue(objectPathes); + } + + template::value, int> = 0> + QVariant castToQVariant(const QMap& value) { + QMap objectPathesMap; + for (const QString& key: value.keys()) { + objectPathesMap[key] = getOrCreateAdapter::type::IPCLocalAdapterType>(value[key])->objectPath(); + } + return QVariant::fromValue(objectPathesMap); + } + protected: - std::unique_ptr m_pendingOutgoingMessage; QString m_introspectionData; QString m_serviceName; @@ -116,6 +139,13 @@ class LocalIPCServiceAdapterBase : public IPCServiceAdapterBase bool m_alreadyInitialized = false; }; +inline void LocalIPCServiceAdapterBase::sendPropertiesChanged(const QVariantMap &dirtyProperties ) +{ + LocalIPCMessage reply(FaceliftIPCCommon::PROPERTIES_INTERFACE_NAME, FaceliftIPCCommon::PROPERTIES_CHANGED_SIGNAL_NAME); + reply << interfaceName(); + reply << QVariant::fromValue(dirtyProperties); + this->send(reply); +} } diff --git a/tests/combined/check_combined.js b/tests/combined/check_combined.js index c93e9c9a..460dcb30 100644 --- a/tests/combined/check_combined.js +++ b/tests/combined/check_combined.js @@ -42,6 +42,8 @@ function defaults() { compare(api.structProperty2.cs.aString, ""); compare(api.structProperty2.e, 0); + compare(api.structWithExtDependency.otherEnums, []); + compare(api.intListProperty, []); compare(api.boolListProperty.length, 0); compare(api.enumListProperty.length, 0); @@ -66,6 +68,8 @@ function initialized() { compare(api.structProperty2.cs.aString, "ok"); compare(api.structProperty2.e, 1); + compare(api.structWithExtDependency.otherEnums[0], 1); + compare(api.intListProperty.length, 5); compare(api.intListProperty[2], 3); compare(api.boolListProperty.length, 3); @@ -85,6 +89,8 @@ function initialized() { compare(api.intMapProperty.one, 1); compare(api.intMapProperty.two, 2); + + compare(api.emptyString, ""); } function methods() { @@ -119,6 +125,8 @@ function methods() { os.ival = 101; compare(api.method7(os), OtherEnum.O3); + compare(api.listOfAnotherEnums()[0], OtherEnum.O2); + if (!api.qmlImplementationUsed) { api.interfaceProperty.doSomething(); compare(api.otherInterfaceProperty.otherMethod(OtherEnum.O3), "O3"); @@ -128,6 +136,9 @@ function methods() { asyncResult.answer = result; }); tryCompare(asyncResult, "answer", 42); + + api.interfaceMapProperty["key1"].doSomething(); + api.interfaceListProperty[0].doSomething(); } } diff --git a/tests/combined/client.cpp b/tests/combined/client.cpp new file mode 100644 index 00000000..e69de29b diff --git a/tests/combined/impl/cpp/CombinedTestsCppImplementation.h b/tests/combined/impl/cpp/CombinedTestsCppImplementation.h index b14c4c9b..a62cd4c1 100644 --- a/tests/combined/impl/cpp/CombinedTestsCppImplementation.h +++ b/tests/combined/impl/cpp/CombinedTestsCppImplementation.h @@ -100,9 +100,17 @@ class CombinedInterfaceImplementation : public CombinedInterfaceImplementationBa s2.sete(CombiEnum::E2); m_structProperty2 = s2; + StructWithExtDependency structWithExtDep; + structWithExtDep.setotherEnums({OtherEnum::O2}); + structWithExtDep.setotherEnumMap({{"O1", OtherEnum::O1}, {"O2", OtherEnum::O2}}); + m_structWithExtDependency.setValue(structWithExtDep); + m_interfaceProperty.setValue(new CombinedInterface2Implementation(this, "#7")); m_otherInterfaceProperty.setValue(new OtherInterfaceImplementation(this)); + m_interfaceListProperty.addElement(new CombinedInterface2Implementation(this, "")); + m_interfaceMapProperty = facelift::Map({{"key1", new CombinedInterface2Implementation(this, "blabla")}}); + m_intListProperty = { 1, 2, 3, 5, 8 }; m_boolListProperty = { false, true, true }; m_enumListProperty = { CombiEnum::E2 }; @@ -239,4 +247,15 @@ class CombinedInterfaceImplementation : public CombinedInterfaceImplementationBa return OtherEnum::O3; return OtherEnum::O1; } + + HugeStruct hungryBeast(const tests::combined::HugeStruct& hugeStruct) override + { + return hugeStruct; + } + + QList listOfAnotherEnums() override + { + QList anotherEnums{tests::combined::another::AnotherEnum::O2}; + return anotherEnums; + } }; diff --git a/tests/combined/impl/qml/CombinedTestsQmlImplementation.qml b/tests/combined/impl/qml/CombinedTestsQmlImplementation.qml index a520400d..ce075e33 100644 --- a/tests/combined/impl/qml/CombinedTestsQmlImplementation.qml +++ b/tests/combined/impl/qml/CombinedTestsQmlImplementation.qml @@ -100,6 +100,10 @@ CombinedInterfaceImplementationBase { return OtherEnum.O1; } + listOfAnotherEnums: function() { + return [OtherEnum.O2]; + } + initialize: function() { enumProperty = CombiEnum.E2; @@ -112,6 +116,9 @@ CombinedInterfaceImplementationBase { structProperty2.cs.aString = "ok"; structProperty2.e = CombiEnum.E2; + structWithExtDependency.otherEnums = [OtherEnum.O2]; + structWithExtDependency.otherEnumMap = {"O1": OtherEnum.O1, "O2": OtherEnum.O2}; + intListProperty = [ 1, 2, 3, 5, 8 ]; boolListProperty = [ false, true, true ]; enumListProperty = [ CombiEnum.E2 ]; diff --git a/src/ipc/ipc-common/ipc-serialization.cpp b/tests/combined/interface/another.qface similarity index 91% rename from src/ipc/ipc-common/ipc-serialization.cpp rename to tests/combined/interface/another.qface index 8a42c4c4..aa9ef41f 100644 --- a/src/ipc/ipc-common/ipc-serialization.cpp +++ b/tests/combined/interface/another.qface @@ -1,6 +1,6 @@ /********************************************************************** ** -** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Luxoft Sweden AB ** ** This file is part of the FaceLift project ** @@ -28,4 +28,10 @@ ** **********************************************************************/ -#include "ipc-serialization.h" +module tests.combined.another 1.0 + +enum AnotherEnum { + O1, + O2, + O3 +} diff --git a/tests/combined/interface/combined.qface b/tests/combined/interface/combined.qface index 1ae09edc..af4a77fa 100644 --- a/tests/combined/interface/combined.qface +++ b/tests/combined/interface/combined.qface @@ -30,6 +30,7 @@ module tests.combined 1.0 import tests.combined.other 1.0 +import tests.combined.another 1.0 @ipc-async: true @ipc-sync: true @@ -45,6 +46,7 @@ interface CombinedInterface { int intProperty; CombiStruct structProperty; CombiStruct2 structProperty2; + StructWithExtDependency structWithExtDependency; readonly CombinedInterface2 interfaceProperty; readonly list interfaceListProperty; @@ -79,7 +81,15 @@ interface CombinedInterface { signal eventBoolAndCombiStruct(bool p, CombiStruct q); signal eventWithList(list p, bool q); signal eventWithMap(map p); - signal eventWithStructWithList(StructWithList p) + signal eventWithStructWithList(StructWithList p); + + list listOfAnotherEnums(); + + readonly string emptyString; // check QVariant delivery + + OversizedStruct oversizedStruct; + HugeStruct hugeStruct; + HugeStruct hungryBeast(HugeStruct hugeStruct); } @ipc-async: true @@ -98,6 +108,14 @@ struct CombiStruct2 { CombiEnum e; } +struct StructWithExtDependency { + string aString; + int anInt; + tests.combined.other.OtherStruct otherStruct; + list otherEnums; + map otherEnumMap; +} + struct StructWithList { list listOfInts; list listOfStructs; @@ -109,3 +127,38 @@ enum CombiEnum { E2, E3, } + +struct FirstLevel { +string someString; +int someInt; +bool someBool; +string someOtherString; +int someOtherInt; +bool someOtherBool; +} + +struct SecondLevel { +FirstLevel firstLevel; +FirstLevel anotherfirstLevel; +FirstLevel yetAnotherFirstLevel; +} + +struct ThirdLevel { +SecondLevel secondLevel; +SecondLevel anotherSecondLevel; +SecondLevel yetAnotherSecondLevel; +} + +struct HugeStruct { + ThirdLevel thirdLevel; + ThirdLevel anotherThirdLevel; + ThirdLevel yetAnotherThirdLevel; +} + +@toByteArrayOverDBus: true +struct OversizedStruct { +ThirdLevel thirdLevel; +ThirdLevel anotherThirdLevel; +ThirdLevel yetAnotherThirdLevel; +ThirdLevel theKiller; +} diff --git a/tests/combined/interface/other.qface b/tests/combined/interface/other.qface index 512461b2..2e78260d 100644 --- a/tests/combined/interface/other.qface +++ b/tests/combined/interface/other.qface @@ -29,6 +29,7 @@ **********************************************************************/ module tests.combined.other 1.0 +import tests.combined.another 1.0 @ipc-async: true @ipc-sync: true @@ -44,6 +45,8 @@ interface OtherInterface { struct OtherStruct { string str; int ival; + tests.combined.another.AnotherEnum anotherenum; + OtherEnum otherEnum; } enum OtherEnum { diff --git a/tests/models/check_models.js b/tests/models/check_models.js index 901db31a..c8dce67a 100644 --- a/tests/models/check_models.js +++ b/tests/models/check_models.js @@ -43,6 +43,7 @@ function checkInit() tryVerify(function() { return api.ready; }); verify(api.theModel); compare(api.theModel.rowCount(), 100); + compare(api.oversizedStruct.theKiller.anotherSecondLevel.firstLevel.someOtherString, "someOtherString"); for(var i = 0; i < api.theModel.rowCount(); ++i) { compare(getData(i).name, "entry " + i); compare(getData(i).enabled, !(i%2)); diff --git a/tests/models/impl/cpp/ModelInterfaceCppImplementation.h b/tests/models/impl/cpp/ModelInterfaceCppImplementation.h index 0a153441..b916a36d 100644 --- a/tests/models/impl/cpp/ModelInterfaceCppImplementation.h +++ b/tests/models/impl/cpp/ModelInterfaceCppImplementation.h @@ -48,6 +48,34 @@ class ModelInterfaceImplementation : public ModelInterfaceImplementationBase m_items.append(i); m_nextAvailableID = i; + FirstLevel firstLevel; + firstLevel.setsomeString("someString"); + firstLevel.setsomeInt(10); + firstLevel.setsomeBool(true); + firstLevel.setsomeOtherString("someOtherString"); + firstLevel.setsomeOtherInt(20); + firstLevel.setsomeOtherBool(true); + SecondLevel secondLevel; + secondLevel.setfirstLevel(firstLevel); + secondLevel.setanotherfirstLevel(firstLevel); + secondLevel.setyetAnotherFirstLevel(firstLevel); + ThirdLevel thirdLevel; + thirdLevel.setsecondLevel(secondLevel); + thirdLevel.setanotherSecondLevel(secondLevel); + thirdLevel.setyetAnotherSecondLevel(secondLevel); + + HugeStruct hugeStruct; + hugeStruct.setthirdLevel(thirdLevel); + hugeStruct.setanotherThirdLevel(thirdLevel); + hugeStruct.setyetAnotherThirdLevel(thirdLevel); + m_hugeStruct.setValue(hugeStruct); + + OversizedStruct oversizedStruct; + oversizedStruct.setthirdLevel(thirdLevel); + oversizedStruct.setanotherThirdLevel(thirdLevel); + oversizedStruct.setyetAnotherThirdLevel(thirdLevel); + oversizedStruct.settheKiller(thirdLevel); + m_oversizedStruct.setValue(oversizedStruct); m_theModel.reset(m_items.size(), std::bind(&ModelInterfaceImplementation::getItem, this, std::placeholders::_1)); @@ -93,6 +121,11 @@ class ModelInterfaceImplementation : public ModelInterfaceImplementationBase emit m_theModel.dataChanged(first, last); } + HugeStruct hungryBeast(const tests::models::HugeStruct& hugeStruct) override + { + return hugeStruct; + } + private: QVector m_items; int m_nextAvailableID = 0; diff --git a/tests/models/interface/models.qface b/tests/models/interface/models.qface index e4ffddd6..2ce5297a 100644 --- a/tests/models/interface/models.qface +++ b/tests/models/interface/models.qface @@ -42,4 +42,44 @@ interface ModelInterface { void deleteModelItems(int first, int last); void insertNewModelItems(int first, int last); void renameModelItem(int first, int last, int serial); + + OversizedStruct oversizedStruct; + HugeStruct hugeStruct; + HugeStruct hungryBeast(HugeStruct hugeStruct); +} + + +struct FirstLevel { +string someString; +int someInt; +bool someBool; +string someOtherString; +int someOtherInt; +bool someOtherBool; +} + +struct SecondLevel { +FirstLevel firstLevel; +FirstLevel anotherfirstLevel; +FirstLevel yetAnotherFirstLevel; +} + +struct ThirdLevel { +SecondLevel secondLevel; +SecondLevel anotherSecondLevel; +SecondLevel yetAnotherSecondLevel; +} + +struct HugeStruct { + ThirdLevel thirdLevel; + ThirdLevel anotherThirdLevel; + ThirdLevel yetAnotherThirdLevel; +} + +@toByteArrayOverDBus: true +struct OversizedStruct { +ThirdLevel thirdLevel; +ThirdLevel anotherThirdLevel; +ThirdLevel yetAnotherThirdLevel; +ThirdLevel theKiller; } diff --git a/tests/objectregistry/client.cpp b/tests/objectregistry/client.cpp index 30d94104..b224e4ac 100644 --- a/tests/objectregistry/client.cpp +++ b/tests/objectregistry/client.cpp @@ -30,8 +30,8 @@ #include "client.h" #include #include "DBusManager.h" -#include "DBusIPCMessage.h" #include "DBusIPCCommon.h" +#include "DBusIPCMessage.h" #include void tests::ipc::Tester::registerAnotherAdapter()