diff --git a/guh.pri b/guh.pri index 44ac0d59..7624c8ae 100644 --- a/guh.pri +++ b/guh.pri @@ -2,7 +2,7 @@ GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"') # define protocol versions -JSON_PROTOCOL_VERSION=30 +JSON_PROTOCOL_VERSION=31 REST_API_VERSION=1 DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \ diff --git a/server/guhcore.cpp b/server/guhcore.cpp index dfb8895c..1e4cc426 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -258,6 +258,33 @@ DeviceManager::DeviceError GuhCore::executeAction(const Action &action) return ret; } +void GuhCore::executeRuleActions(const QList ruleActions) +{ + foreach (const RuleAction &ruleAction, ruleActions) { + Action action = ruleAction.toAction(); + qCDebug(dcRuleEngine) << "executing action" << ruleAction.actionTypeId() << action.params(); + DeviceManager::DeviceError status = executeAction(action); + switch(status) { + case DeviceManager::DeviceErrorNoError: + break; + case DeviceManager::DeviceErrorSetupFailed: + qCWarning(dcRuleEngine) << "Error executing action. Device setup failed."; + break; + case DeviceManager::DeviceErrorAsync: + qCDebug(dcRuleEngine) << "Executing asynchronous action."; + break; + case DeviceManager::DeviceErrorInvalidParameter: + qCWarning(dcRuleEngine) << "Error executing action. Invalid action parameter."; + break; + default: + qCWarning(dcRuleEngine) << "Error executing action:" << status; + } + + if (status != DeviceManager::DeviceErrorAsync) + m_logger->logAction(action, status == DeviceManager::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status); + } +} + /*! Calls the metheod DeviceManager::findDeviceClass(\a deviceClassId). * \sa DeviceManager::findDeviceClass(), */ DeviceClass GuhCore::findDeviceClass(const DeviceClassId &deviceClassId) const @@ -344,16 +371,16 @@ Rule GuhCore::findRule(const RuleId &ruleId) /*! Calls the metheod RuleEngine::addRule(\a id, \a name, \a eventDescriptorList, \a stateEvaluator \a actionList, \a exitActionList, \a enabled). * \sa RuleEngine::addRule(), */ -RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled) +RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled, bool executable) { - return m_ruleEngine->addRule(id, name, eventDescriptorList, stateEvaluator, actionList, exitActionList, enabled); + return m_ruleEngine->addRule(id, name, eventDescriptorList, stateEvaluator, actionList, exitActionList, enabled, executable); } /*! Calls the metheod RuleEngine::editRule(\a id, \a name, \a eventDescriptorList, \a stateEvaluator \a actionList, \a exitActionList, \a enabled). * \sa RuleEngine::editRule(), */ -RuleEngine::RuleError GuhCore::editRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled) +RuleEngine::RuleError GuhCore::editRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled, bool executable) { - return m_ruleEngine->editRule(id, name, eventDescriptorList, stateEvaluator, actionList, exitActionList, enabled); + return m_ruleEngine->editRule(id, name, eventDescriptorList, stateEvaluator, actionList, exitActionList, enabled, executable); } /*! Calls the metheod RuleEngine::removeRule(\a id). @@ -388,6 +415,16 @@ RuleEngine::RuleError GuhCore::disableRule(const RuleId &ruleId) return m_ruleEngine->disableRule(ruleId); } +RuleEngine::RuleError GuhCore::executeRuleActions(const RuleId &ruleId) +{ + return m_ruleEngine->executeActions(ruleId); +} + +RuleEngine::RuleError GuhCore::executeRuleExitActions(const RuleId &ruleId) +{ + return m_ruleEngine->executeExitActions(ruleId); +} + /*! Returns a pointer to the \l{DeviceManager} instance owned by GuhCore.*/ DeviceManager *GuhCore::deviceManager() const { @@ -491,30 +528,7 @@ void GuhCore::gotEvent(const Event &event) actions.append(ruleAction); } - // Now execute all the associated actions - foreach (const RuleAction &ruleAction, actions) { - Action action = ruleAction.toAction(); - qCDebug(dcRuleEngine) << "executing action" << ruleAction.actionTypeId(); - DeviceManager::DeviceError status = executeAction(action); - switch(status) { - case DeviceManager::DeviceErrorNoError: - break; - case DeviceManager::DeviceErrorSetupFailed: - qCWarning(dcRuleEngine) << "Error executing action. Device setup failed."; - break; - case DeviceManager::DeviceErrorAsync: - qCDebug(dcRuleEngine) << "Executing asynchronous action."; - break; - case DeviceManager::DeviceErrorInvalidParameter: - qCWarning(dcRuleEngine) << "Error executing action. Invalid action parameter."; - break; - default: - qCWarning(dcRuleEngine) << "Error executing action:" << status; - } - - if (status != DeviceManager::DeviceErrorAsync) - m_logger->logAction(action, status == DeviceManager::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status); - } + executeRuleActions(actions); } /*! Return the instance of the log engine */ diff --git a/server/guhcore.h b/server/guhcore.h index 9e93afe5..1ee0c6f7 100644 --- a/server/guhcore.h +++ b/server/guhcore.h @@ -83,15 +83,19 @@ public: DeviceManager::DeviceError executeAction(const Action &action); + void executeRuleActions(const QList ruleActions); + QList rules() const; QList ruleIds() const; Rule findRule(const RuleId &ruleId); - RuleEngine::RuleError addRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled = true); - RuleEngine::RuleError editRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled = true); + RuleEngine::RuleError addRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled = true, bool executable = true); + RuleEngine::RuleError editRule(const RuleId &id, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, const QList &exitActionList, bool enabled = true, bool executable = true); RuleEngine::RuleError removeRule(const RuleId &id); QList findRules(const DeviceId &deviceId); RuleEngine::RuleError enableRule(const RuleId &ruleId); RuleEngine::RuleError disableRule(const RuleId &ruleId); + RuleEngine::RuleError executeRuleActions(const RuleId &ruleId); + RuleEngine::RuleError executeRuleExitActions(const RuleId &ruleId); LogEngine* logEngine() const; JsonRPCServer *jsonRPCServer() const; diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 6afbb074..99d6edce 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -209,6 +209,7 @@ void JsonTypes::init() s_rule.insert("id", basicTypeToString(Uuid)); s_rule.insert("name", basicTypeToString(String)); s_rule.insert("enabled", basicTypeToString(Bool)); + s_rule.insert("executable", basicTypeToString(Bool)); s_rule.insert("active", basicTypeToString(Bool)); s_rule.insert("eventDescriptors", QVariantList() << eventDescriptorRef()); s_rule.insert("actions", QVariantList() << ruleActionRef()); @@ -220,6 +221,8 @@ void JsonTypes::init() s_ruleDescription.insert("name", basicTypeToString(String)); s_ruleDescription.insert("enabled", basicTypeToString(Bool)); s_ruleDescription.insert("active", basicTypeToString(Bool)); + s_ruleDescription.insert("executable", basicTypeToString(Bool)); + // LogEntry s_logEntry.insert("timestamp", basicTypeToString(Int)); @@ -579,6 +582,8 @@ QVariantMap JsonTypes::packRule(const Rule &rule) ruleMap.insert("name", rule.name()); ruleMap.insert("enabled", rule.enabled()); ruleMap.insert("active", rule.active()); + ruleMap.insert("executable", rule.executable()); + QVariantList eventDescriptorList; foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) { eventDescriptorList.append(JsonTypes::packEventDescriptor(eventDescriptor)); @@ -616,6 +621,7 @@ QVariantMap JsonTypes::packRuleDescription(const Rule &rule) ruleDescriptionMap.insert("name", rule.name()); ruleDescriptionMap.insert("enabled", rule.enabled()); ruleDescriptionMap.insert("active", rule.active()); + ruleDescriptionMap.insert("executable", rule.executable()); return ruleDescriptionMap; } diff --git a/server/jsonrpc/logginghandler.cpp b/server/jsonrpc/logginghandler.cpp index 99990aab..65f8dcab 100644 --- a/server/jsonrpc/logginghandler.cpp +++ b/server/jsonrpc/logginghandler.cpp @@ -1,4 +1,4 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015 Simon Stuerz * * Copyright (C) 2014 Michael Zanetti * diff --git a/server/jsonrpc/ruleshandler.cpp b/server/jsonrpc/ruleshandler.cpp index 86bd1eb1..10372c0d 100644 --- a/server/jsonrpc/ruleshandler.cpp +++ b/server/jsonrpc/ruleshandler.cpp @@ -71,6 +71,7 @@ RulesHandler::RulesHandler(QObject *parent) : params.insert("o:stateEvaluator", JsonTypes::stateEvaluatorRef()); params.insert("o:exitActions", QVariantList() << JsonTypes::ruleActionRef()); params.insert("o:enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + params.insert("o:executable", JsonTypes::basicTypeToString(JsonTypes::Bool)); params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); QVariantList actions; actions.append(JsonTypes::ruleActionRef()); @@ -92,6 +93,7 @@ RulesHandler::RulesHandler(QObject *parent) : params.insert("o:stateEvaluator", JsonTypes::stateEvaluatorRef()); params.insert("o:exitActions", QVariantList() << JsonTypes::ruleActionRef()); params.insert("o:enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + params.insert("o:executable", JsonTypes::basicTypeToString(JsonTypes::Bool)); actions.append(JsonTypes::ruleActionRef()); params.insert("actions", actions); setParams("EditRule", params); @@ -129,6 +131,20 @@ RulesHandler::RulesHandler(QObject *parent) : returns.insert("ruleError", JsonTypes::ruleErrorRef()); setReturns("DisableRule", returns); + params.clear(); returns.clear(); + setDescription("ExecuteActions", "Execute the action list of the rule with the given ruleId."); + params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); + setParams("ExecuteActions", params); + returns.insert("ruleError", JsonTypes::ruleErrorRef()); + setReturns("ExecuteActions", returns); + + params.clear(); returns.clear(); + setDescription("ExecuteExitActions", "Execute the exit action list of the rule with the given ruleId."); + params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); + setParams("ExecuteExitActions", params); + returns.insert("ruleError", JsonTypes::ruleErrorRef()); + setReturns("ExecuteExitActions", returns); + // Notifications params.clear(); returns.clear(); setDescription("RuleRemoved", "Emitted whenever a Rule was removed."); @@ -227,9 +243,10 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) QString name = params.value("name", QString()).toString(); bool enabled = params.value("enabled", true).toBool(); + bool executable = params.value("executable", true).toBool(); RuleId newRuleId = RuleId::createRuleId(); - RuleEngine::RuleError status = GuhCore::instance()->addRule(newRuleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled); + RuleEngine::RuleError status = GuhCore::instance()->addRule(newRuleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled, executable); QVariantMap returns; if (status == RuleEngine::RuleErrorNoError) { returns.insert("ruleId", newRuleId.toString()); @@ -281,9 +298,10 @@ JsonReply *RulesHandler::EditRule(const QVariantMap ¶ms) QString name = params.value("name", QString()).toString(); bool enabled = params.value("enabled", true).toBool(); + bool executable = params.value("executable", true).toBool(); RuleId ruleId = RuleId(params.value("ruleId").toString()); - RuleEngine::RuleError status = GuhCore::instance()->editRule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled); + RuleEngine::RuleError status = GuhCore::instance()->editRule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled, executable); QVariantMap returns; if (status == RuleEngine::RuleErrorNoError) { returns.insert("rule", JsonTypes::packRule(GuhCore::instance()->findRule(ruleId))); @@ -326,6 +344,24 @@ JsonReply *RulesHandler::DisableRule(const QVariantMap ¶ms) return createReply(statusToReply(GuhCore::instance()->disableRule(RuleId(params.value("ruleId").toString())))); } +JsonReply *RulesHandler::ExecuteActions(const QVariantMap ¶ms) +{ + QVariantMap returns; + RuleId ruleId(params.value("ruleId").toString()); + RuleEngine::RuleError status = GuhCore::instance()->executeRuleActions(ruleId); + returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + return createReply(returns); +} + +JsonReply *RulesHandler::ExecuteExitActions(const QVariantMap ¶ms) +{ + QVariantMap returns; + RuleId ruleId(params.value("ruleId").toString()); + RuleEngine::RuleError status = GuhCore::instance()->executeRuleExitActions(ruleId); + returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + return createReply(returns); +} + void RulesHandler::ruleRemovedNotification(const RuleId &ruleId) { QVariantMap params; diff --git a/server/jsonrpc/ruleshandler.h b/server/jsonrpc/ruleshandler.h index f97eee51..50fe464d 100644 --- a/server/jsonrpc/ruleshandler.h +++ b/server/jsonrpc/ruleshandler.h @@ -34,16 +34,19 @@ public: QString name() const override; - Q_INVOKABLE JsonReply* GetRules(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* GetRuleDetails(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetRules(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetRuleDetails(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* AddRule(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* EditRule(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* RemoveRule(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* FindRules(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *AddRule(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *EditRule(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *RemoveRule(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *FindRules(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* EnableRule(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* DisableRule(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *EnableRule(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *DisableRule(const QVariantMap ¶ms); + + Q_INVOKABLE JsonReply *ExecuteActions(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *ExecuteExitActions(const QVariantMap ¶ms); signals: void RuleRemoved(const QVariantMap ¶ms); diff --git a/server/logging/logging.h b/server/logging/logging.h index 70c65df4..f7bdb79b 100644 --- a/server/logging/logging.h +++ b/server/logging/logging.h @@ -57,7 +57,9 @@ public: enum LoggingEventType { LoggingEventTypeTrigger, - LoggingEventTypeActiveChange + LoggingEventTypeActiveChange, + LoggingEventTypeActionsExecuted, + LoggingEventTypeExitActionsExecuted }; }; diff --git a/server/rest/rulesresource.cpp b/server/rest/rulesresource.cpp index fea16fbf..a7a318a7 100644 --- a/server/rest/rulesresource.cpp +++ b/server/rest/rulesresource.cpp @@ -170,6 +170,14 @@ HttpReply *RulesResource::proccessPostRequest(const HttpRequest &request, const if (urlTokens.count() == 5 && urlTokens.at(4) == "disable") return disableRule(m_ruleId); + // POST /api/v1/rules/{ruleId}/executeactions + if (urlTokens.count() == 5 && urlTokens.at(4) == "executeactions") + return executeActions(m_ruleId); + + // POST /api/v1/rules/{ruleId}/executeexitactions + if (urlTokens.count() == 5 && urlTokens.at(4) == "executeexitactions") + return executeExitActions(m_ruleId); + return createErrorReply(HttpReply::NotImplemented); } @@ -306,6 +314,30 @@ HttpReply *RulesResource::disableRule(const RuleId &ruleId) const return createRuleErrorReply(HttpReply::Ok, status); } +HttpReply *RulesResource::executeActions(const RuleId &ruleId) const +{ + qCDebug(dcRest) << "Execute actions of rule with id" << ruleId.toString(); + + RuleEngine::RuleError status = GuhCore::instance()->executeRuleActions(ruleId); + + if (status != RuleEngine::RuleErrorNoError) + return createRuleErrorReply(HttpReply::InternalServerError, status); + + return createRuleErrorReply(HttpReply::Ok, status); +} + +HttpReply *RulesResource::executeExitActions(const RuleId &ruleId) const +{ + qCDebug(dcRest) << "Execute exit actions of rule with id" << ruleId.toString(); + + RuleEngine::RuleError status = GuhCore::instance()->executeRuleExitActions(ruleId); + + if (status != RuleEngine::RuleErrorNoError) + return createRuleErrorReply(HttpReply::InternalServerError, status); + + return createRuleErrorReply(HttpReply::Ok, status); +} + HttpReply *RulesResource::editRule(const RuleId &ruleId, const QByteArray &payload) const { qCDebug(dcRest) << "Edit rule with id" << ruleId.toString(); diff --git a/server/rest/rulesresource.h b/server/rest/rulesresource.h index e83bb5f1..332fc7a8 100644 --- a/server/rest/rulesresource.h +++ b/server/rest/rulesresource.h @@ -64,6 +64,9 @@ private: HttpReply *addRule(const QByteArray &payload) const; HttpReply *enableRule(const RuleId &ruleId) const; HttpReply *disableRule(const RuleId &ruleId) const; + HttpReply *executeActions(const RuleId &ruleId) const; + HttpReply *executeExitActions(const RuleId &ruleId) const; + // Put methods HttpReply *editRule(const RuleId &ruleId, const QByteArray &payload) const; diff --git a/server/rule.cpp b/server/rule.cpp index 901ef7bf..8bdaddf6 100644 --- a/server/rule.cpp +++ b/server/rule.cpp @@ -52,7 +52,8 @@ Rule::Rule(const RuleId &id, const QString &name, const QList & m_stateEvaluator(stateEvaluator), m_actions(actions), m_enabled(false), - m_active(false) + m_active(false), + m_executable(false) { } @@ -66,7 +67,8 @@ Rule::Rule(const RuleId &id, const QString &name, const QList & m_actions(actions), m_exitActions(exitActions), m_enabled(false), - m_active(false) + m_active(false), + m_executable(false) { } @@ -80,7 +82,8 @@ Rule::Rule(const RuleId &id, const QString &name, const StateEvaluator &stateEva m_actions(actions), m_exitActions(exitActions), m_enabled(false), - m_active(false) + m_active(false), + m_executable(false) { } @@ -120,13 +123,13 @@ QString Rule::name() const return m_name; } -/*! Returns wheter the rule is enabled or not. */ +/*! Returns true if the rule is enabled. */ bool Rule::enabled() const { return m_enabled; } -/*! Set the disabled flag of this rule. In order to actually disable the rule you still need to - * update the RulesEngine */ +/*! Set the \a enabled flag of this rule. In order to actually enable/disable the rule you still need to + * update the \l{RulesEngine} */ void Rule::setEnabled(bool enabled) { m_enabled = enabled; @@ -138,6 +141,18 @@ bool Rule::active() const return m_active; } +/*! Set the rule \a executable. */ +void Rule::setExecutable(const bool &executable) +{ + m_executable = executable; +} + +/*! Returns true if the rule is executable. */ +bool Rule::executable() const +{ + return m_executable; +} + void Rule::setName(const QString &name) { m_name = name; diff --git a/server/rule.h b/server/rule.h index a0f73acf..185e557e 100644 --- a/server/rule.h +++ b/server/rule.h @@ -51,6 +51,9 @@ public: bool active() const; + void setExecutable(const bool &executable); + bool executable() const; + private: friend class RuleEngine; void setName(const QString &name); @@ -66,6 +69,7 @@ private: bool m_enabled; bool m_active; + bool m_executable; }; } diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index a034fafb..d3d626b8 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -110,6 +110,7 @@ RuleEngine::RuleEngine(QObject *parent) : QString name = settings.value("name", idString).toString(); bool enabled = settings.value("enabled", true).toBool(); + bool executable = settings.value("executable", true).toBool(); qCDebug(dcRuleEngine) << "load rule" << name << idString; @@ -195,6 +196,7 @@ RuleEngine::RuleEngine(QObject *parent) : Rule rule = Rule(RuleId(idString), name, eventDescriptorList, stateEvaluator, actions, exitActions); rule.setEnabled(enabled); + rule.setExecutable(executable); appendRule(rule); settings.endGroup(); } @@ -265,7 +267,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n /*! Add a new \l{Rule} with the given \a ruleId, \a name, \a eventDescriptorList, \a stateEvaluator, the list of \a actions the list of \a exitActions and the \a enabled value to the engine. If \a fromEdit is true, the notification Rules.RuleAdded will not be emitted. */ -RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled, bool fromEdit) +RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled, bool executable, bool fromEdit) { if (ruleId.isNull()) { return RuleErrorInvalidRuleId; @@ -343,6 +345,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n Rule rule = Rule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions); rule.setEnabled(enabled); + rule.setExecutable(executable); appendRule(rule); saveRule(rule); if (!fromEdit) @@ -354,13 +357,13 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n /*! Edit a \l{Rule} with the given \a ruleId, \a name, \a eventDescriptorList, \a stateEvaluator, the list of \a actions the list of \a exitActions and the \a enabled in the engine. */ -RuleEngine::RuleError RuleEngine::editRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled) +RuleEngine::RuleError RuleEngine::editRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled, bool executable) { - if (ruleId.isNull()) { + if (ruleId.isNull()) return RuleErrorInvalidRuleId; - } - // store rule in case the add new rule fails + + // Store rule in case the add new rule fails Rule rule = findRule(ruleId); if (rule.id().isNull()) { @@ -368,15 +371,15 @@ RuleEngine::RuleError RuleEngine::editRule(const RuleId &ruleId, const QString & return RuleErrorRuleNotFound; } - // first remove old rule with this id + // First remove old rule with this id RuleError removeResult = removeRule(ruleId, true); if (removeResult != RuleErrorNoError) { // no need to restore, rule is still in system return removeResult; } - // the rule is removed, now add it with the same id and new vonfiguration - RuleError addResult = addRule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled, true); + // The rule is removed, now add it with the same id and new vonfiguration + RuleError addResult = addRule(ruleId, name, eventDescriptorList, stateEvaluator, actions, exitActions, enabled, executable, true); if (addResult != RuleErrorNoError) { // restore rule appendRule(rule); @@ -468,6 +471,62 @@ RuleEngine::RuleError RuleEngine::disableRule(const RuleId &ruleId) return RuleErrorNoError; } +RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId) +{ + // check if rule exits + if (!m_rules.contains(ruleId)) { + qCWarning(dcRuleEngine) << "Not executing rule actions: rule not found."; + return RuleErrorRuleNotFound; + } + + Rule rule = m_rules.value(ruleId); + + // check if rule is executable + if (!rule.executable()) { + qCWarning(dcRuleEngine) << "Not executing rule actions: rule is not executable."; + return RuleErrorNotExecutable; + } + + // check if an Action is eventBased + foreach (const RuleAction &ruleAction, rule.actions()) { + if (ruleAction.isEventBased()) { + qCWarning(dcRuleEngine) << "Not executing rule actions: rule action depends on an event:" << ruleAction.actionTypeId() << ruleAction.ruleActionParams(); + return RuleErrorContainsEventBasesAction; + } + } + + qCDebug(dcRuleEngine) << "Executing rule actions of rule" << rule.name() << rule.id(); + GuhCore::instance()->executeRuleActions(rule.actions()); + return RuleErrorNoError; +} + +RuleEngine::RuleError RuleEngine::executeExitActions(const RuleId &ruleId) +{ + // check if rule exits + if (!m_rules.contains(ruleId)) { + qCWarning(dcRuleEngine) << "Not executing rule exit actions: rule not found."; + return RuleErrorRuleNotFound; + } + + Rule rule = m_rules.value(ruleId); + + // check if rule is executable + if (!rule.executable()) { + qCWarning(dcRuleEngine) << "Not executing rule exit actions: rule is not executable."; + return RuleErrorNotExecutable; + } + + if (rule.exitActions().isEmpty()) { + qCWarning(dcRuleEngine) << "Not executing rule exit actions: rule has no exit actions."; + return RuleErrorNoExitActions; + } + + qCDebug(dcRuleEngine) << "Executing rule exit actions of rule" << rule.name() << rule.id(); + GuhCore::instance()->executeRuleActions(rule.exitActions()); + return RuleErrorNoError; +} + + /*! Returns the \l{Rule} with the given \a ruleId. If the \l{Rule} does not exist, it will return \l{Rule::Rule()} */ Rule RuleEngine::findRule(const RuleId &ruleId) { @@ -580,6 +639,7 @@ void RuleEngine::saveRule(const Rule &rule) settings.beginGroup(rule.id().toString()); settings.setValue("name", rule.name()); settings.setValue("enabled", rule.enabled()); + settings.setValue("executable", rule.executable()); settings.beginGroup("events"); for (int i = 0; i < rule.eventDescriptors().count(); i++) { const EventDescriptor &eventDescriptor = rule.eventDescriptors().at(i); diff --git a/server/ruleengine.h b/server/ruleengine.h index 111be986..5c7a3dc1 100644 --- a/server/ruleengine.h +++ b/server/ruleengine.h @@ -49,7 +49,10 @@ public: RuleErrorInvalidRuleFormat, RuleErrorMissingParameter, RuleErrorInvalidRuleActionParameter, - RuleErrorTypesNotMatching + RuleErrorTypesNotMatching, + RuleErrorNotExecutable, + RuleErrorContainsEventBasesAction, + RuleErrorNoExitActions }; enum RemovePolicy { @@ -62,9 +65,8 @@ public: QList evaluateEvent(const Event &event); RuleError addRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const QList &actions, bool enabled = true); - RuleError addRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled = true, bool fromEdit = false); - RuleError editRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled = true); - + RuleError addRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled = true, bool executable = true, bool fromEdit = false); + RuleError editRule(const RuleId &ruleId, const QString &name, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions, const QList &exitActions, bool enabled = true, bool executable = true); QList rules() const; QList ruleIds() const; @@ -74,6 +76,9 @@ public: RuleError enableRule(const RuleId &ruleId); RuleError disableRule(const RuleId &ruleId); + RuleError executeActions(const RuleId &ruleId); + RuleError executeExitActions(const RuleId &ruleId); + Rule findRule(const RuleId &ruleId); QList findRules(const DeviceId &deviceId); diff --git a/tests/auto/api.json b/tests/auto/api.json index cfd595d6..1b172834 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -30 +31 { "methods": { "Actions.ExecuteAction": { @@ -322,6 +322,7 @@ "o:eventDescriptorList": [ "$ref:EventDescriptor" ], + "o:executable": "Bool", "o:exitActions": [ "$ref:RuleAction" ], @@ -353,6 +354,7 @@ "o:eventDescriptorList": [ "$ref:EventDescriptor" ], + "o:executable": "Bool", "o:exitActions": [ "$ref:RuleAction" ], @@ -373,6 +375,24 @@ "ruleError": "$ref:RuleError" } }, + "Rules.ExecuteActions": { + "description": "Execute the action list of the rule with the given ruleId.", + "params": { + "ruleId": "Uuid" + }, + "returns": { + "ruleError": "$ref:RuleError" + } + }, + "Rules.ExecuteExitActions": { + "description": "Execute the exit action list of the rule with the given ruleId.", + "params": { + "ruleId": "Uuid" + }, + "returns": { + "ruleError": "$ref:RuleError" + } + }, "Rules.FindRules": { "description": "Find a list of rules containing any of the given parameters.", "params": { @@ -638,7 +658,9 @@ ], "LoggingEventType": [ "LoggingEventTypeTrigger", - "LoggingEventTypeActiveChange" + "LoggingEventTypeActiveChange", + "LoggingEventTypeActionsExecuted", + "LoggingEventTypeExitActionsExecuted" ], "LoggingLevel": [ "LoggingLevelInfo", @@ -693,6 +715,7 @@ "eventDescriptors": [ "$ref:EventDescriptor" ], + "executable": "Bool", "exitActions": [ "$ref:RuleAction" ], @@ -716,6 +739,7 @@ "RuleDescription": { "active": "Bool", "enabled": "Bool", + "executable": "Bool", "id": "Uuid", "name": "String" }, @@ -730,7 +754,10 @@ "RuleErrorInvalidRuleFormat", "RuleErrorMissingParameter", "RuleErrorInvalidRuleActionParameter", - "RuleErrorTypesNotMatching" + "RuleErrorTypesNotMatching", + "RuleErrorNotExecutable", + "RuleErrorContainsEventBasesAction", + "RuleErrorNoExitActions" ], "SetupMethod": [ "SetupMethodJustAdd",