add database manager

This commit is contained in:
Evgenii Alekseev 2017-02-21 02:15:48 +03:00
parent 6bc4668271
commit 8261f610f7
11 changed files with 631 additions and 7 deletions

2
.gitignore vendored
View File

@ -41,8 +41,6 @@ build
# archives
*src.tar.[gx]z
*pkg.tar.[gx]z
src
pkg
*.deb
# clion settings

View File

@ -9,7 +9,7 @@ if (POLICY CMP0063)
cmake_policy(SET CMP0063 OLD)
endif ()
project(awesomewidgets)
project(queued)
set(PROJECT_AUTHOR "Evgeniy Alekseev")
set(PROJECT_CONTACT "esalexeev@gmail.com")
set(PROJECT_LICENSE "MIT")

View File

@ -1,12 +1,12 @@
# main qt libraries
find_package(Qt5 5.6.0 REQUIRED COMPONENTS Core DBus Test)
find_package(Qt5 5.6.0 REQUIRED COMPONENTS Core DBus Sql Test)
add_definitions(
${Qt5Core_DEFINITIONS} ${Qt5DBus_DEFINITIONS}
${Qt5Core_DEFINITIONS} ${Qt5DBus_DEFINITIONS} ${Qt5Sql_DEFINITIONS}
)
set(Qt_INCLUDE
${Qt5Core_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS}
${Qt5Core_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS} ${Qt5Sql_INCLUDE_DIRS}
)
set(Qt_LIBRARIES
${Qt5Core_LIBRARIES} ${Qt5DBus_LIBRARIES}
${Qt5Core_LIBRARIES} ${Qt5DBus_LIBRARIES} ${Qt5Sql_LIBRARIES}
)

View File

@ -24,6 +24,7 @@
#ifndef QUEUED_H
#define QUEUED_H
#include "QueuedDatabase.h"
#include "QueuedDebug.h"
#include "QueuedProcess.h"
#include "QueuedProcessManager.h"

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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 QueuedDatabase.h
* Header of Queued library
* @author Evgeniy Alekseev
* @copyright MIT
* @bug https://github.com/arcan1s/queued/issues
*/
#ifndef QUEUEDDATABASE_H
#define QUEUEDDATABASE_H
#include <QHash>
#include <QObject>
#include <QSqlDatabase>
typedef QHash<QString, QStringList> QueuedDBSchema;
/**
* @brief queued adaptor to databases
*/
class QueuedDatabase : public QObject
{
Q_OBJECT
Q_PROPERTY(QString path READ path)
// TODO add fields SQL parameters (type whatever), Qt specific types
const QueuedDBSchema DBSchema = {
{"users",
{"_id", "name", "uid", "gid", "password_sha512", "email", "cpu", "gpu",
"memory", "gpumemory", "storage"}},
{"tasks", {"_id", "userId", "command", "arguments", "workDirectory"}}};
public:
/**
* @brief QueuedDatabase class constructor
* @param parent pointer to parent item
* @param path path to database
* @param driver database driver
*/
explicit QueuedDatabase(QObject *parent, const QString path,
const QString driver);
/**
* @brief QueuedDatabase class destructor
*/
virtual ~QueuedDatabase();
/**
* @brief check and create database
*/
void checkDatabase();
/**
* @brief open database
* @param _hostname hostname to connect, may be empty
* @param _port port to connect, may be 0
* @param _username username to connect, may be empty
* @param _password password to connect, will be ignored if _username
* is empty
*/
void open(const QString _hostname, const int _port, const QString _username,
const QString _password);
/**
* @brief path to database
* @return path to used database
*/
QString path() const;
private:
/**
* @brief database
*/
QSqlDatabase m_database;
/**
* @brief database path
*/
QString m_path;
/**
* @brief create or update actual schema in table
* @param _table table name
*/
void createSchema(const QString _table);
/**
* @brief create given table
* @param _table table name
*/
void createTable(const QString _table);
};
#endif /* QUEUEDDATABASE_H */

View File

@ -31,6 +31,7 @@
typedef QHash<long long, QueuedProcess *> QueuedProcessMap;
typedef QHash<long long, QMetaObject::Connection> QueuedProcessConnectionMap;
/**
* @brief implementation over QProcess to run processes
@ -103,6 +104,10 @@ private slots:
const long long _index);
private:
/**
* @brief connection map
*/
QueuedProcessConnectionMap m_connections;
/**
* @brief action on exit
*/

View File

