/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of guh. * * * * Guh is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, version 2 of the License. * * * * Guh is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with guh. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! \class GuhCore \brief The main entry point for the Guh Server and the place where all the messages are dispatched. \ingroup core \inmodule server GuhCore is a singleton instance and the main entry point of the Guh daemon. It is responsible to instantiate, set up and connect all the other components. */ /*! \enum GuhCore::RunningMode \value RunningModeApplication Guh runns as application. \value RunningModeService Guh is started as service (daemon). */ /*! \fn void GuhCore::eventTriggered(const Event &event); This signal is emitted when an \a event happend. */ /*! \fn void GuhCore::deviceStateChanged(Device *device, const QUuid &stateTypeId, const QVariant &value); This signal is emitted when the \l{State} of a \a device changed. The \a stateTypeId parameter describes the \l{StateType} and the \a value parameter holds the new value. */ /*! \fn void GuhCore::actionExecuted(const ActionId &id, DeviceManager::DeviceError status); This signal is emitted when the \l{Action} with the given \a id is finished. The \a status of the \l{Action} execution will be described as \l{DeviceManager::DeviceError}{DeviceError}. */ /*! \fn void GuhCore::devicesDiscovered(const DeviceClassId &deviceClassId, const QList deviceDescriptors); This signal is emitted when the discovery of a \a deviceClassId is finished. The \a deviceDescriptors parameter describes the list of \l{DeviceDescriptor}{DeviceDescriptors} of all discovered \l{Device}{Devices}. \sa discoverDevices() */ /*! \fn void GuhCore::deviceSetupFinished(Device *device, DeviceManager::DeviceError status); This signal is emitted when the setup of a \a device is finished. The \a status parameter describes the \l{DeviceManager::DeviceError}{DeviceError} that occurred. */ /*! \fn void GuhCore::pairingFinished(const PairingTransactionId &pairingTransactionId, DeviceManager::DeviceError status, const DeviceId &deviceId); The DeviceManager will emit a this Signal when the pairing of a \l{Device} with the \a deviceId and \a pairingTransactionId is finished. The \a status of the pairing will be described as \l{DeviceManager::DeviceError}{DeviceError}. */ #include "guhcore.h" #include "jsonrpcserver.h" #include "ruleengine.h" #include "logging/logengine.h" #include "devicemanager.h" #include "plugin/device.h" #include GuhCore* GuhCore::s_instance = 0; /*! Returns a pointer to the single \l{GuhCore} instance. */ GuhCore *GuhCore::instance() { if (!s_instance) { s_instance = new GuhCore(); } return s_instance; } /*! Destructor of the \l{GuhCore}. */ GuhCore::~GuhCore() { m_logger->logSystemEvent(false); qDebug() << "Shutting down. Bye."; } /*! Destroyes the \l{GuhCore} instance. */ void GuhCore::destroy() { delete s_instance; s_instance = 0; } /*! Returns the runningMode of this instance. */ GuhCore::RunningMode GuhCore::runningMode() const { return m_runningMode; } /*! Set the \a runningMode of this instance. */ void GuhCore::setRunningMode(const RunningMode &runningMode) { m_runningMode = runningMode; } /*! Calls the metheod DeviceManager::plugins(). * \sa DeviceManager::plugins(), */ QList GuhCore::plugins() const { return m_deviceManager->plugins(); } /*! Calls the metheod DeviceManager::setPluginConfig(\a pluginId, \a params). * \sa DeviceManager::setPluginConfig(), */ DeviceManager::DeviceError GuhCore::setPluginConfig(const PluginId &pluginId, const ParamList ¶ms) { return m_deviceManager->setPluginConfig(pluginId, params); } /*! Calls the metheod DeviceManager::supportedVendors(). * \sa DeviceManager::supportedVendors(), */ QList GuhCore::supportedVendors() const { return m_deviceManager->supportedVendors(); } /*! Calls the metheod DeviceManager::supportedDevices(\a vendorId). * \sa DeviceManager::supportedDevices(), */ QList GuhCore::supportedDevices(const VendorId &vendorId) const { return m_deviceManager->supportedDevices(vendorId); } /*! Removes a configured \l{Device} with the given \a deviceId and \a removePolicyList. */ DeviceManager::DeviceError GuhCore::removeConfiguredDevice(const DeviceId &deviceId, const QHash &removePolicyList) { QHash toBeChanged; QList unhandledRules; foreach (const RuleId &ruleId, m_ruleEngine->findRules(deviceId)) { bool found = false; foreach (const RuleId &policyRuleId, removePolicyList.keys()) { if (ruleId == policyRuleId) { found = true; toBeChanged.insert(ruleId, removePolicyList.value(ruleId)); break; } } if (!found) { unhandledRules.append(ruleId); } } if (!unhandledRules.isEmpty()) { qWarning() << "There are unhandled rules which depend on this device."; return DeviceManager::DeviceErrorDeviceInUse; } // Update the rules... foreach (const RuleId &ruleId, toBeChanged.keys()) { if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyCascade) { m_ruleEngine->removeRule(ruleId); } else if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyUpdate){ m_ruleEngine->removeDeviceFromRule(ruleId, deviceId); } } return m_deviceManager->removeConfiguredDevice(deviceId); } /*! Calls the metheod DeviceManager::pairDevice(\a pairingTransactionId, \a deviceClassId, \a deviceDescriptorId). * Returns \l{DeviceManager::DeviceError}{DeviceError} to inform about the result. * \sa DeviceManager::pairDevice(), */ DeviceManager::DeviceError GuhCore::pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId) { return m_deviceManager->pairDevice(pairingTransactionId, deviceClassId, deviceDescriptorId); } /*! Calls the metheod DeviceManager::pairDevice(\a pairingTransactionId, \a deviceClassId, \a params). * Returns \l{DeviceManager::DeviceError}{DeviceError} to inform about the result. * \sa DeviceManager::pairDevice(), */ DeviceManager::DeviceError GuhCore::pairDevice(const PairingTransactionId &pairingTransactionId, const DeviceClassId &deviceClassId, const ParamList ¶ms) { return m_deviceManager->pairDevice(pairingTransactionId, deviceClassId, params); } /*! Calls the metheod DeviceManager::confirmPairing(\a pairingTransactionId, \a secret). * Returns \l{DeviceManager::DeviceError}{DeviceError} to inform about the result. * \sa DeviceManager::confirmPairing(), */ DeviceManager::DeviceError GuhCore::confirmPairing(const PairingTransactionId &pairingTransactionId, const QString &secret) { return m_deviceManager->confirmPairing(pairingTransactionId, secret); } /*! Calls the metheod DeviceManager::executeAction(\a action). * \sa DeviceManager::executeAction(), */ DeviceManager::DeviceError GuhCore::executeAction(const Action &action) { DeviceManager::DeviceError ret = m_deviceManager->executeAction(action); if (ret == DeviceManager::DeviceErrorNoError) { m_logger->logAction(action); } else if (ret == DeviceManager::DeviceErrorAsync) { m_pendingActions.insert(action.id(), action); } else { m_logger->logAction(action, Logging::LoggingLevelAlert, ret); } return ret; } /*! Calls the metheod DeviceManager::findDeviceClass(\a deviceClassId). * \sa DeviceManager::findDeviceClass(), */ DeviceClass GuhCore::findDeviceClass(const DeviceClassId &deviceClassId) const { return m_deviceManager->findDeviceClass(deviceClassId); } /*! Calls the metheod DeviceManager::discoverDevices(\a deviceClassId, \a params). * \sa DeviceManager::discoverDevices(), */ DeviceManager::DeviceError GuhCore::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) { return m_deviceManager->discoverDevices(deviceClassId, params); } /*! Calls the metheod DeviceManager::addConfiguredDevice(\a deviceClassId, \a params, \a newId). * \sa DeviceManager::addConfiguredDevice(), */ DeviceManager::DeviceError GuhCore::addConfiguredDevice(const DeviceClassId &deviceClassId, const ParamList ¶ms, const DeviceId &newId) { return m_deviceManager->addConfiguredDevice(deviceClassId, params, newId); } /*! Calls the metheod DeviceManager::addConfiguredDevice(\a deviceClassId, \a deviceDescriptorId, \a newId). * \sa DeviceManager::addConfiguredDevice(), */ DeviceManager::DeviceError GuhCore::addConfiguredDevice(const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId, const DeviceId &newId) { return m_deviceManager->addConfiguredDevice(deviceClassId, deviceDescriptorId, newId); } /*! Calls the metheod DeviceManager::configuredDevices(). * \sa DeviceManager::configuredDevices(), */ QList GuhCore::configuredDevices() const { return m_deviceManager->configuredDevices(); } /*! Calls the metheod DeviceManager::findConfiguredDevice(\a deviceId). * \sa DeviceManager::findConfiguredDevice(), */ Device *GuhCore::findConfiguredDevice(const DeviceId &deviceId) const { return m_deviceManager->findConfiguredDevice(deviceId); } /*! Calls the metheod DeviceManager::findConfiguredDevice(\a deviceClassId). * \sa DeviceManager::findConfiguredDevice(), */ QList GuhCore::findConfiguredDevices(const DeviceClassId &deviceClassId) const { return m_deviceManager->findConfiguredDevices(deviceClassId); } /*! Calls the metheod RuleEngine::rule(). * \sa RuleEngine, */ QList GuhCore::rules() const { return m_ruleEngine->rules(); } /*! Calls the metheod RuleEngine::ruleIds(). * \sa RuleEngine, */ QList GuhCore::ruleIds() const { return m_ruleEngine->ruleIds(); } /*! Calls the metheod RuleEngine::findRule(\a ruleId). * \sa RuleEngine, */ Rule GuhCore::findRule(const RuleId &ruleId) { return m_ruleEngine->findRule(ruleId); } /*! Calls the metheod RuleEngine::addRule(\a id, \a eventDescriptorList, \a stateEvaluator \a actionList, \a enabled). * \sa RuleEngine, */ RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actionList, bool enabled) { return m_ruleEngine->addRule(id, eventDescriptorList, stateEvaluator, actionList, enabled); } /*! Calls the metheod RuleEngine::removeRule(\a id). * \sa RuleEngine, */ RuleEngine::RuleError GuhCore::removeRule(const RuleId &id) { return m_ruleEngine->removeRule(id); } /*! Calls the metheod RuleEngine::findRules(\a deviceId). * \sa RuleEngine, */ QList GuhCore::findRules(const DeviceId &deviceId) { return m_ruleEngine->findRules(deviceId); } RuleEngine::RuleError GuhCore::enableRule(const RuleId &ruleId) { return m_ruleEngine->enableRule(ruleId); } RuleEngine::RuleError GuhCore::disableRule(const RuleId &ruleId) { return m_ruleEngine->disableRule(ruleId); } /*! Returns a pointer to the \l{DeviceManager} instance owned by GuhCore.*/ DeviceManager *GuhCore::deviceManager() const { return m_deviceManager; } /*! Returns a pointer to the \l{RuleEngine} instance owned by GuhCore.*/ RuleEngine *GuhCore::ruleEngine() const { return m_ruleEngine; } /*! Constructs GuhCore with the given \a parent. This is private. Use \l{GuhCore::instance()} to access the single instance.*/ GuhCore::GuhCore(QObject *parent) : QObject(parent) { qDebug() << "*****************************************"; qDebug() << "* GUH version:" << GUH_VERSION_STRING << "starting up. *"; qDebug() << "*****************************************"; m_logger = new LogEngine(this); qDebug() << "*****************************************"; qDebug() << "* Creating Device Manager *"; qDebug() << "*****************************************"; m_deviceManager = new DeviceManager(this); qDebug() << "*****************************************"; qDebug() << "* Creating Rule Engine *"; qDebug() << "*****************************************"; m_ruleEngine = new RuleEngine(this); qDebug() << "*****************************************"; qDebug() << "* Starting JSON RPC Server *"; qDebug() << "*****************************************"; m_jsonServer = new JsonRPCServer(this); connect(m_deviceManager, &DeviceManager::eventTriggered, this, &GuhCore::gotEvent); connect(m_deviceManager, &DeviceManager::deviceStateChanged, this, &GuhCore::deviceStateChanged); connect(m_deviceManager, &DeviceManager::actionExecutionFinished, this, &GuhCore::actionExecutionFinished); connect(m_deviceManager, &DeviceManager::devicesDiscovered, this, &GuhCore::devicesDiscovered); connect(m_deviceManager, &DeviceManager::deviceSetupFinished, this, &GuhCore::deviceSetupFinished); connect(m_deviceManager, &DeviceManager::pairingFinished, this, &GuhCore::pairingFinished); m_logger->logSystemEvent(true); } /*! Connected to the DeviceManager's emitEvent signal. Events received in here will be evaluated by the \l{RuleEngine} and the according \l{Action}{Actions} are executed.*/ void GuhCore::gotEvent(const Event &event) { m_logger->logEvent(event); emit eventTriggered(event); QList actions; foreach (const Rule &rule, m_ruleEngine->evaluateEvent(event)) { if (rule.eventDescriptors().count() > 0) { m_logger->logRuleTriggered(rule); actions.append(rule.actions()); } else { m_logger->logRuleActiveChanged(rule); if (rule.active()) { actions.append(rule.actions()); } else { // TODO: execute state exit actions } } } // Now execute all the associated actions foreach (const Action &action, actions) { qDebug() << "executing action" << action.actionTypeId(); DeviceManager::DeviceError status = m_deviceManager->executeAction(action); switch(status) { case DeviceManager::DeviceErrorNoError: break; case DeviceManager::DeviceErrorSetupFailed: qDebug() << "Error executing action. Device setup failed."; break; case DeviceManager::DeviceErrorInvalidParameter: qDebug() << "Error executing action. Invalid action parameter."; break; default: qDebug() << "Error executing action:" << status; } m_logger->logAction(action, status == DeviceManager::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status); } } /*! Return the instance of the log engine */ LogEngine* GuhCore::logEngine() const { return m_logger; } void GuhCore::actionExecutionFinished(const ActionId &id, DeviceManager::DeviceError status) { emit actionExecuted(id, status); Action action = m_pendingActions.take(id); m_logger->logAction(action, status == DeviceManager::DeviceErrorNoError ? Logging::LoggingLevelInfo : Logging::LoggingLevelAlert, status); }