implement support of plugin supinfo

This commit is contained in:
Evgenii Alekseev 2017-11-27 23:12:37 +03:00
parent 9dd63fc77e
commit 5f229b8ade
26 changed files with 492 additions and 30 deletions

View File

@ -0,0 +1,44 @@
{
"author": "Queued team",
"description": "Send email on job updates",
"homepage": "https://github.com/arcan1s/queued",
"license": "MIT",
"options": {
"From": {
"default": "mail@example.com",
"description": "from email field",
"type": "string"
},
"InsecureCurl": {
"default": false,
"description": "ignore insecure warnings",
"type": "boolean"
},
"Password": {
"default": "",
"description": "email service auth password",
"type": "string"
},
"Port": {
"default": 465,
"description": "email service port",
"type": "integer"
},
"Server": {
"default": "smtp://smtp.example.com",
"description": "email server url",
"type": "string"
},
"UseSSL": {
"default": false,
"description": "use ssl for connection",
"type": "boolean"
},
"Username": {
"default": "",
"description": "email service auth username",
"type": "string"
}
}
}

View File

@ -58,4 +58,6 @@ macro(queued_install_plugin PLUGIN_ROOT)
# install
install (TARGETS "${PLUGIN}" DESTINATION "${QUEUED_PLUGIN_ROOT}")
install (FILES "${PLUGIN_ROOT}/${PLUGIN}.json" DESTINATION
"${QUEUED_PLUGIN_ROOT}")
endmacro()

View File

@ -38,6 +38,7 @@
#include "QueuedPluginInterface.h"
#include "QueuedPluginManager.h"
#include "QueuedPluginManagerInterface.h"
#include "QueuedPluginSpecification.h"
#include "QueuedProcess.h"
#include "QueuedProcessManager.h"
#include "QueuedPropertyInterface.h"

View File

@ -27,8 +27,11 @@
#include <QObject>
#include <QVariant>
#include "QueuedStaticConfig.h"
namespace QueuedConfig
{
enum class QueuedSettings;
}
/**
* @brief implementation over database stored settings

View File

@ -26,14 +26,20 @@
#include <QObject>
#include "QueuedEnums.h"
#include "QueuedLimits.h"
#include "QueuedResult.h"
class QueuedCorePrivate;
class QueuedProcess;
class QueuedUser;
namespace QueuedEnums
{
enum class Permission;
};
namespace QueuedLimits
{
struct Limits;
}
/**
* @brief aggregator of queued classes
@ -214,13 +220,26 @@ public:
QueuedResult<QList<QVariantHash>>
performanceReport(const QDateTime &_from, const QDateTime &_to,
const QString &_token) const;
/**
* @brief get plugin description
* @param _plugin
* plugin name
* @param _token
* user auth token
* @return dictionary of PluginSpecification representation
*/
QueuedResult<QVariantHash> plugin(const QString &_plugin,
const QString &_token);
/**
* @brief get plugin settings
* @param _plugin
* plugin name
* @param _token
* user auth token
* @return hash of plugin settings
*/
QVariantHash pluginSettings(const QString &_plugin);
QueuedResult<QVariantHash> pluginSettings(const QString &_plugin,
const QString &_token);
/**
* @brief remove plugin from autoload and unload it now
* @param _plugin

View File

@ -28,10 +28,14 @@
#include <QDBusReply>
#include "QueuedProcess.h"
#include "QueuedStaticConfig.h"
#include "QueuedUser.h"
namespace QueuedPluginSpecification
{
struct Plugin;
};
/**
* @addtogroup QueuedCoreAdaptor
* @brief adaptor to DBus methods
@ -190,6 +194,16 @@ sendUserPermissionRemove(const long long _id,
const QueuedEnums::Permission _permission,
const QString &_token);
// specific methods for properties
/**
* @brief get plugin
* @param _plugin
* plugin name
* @param _token
* user auth token
* @return plugin specification body
*/
QueuedResult<QueuedPluginSpecification::Plugin>
getPlugin(const QString &_plugin, const QString &_token);
/**
* @brief get option
* @param _property

View File

@ -31,6 +31,10 @@
class QueuedPluginInterface;
class QueuedPluginManagerInterface;
namespace QueuedPluginSpecification
{
struct Plugin;
};
/**
* @brief report manager for queued
@ -79,6 +83,13 @@ public:
* @return true on success load otherwise return false
*/
bool loadPlugin(const QString &_name, const QVariantHash &_settings);
/**
* @brief load plugin specification
* @param _name
* plugin name
* @return plugin specification object
*/
QueuedPluginSpecification::Plugin loadSpecification(const QString &_name);
/**
* @brief path to plugin location
* @return full path to plugin location

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2017 Queued team
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
*
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* @file QueuedPluginSpecification.h
* Header of Queued library
* @author Queued team
* @copyright MIT
* @bug https://github.com/arcan1s/queued/issues
*/
#ifndef QUEUEDPLUGINSPECIFICATION_H
#define QUEUEDPLUGINSPECIFICATION_H
#include <QString>
/**
* @addtogroup QueuedPluginSpecification
* @brief plugin specification representation
*/
namespace QueuedPluginSpecification
{
/**
* @struct PluginOption
* @brief plugin option structure
* @var PluginOption::defaultValue
* option default value
* @var PluginOption::description
* option description
* @var PluginOption::name
* option name
* @var PluginOption::type
* option type
*/
struct PluginOption {
QVariant defaultValue;
QString description;
QString name;
QString type;
};
/**
* @struct Plugin
* @brief plugin specification structure
* @var Plugin::author
* plugin author
* @var Plugin::description
* plugin description
* @var Plugin::homepage
* plugin license
* @var Plugin::license
* plugin license
* @param Plugin::options
* plugin options
*/
struct Plugin {
QString author;
QString description;
QString homepage;
QString license;
QList<PluginOption> options;
};
/**
* @brief dump specification to map
* @param _plugin
* plugin object
* @return specification dump
*/
QVariantHash dumpSpecification(const Plugin &_plugin);
/**
* @brief init specification from file
* @param _path
* path to specification file
* @return initialized object
*/
Plugin readSpecification(const QString &_path);
/**
* @brief init specification from map
* @param _map
* specification map
* @return initialized object
*/
Plugin readSpecification(const QVariantHash &_map);
};
#endif /* QUEUEDPLUGINSPECIFICATION_H */

