integrate plugin engine

This commit is contained in:
Evgenii Alekseev 2017-03-10 06:38:54 +03:00
parent d177aa81af
commit 2d8d501f02
11 changed files with 299 additions and 18 deletions

View File

@ -106,12 +106,14 @@ public:
signals: signals:
/** /**
* @brief emits on each value update * @brief emits on each value update
* @param _id
* internal key id
* @param _key * @param _key
* changed key * changed key
* @param _value * @param _value
* changed value * changed value
*/ */
void valueUpdated(const QueuedCfg::QueuedSettings _key, void valueUpdated(const QueuedCfg::QueuedSettings _id, const QString &_key,
const QVariant &_value); const QVariant &_value);
private: private:

View File

@ -97,6 +97,8 @@ typedef struct {
* internal field to control current database version * internal field to control current database version
* @var QueuedSettings::ProcessCommandLine * @var QueuedSettings::ProcessCommandLine
* control process command line * control process command line
* @var QueuedSettings::Plugins
* plugin list
*/ */
enum class QueuedSettings { enum class QueuedSettings {
Invalid = 1 << 0, Invalid = 1 << 0,
@ -108,6 +110,7 @@ enum class QueuedSettings {
TokenExpiration = 1 << 6, TokenExpiration = 1 << 6,
DatabaseVersion = 1 << 7, DatabaseVersion = 1 << 7,
ProcessCommandLine = 1 << 8, ProcessCommandLine = 1 << 8,
Plugins = 1 << 9,
}; };
/** /**
* @ingroup QueuedCfg * @ingroup QueuedCfg
@ -148,7 +151,8 @@ const QueuedSettingsDefaultMap QueuedSettingsDefaults = {
{QueuedSettings::ProcessCommandLine, {QueuedSettings::ProcessCommandLine,
"systemd-run\x01--scope\x01--unit={name}\x01--uid={uid}\x01--gid={gid}" "systemd-run\x01--scope\x01--unit={name}\x01--uid={uid}\x01--gid={gid}"
"\x01-p\x01CPUQuota={cpu}%\x01-p\x01MemoryHigh={memory}\x01{" "\x01-p\x01CPUQuota={cpu}%\x01-p\x01MemoryHigh={memory}\x01{"
"application}"}}}; "application}"}},
{"Plugins", {QueuedSettings::Plugins, ""}}};
}; };
#endif /* QUEUEDCONFIGURATION_H */ #endif /* QUEUEDCONFIGURATION_H */

View File

@ -35,6 +35,7 @@
class QueuedAdvancedSettings; class QueuedAdvancedSettings;
class QueuedDatabase; class QueuedDatabase;
class QueuedDatabaseManager; class QueuedDatabaseManager;
class QueuedPluginManager;
class QueuedProcess; class QueuedProcess;
class QueuedProcessManager; class QueuedProcessManager;
class QueuedReportManager; class QueuedReportManager;
@ -58,6 +59,16 @@ public:
* @brief QueuedCore class destructor * @brief QueuedCore class destructor
*/ */
virtual ~QueuedCore(); virtual ~QueuedCore();
/**
* @brief add plugin to autoload and load it now
* @param _plugin
* plugin name
* @param _auth
* user auth structure
* @return true on successfully addition
*/
bool addPlugin(const QString &_plugin,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief add new task * @brief add new task
* @param _command * @param _command
@ -175,6 +186,23 @@ public:
* @return option value or empty QVariant * @return option value or empty QVariant
*/ */
QVariant option(const QString &_key); QVariant option(const QString &_key);
/**
* @brief get plugin settings
* @param _plugin
* plugin name
* @return hash of plugin settings
*/
QVariantHash pluginSettings(const QString &_plugin);
/**
* @brief remove plugin from autoload and unload it now
* @param _plugin
* plugin name
* @param _auth
* user auth structure
* @return true on successful plugin removal
*/
bool removePlugin(const QString &_plugin,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief force start task * @brief force start task
* @param _id * @param _id
@ -226,13 +254,15 @@ public:
private slots: private slots:
/** /**
* @brief notify clients about settings update * @brief notify clients about settings update
* @param _id
* updated key id
* @param _key * @param _key
* updated key * updated key
* @param _value * @param _value
* new value * new value
*/ */
void updateSettings(const QueuedCfg::QueuedSettings _key, void updateSettings(const QueuedCfg::QueuedSettings _id,
const QVariant &_value); const QString &_key, const QVariant &_value);
/** /**
* @brief update process time * @brief update process time
* @param _id * @param _id
@ -266,6 +296,10 @@ private:
* @brief pointer to database manager object * @brief pointer to database manager object
*/ */
QueuedDatabaseManager *m_databaseManager = nullptr; QueuedDatabaseManager *m_databaseManager = nullptr;
/**
* @brief pointer to plugin manager
*/
QueuedPluginManager *m_plugins = nullptr;
/** /**
* @brief pointer to process manager * @brief pointer to process manager
*/ */
@ -302,6 +336,10 @@ private:
* @throw QueuedDBusException * @throw QueuedDBusException
*/ */
void initDBus(); void initDBus();
/**
* @brief init plugins
*/
void initPlugins();
/** /**
* @brief init processes * @brief init processes
*/ */
@ -364,6 +402,15 @@ private:
* @return true on successful option edition * @return true on successful option edition
*/ */
bool editOptionPrivate(const QString &_key, const QVariant &_value); bool editOptionPrivate(const QString &_key, const QVariant &_value);
/**
* @brief edit plugin list
* @param _plugin
* plugin name
* @param add
* true if it requires add plugin
* @return true on successful action
*/
bool editPluginPrivate(const QString &_plugin, const bool _add);
/** /**
* @brief edit task * @brief edit task
* @param _id * @param _id

View File

@ -76,6 +76,30 @@ public slots:
*/ */
bool OptionEdit(const QString &key, const QDBusVariant &value, bool OptionEdit(const QString &key, const QDBusVariant &value,
const QString &whoAmI, const QString &token); const QString &whoAmI, const QString &token);
/**
* @brief add plugin
* @param plugin
* plugin name
* @param whoAmI
* auth user name
* @param token
* auth user token
* @return true on successful plugin addition
*/
bool PluginAdd(const QString &plugin, const QString &whoAmI,
const QString &token);
/**
* @brief remove plugin
* @param plugin
* plugin name
* @param whoAmI
* auth user name
* @param token
* auth user token
* @return true on successful plugin removal
*/
bool PluginRemove(const QString &plugin, const QString &whoAmI,
const QString &token);
/** /**
* @brief add new task * @brief add new task
* @param command * @param command

View File

@ -54,6 +54,14 @@ public:
* @remark plugin settings will be stored as "plugin.name.Key" * @remark plugin settings will be stored as "plugin.name.Key"
*/ */
virtual void init(const QVariantHash &_settings) = 0; virtual void init(const QVariantHash &_settings) = 0;
/**
* @brief method which will be called on option update
* @param _key
* option key
* @param _value
* option value
*/
virtual void updateSettings(const QString &_key, const QVariant &_value);
}; };
Q_DECLARE_INTERFACE(QueuedPluginInterface, PLUGIN_INTERFACE_NAME) Q_DECLARE_INTERFACE(QueuedPluginInterface, PLUGIN_INTERFACE_NAME)

View File

@ -26,6 +26,7 @@
#include <QHash> #include <QHash>
#include <QObject> #include <QObject>
#include <QPair>
class QueuedPluginInterface; class QueuedPluginInterface;
@ -55,6 +56,13 @@ public:
* @brief QueuedPluginManager class destructor * @brief QueuedPluginManager class destructor
*/ */
virtual ~QueuedPluginManager(); virtual ~QueuedPluginManager();
/**
* @brief get option name from database format
* @param _key
* option key
* @return plugin name and option key in plugin format
*/
static QPair<QString, QString> convertOptionName(const QString &_key);
/** /**
* @brief plugin manager interface * @brief plugin manager interface
* @return pointer to plugin manager interface * @return pointer to plugin manager interface
@ -82,6 +90,16 @@ public:
*/ */
bool unloadPlugin(const QString &_name); bool unloadPlugin(const QString &_name);
public slots:
/**
* @brief notifies plugin about option changes
* @param _key
* database option key
* @param _value
* option value
*/
void optionChanged(const QString &_key, const QVariant &_value);
private: private:
/** /**
* @brief loaded plugins * @brief loaded plugins

View File

@ -37,11 +37,9 @@ class QueuedPluginManagerInterface : public QObject
public: public:
/** /**
* @brief QueuedPluginManagerInterface class constructor * @brief QueuedPluginManagerInterface class constructor
* @param parent
* pointer to parent object
*/ */
explicit QueuedPluginManagerInterface(QObject *parent) explicit QueuedPluginManagerInterface()
: QObject(parent){}; : QObject(nullptr){};
/** /**
* @brief QueuedPluginManagerInterface class destructor * @brief QueuedPluginManagerInterface class destructor
*/ */

View File

@ -148,7 +148,7 @@ void QueuedAdvancedSettings::set(const QString &_key, const QVariant &_value)
m_values[_key.toLower()] = _value; m_values[_key.toLower()] = _value;
auto id = QueuedCfg::QueuedSettingsDefaults[internalId(_key)].id; auto id = QueuedCfg::QueuedSettingsDefaults[internalId(_key)].id;
emit(valueUpdated(id, _value)); emit(valueUpdated(id, _key, _value));
} }

