From 7c4354a6e1d3cb2583857b164a20e671afcc1c92 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 3 May 2014 19:59:24 +0200 Subject: [PATCH] add api to do async action executions --- libguh/devicemanager.cpp | 1 + libguh/devicemanager.h | 1 + libguh/plugin/deviceplugin.cpp | 14 +++++++++- libguh/plugin/deviceplugin.h | 1 + libguh/types/action.cpp | 8 +++++- libguh/types/action.h | 5 +++- libguh/types/event.cpp | 8 ++++++ libguh/types/event.h | 3 +++ libguh/types/state.cpp | 6 +++++ libguh/types/state.h | 3 +++ libguh/typeutils.h | 3 +++ server/jsonrpc/actionhandler.cpp | 44 ++++++++++++++++++++++++-------- server/jsonrpc/actionhandler.h | 10 ++++++++ server/jsonrpc/ruleshandler.cpp | 2 +- server/ruleengine.cpp | 2 +- 15 files changed, 96 insertions(+), 15 deletions(-) diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 76f70124..4299385e 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -418,6 +418,7 @@ void DeviceManager::loadPlugins() connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::emitEvent); connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered); connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); + connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished); } } } diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index 0129e571..48489a83 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -93,6 +93,7 @@ signals: void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value); void devicesDiscovered(const DeviceClassId &deviceClassId, const QList &devices); void deviceSetupFinished(Device *device, DeviceError status, const QString &errorMessage); + void actionExecutionFinished(const ActionId, DeviceError status, const QString &errorMessage); public slots: QPair executeAction(const Action &action); diff --git a/libguh/plugin/deviceplugin.cpp b/libguh/plugin/deviceplugin.cpp index 1479ce42..c726d55c 100644 --- a/libguh/plugin/deviceplugin.cpp +++ b/libguh/plugin/deviceplugin.cpp @@ -74,9 +74,21 @@ pure virtual methods: \l{DevicePlugin::pluginName()}, \l{DevicePlugin::pluginId( return report(DeviceManager::DeviceErrorSetupFailed, device->id()); Keep the message short, the DeviceManager will format it for you. - \sa DevicePlugin::report() + It is possible to execute actions asynchronously. You never should do anything blocking for + a long time (e.g. wait on a network reply from the internet) but instead return + DeviceManager::DeviceErrorAsync and continue processing in an async manner. Once + you have the reply ready, emit actionExecutionFinished() with the appropriate parameters. + + \sa DevicePlugin::report() DevicePlugin::actionExecutionFinished() */ +/*! + \fn void DevicePlugin::actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage) + This signal is to be emitted when you previously have returned DeviceManager::DeviceErrorAsync + in a call of executeAction(). It is used to deliver the return value that previously has + been omitted by filling in DeviceErrorAsync. + */ + /*! \fn void DevicePlugin::emitEvent(const Event &event) To produce a new event in the system, create a new \l{Event} and emit it with \a event. diff --git a/libguh/plugin/deviceplugin.h b/libguh/plugin/deviceplugin.h index f8237b3c..1689fc94 100644 --- a/libguh/plugin/deviceplugin.h +++ b/libguh/plugin/deviceplugin.h @@ -71,6 +71,7 @@ signals: void emitEvent(const Event &event); void devicesDiscovered(const DeviceClassId &deviceClassId, const QList &deviceDescriptors); void deviceSetupFinished(Device *device, DeviceManager::DeviceSetupStatus status, const QString &errorMessage); + void actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage); protected: DeviceManager *deviceManager() const; diff --git a/libguh/types/action.cpp b/libguh/types/action.cpp index 33e3a17b..638e1d7b 100644 --- a/libguh/types/action.cpp +++ b/libguh/types/action.cpp @@ -33,12 +33,18 @@ #include "action.h" /*! Construct an Action with the given \a deviceId and \a actionTypeId */ -Action::Action(const DeviceId &deviceId, const ActionTypeId &actionTypeId) : +Action::Action(const ActionTypeId &actionTypeId, const DeviceId &deviceId) : + m_id(ActionId::createActionId()), m_actionTypeId(actionTypeId), m_deviceId(deviceId) { } +ActionId Action::id() const +{ + return m_id; +} + /*! An Action is valid if actionTypeId and deviceId are valid uuids. Returns true if valid, false if not. */ bool Action::isValid() const { diff --git a/libguh/types/action.h b/libguh/types/action.h index 3488990e..9b4eccac 100644 --- a/libguh/types/action.h +++ b/libguh/types/action.h @@ -27,7 +27,9 @@ class Action { public: - explicit Action(const DeviceId &deviceId, const ActionTypeId &actionTypeId); + explicit Action(const ActionTypeId &actionTypeId, const DeviceId &deviceId); + + ActionId id() const; bool isValid() const; @@ -39,6 +41,7 @@ public: Param param(const QString ¶mName) const; private: + ActionId m_id; ActionTypeId m_actionTypeId; DeviceId m_deviceId; QList m_params; diff --git a/libguh/types/event.cpp b/libguh/types/event.cpp index dd7ba201..0f84f997 100644 --- a/libguh/types/event.cpp +++ b/libguh/types/event.cpp @@ -37,12 +37,20 @@ the \l{Device} given by \a deviceId and the parameters given by \a params. The parameters must match the description in the reflecting \l{Event}.*/ Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶ms): + m_id(EventId::createEventId()), m_eventTypeId(eventTypeId), m_deviceId(deviceId), m_params(params) { } +/*! Returns this event's id. Each newly created event will have a new UUID generated. The id will be copied + in the copy ctor.*/ +EventId Event::eventId() const +{ + return m_id; +} + /*! Returns the id of the \l{EventType} which describes this Event.*/ EventTypeId Event::eventTypeId() const { diff --git a/libguh/types/event.h b/libguh/types/event.h index b4a0a499..cf9f9efa 100644 --- a/libguh/types/event.h +++ b/libguh/types/event.h @@ -31,6 +31,8 @@ class Event public: Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶ms = QList()); + EventId eventId() const; + EventTypeId eventTypeId() const; DeviceId deviceId() const; @@ -41,6 +43,7 @@ public: bool operator ==(const Event &other) const; private: + EventId m_id; EventTypeId m_eventTypeId; DeviceId m_deviceId; QList m_params; diff --git a/libguh/types/state.cpp b/libguh/types/state.cpp index d9a788fe..806045df 100644 --- a/libguh/types/state.cpp +++ b/libguh/types/state.cpp @@ -34,11 +34,17 @@ /*! Constructs a State reflecting the \l{StateType} given by \a stateTypeId and associated with the \l{Device} given by \a deviceId */ State::State(const StateTypeId &stateTypeId, const DeviceId &deviceId): + m_id(StateId::createStateId()), m_stateTypeId(stateTypeId), m_deviceId(deviceId) { } +StateId State::id() const +{ + return m_id; +} + /*! Returns the id of the StateType describing this State. */ StateTypeId State::stateTypeId() const { diff --git a/libguh/types/state.h b/libguh/types/state.h index fe5eb784..872d1d31 100644 --- a/libguh/types/state.h +++ b/libguh/types/state.h @@ -29,6 +29,8 @@ class State public: State(const StateTypeId &stateTypeId, const DeviceId &deviceId); + StateId id() const; + StateTypeId stateTypeId() const; DeviceId deviceId() const; @@ -37,6 +39,7 @@ public: void setValue(const QVariant &value); private: + StateId m_id; StateTypeId m_stateTypeId; DeviceId m_deviceId; QVariant m_value; diff --git a/libguh/typeutils.h b/libguh/typeutils.h index 985a1036..ed2ee8e3 100644 --- a/libguh/typeutils.h +++ b/libguh/typeutils.h @@ -42,8 +42,11 @@ DECLARE_TYPE_ID(Device) DECLARE_TYPE_ID(DeviceDescriptor) DECLARE_TYPE_ID(EventType) +DECLARE_TYPE_ID(Event) DECLARE_TYPE_ID(StateType) +DECLARE_TYPE_ID(State) DECLARE_TYPE_ID(ActionType) +DECLARE_TYPE_ID(Action) DECLARE_TYPE_ID(Plugin) #endif // TYPEUTILS_H diff --git a/server/jsonrpc/actionhandler.cpp b/server/jsonrpc/actionhandler.cpp index 46a7c9a7..f95f8a37 100644 --- a/server/jsonrpc/actionhandler.cpp +++ b/server/jsonrpc/actionhandler.cpp @@ -36,6 +36,8 @@ ActionHandler::ActionHandler(QObject *parent) : returns.insert("success", "bool"); returns.insert("errorMessage", "string"); setReturns("ExecuteAction", returns); + + connect(GuhCore::instance()->deviceManager(), &DeviceManager::actionExecutionFinished, this, &ActionHandler::actionExecuted); } QString ActionHandler::name() const @@ -50,36 +52,58 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms) ActionTypeId actionTypeId(params.value("actionTypeId").toString()); QList actionParams = JsonTypes::unpackParams(params.value("params").toList()); - Action action(deviceId, actionTypeId); + Action action(actionTypeId, deviceId); action.setParams(actionParams); qDebug() << "actions params in json" << action.params() << params; - QVariantMap returns; - QPair error = GuhCore::instance()->deviceManager()->executeAction(action); + QPair status = GuhCore::instance()->deviceManager()->executeAction(action); + if (status.first == DeviceManager::DeviceErrorAsync) { + JsonReply *reply = createAsyncReply("ExecuteAction"); + m_asyncActionExecutions.insert(action.id(), reply); + return reply; + } - switch (error.first) { + QVariantMap returns = statusToReply(status.first, status.second); + return createReply(returns); +} + +void ActionHandler::actionExecuted(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage) +{ + if (!m_asyncActionExecutions.contains(id)) { + return; // Not the action we are waiting for. + } + + JsonReply *reply = m_asyncActionExecutions.take(id); + reply->setData(statusToReply(status, errorMessage)); + reply->finished(); +} + +QVariantMap ActionHandler::statusToReply(DeviceManager::DeviceError status, const QString &errorMessage) +{ + QVariantMap returns; + + switch (status) { case DeviceManager::DeviceErrorNoError: returns.insert("success", true); returns.insert("errorMessage", ""); break; case DeviceManager::DeviceErrorDeviceNotFound: - returns.insert("errorMessage", QString("No such device: %1").arg(error.second)); + returns.insert("errorMessage", QString("No such device: %1").arg(errorMessage)); returns.insert("success", false); break; case DeviceManager::DeviceErrorActionTypeNotFound: - returns.insert("errorMessage", QString("ActionType not found: %1").arg(error.second)); + returns.insert("errorMessage", QString("ActionType not found: %1").arg(errorMessage)); returns.insert("success", false); break; case DeviceManager::DeviceErrorMissingParameter: - returns.insert("errorMessage", QString("Missing parameter: %1").arg(error.second)); + returns.insert("errorMessage", QString("Missing parameter: %1").arg(errorMessage)); returns.insert("success", false); break; default: - returns.insert("errorMessage", QString("Unknown error %1 %2").arg(error.first).arg(error.second)); + returns.insert("errorMessage", QString("Unknown error %1 %2").arg(status).arg(errorMessage)); returns.insert("success", false); } - - return createReply(returns); + return returns; } diff --git a/server/jsonrpc/actionhandler.h b/server/jsonrpc/actionhandler.h index a75d43b9..151feaa8 100644 --- a/server/jsonrpc/actionhandler.h +++ b/server/jsonrpc/actionhandler.h @@ -20,6 +20,7 @@ #define ACTIONHANDLER_H #include "jsonhandler.h" +#include "devicemanager.h" class ActionHandler : public JsonHandler { @@ -30,6 +31,15 @@ public: QString name() const; Q_INVOKABLE JsonReply* ExecuteAction(const QVariantMap ¶ms); + +private slots: + void actionExecuted(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage); + +private: + QVariantMap statusToReply(DeviceManager::DeviceError status, const QString &errorMessage); + +private: + QHash m_asyncActionExecutions; }; #endif // ACTIONHANDLER_H diff --git a/server/jsonrpc/ruleshandler.cpp b/server/jsonrpc/ruleshandler.cpp index 9c017fa7..8f5fd95c 100644 --- a/server/jsonrpc/ruleshandler.cpp +++ b/server/jsonrpc/ruleshandler.cpp @@ -90,7 +90,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) qDebug() << "got action list" << actionList.count(); foreach (const QVariant &actionVariant, actionList) { QVariantMap actionMap = actionVariant.toMap(); - Action action(DeviceId(actionMap.value("deviceId").toString()), ActionTypeId(actionMap.value("actionTypeId").toString())); + Action action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString())); action.setParams(JsonTypes::unpackParams(actionMap.value("params").toList())); actions.append(action); } diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index 71761385..b15a2aea 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -110,7 +110,7 @@ RuleEngine::RuleEngine(QObject *parent) : QList actions; foreach (const QString &actionIdString, settings.childGroups()) { settings.beginGroup(actionIdString); - Action action = Action(DeviceId(settings.value("deviceId").toString()), ActionTypeId(settings.value("actionTypeId").toString())); + Action action = Action(ActionTypeId(settings.value("actionTypeId").toString()), DeviceId(settings.value("deviceId").toString())); QList params; foreach (QString paramNameString, settings.childGroups()) { if (paramNameString.startsWith("Param-")) {