View File

@ -27,10 +27,12 @@
#include <QDateTime>
#include <QProcess>
#include "QueuedLimits.h"
class QueuedControlGroupsAdaptor;
namespace QueuedLimits
{
struct Limits;
};
/**
* @brief implementation over QProcess to run processes
@ -78,7 +80,7 @@ public:
* @var QueuedProcessDefinitions::limits
* task limits
*/
typedef struct {
struct QueuedProcessDefinitions {
QString command;
QStringList arguments;
QString workingDirectory;
@ -89,7 +91,7 @@ public:
QDateTime endTime;
long long user = 0;
QString limits;
} QueuedProcessDefinitions;
};
/**
* @brief QueuedProcess class constructor

View File

@ -28,11 +28,14 @@
#include <QHash>
#include <QObject>
#include "QueuedEnums.h"
#include "QueuedProcess.h"
class QueuedPluginManagerInterface;
namespace QueuedEnums
{
enum class ExitAction;
};
/**
* @brief implementation over QProcess to run processes
@ -183,7 +186,7 @@ private:
/**
* @brief action on exit
*/
QueuedEnums::ExitAction m_onExit = QueuedEnums::ExitAction::Terminate;
QueuedEnums::ExitAction m_onExit;
/**
* @brief processes list
*/

View File

