also implement async replies

This commit is contained in:
Michael Zanetti 2014-04-13 22:40:11 +02:00
parent 961079c9d9
commit c56ebcb6a2
25 changed files with 454 additions and 96 deletions

View File

@ -146,18 +146,20 @@ QList<DeviceClass> DeviceManager::supportedDevices(const VendorId &vendorId) con
return ret;
}
QList<DeviceDescription> DeviceManager::discoveredDevices(const DeviceClassId &deviceClassId) const
DeviceManager::DeviceError DeviceManager::discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const
{
QList<DeviceDescription> ret;
DeviceClass deviceClass = findDeviceClass(deviceClassId);
if (!deviceClass.isValid()) {
return ret;
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
if (deviceClass.createMethod() != DeviceClass::CreateMethodDiscovery) {
return DeviceManager::DeviceErrorCreationMethodNotSupported;
}
DevicePlugin *plugin = m_devicePlugins.value(deviceClass.pluginId());
if (!plugin) {
return ret;
return DeviceManager::DeviceErrorPluginNotFound;
}
ret = plugin->discoveredDevices(deviceClassId);
return plugin->discoverDevices(deviceClassId, params);
}
/*! Add a new configured device for the given \l{DeviceClass} and the given parameters.
@ -175,7 +177,7 @@ DeviceManager::DeviceError DeviceManager::addConfiguredDevice(const DeviceClassI
if (deviceClass.createMethod() == DeviceClass::CreateMethodUser) {
return addConfiguredDeviceInternal(deviceClassId, params, id);
}
return DeviceErrorCreationNotSupported;
return DeviceErrorCreationMethodNotSupported;
}
DeviceManager::DeviceError DeviceManager::addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const QVariantMap &params, const DeviceId id)
@ -366,6 +368,7 @@ void DeviceManager::loadPlugins()
m_devicePlugins.insert(pluginIface->pluginId(), pluginIface);
connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::emitEvent);
connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered);
}
}
}
@ -430,6 +433,12 @@ void DeviceManager::createNewAutoDevices()
storeConfiguredDevices();
}
void DeviceManager::slotDevicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
m_discoveredDevices[deviceClassId] = deviceDescriptors;
emit devicesDiscovered(deviceClassId, deviceDescriptors);
}
void DeviceManager::slotDeviceStateValueChanged(const QUuid &stateTypeId, const QVariant &value)
{
Device *device = qobject_cast<Device*>(sender());

View File

@ -21,7 +21,7 @@
#include "plugin/deviceclass.h"
#include "plugin/device.h"
#include "plugin/devicedescription.h"
#include "plugin/devicedescriptor.h"
#include "types/event.h"
#include "types/action.h"
@ -55,7 +55,7 @@ public:
DeviceErrorPluginNotFound,
DeviceErrorSetupFailed,
DeviceErrorDuplicateUuid,
DeviceErrorCreationNotSupported,
DeviceErrorCreationMethodNotSupported,
DeviceErrorDeviceParameterError,
DeviceErrorActionParameterError
};
@ -68,7 +68,7 @@ public:
QList<Vendor> supportedVendors() const;
QList<DeviceClass> supportedDevices(const VendorId &vendorId = VendorId()) const;
QList<DeviceDescription> discoveredDevices(const DeviceClassId &deviceClassId) const;
DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const;
QList<Device*> configuredDevices() const;
DeviceError addConfiguredDevice(const DeviceClassId &deviceClassId, const QVariantMap &params, const DeviceId id = DeviceId::createDeviceId());
@ -82,6 +82,7 @@ signals:
void loaded();
void emitEvent(const Event &event);
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices);
public slots:
DeviceError executeAction(const Action &action);
@ -91,6 +92,7 @@ private slots:
void loadConfiguredDevices();
void storeConfiguredDevices();
void createNewAutoDevices();
void slotDevicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
// Only connect this to Devices. It will query the sender()
void slotDeviceStateValueChanged(const QUuid &stateTypeId, const QVariant &value);
@ -106,6 +108,7 @@ private:
QHash<VendorId, QList<DeviceClassId> > m_vendorDeviceMap;
QHash<DeviceClassId, DeviceClass> m_supportedDevices;
QList<Device*> m_configuredDevices;
QHash<DeviceClassId, QList<DeviceDescriptor> > m_discoveredDevices;
QHash<PluginId, DevicePlugin*> m_devicePlugins;

View File

@ -9,6 +9,7 @@ INSTALLS += target
SOURCES += plugin/device.cpp \
plugin/deviceclass.cpp \
plugin/deviceplugin.cpp \
plugin/devicedescriptor.cpp \
devicemanager.cpp \
hardware/radio433.cpp \
hardware/gpio.cpp \
@ -19,11 +20,11 @@ SOURCES += plugin/device.cpp \
types/eventtype.cpp \
types/event.cpp \
types/vendor.cpp \
plugin/devicedescription.cpp
HEADERS += plugin/device.h \
plugin/deviceclass.h \
plugin/deviceplugin.h \
plugin/devicedescriptor.h \
devicemanager.h \
hardware/radio433.h \
hardware/gpio.h \
@ -35,5 +36,4 @@ HEADERS += plugin/device.h \
types/event.h \
types/vendor.h \
types/typeutils.h \
plugin/devicedescription.h

View File

@ -1,5 +0,0 @@
#include "devicedescription.h"
DeviceDescription::DeviceDescription()
{
}

View File

@ -1,10 +0,0 @@
#ifndef DEVICEDESCRIPTION_H
#define DEVICEDESCRIPTION_H
class DeviceDescription
{
public:
DeviceDescription();
};
#endif // DEVICEDESCRIPTION_H

View File

@ -0,0 +1,49 @@
#include "devicedescriptor.h"
DeviceDescriptor::DeviceDescriptor(const DeviceDescriptorId &id, const DeviceClassId &deviceClassId, const QString &title, const QString &description) :
m_id(id),
m_deviceClassId(deviceClassId),
m_title(title),
m_description(description)
{
}
DeviceDescriptorId DeviceDescriptor::id() const
{
return m_id;
}
DeviceClassId DeviceDescriptor::deviceClassId() const
{
return m_deviceClassId;
}
QString DeviceDescriptor::title() const
{
return m_title;
}
void DeviceDescriptor::setTitle(const QString &title)
{
m_title = title;
}
QString DeviceDescriptor::description() const
{
return m_description;
}
void DeviceDescriptor::setDescription(const QString &description)
{
m_description = description;
}
QVariantMap DeviceDescriptor::params() const
{
return m_params;
}
void DeviceDescriptor::setParams(const QVariantMap &params)
{
m_params = params;
}

View File

@ -0,0 +1,33 @@
#ifndef DEVICEDESCRIPTION_H
#define DEVICEDESCRIPTION_H
#include <typeutils.h>
#include <QVariantMap>
class DeviceDescriptor
{
public:
DeviceDescriptor(const DeviceDescriptorId &id, const DeviceClassId &deviceClassId, const QString &title = QString(), const QString &description = QString());
DeviceDescriptorId id() const;
DeviceClassId deviceClassId() const;
QString title() const;
void setTitle(const QString &title);
QString description() const;
void setDescription(const QString &description);
QVariantMap params() const;
void setParams(const QVariantMap &params);
private:
DeviceDescriptorId m_id;
DeviceClassId m_deviceClassId;
QString m_title;
QString m_description;
QVariantMap m_params;
};
#endif // DEVICEDESCRIPTION_H

View File

@ -126,9 +126,11 @@ bool DevicePlugin::configureAutoDevice(QList<Device*> loadedDevices, Device *dev
return false;
}
QList<DeviceDescription> DevicePlugin::discoveredDevices(const DeviceClassId &deviceClassId) const
DeviceManager::DeviceError DevicePlugin::discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const
{
return QList<DeviceDescription>();
Q_UNUSED(deviceClassId)
Q_UNUSED(params)
return DeviceManager::DeviceErrorCreationMethodNotSupported;
}
/*! This will be called when a new device is created. The plugin has the chance to do some setup.

View File

@ -49,7 +49,7 @@ public:
virtual DeviceManager::HardwareResources requiredHardware() const = 0;
virtual bool configureAutoDevice(QList<Device *> loadedDevices, Device *device) const;
virtual QList<DeviceDescription> discoveredDevices(const DeviceClassId &deviceClassId) const;
virtual DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const;
virtual bool deviceCreated(Device *device);
virtual void deviceRemoved(Device *device);
@ -67,6 +67,7 @@ public slots:
signals:
void emitEvent(const Event &event);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
protected:
DeviceManager *deviceManager() const;

View File

@ -18,11 +18,11 @@ Q_DECLARE_METATYPE(type##Id);
DECLARE_TYPE_ID(Vendor)
DECLARE_TYPE_ID(DeviceClass)
DECLARE_TYPE_ID(Device)
DECLARE_TYPE_ID(DeviceDescriptor)
DECLARE_TYPE_ID(EventType)
DECLARE_TYPE_ID(StateType)
DECLARE_TYPE_ID(ActionType)
DECLARE_TYPE_ID(Plugin)
#endif // TYPEUTILS_H

View File

@ -289,8 +289,9 @@ QList<DeviceClass> DevicePluginOpenweathermap::supportedDevices() const
return ret;
}
QList<DeviceDescription> DevicePluginOpenweathermap::discoveredDevices(const DeviceClassId &deviceClassId) const
DeviceManager::DeviceError DevicePluginOpenweathermap::discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const
{
qDebug() << "should discover divces for" << deviceClassId << params;
// m_openweaher->
}

View File

@ -38,7 +38,7 @@ public:
QList<Vendor> supportedVendors() const override;
QList<DeviceClass> supportedDevices() const override;
QList<DeviceDescription> discoveredDevices(const DeviceClassId &deviceClassId) const;
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QVariantMap &params) const override;
DeviceManager::HardwareResources requiredHardware() const override;

View File

@ -43,7 +43,7 @@ QString ActionHandler::name() const
return "Actions";
}
QVariantMap ActionHandler::ExecuteAction(const QVariantMap &params)
JsonReply* ActionHandler::ExecuteAction(const QVariantMap &params)
{
DeviceId deviceId(params.value("deviceId").toString());
@ -81,5 +81,5 @@ QVariantMap ActionHandler::ExecuteAction(const QVariantMap &params)
returns.insert("success", false);
}
return returns;
return createReply(returns);
}

View File

@ -29,7 +29,7 @@ public:
QString name() const;
Q_INVOKABLE QVariantMap ExecuteAction(const QVariantMap &params);
Q_INVOKABLE JsonReply* ExecuteAction(const QVariantMap &params);
};
#endif // ACTIONHANDLER_H

View File

@ -85,6 +85,20 @@ DeviceHandler::DeviceHandler(QObject *parent) :
returns.insert("devices", devices);
setReturns("GetConfiguredDevices", returns);
params.clear(); returns.clear();
setDescription("GetDiscoveredDevices", "Performs a device discovery and returns the results. This function may take a while to return.");
params.insert("deviceClassId", "uuid");
QVariantList discoveryParams;
discoveryParams.append(JsonTypes::paramRef());
params.insert("o:discoveryParams", discoveryParams);
setParams("GetDiscoveredDevices", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
QVariantList deviceDescriptors;
deviceDescriptors.append(JsonTypes::deviceDescriptorRef());
returns.insert("o:deviceDescriptors", deviceDescriptors);
setReturns("GetDiscoveredDevices", returns);
params.clear(); returns.clear();
setDescription("RemoveConfiguredDevice", "Remove a device from the system.");
params.insert("deviceId", "uuid");
@ -146,7 +160,7 @@ QString DeviceHandler::name() const
return "Devices";
}
QVariantMap DeviceHandler::GetSupportedVendors(const QVariantMap &params) const
JsonReply* DeviceHandler::GetSupportedVendors(const QVariantMap &params) const
{
QVariantMap returns;
QVariantList supportedVendors;
@ -154,10 +168,10 @@ QVariantMap DeviceHandler::GetSupportedVendors(const QVariantMap &params) const
supportedVendors.append(JsonTypes::packVendor(vendor));
}
returns.insert("vendors", supportedVendors);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
JsonReply* DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
{
QVariantMap returns;
QVariantList supportedDeviceList;
@ -171,10 +185,37 @@ QVariantMap DeviceHandler::GetSupportedDevices(const QVariantMap &params) const
supportedDeviceList.append(JsonTypes::packDeviceClass(deviceClass));
}
returns.insert("deviceClasses", supportedDeviceList);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetPlugins(const QVariantMap &params) const
JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap &params) const
{
QVariantMap returns;
DeviceClassId deviceClassId = DeviceClassId(params.value("deviceClassId").toString());
DeviceManager::DeviceError status = GuhCore::instance()->deviceManager()->discoverDevices(deviceClassId, params.value("discoveryParams").toMap());
switch (status) {
case DeviceManager::DeviceErrorNoError: {
JsonReply *reply = createAsyncReply("GetDiscoveredDevices");
m_discoverRequests.insert(deviceClassId, reply);
return reply;
}
case DeviceManager::DeviceErrorDeviceClassNotFound:
returns.insert("errorMessage", "Cannot discover devices. Unknown DeviceClassId.");
break;
case DeviceManager::DeviceErrorPluginNotFound:
returns.insert("errorMessage", "Cannot discover devices. Plugin for DeviceClass not found.");
break;
default:
returns.insert("errorMessage", QString("Unknown error %1").arg(status));
}
returns.insert("success", false);
return createReply(returns);
}
JsonReply* DeviceHandler::GetPlugins(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
@ -187,18 +228,23 @@ QVariantMap DeviceHandler::GetPlugins(const QVariantMap &params) const
plugins.append(pluginMap);
}
returns.insert("plugins", plugins);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::SetPluginConfiguration(const QVariantMap &params)
JsonReply* DeviceHandler::SetPluginConfiguration(const QVariantMap &params)
{
QVariantMap returns;
PluginId pluginId = PluginId(params.value("pluginId").toString());
QVariantMap pluginParams = params.value("pluginParams").toMap();
GuhCore::instance()->deviceManager()->setPluginConfig(pluginId, pluginParams);
return QVariantMap();
// TODO: handle return values
returns.insert("errorMessage", QString());
returns.insert("success", true);
return createReply(returns);
}
QVariantMap DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
{
DeviceClassId deviceClass(params.value("deviceClassId").toString());
QVariantMap deviceParams = params.value("deviceParams").toMap();
@ -223,7 +269,7 @@ QVariantMap DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
returns.insert("errorMessage", "Error creating device. Device setup failed.");
returns.insert("success", false);
break;
case DeviceManager::DeviceErrorCreationNotSupported:
case DeviceManager::DeviceErrorCreationMethodNotSupported:
returns.insert("errorMessage", "Error creating device. This device can't be created this way.");
returns.insert("success", false);
break;
@ -235,10 +281,10 @@ QVariantMap DeviceHandler::AddConfiguredDevice(const QVariantMap &params)
returns.insert("errorMessage", "Unknown error.");
returns.insert("success", false);
}
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap returns;
@ -247,28 +293,28 @@ QVariantMap DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
configuredDeviceList.append(JsonTypes::packDevice(device));
}
returns.insert("devices", configuredDeviceList);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
{
QVariantMap returns;
switch(GuhCore::instance()->deviceManager()->removeConfiguredDevice(DeviceId(params.value("deviceId").toString()))) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
returns.insert("errorMessage", "");
return returns;
return createReply(returns);
case DeviceManager::DeviceErrorDeviceNotFound:
returns.insert("success", false);
returns.insert("errorMessage", "No such device.");
return returns;
return createReply(returns);
}
returns.insert("success", false);
returns.insert("errorMessage", "Unknown error.");
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetEventTypes(const QVariantMap &params) const
JsonReply* DeviceHandler::GetEventTypes(const QVariantMap &params) const
{
QVariantMap returns;
@ -278,10 +324,10 @@ QVariantMap DeviceHandler::GetEventTypes(const QVariantMap &params) const
eventList.append(JsonTypes::packEventType(eventType));
}
returns.insert("eventTypes", eventList);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetActionTypes(const QVariantMap &params) const
JsonReply* DeviceHandler::GetActionTypes(const QVariantMap &params) const
{
QVariantMap returns;
@ -291,10 +337,10 @@ QVariantMap DeviceHandler::GetActionTypes(const QVariantMap &params) const
actionList.append(JsonTypes::packActionType(actionType));
}
returns.insert("actionTypes", actionList);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetStateTypes(const QVariantMap &params) const
JsonReply* DeviceHandler::GetStateTypes(const QVariantMap &params) const
{
QVariantMap returns;
@ -304,10 +350,10 @@ QVariantMap DeviceHandler::GetStateTypes(const QVariantMap &params) const
stateList.append(JsonTypes::packStateType(stateType));
}
returns.insert("stateTypes", stateList);
return returns;
return createReply(returns);
}
QVariantMap DeviceHandler::GetStateValue(const QVariantMap &params) const
JsonReply* DeviceHandler::GetStateValue(const QVariantMap &params) const
{
QVariantMap returns;
@ -315,19 +361,19 @@ QVariantMap DeviceHandler::GetStateValue(const QVariantMap &params) const
if (!device) {
returns.insert("success", false);
returns.insert("errorMessage", "No such device");
return returns;
return createReply(returns);
}
if (!device->hasState(params.value("stateTypeId").toUuid())) {
returns.insert("success", false);
returns.insert("errorMessage", QString("Device %1 %2 doesn't have such a state.").arg(device->name()).arg(device->id().toString()));
return returns;
return createReply(returns);
}
QVariant stateValue = device->stateValue(params.value("stateTypeId").toUuid());
returns.insert("success", true);
returns.insert("errorMessage", "");
returns.insert("value", stateValue);
return returns;
return createReply(returns);
}
void DeviceHandler::deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value)
@ -339,3 +385,23 @@ void DeviceHandler::deviceStateChanged(Device *device, const QUuid &stateTypeId,
emit StateChanged(params);
}
void DeviceHandler::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
if (!m_discoverRequests.contains(deviceClassId)) {
return; // We didn't start this discovery... Ignore it.
}
JsonReply *reply = m_discoverRequests.take(deviceClassId);
QVariantList list;
foreach (const DeviceDescriptor &descriptor, deviceDescriptors) {
list.append(JsonTypes::packDeviceDescriptor(descriptor));
}
QVariantMap returns;
returns.insert("deviceDescriptors", list);
returns.insert("success", true);
returns.insert("errorMessage", "");
reply->setData(returns);
reply->finished();
}

View File

@ -29,33 +29,41 @@ public:
QString name() const override;
Q_INVOKABLE QVariantMap GetSupportedVendors(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetSupportedVendors(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetSupportedDevices(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetSupportedDevices(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetPlugins(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetDiscoveredDevices(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap SetPluginConfiguration(const QVariantMap &params);
Q_INVOKABLE JsonReply* GetPlugins(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap AddConfiguredDevice(const QVariantMap &params);
Q_INVOKABLE JsonReply* SetPluginConfiguration(const QVariantMap &params);
Q_INVOKABLE QVariantMap GetConfiguredDevices(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* AddConfiguredDevice(const QVariantMap &params);
Q_INVOKABLE QVariantMap RemoveConfiguredDevice(const QVariantMap &params);
Q_INVOKABLE JsonReply* GetConfiguredDevices(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetEventTypes(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* RemoveConfiguredDevice(const QVariantMap &params);
Q_INVOKABLE QVariantMap GetActionTypes(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetEventTypes(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetStateTypes(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetActionTypes(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap GetStateValue(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetStateTypes(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* GetStateValue(const QVariantMap &params) const;
signals:
void StateChanged(const QVariantMap &params);
private slots:
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
private:
// A cache for async replies
mutable QHash<DeviceClassId, JsonReply*> m_discoverRequests;
};
#endif // DEVICEHANDLER_H

View File

@ -119,3 +119,90 @@ void JsonHandler::setReturns(const QString &methodName, const QVariantMap &retur
}
qWarning() << "Cannot set returns. No such method:" << methodName;
}
JsonReply *JsonHandler::createReply(const QVariantMap &data) const
{
return JsonReply::createReply(const_cast<JsonHandler*>(this), data);
}
JsonReply* JsonHandler::createAsyncReply(const QString &method) const
{
return JsonReply::createAsyncReply(const_cast<JsonHandler*>(this), method);
}
JsonReply::JsonReply(Type type, JsonHandler *handler, const QString &method, const QVariantMap &data):
m_handler(handler),
m_method(method),
m_type(type),
m_data(data)
{
connect(&m_timeout, &QTimer::timeout, this, &JsonReply::timeout);
}
JsonReply *JsonReply::createReply(JsonHandler *handler, const QVariantMap &data)
{
return new JsonReply(TypeSync, handler, QString(), data);
}
JsonReply *JsonReply::createAsyncReply(JsonHandler *handler, const QString &method)
{
return new JsonReply(TypeAsync, handler, method);
}
JsonReply::Type JsonReply::type() const
{
return m_type;
}
QVariantMap JsonReply::data() const
{
return m_data;
}
void JsonReply::setData(const QVariantMap &data)
{
m_data = data;
}
JsonHandler *JsonReply::handler() const
{
return m_handler;
}
QString JsonReply::method() const
{
return m_method;
}
QUuid JsonReply::clientId() const
{
return m_clientId;
}
void JsonReply::setClientId(const QUuid &clientId)
{
m_clientId = clientId;
}
int JsonReply::commandId() const
{
return m_commandId;
}
void JsonReply::setCommandId(int commandId)
{
m_commandId = commandId;
}
void JsonReply::startWait()
{
m_timeout.start(5000);
}
void JsonReply::timeout()
{
m_data.insert("success", false);
m_data.insert("errorMessage", "Command timed out.");
finished();
}

View File

@ -24,6 +24,57 @@
#include <QObject>
#include <QVariantMap>
#include <QMetaMethod>
#include <QTimer>
class JsonHandler;
class JsonReply: public QObject
{
Q_OBJECT
public:
enum Type {
TypeSync,
TypeAsync
};
static JsonReply* createReply(JsonHandler *handler, const QVariantMap &data);
static JsonReply* createAsyncReply(JsonHandler *handler, const QString &method);
Type type() const;
QVariantMap data() const;
void setData(const QVariantMap &data);
JsonHandler *handler() const;
QString method() const;
QUuid clientId() const;
void setClientId(const QUuid &clientId);
int commandId() const;
void setCommandId(int commandId);
public slots:
void startWait();
signals:
void finished();
private slots:
void timeout();
private:
JsonReply(Type type, JsonHandler *handler, const QString &method, const QVariantMap &data = QVariantMap());
Type m_type;
QVariantMap m_data;
JsonHandler *m_handler;
QString m_method;
QUuid m_clientId;
int m_commandId;
QTimer m_timeout;
};
class JsonHandler : public QObject
{
@ -39,11 +90,17 @@ public:
QPair<bool, QString> validateParams(const QString &methodName, const QVariantMap &params);
QPair<bool, QString> validateReturns(const QString &methodName, const QVariantMap &returns);
signals:
void asyncReply(int id, const QVariantMap &params);
protected:
void setDescription(const QString &methodName, const QString &description);
void setParams(const QString &methodName, const QVariantMap &params);
void setReturns(const QString &methodName, const QVariantMap &returns);
JsonReply *createReply(const QVariantMap &data) const;
JsonReply *createAsyncReply(const QString &method) const;
private:
QHash<QString, QString> m_descriptions;
QHash<QString, QVariantMap> m_params;

View File

@ -90,7 +90,7 @@ QString JsonRPCServer::name() const
return QStringLiteral("JSONRPC");
}
QVariantMap JsonRPCServer::Introspect(const QVariantMap &params) const
JsonReply* JsonRPCServer::Introspect(const QVariantMap &params) const
{
Q_UNUSED(params)
@ -108,19 +108,19 @@ QVariantMap JsonRPCServer::Introspect(const QVariantMap &params) const
}
data.insert("notifications", signalsMap);
return data;
return createReply(data);
}
QVariantMap JsonRPCServer::Version(const QVariantMap &params) const
JsonReply* JsonRPCServer::Version(const QVariantMap &params) const
{
Q_UNUSED(params)
QVariantMap data;
data.insert("version", "0.0.0");
return data;
return createReply(data);
}
QVariantMap JsonRPCServer::SetNotificationStatus(const QVariantMap &params)
JsonReply* JsonRPCServer::SetNotificationStatus(const QVariantMap &params)
{
QUuid clientId = this->property("clientId").toUuid();
// qDebug() << "got client socket" << clientId;
@ -129,7 +129,7 @@ QVariantMap JsonRPCServer::SetNotificationStatus(const QVariantMap &params)
returns.insert("success", "true");
returns.insert("errorMessage", "No error");
returns.insert("enabled", m_clients[clientId]);
return returns;
return createReply(returns);
}
void JsonRPCServer::setup()
@ -192,10 +192,19 @@ void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &jsonDat
// Hack: attach clientId to handler to be able to handle the JSONRPC methods. Do not use this outside of jsonrpcserver
handler->setProperty("clientId", clientId);
QVariantMap returns;
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(QVariantMap, returns), Q_ARG(QVariantMap, params));
Q_ASSERT((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, returns).first);
sendResponse(clientId, commandId, returns);
JsonReply *reply;
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(JsonReply*, reply), Q_ARG(QVariantMap, params));
if (reply->type() == JsonReply::TypeAsync) {
qDebug() << "got an async reply...";
reply->setClientId(clientId);
reply->setCommandId(commandId);
connect(reply, &JsonReply::finished, this, &JsonRPCServer::asyncReplyFinished);
reply->startWait();
} else {
Q_ASSERT((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, reply->data()).first);
sendResponse(clientId, commandId, reply->data());
reply->deleteLater();
}
}
void JsonRPCServer::sendNotification(const QVariantMap &params)
@ -212,9 +221,24 @@ void JsonRPCServer::sendNotification(const QVariantMap &params)
m_tcpServer->sendData(m_clients.keys(true), jsonDoc.toJson());
}
void JsonRPCServer::sendAsyncReply(int id, const QVariantMap &params)
{
qDebug() << "should send async reply";
}
void JsonRPCServer::asyncReplyFinished()
{
JsonReply *reply = qobject_cast<JsonReply*>(sender());
qDebug() << "got async reply:" << reply->method() << reply->data();
Q_ASSERT(reply->handler()->validateReturns(reply->method(), reply->data()).first);
sendResponse(reply->clientId(), reply->commandId(), reply->data());
reply->deleteLater();
}
void JsonRPCServer::registerHandler(JsonHandler *handler)
{
m_handlers.insert(handler->name(), handler);
connect(handler, &JsonHandler::asyncReply, this, &JsonRPCServer::sendAsyncReply);
for (int i = 0; i < handler->metaObject()->methodCount(); ++i) {
QMetaMethod method = handler->metaObject()->method(i);
if (method.methodType() == QMetaMethod::Signal && QString(method.name()).contains(QRegExp("^[A-Z]"))) {

View File

@ -44,9 +44,9 @@ public:
// JsonHandler API implementation
QString name() const;
Q_INVOKABLE QVariantMap Introspect(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap Version(const QVariantMap &params) const;
Q_INVOKABLE QVariantMap SetNotificationStatus(const QVariantMap &params);
Q_INVOKABLE JsonReply* Introspect(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* Version(const QVariantMap &params) const;
Q_INVOKABLE JsonReply* SetNotificationStatus(const QVariantMap &params);
signals:
void commandReceived(const QString &targetNamespace, const QString &command, const QVariantMap &params);
@ -60,6 +60,9 @@ private slots:
void processData(const QUuid &clientId, const QByteArray &jsonData);
void sendNotification(const QVariantMap &params);
void sendAsyncReply(int id, const QVariantMap &params);
void asyncReplyFinished();
private:
void registerHandler(JsonHandler *handler);

View File

@ -44,6 +44,7 @@ QVariantMap JsonTypes::s_plugin;
QVariantMap JsonTypes::s_vendor;
QVariantMap JsonTypes::s_deviceClass;
QVariantMap JsonTypes::s_device;
QVariantMap JsonTypes::s_deviceDescriptor;
QVariantMap JsonTypes::s_rule;
void JsonTypes::init()
@ -120,6 +121,11 @@ void JsonTypes::init()
s_device.insert("name", "string");
s_device.insert("params", QVariantList() << paramRef());
// DeviceDescription
s_deviceDescriptor.insert("id", "uuid");
s_deviceDescriptor.insert("title", "string");
s_deviceDescriptor.insert("description", "string");
s_rule.insert("id", "uuid");
s_rule.insert("ruleType", ruleTypesRef());
s_rule.insert("events", QVariantList() << eventRef());
@ -151,6 +157,7 @@ QVariantMap JsonTypes::allTypes()
allTypes.insert("State", stateDescription());
allTypes.insert("Event", eventDescription());
allTypes.insert("Device", deviceDescription());
allTypes.insert("DeviceDescriptor", deviceDescriptorDescription());
allTypes.insert("Action", actionDescription());
allTypes.insert("RuleType", ruleTypes());
allTypes.insert("Rule", ruleDescription());
@ -252,6 +259,15 @@ QVariantMap JsonTypes::packDevice(Device *device)
return variant;
}
QVariantMap JsonTypes::packDeviceDescriptor(const DeviceDescriptor &descriptor)
{
QVariantMap variant;
variant.insert("id", descriptor.id());
variant.insert("title", descriptor.title());
variant.insert("description", descriptor.description());
return variant;
}
QVariantMap JsonTypes::packRule(const Rule &rule)
{
QVariantMap ruleMap;

View File

@ -20,6 +20,7 @@
#define JSONTYPES_H
#include "plugin/deviceclass.h"
#include "plugin/devicedescriptor.h"
#include "rule.h"
#include "types/event.h"
@ -77,6 +78,7 @@ public:
DECLARE_OBJECT(vendor, "Vendor")
DECLARE_OBJECT(deviceClass, "DeviceClass")
DECLARE_OBJECT(device, "Device")
DECLARE_OBJECT(deviceDescriptor, "DeviceDescriptor")
DECLARE_OBJECT(rule, "Rule")
static QVariantMap packEventType(const EventType &eventType);
@ -88,6 +90,7 @@ public:
static QVariantMap packDeviceClass(const DeviceClass &deviceClass);
static QVariantMap packPlugin(DevicePlugin *plugin);
static QVariantMap packDevice(Device *device);
static QVariantMap packDeviceDescriptor(const DeviceDescriptor &descriptor);
static QVariantMap packRule(const Rule &rule);
static QPair<bool, QString> validateMap(const QVariantMap &templateMap, const QVariantMap &map);

View File

@ -60,7 +60,7 @@ QString RulesHandler::name() const
return "Rules";
}
QVariantMap RulesHandler::GetRules(const QVariantMap &params)
JsonReply* RulesHandler::GetRules(const QVariantMap &params)
{
Q_UNUSED(params)
@ -73,10 +73,10 @@ QVariantMap RulesHandler::GetRules(const QVariantMap &params)
QVariantMap returns;
returns.insert("rules", rulesList);
return returns;
return createReply(returns);
}
QVariantMap RulesHandler::AddRule(const QVariantMap &params)
JsonReply* RulesHandler::AddRule(const QVariantMap &params)
{
QVariantMap eventMap = params.value("event").toMap();
@ -99,7 +99,7 @@ QVariantMap RulesHandler::AddRule(const QVariantMap &params)
if (actions.count() == 0) {
returns.insert("success", false);
returns.insert("errorMessage", "Missing parameter: \"actions\".");
return returns;
return createReply(returns);
}
switch(GuhCore::instance()->ruleEngine()->addRule(event, actions)) {
@ -119,10 +119,10 @@ QVariantMap RulesHandler::AddRule(const QVariantMap &params)
returns.insert("success", false);
returns.insert("errorMessage", "Unknown error");
}
return returns;
return createReply(returns);
}
QVariantMap RulesHandler::RemoveRule(const QVariantMap &params)
JsonReply* RulesHandler::RemoveRule(const QVariantMap &params)
{
QVariantMap returns;
QUuid ruleId = params.value("ruleId").toUuid();
@ -138,5 +138,5 @@ QVariantMap RulesHandler::RemoveRule(const QVariantMap &params)
returns.insert("success", false);
returns.insert("errorMessage", "Unknown error");
}
return returns;
return createReply(returns);
}

View File

@ -29,10 +29,10 @@ public:
QString name() const override;
Q_INVOKABLE QVariantMap GetRules(const QVariantMap &params);
Q_INVOKABLE JsonReply* GetRules(const QVariantMap &params);
Q_INVOKABLE QVariantMap AddRule(const QVariantMap &params);
Q_INVOKABLE QVariantMap RemoveRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* AddRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* RemoveRule(const QVariantMap &params);
};

View File

@ -0,0 +1,11 @@
#!/bin/bash
if [ -z $2 ]; then
echo "usage $0 host deviceclassid [paramname paramvalue]"
elif [ -z $3 ]; then
(echo '{"id":1, "method":"Devices.GetDiscoveredDevices", "params":{"deviceClassId":"'$2'"}}'; sleep 6) | nc $1 1234
elif [ -z $4 ]; then
echo "usage $0 host deviceclassid [paramname paramvalue]"
else
(echo '{"id":1, "method":"Devices.GetDiscoveredDevices", "params":{"deviceClassId":"'$2'", "discoveryParams": {"'$3'":"'$4'"}}}'; sleep 6) | nc $1 1234
fi