add api to do async action executions

This commit is contained in:
Michael Zanetti 2014-05-03 19:59:24 +02:00
parent 2e0dfa9947
commit 7c4354a6e1
15 changed files with 96 additions and 15 deletions

View File

@ -418,6 +418,7 @@ void DeviceManager::loadPlugins()
connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::emitEvent); connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::emitEvent);
connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered); connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered);
connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished);
connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished);
} }
} }
} }

View File

@ -93,6 +93,7 @@ signals:
void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value); void deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices); void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices);
void deviceSetupFinished(Device *device, DeviceError status, const QString &errorMessage); void deviceSetupFinished(Device *device, DeviceError status, const QString &errorMessage);
void actionExecutionFinished(const ActionId, DeviceError status, const QString &errorMessage);
public slots: public slots:
QPair<DeviceError, QString> executeAction(const Action &action); QPair<DeviceError, QString> executeAction(const Action &action);

View File

@ -74,9 +74,21 @@ pure virtual methods: \l{DevicePlugin::pluginName()}, \l{DevicePlugin::pluginId(
return report(DeviceManager::DeviceErrorSetupFailed, device->id()); return report(DeviceManager::DeviceErrorSetupFailed, device->id());
Keep the message short, the DeviceManager will format it for you. 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) \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. To produce a new event in the system, create a new \l{Event} and emit it with \a event.

View File

@ -71,6 +71,7 @@ signals:
void emitEvent(const Event &event); void emitEvent(const Event &event);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors); void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &deviceDescriptors);
void deviceSetupFinished(Device *device, DeviceManager::DeviceSetupStatus status, const QString &errorMessage); void deviceSetupFinished(Device *device, DeviceManager::DeviceSetupStatus status, const QString &errorMessage);
void actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage);
protected: protected:
DeviceManager *deviceManager() const; DeviceManager *deviceManager() const;

View File

@ -33,12 +33,18 @@
#include "action.h" #include "action.h"
/*! Construct an Action with the given \a deviceId and \a actionTypeId */ /*! 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_actionTypeId(actionTypeId),
m_deviceId(deviceId) 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. */ /*! An Action is valid if actionTypeId and deviceId are valid uuids. Returns true if valid, false if not. */
bool Action::isValid() const bool Action::isValid() const
{ {

View File

@ -27,7 +27,9 @@
class Action class Action
{ {
public: public:
explicit Action(const DeviceId &deviceId, const ActionTypeId &actionTypeId); explicit Action(const ActionTypeId &actionTypeId, const DeviceId &deviceId);
ActionId id() const;
bool isValid() const; bool isValid() const;
@ -39,6 +41,7 @@ public:
Param param(const QString &paramName) const; Param param(const QString &paramName) const;
private: private:
ActionId m_id;
ActionTypeId m_actionTypeId; ActionTypeId m_actionTypeId;
DeviceId m_deviceId; DeviceId m_deviceId;
QList<Param> m_params; QList<Param> m_params;

View File

@ -37,12 +37,20 @@
the \l{Device} given by \a deviceId and the parameters given by \a params. The parameters must 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}.*/ match the description in the reflecting \l{Event}.*/
Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params): Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params):
m_id(EventId::createEventId()),
m_eventTypeId(eventTypeId), m_eventTypeId(eventTypeId),
m_deviceId(deviceId), m_deviceId(deviceId),
m_params(params) 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.*/ /*! Returns the id of the \l{EventType} which describes this Event.*/
EventTypeId Event::eventTypeId() const EventTypeId Event::eventTypeId() const
{ {

View File

@ -31,6 +31,8 @@ class Event
public: public:
Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params = QList<Param>()); Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params = QList<Param>());
EventId eventId() const;
EventTypeId eventTypeId() const; EventTypeId eventTypeId() const;
DeviceId deviceId() const; DeviceId deviceId() const;
@ -41,6 +43,7 @@ public:
bool operator ==(const Event &other) const; bool operator ==(const Event &other) const;
private: private:
EventId m_id;
EventTypeId m_eventTypeId; EventTypeId m_eventTypeId;
DeviceId m_deviceId; DeviceId m_deviceId;
QList<Param> m_params; QList<Param> m_params;

View File

@ -34,11 +34,17 @@
/*! Constructs a State reflecting the \l{StateType} given by \a stateTypeId /*! Constructs a State reflecting the \l{StateType} given by \a stateTypeId
and associated with the \l{Device} given by \a deviceId */ and associated with the \l{Device} given by \a deviceId */
State::State(const StateTypeId &stateTypeId, const DeviceId &deviceId): State::State(const StateTypeId &stateTypeId, const DeviceId &deviceId):
m_id(StateId::createStateId()),
m_stateTypeId(stateTypeId), m_stateTypeId(stateTypeId),
m_deviceId(deviceId) m_deviceId(deviceId)
{ {
} }
StateId State::id() const
{
return m_id;
}
/*! Returns the id of the StateType describing this State. */ /*! Returns the id of the StateType describing this State. */
StateTypeId State::stateTypeId() const StateTypeId State::stateTypeId() const
{ {

View File

@ -29,6 +29,8 @@ class State
public: public:
State(const StateTypeId &stateTypeId, const DeviceId &deviceId); State(const StateTypeId &stateTypeId, const DeviceId &deviceId);
StateId id() const;
StateTypeId stateTypeId() const; StateTypeId stateTypeId() const;
DeviceId deviceId() const; DeviceId deviceId() const;
@ -37,6 +39,7 @@ public:
void setValue(const QVariant &value); void setValue(const QVariant &value);
private: private:
StateId m_id;
StateTypeId m_stateTypeId; StateTypeId m_stateTypeId;
DeviceId m_deviceId; DeviceId m_deviceId;
QVariant m_value; QVariant m_value;

View File

@ -42,8 +42,11 @@ DECLARE_TYPE_ID(Device)
DECLARE_TYPE_ID(DeviceDescriptor) DECLARE_TYPE_ID(DeviceDescriptor)
DECLARE_TYPE_ID(EventType) DECLARE_TYPE_ID(EventType)
DECLARE_TYPE_ID(Event)
DECLARE_TYPE_ID(StateType) DECLARE_TYPE_ID(StateType)
DECLARE_TYPE_ID(State)
DECLARE_TYPE_ID(ActionType) DECLARE_TYPE_ID(ActionType)
DECLARE_TYPE_ID(Action)
DECLARE_TYPE_ID(Plugin) DECLARE_TYPE_ID(Plugin)
#endif // TYPEUTILS_H #endif // TYPEUTILS_H

View File

@ -36,6 +36,8 @@ ActionHandler::ActionHandler(QObject *parent) :
returns.insert("success", "bool"); returns.insert("success", "bool");
returns.insert("errorMessage", "string"); returns.insert("errorMessage", "string");
setReturns("ExecuteAction", returns); setReturns("ExecuteAction", returns);
connect(GuhCore::instance()->deviceManager(), &DeviceManager::actionExecutionFinished, this, &ActionHandler::actionExecuted);
} }
QString ActionHandler::name() const QString ActionHandler::name() const
@ -50,36 +52,58 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap &params)
ActionTypeId actionTypeId(params.value("actionTypeId").toString()); ActionTypeId actionTypeId(params.value("actionTypeId").toString());
QList<Param> actionParams = JsonTypes::unpackParams(params.value("params").toList()); QList<Param> actionParams = JsonTypes::unpackParams(params.value("params").toList());
Action action(deviceId, actionTypeId); Action action(actionTypeId, deviceId);
action.setParams(actionParams); action.setParams(actionParams);
qDebug() << "actions params in json" << action.params() << params; qDebug() << "actions params in json" << action.params() << params;
QVariantMap returns; QPair<DeviceManager::DeviceError, QString> status = GuhCore::instance()->deviceManager()->executeAction(action);
QPair<DeviceManager::DeviceError, QString> error = 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: case DeviceManager::DeviceErrorNoError:
returns.insert("success", true); returns.insert("success", true);
returns.insert("errorMessage", ""); returns.insert("errorMessage", "");
break; break;
case DeviceManager::DeviceErrorDeviceNotFound: 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); returns.insert("success", false);
break; break;
case DeviceManager::DeviceErrorActionTypeNotFound: 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); returns.insert("success", false);
break; break;
case DeviceManager::DeviceErrorMissingParameter: 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); returns.insert("success", false);
break; break;
default: 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); returns.insert("success", false);
} }
return returns;
return createReply(returns);
} }