@ -53,6 +53,15 @@ public:
virtual ~QueuedPropertyInterface();
public slots:
/**
* @brief get plugin description
* @param plugin
* plugin name
* @param token
* user auth token
* @return plugin properties
*/
QDBusVariant Plugin(const QString &plugin, const QString &token);
/**
* @brief get advanced option
* @param property

View File

@ -27,7 +27,7 @@
#include <QDateTime>
#include <QObject>
#include <queued/QueuedEnums.h>
#include "QueuedEnums.h"
class QueuedCore;

View File

@ -28,6 +28,7 @@
#include <result/result.hpp>
namespace QueuedEnums
{
enum class ReturnStatus;
@ -98,6 +99,7 @@ Q_DECLARE_METATYPE(QueuedResult<QString>)
Q_DECLARE_METATYPE(QueuedResult<QStringList>)
Q_DECLARE_METATYPE(QueuedResult<QVariant>)
Q_DECLARE_METATYPE(QueuedResult<QList<QVariantHash>>)
Q_DECLARE_METATYPE(QueuedResult<QVariantHash>)
Q_DECLARE_METATYPE(QueuedResult<QueuedStatusMap>)
/**
* @brief DBus marshalling method

View File

@ -47,11 +47,11 @@ namespace QueuedConfig
* @var QueuedAdminSetup::salt
* user passwords salt
*/
typedef struct {
struct QueuedAdminSetup {
QString name;
QString password;
QString salt;
} QueuedAdminSetup;
};
/**
* @struct QueuedDBSetup
* @brief structure to define database setup
@ -68,14 +68,14 @@ typedef struct {
* @var QueuedDBSetup::username
* username to connect if any
*/
typedef struct {
struct QueuedDBSetup {
QString driver;
QString hostname;
QString password;
QString path;
int port;
QString username;
} QueuedDBSetup;
};
/**
* @enum QueuedSettings
* @brief settings keys enum
@ -129,11 +129,11 @@ enum class QueuedSettings {
* @var QueuedSettingsField::defaultValue
* settings default value
*/
typedef struct {
struct QueuedSettingsField {
QueuedSettings id;
QVariant defaultValue;
bool isAdmin = true;
} QueuedSettingsField;
};
/**
* @typedef QueuedSettingsDefaultMap
* map of settings indices to related values

View File

@ -28,9 +28,13 @@
#include <QVariant>
#include "QueuedEnums.h"
#include "QueuedLimits.h"
namespace QueuedLimits
{
struct Limits;
};
/**
* @brief representation of user in queued
*/
@ -62,14 +66,14 @@ public:
* @var limits
* user defined limits
*/
typedef struct {
struct QueuedUserDefinitions {
QString name;
QString email;
QString password;
uint permissions = 0;
uint priority = 0;
QString limits;
} QueuedUserDefinitions;
};
/**
* @brief QueuedUser class constructor

View File

@ -27,7 +27,6 @@
#include <QHash>
#include <QObject>
#include "QueuedEnums.h"
#include "QueuedUser.h"

View File

@ -223,13 +223,26 @@ public:
QueuedResult<QList<QVariantHash>>
performanceReport(const QDateTime &_from, const QDateTime &_to,
const QString &_token) const;
/**
* @brief get plugin description
* @param _plugin
* plugin name
* @param _token
* user auth token
* @return dictionary of PluginSpecification representation
*/
QueuedResult<QVariantHash> plugin(const QString &_plugin,
const QString &_token);
/**
* @brief get plugin settings
* @param _plugin
* plugin name
* @param _token
* user auth token
* @return hash of plugin settings
*/
QVariantHash pluginSettings(const QString &_plugin);
QueuedResult<QVariantHash> pluginSettings(const QString &_plugin,
const QString &_token);
/**
* @brief remove plugin from autoload and unload it now
* @param _plugin

View File

@ -208,14 +208,27 @@ QueuedCore::performanceReport(const QDateTime &_from, const QDateTime &_to,
}
/**
* @fn plugin
*/
QueuedResult<QVariantHash> QueuedCore::plugin(const QString &_plugin,
const QString &_token)
{
qCDebug(LOG_LIB) << "Get data for plugin" << _plugin;
return m_impl->plugin(_plugin, _token);
}
/**
* @fn pluginSettings
*/
QVariantHash QueuedCore::pluginSettings(const QString &_plugin)
QueuedResult<QVariantHash> QueuedCore::pluginSettings(const QString &_plugin,
const QString &_token)
{
qCDebug(LOG_LIB) << "Get plugin settings for" << _plugin;
return m_impl->pluginSettings(_plugin);
return m_impl->pluginSettings(_plugin, _token);
}

View File

