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::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered);
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 devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &devices);
void deviceSetupFinished(Device *device, DeviceError status, const QString &errorMessage);
void actionExecutionFinished(const ActionId, DeviceError status, const QString &errorMessage);
public slots:
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());
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.

View File

@ -71,6 +71,7 @@ signals:
void emitEvent(const Event &event);
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> &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;

View File

@ -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
{

View File

@ -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 &paramName) const;
private:
ActionId m_id;
ActionTypeId m_actionTypeId;
DeviceId m_deviceId;
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
match the description in the reflecting \l{Event}.*/
Event::Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params):
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
{

View File

@ -31,6 +31,8 @@ class Event
public:
Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList<Param> &params = QList<Param>());
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<Param> m_params;

View File

@ -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
{

View File

@ -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;

View File

@ -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

View File

@ -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 &params)
ActionTypeId actionTypeId(params.value("actionTypeId").toString());
QList<Param> 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<DeviceManager::DeviceError, QString> error = GuhCore::instance()->deviceManager()->executeAction(action);
QPair<DeviceManager::DeviceError, QString> 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;
}

View File

@ -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 &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

View File

@ -90,7 +90,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
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);
}

View File

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