View File

@ -53,6 +53,25 @@ QueuedCore::~QueuedCore()
} }
/**
* @fn addPlugin
*/
bool QueuedCore::addPlugin(
const QString &_plugin,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{
qCDebug(LOG_LIB) << "Add plugin" << _plugin;
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user << "not allowed to add plugin";
return false;
}
return editPluginPrivate(_plugin, true);
}
/** /**
* @addTask * @addTask
*/ */
@ -309,6 +328,46 @@ QVariant QueuedCore::option(const QString &_key)
} }
/**
* @fn pluginSettings
*/
QVariantHash QueuedCore::pluginSettings(const QString &_plugin)
{
qCDebug(LOG_LIB) << "Get plugin settings for" << _plugin;
auto dbSettings
= m_database->get(QueuedDB::SETTINGS_TABLE,
QString("WHERE key LIKE 'Plugin.%1.%'").arg(_plugin));
QVariantHash settings;
std::for_each(dbSettings.cbegin(), dbSettings.cend(),
[&settings](const QVariantHash &value) {
settings[value["key"].toString()] = value["value"];
});
return settings;
}
/**
* @fn removePlugin
*/
bool QueuedCore::removePlugin(
const QString &_plugin,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{
qCDebug(LOG_LIB) << "Remove plugin" << _plugin;
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to remove plugin";
return false;
}
return editPluginPrivate(_plugin, false);
}
/** /**
* @fn startTask * @fn startTask
*/ */
@ -430,6 +489,8 @@ void QueuedCore::deinit()
delete m_databaseManager; delete m_databaseManager;
if (m_reports) if (m_reports)
delete m_reports; delete m_reports;
if (m_plugins)
delete m_plugins;
if (m_processes) if (m_processes)
delete m_processes; delete m_processes;
if (m_users) if (m_users)
@ -455,15 +516,17 @@ void QueuedCore::init(const QString &_configuration)
// init parts // init parts
initSettings(_configuration); initSettings(_configuration);
initPlugins();
initUsers(); initUsers();
initProcesses(); initProcesses();
// settings update notifier // settings update notifier
m_connections += connect( m_connections += connect(
m_advancedSettings, m_advancedSettings,
SIGNAL(valueUpdated(const QueuedCfg::QueuedSettings, const QVariant &)), SIGNAL(valueUpdated(const QueuedCfg::QueuedSettings, const QString &,
const QVariant &)),
this, SLOT(updateSettings(const QueuedCfg::QueuedSettings, this, SLOT(updateSettings(const QueuedCfg::QueuedSettings,
const QVariant &))); const QString &, const QVariant &)));
// dbus session // dbus session
initDBus(); initDBus();
@ -473,15 +536,19 @@ void QueuedCore::init(const QString &_configuration)
/** /**
* @fn updateSettings * @fn updateSettings
*/ */
void QueuedCore::updateSettings(const QueuedCfg::QueuedSettings _key, void QueuedCore::updateSettings(const QueuedCfg::QueuedSettings _id,
const QVariant &_value) const QString &_key, const QVariant &_value)
{ {
qCDebug(LOG_LIB) << "Received update for" << static_cast<int>(_key) qCDebug(LOG_LIB) << "Received update for" << static_cast<int>(_id) << _key
<< "with value" << _value; << "with value" << _value;
// FIXME propbably there is a better way to change settings // FIXME propbably there is a better way to change settings
switch (_key) { switch (_id) {
case QueuedCfg::QueuedSettings::Invalid: case QueuedCfg::QueuedSettings::Invalid:
// check if it is plugin settings
if (_key.startsWith("Plugin."))
m_plugins->optionChanged(_key, _value);
// do nothing otherwise
break; break;
case QueuedCfg::QueuedSettings::DatabaseInterval: case QueuedCfg::QueuedSettings::DatabaseInterval:
m_databaseManager->setInterval(_value.toLongLong()); m_databaseManager->setInterval(_value.toLongLong());
@ -500,6 +567,9 @@ void QueuedCore::updateSettings(const QueuedCfg::QueuedSettings _key,
m_processes->setOnExitAction( m_processes->setOnExitAction(
static_cast<QueuedProcessManager::OnExitAction>(_value.toInt())); static_cast<QueuedProcessManager::OnExitAction>(_value.toInt()));
break; break;
case QueuedCfg::QueuedSettings::Plugins:
// do nothing here
break;
case QueuedCfg::QueuedSettings::ProcessCommandLine: case QueuedCfg::QueuedSettings::ProcessCommandLine:
m_processes->setProcessLine(_value.toString()); m_processes->setProcessLine(_value.toString());
break; break;
@ -601,6 +671,22 @@ void QueuedCore::initDBus()
} }
/**
* @fn initPlugins
*/
void QueuedCore::initPlugins()
{
QStringList pluginList
= m_advancedSettings->get(QueuedCfg::QueuedSettings::Plugins)
.toString()
.split('\x01');
m_plugins = new QueuedPluginManager(this);
for (auto &plugin : pluginList)
m_plugins->loadPlugin(plugin, pluginSettings(plugin));
}
/** /**
* @fn initProcesses * @fn initProcesses
*/ */
@ -796,8 +882,35 @@ bool QueuedCore::editOptionPrivate(const QString &_key, const QVariant &_value)
} }
// add to child object // add to child object
if (status) if (status) {
m_advancedSettings->set(_key, _value); m_advancedSettings->set(_key, _value);
// notify plugin if required
}
return status;
}
/**
* @fn editPluginPrivate
*/
bool QueuedCore::editPluginPrivate(const QString &_plugin, const bool _add)
{
qCDebug(LOG_LIB) << "Edit plugin" << _plugin << "add" << _add;
QStringList pluginList
= m_advancedSettings->get(QueuedCfg::QueuedSettings::Plugins)
.toString()
.split('\x01');
bool status = false;
if (_add && !pluginList.contains(_plugin))
status = m_plugins->loadPlugin(_plugin, pluginSettings(_plugin));
else if (!_add && pluginList.contains(_plugin))
status = m_plugins->unloadPlugin(_plugin);
else
qCDebug(LOG_LIB) << "Plugin" << _plugin
<< "not loaded or already loaded";
return status; return status;
} }