@ -287,6 +287,31 @@ QueuedResult<bool> QueuedCoreAdaptor::sendUserPermissionRemove(
}
/**
* @fn getPlugin
*/
QueuedResult<QueuedPluginSpecification::Plugin>
QueuedCoreAdaptor::getPlugin(const QString &_plugin, const QString &_token)
{
qCDebug(LOG_DBUS) << "Get information for plugin" << _plugin;
QVariantList args = {_plugin, _token};
auto result = sendRequest<QVariantHash>(
QueuedConfig::DBUS_SERVICE, QueuedConfig::DBUS_PROPERTY_PATH,
QueuedConfig::DBUS_SERVICE, "Plugin", args);
QueuedResult<QueuedPluginSpecification::Plugin> output;
result.match(
[&output](const QVariantHash &res) {
output = QueuedPluginSpecification::readSpecification(res);
},
[&output](const QueuedError &err) { output = err; });
return output;
}
/**
* @fn getOption
*/

View File

@ -383,13 +383,38 @@ QueuedResult<QList<QVariantHash>> QueuedCorePrivate::performanceReport(
}
/**
* @fn plugin
*/
QueuedResult<QVariantHash> QueuedCorePrivate::plugin(const QString &_plugin,
const QString &_token)
{
bool isAdmin = m_users->authorize(_token, QueuedEnums::Permission::Admin);
if (!isAdmin)
return QueuedError("Not allowed",
QueuedEnums::ReturnStatus::InsufficientPermissions);
auto spec = m_plugins->loadSpecification(_plugin);
auto map = QueuedPluginSpecification::dumpSpecification(spec);
// do something if we need
return map;
}
/**
* @fn pluginSettings
*/
QVariantHash QueuedCorePrivate::pluginSettings(const QString &_plugin)
QueuedResult<QVariantHash>
QueuedCorePrivate::pluginSettings(const QString &_plugin, const QString &_token)
{
qCDebug(LOG_LIB) << "Get plugin settings for" << _plugin;
bool isAdmin = m_users->authorize(_token, QueuedEnums::Permission::Admin);
if (!isAdmin)
return QueuedError("Not allowed",
QueuedEnums::ReturnStatus::InsufficientPermissions);
auto dbSettings
= m_database->get(QueuedDB::SETTINGS_TABLE,
QString("WHERE key LIKE 'Plugin.%1.%'").arg(_plugin));
@ -401,6 +426,15 @@ QVariantHash QueuedCorePrivate::pluginSettings(const QString &_plugin)
settings[key] = value["value"];
});
// append default
auto spec = m_plugins->loadSpecification(_plugin);
QVariantHash defaultOpts;
for (auto &opt : spec.options) {
if (settings.contains(opt.name))
continue;
settings[opt.name] = opt.defaultValue;
}
return settings;
}

View File