View File

@ -20,6 +20,7 @@
#define ACTIONHANDLER_H #define ACTIONHANDLER_H
#include "jsonhandler.h" #include "jsonhandler.h"
#include "devicemanager.h"
class ActionHandler : public JsonHandler class ActionHandler : public JsonHandler
{ {
@ -30,6 +31,15 @@ public:
QString name() const; QString name() const;
Q_INVOKABLE JsonReply* ExecuteAction(const QVariantMap &params); Q_INVOKABLE JsonReply* ExecuteAction(const QVariantMap &params);
private slots:
void actionExecuted(const ActionId &id, DeviceManager::DeviceError status, const QString &errorMessage);
private:
QVariantMap statusToReply(DeviceManager::DeviceError status, const QString &errorMessage);
private:
QHash<ActionId, JsonReply*> m_asyncActionExecutions;
}; };
#endif // ACTIONHANDLER_H #endif // ACTIONHANDLER_H

View File

@ -90,7 +90,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
qDebug() << "got action list" << actionList.count(); qDebug() << "got action list" << actionList.count();
foreach (const QVariant &actionVariant, actionList) { foreach (const QVariant &actionVariant, actionList) {
QVariantMap actionMap = actionVariant.toMap(); 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())); action.setParams(JsonTypes::unpackParams(actionMap.value("params").toList()));
actions.append(action); actions.append(action);
} }

View File

@ -110,7 +110,7 @@ RuleEngine::RuleEngine(QObject *parent) :
QList<Action> actions; QList<Action> actions;
foreach (const QString &actionIdString, settings.childGroups()) { foreach (const QString &actionIdString, settings.childGroups()) {
settings.beginGroup(actionIdString); 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<Param> params; QList<Param> params;
foreach (QString paramNameString, settings.childGroups()) { foreach (QString paramNameString, settings.childGroups()) {
if (paramNameString.startsWith("Param-")) { if (paramNameString.startsWith("Param-")) {