View File

@ -74,6 +74,31 @@ bool QueuedCoreInterface::OptionEdit(const QString &key,
} }
/**
* @fn PluginAdd
*/
bool QueuedCoreInterface::PluginAdd(const QString &plugin,
const QString &whoAmI, const QString &token)
{
qCDebug(LOG_DBUS) << "Add plugin" << plugin << "auth by" << whoAmI;
return m_core->addPlugin(plugin, QueuedUserManager::auth(whoAmI, token));
}
/**
* @fn PluginRemove
*/
bool QueuedCoreInterface::PluginRemove(const QString &plugin,
const QString &whoAmI,
const QString &token)
{
qCDebug(LOG_DBUS) << "Remove plugin" << plugin << "auth by" << whoAmI;
return m_core->removePlugin(plugin, QueuedUserManager::auth(whoAmI, token));
}
/** /**
* @fn TaskAdd * @fn TaskAdd
*/ */

View File

@ -39,7 +39,7 @@ QueuedPluginManager::QueuedPluginManager(QObject *parent)
{ {
qCDebug(LOG_PL) << __PRETTY_FUNCTION__; qCDebug(LOG_PL) << __PRETTY_FUNCTION__;
m_interface = new QueuedPluginManagerInterface(this); m_interface = new QueuedPluginManagerInterface();
} }
@ -58,6 +58,25 @@ QueuedPluginManager::~QueuedPluginManager()
} }
/**
* @fn convertOptionName
*/
QPair<QString, QString>
QueuedPluginManager::convertOptionName(const QString &_key)
{
qCDebug(LOG_PL) << "Convert option name" << _key;
QStringList fields = _key.split('.');
// Plugin.
fields.takeFirst();
// plugin name
QString plugin = fields.takeFirst();
QString option = fields.join('.');
return {plugin, option};
}
/** /**
* @fn interface * @fn interface
*/ */
@ -76,6 +95,10 @@ bool QueuedPluginManager::loadPlugin(const QString &_name,
qCDebug(LOG_PL) << "Load plugin" << _name << "with settings" << _settings; qCDebug(LOG_PL) << "Load plugin" << _name << "with settings" << _settings;
QString libraryName = QString("lib%2.so").arg(_name); QString libraryName = QString("lib%2.so").arg(_name);
// init plugin settings with valid keys
QVariantHash pluginSettings;
for (auto &key : _settings.keys())
pluginSettings[convertOptionName(key).first] = _settings[key];
for (auto &dir : pluginLocations()) { for (auto &dir : pluginLocations()) {
if (!QDir(dir).entryList(QDir::Files).contains(libraryName)) if (!QDir(dir).entryList(QDir::Files).contains(libraryName))
@ -93,7 +116,7 @@ bool QueuedPluginManager::loadPlugin(const QString &_name,
<< "error" << loader.errorString(); << "error" << loader.errorString();
if (item) { if (item) {
m_plugins[_name] = item; m_plugins[_name] = item;
item->init(_settings); item->init(pluginSettings);
item->connect(interface()); item->connect(interface());
} else { } else {
qCCritical(LOG_PL) << "Could not cast plugin" << _name; qCCritical(LOG_PL) << "Could not cast plugin" << _name;
@ -140,3 +163,22 @@ bool QueuedPluginManager::unloadPlugin(const QString &_name)
return true; return true;
} }
/**
* @fn optionChanged
*/
void QueuedPluginManager::optionChanged(const QString &_key,
const QVariant &_value)
{
qCDebug(LOG_PL) << "Option" << _key << "changed to" << _value;
auto option = convertOptionName(_key);
if (!m_plugins.contains(option.first)) {
qCWarning(LOG_PL) << "Plugin" << option.first << "not found for"
<< _key;
return;
}
return m_plugins[option.first]->updateSettings(option.second, _value);
}