@ -0,0 +1,20 @@
# set files
file (GLOB_RECURSE SUBPROJECT_SOURCES "*.cpp")
file (GLOB_RECURSE SUBPROJECT_HEADERS "*.h" "${PROJECT_LIBRARY_DIR}/*h")
# include_path
include_directories ("${PROJECT_LIBRARY_DIR}/include"
"${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_BINARY_DIR}"
"${Qt_INCLUDE}")
qt5_wrap_cpp (SUBPROJECT_MOC_SOURCES "${SUBPROJECT_HEADERS}")
add_library ("${SUBPROJECT}" SHARED "${SUBPROJECT_SOURCES}" "${SUBPROJECT_HEADERS}"
"${SUBPROJECT_MOC_SOURCES}")
set_target_properties ("${SUBPROJECT}" PROPERTIES
SOVERSION "${PROJECT_VERSION_MAJOR}"
VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
target_link_libraries ("${SUBPROJECT}" "${Qt_LIBRARIES}")
# install properties
install (TARGETS "${SUBPROJECT}" DESTINATION "${LIB_INSTALL_DIR}")

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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 QueuedDatabase.cpp
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#include "queued/Queued.h"
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
/**
* @fn QueuedDatabase
*/
QueuedDatabase::QueuedDatabase(QObject *parent, const QString path,
const QString driver)
: QObject(parent)
, m_path(path)
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
m_database = QSqlDatabase::addDatabase(driver);
m_database.setDatabaseName(path);
}
/**
* @fn ~QueuedDatabase
*/
QueuedDatabase::~QueuedDatabase()
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
}
/**
* @fn open
*/
void QueuedDatabase::open(const QString _hostname, const int _port,
const QString _username, const QString _password)
{
qCDebug(LOG_LIB) << "Open database at" << _hostname << _port << "as user"
<< _username;
if (!_hostname.isEmpty())
m_database.setHostName(_hostname);
if (_port > 0)
m_database.setPort(_port);
bool status = _username.isEmpty() ? m_database.open()
: m_database.open(_username, _password);
qCDebug(LOG_LIB) << "Open database status" << status;
if (status)
return checkDatabase();
}
/**
* @fn checkDatabase
*/
void QueuedDatabase::checkDatabase()
{
QStringList tables = m_database.tables();
for (auto table : DBSchema.keys()) {
// create table if does not exist
if (!tables.contains(table))
createTable(table);
// update schema
createSchema(table);
}
}
/**
* @fn path
*/
QString QueuedDatabase::path() const
{
return m_path;
}
/**
* @fn createSchema
*/
void QueuedDatabase::createSchema(const QString _table)
{
qCDebug(LOG_LIB) << "Create schema for" << _table;
QSqlRecord record = m_database.record(_table);
// get column names
QStringList columns;
for (int i = 0; i < record.count(); i++)
columns.append(record.fieldName(i));
// check and append if any
for (auto column : DBSchema[_table]) {
if (columns.contains(column))
continue;
QSqlQuery query
= m_database.exec(QString("ALTER TABLE '%1' add column `%2`")
.arg(_table)
.arg(column));
QSqlError error = query.lastError();
if (error.isValid())
qCCritical(LOG_LIB) << "Could not insert column" << column
<< "to table" << _table
<< "error:" << error.text();
}
}
/**
* @fn createTable
*/
void QueuedDatabase::createTable(const QString _table)
{
qCDebug(LOG_LIB) << "Create table" << _table;
QSqlQuery query = m_database.exec(
QString("CREATE TABLE '%1' (`_id` INTEGER PRIMARY KEY AUTOINCREMENT)")
.arg(_table));
QSqlError error = query.lastError();
if (error.isValid())
qCCritical(LOG_LIB) << "Could not create table" << _table
<< "error:" << error.text();
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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 QueuedDebug.cpp
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#include "queued/Queued.h"
#include "version.h"
Q_LOGGING_CATEGORY(LOG_CTL, "org.queued.control", QtMsgType::QtWarningMsg)
Q_LOGGING_CATEGORY(LOG_DBUS, "org.queued.dbus", QtMsgType::QtWarningMsg)
Q_LOGGING_CATEGORY(LOG_LIB, "org.queued.library", QtMsgType::QtWarningMsg)
Q_LOGGING_CATEGORY(LOG_PL, "org.queued.plugin", QtMsgType::QtWarningMsg)
Q_LOGGING_CATEGORY(LOG_SERV, "org.queued.server", QtMsgType::QtWarningMsg)
/**
* @fn getBuildData
*/
QStringList QueuedDebug::getBuildData()
{
QStringList metadata;
return metadata;
}

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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 QueuedProcess.cpp
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#include "queued/Queued.h"
#include <unistd.h>
/**
* @class QueuedProcess
*/
/**
* @fn QueuedProcess
*/
QueuedProcess::QueuedProcess(QObject *parent,
const QueuedProcessDefinitions definitions,
const long long index)
: QProcess(parent)
, m_definitions(definitions)
, m_index(index)
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
setArguments(m_definitions.args);
setProgram(m_definitions.cmd);
setWorkingDirectory(m_definitions.workingDirectory);
}
/**
* @fn ~QueuedProcess
*/
QueuedProcess::~QueuedProcess()
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
}
/**
* @fn index
*/
long long QueuedProcess::index() const
{
return m_index;
}
/**
* @fn name
*/
QString QueuedProcess::name() const
{
return QString("queued-%1").arg(index());
}
/**
* @fn removeLimit
*/
void QueuedProcess::removeLimit(const LimitType _limitType)
{
qCDebug(LOG_LIB) << "Remove limit" << static_cast<int>(_limitType);
m_limits.remove(_limitType);
}
/**
* @fn setLimit
*/
void QueuedProcess::setLimit(const LimitType _limitType, const QVariant _value)
{
qCDebug(LOG_LIB) << "Set limit" << static_cast<int>(_limitType) << "to"
<< _value;
if (!_value.isValid())
return removeLimit(_limitType);
bool status = false;
long long intValue = _value.type() == QVariant::String
? convertMemory(_value.toString(), status)
: _value.toLongLong(&status);
if (!status)
removeLimit(_limitType);
else
m_limits[_limitType] = intValue;
}
/**
* @fn operator==
*/
bool QueuedProcess::operator==(const QueuedProcess _other)
{
return name() == _other.name();
}
/**
* @fn setupChildProcess
*/
void QueuedProcess::setupChildProcess()
{
::setgid(m_definitions.gid);
::setuid(m_definitions.uid);
}
/**
* @fn run
*/
void QueuedProcess::run()
{
// TODO set limits to child process and etc
return start();
}
/**
* @fn convertMemory
*/
long long QueuedProcess::convertMemory(QString _value, bool &_status) const
{
qCDebug(LOG_LIB) << "Convert memory value" << _value;
long long intValue;
if (_value.endsWith(QString("K")))
intValue = _value.remove(QString("K")).toLongLong(&_status) * 1024;
else if (_value.endsWith(QString("M")))
intValue
= _value.remove(QString("M")).toLongLong(&_status) * 1024 * 1024;
else if (_value.endsWith(QString("G")))
intValue = _value.remove(QString("G")).toLongLong(&_status) * 1024
* 1024 * 1024;
else
intValue = _value.toInt(&_status);
qCInfo(LOG_LIB) << "Converted value" << intValue;
return intValue;
}

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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 QueuedProcessManager.cpp
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#include "queued/Queued.h"
/**
* @fn QueuedProcessManager
*/
QueuedProcessManager::QueuedProcessManager(QObject *parent,
const OnExitAction onExit)
: QObject(parent)
, m_onExit(onExit)
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
}
/**
* @fn ~QueuedProcessManager
*/
QueuedProcessManager::~QueuedProcessManager()
{
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
QList<long long> indices = m_processes.keys();
for (auto index : indices)
remove(index);
}
/**
* @fn add
*/
QueuedProcess *
QueuedProcessManager::add(const long long _index,
const QueuedProcessDefinitions _definitions)
{
qCDebug(LOG_LIB) << "Add new process" << _definitions.cmd << "with index"
<< _index;
if (m_processes.contains(_index))
return m_processes[_index];
QueuedProcess *process = new QueuedProcess(this, _definitions, _index);
m_processes[_index] = process;
// connect to signal
m_connections[_index] = connect(
process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
&QProcess::finished),
[=](const int exitCode, const QProcess::ExitStatus exitStatus) {
return taskFinished(exitCode, exitStatus, _index);
});
return process;
}
/**
* @fn onExit
*/
QueuedProcessManager::OnExitAction QueuedProcessManager::onExit() const
{
return m_onExit;
}
/**
* @fn process
*/
QueuedProcess *QueuedProcessManager::process(const long long _index)
{
qCDebug(LOG_LIB) << "Get process by index" << _index;
return m_processes.contains(_index) ? m_processes[_index] : nullptr;
}
/**
* @fn processes
*/
QueuedProcessMap QueuedProcessManager::processes()
{
return m_processes;
}
/**
* @fn remove
*/
void QueuedProcessManager::remove(const long long _index)
{
qCDebug(LOG_LIB) << "Remove process by index" << _index;
if (!m_processes.contains(_index))
return;
QueuedProcess *process = m_processes.take(_index);
auto connection = m_connections.take(_index);
disconnect(connection);
switch (m_onExit) {
case OnExitAction::Kill:
process->kill();
break;
case OnExitAction::Terminate:
process->terminate();
break;
}
process->deleteLater();
}
/**
* @fn taskFinished
*/
void QueuedProcessManager::taskFinished(const int _exitCode,
const QProcess::ExitStatus _exitStatus,
const long long _index)
{
qCDebug(LOG_LIB) << "Process" << _index << "finished with code" << _exitCode
<< "and status" << _exitStatus;
// TODO implementation
}