@ -258,7 +258,9 @@ QueuedCorePrivateHelper::editPluginPrivate(const QString &_plugin,
QueuedResult<bool> r;
if (_add && !pluginList.contains(_plugin)) {
if (plugins()->loadPlugin(_plugin, m_core->pluginSettings(_plugin))) {
auto settings = m_core->pluginSettings(_plugin, m_core->m_adminToken);
if ((settings.type() == Result::Content::Value)
&& (plugins()->loadPlugin(_plugin, settings.get()))) {
pluginList.append(_plugin);
r = true;
}

View File

@ -112,8 +112,16 @@ void QueuedCorePrivate::initPlugins()
.split('\n');
m_plugins = m_helper->initObject(m_plugins, m_adminToken);
for (auto &plugin : pluginList)
m_plugins->loadPlugin(plugin, pluginSettings(plugin));
for (auto &plugin : pluginList) {
auto settings = pluginSettings(plugin, m_adminToken);
settings.match(
[this, &plugin](const QVariantHash &opts) {
m_plugins->loadPlugin(plugin, opts);
},
[&plugin](const QueuedError &) {
qCWarning(LOG_LIB) << "Could not load settings for" << plugin;
});
}
}

View File

@ -55,7 +55,7 @@ QueuedPluginManager::~QueuedPluginManager()
for (auto &plugin : plugins)
unloadPlugin(plugin);
delete m_interface;
m_interface->deleteLater();
}
@ -143,6 +143,29 @@ bool QueuedPluginManager::loadPlugin(const QString &_name,
}
QueuedPluginSpecification::Plugin
QueuedPluginManager::loadSpecification(const QString &_name)
{
qCDebug(LOG_PL) << "Load specification for" << _name;
QString jsonName = QString("%1.json").arg(_name);
QString path;
for (auto &dir : pluginLocations()) {
if (!QDir(dir).entryList(QDir::Files).contains(jsonName))
continue;
path = QString("%1/%2").arg(dir).arg(jsonName);
break;
}
if (path.isEmpty()) {
qCWarning(LOG_PL) << "Could not find" << jsonName;
return QueuedPluginSpecification::Plugin();
} else {
return QueuedPluginSpecification::readSpecification(path);
}
}
/**
* @fn pluginLocations
*/

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2017 Queued team
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
*
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* @file QueuedPluginSpecification.cpp
* Source code of queued library
* @author Queued team
* @copyright MIT
* @bug https://github.com/arcan1s/queued/issues
*/
#include <queued/Queued.h>
#include <QFile>
#include <QJsonParseError>
/**
* @fn dumpSpecification
*/
QVariantHash QueuedPluginSpecification::dumpSpecification(const Plugin &_plugin)
{
QVariantHash output = {{"author", _plugin.author},
{"description", _plugin.description},
{"homepage", _plugin.homepage},
{"license", _plugin.license}};
QVariantHash options;
for (auto opt : _plugin.options)
options[opt.name] = QVariantHash({{"default", opt.defaultValue},
{"description", opt.description},
{"type", opt.type}});
output["options"] = options;
return output;
}
/**
* @fn readSpecification
*/
QueuedPluginSpecification::Plugin
QueuedPluginSpecification::readSpecification(const QString &_path)
{
qCDebug(LOG_PL) << "Read specification from" << _path;
QFile jsonFile(_path);
if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(LOG_LIB) << "Could not open" << _path;
return QueuedPluginSpecification::Plugin();
}
QString jsonText = jsonFile.readAll();
jsonFile.close();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonText.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(LOG_LIB) << "Parse error" << error.errorString();
return QueuedPluginSpecification::Plugin();
}
auto map = jsonDoc.toVariant().toMap();
// convert to hash
QVariantHash hash;
QVariantMap::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it)
hash[it.key()] = it.value();
return readSpecification(hash);
}
/**
* @fn readSpecification
*/
QueuedPluginSpecification::Plugin
QueuedPluginSpecification::readSpecification(const QVariantHash &_map)
{
qCDebug(LOG_PL) << "Read specification from" << _map;
QueuedPluginSpecification::Plugin plugin;
// easy part
plugin.author = _map["author"].toString();
plugin.description = _map["description"].toString();
plugin.homepage = _map["homepage"].toString();
plugin.license = _map["license"].toString();
// now lets try to parse options
auto options = _map["options"].toMap();
for (auto &option : options.keys()) {
auto optionMap = options[option].toMap();
QueuedPluginSpecification::PluginOption optionObj;
optionObj.name = option;
optionObj.defaultValue = optionMap["default"];
optionObj.description = optionMap["description"].toString();
optionObj.type = optionMap["type"].toString();
plugin.options.append(optionObj);
}
return plugin;
}

View File

@ -40,6 +40,8 @@ QueuedProcessManager::QueuedProcessManager(QObject *_parent)
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
qRegisterMetaType<QueuedEnums::ExitAction>("QueuedEnums::ExitAction");
m_onExit = QueuedEnums::ExitAction::Terminate;
}

View File

@ -41,6 +41,9 @@ QueuedPropertyInterface::QueuedPropertyInterface(QueuedCore *parent)
qRegisterMetaType<QueuedResult<QVariant>>("QueuedResult<QVariant>");
qDBusRegisterMetaType<QueuedResult<QVariant>>();
qRegisterMetaType<QueuedResult<QVariantHash>>("QueuedResult<QVariantHash>");
qDBusRegisterMetaType<QueuedResult<QVariantHash>>();
}
@ -53,6 +56,18 @@ QueuedPropertyInterface::~QueuedPropertyInterface()
}
/**
* @fn Plugin
*/
QDBusVariant QueuedPropertyInterface::Plugin(const QString &plugin,
const QString &token)
{
qCDebug(LOG_DBUS) << "Get plugin" << plugin;
return QueuedCoreAdaptor::toDBusVariant(m_core->plugin(plugin, token));
}
/**
* @fn Option
*/