Merge pull request #4 from QuasarApp/HanoiTowersPatch

[WIP] Hanoi Towers Patch
This commit is contained in:
Andrei Yankovich 2021-04-16 09:11:58 +03:00 committed by GitHub
commit f7ea0538ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 633 additions and 280 deletions

15
.gitignore vendored
View File

@ -53,3 +53,18 @@ compile_commands.json
# QtCreator local machine specific files for imported projects
*creator.user*
#cmake
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
*_autogen

4
.gitmodules vendored
View File

@ -1,6 +1,4 @@
[submodule "Patronum/QuasarAppLib"]
path = Patronum/QuasarAppLib
url = https://github.com/QuasarApp/QuasarAppLib.git
[submodule "res/DoxyStyle"]
path = res/DoxyStyle
url = https://github.com/QuasarApp/DoxyStyle.git

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2018-2020 QuasarApp.
# Copyright (C) 2018-2021 QuasarApp.
# Distributed under the lgplv3 software license, see the accompanying
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed.
@ -12,10 +12,31 @@ if(TARGET ${PROJECT_NAME})
return()
endif()
include(Patronum/QuasarAppLib/CMake/ccache.cmake)
# Add sub directories
add_subdirectory(Patronum)
add_subdirectory(Tests)
if (NOT DEFINED PATRONUM_TESTS)
set(PATRONUM_TESTS ON)
if (DEFINED TARGET_PLATFORM_TOOLCHAIN)
if (${TARGET_PLATFORM_TOOLCHAIN} STREQUAL "wasm32")
set(PATRONUM_TESTS OFF)
endif()
endif()
if (ANDROID)
set(PATRONUM_TESTS OFF)
endif()
endif()
if (PATRONUM_TESTS)
add_subdirectory(Tests)
else()
message("The ${PROJECT_NAME} tests is disabled.")
endif()
include(Patronum/QuasarAppLib/CMake/QuasarAppCITargets.cmake)
initAll()

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2018-2020 QuasarApp.
# Copyright (C) 2018-2021 QuasarApp.
# Distributed under the lgplv3 software license, see the accompanying
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed.
@ -8,21 +8,23 @@
cmake_minimum_required(VERSION 3.10)
set(CURRENT_PROJECT ${PROJECT_NAME})
add_subdirectory(QuasarAppLib)
include(QuasarAppLib/CMake/ProjectOut.cmake)
include(QuasarAppLib/CMake/Version.cmake)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-DPATRONUM_LIBRARY)
find_package(Qt5 COMPONENTS Core Network REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Network REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network REQUIRED)
add_subdirectory(QuasarAppLib)
add_definitions(-DPATRONUM_LIBRARY)
file(GLOB SOURCE_CPP
"src/*.cpp"
@ -32,8 +34,8 @@ file(GLOB SOURCE_CPP
)
add_library(${CURRENT_PROJECT} SHARED ${SOURCE_CPP})
target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt5::Core Qt5::Network QuasarApp)
add_library(${CURRENT_PROJECT} ${SOURCE_CPP})
target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt::Core Qt::Network QuasarApp)
target_include_directories(${CURRENT_PROJECT} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(${CURRENT_PROJECT} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/Private")

@ -1 +1 @@
Subproject commit c65aba63291c5b93b4457c5a14672a552b7f915f
Subproject commit 693e0e99481bcbc0ffb00d384867880eae14bbf8

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -10,6 +10,7 @@
#include <QList>
#include <QVariantMap>
#include "Patronum_global.h"
namespace Patronum {
@ -34,7 +35,7 @@ enum class ControllerError {
/**
* @brief The IController class
*/
class IController
class PATRONUM_LIBRARYSHARED_EXPORT IController
{
public:
IController() = default;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -9,22 +9,61 @@
#define ISERVICE_H
#include <QList>
#include "Patronum_global.h"
namespace Patronum {
class Feature;
class IService
/**
* @brief The IService class is base interface of the service.
*/
class PATRONUM_LIBRARYSHARED_EXPORT IService
{
public:
IService();
virtual ~IService() = default;
virtual void handleReceive(const QList<Feature>& data) = 0;
virtual QList<Feature> supportedFeatures() = 0;
/**
* @brief handleReceiveData This method get all received comnads and proccess its.
* For each command will invoke the handleReceive method.
* @param data
*/
virtual void handleReceiveData(const QSet<Feature>& data) = 0;
/**
* @brief handleReceive This method invoked when service receive a request from terminal.
* Override this method for wor service.
* @param data This is input data.
* @return This method showld be return true if the @a data command is supported and processed succesful.
* IF you return false then a negative message will be sent to a terminal app.
*/
virtual bool handleReceive(const Feature &data) = 0;
/**
* @brief supportedFeatures Override this method for add your featores for the service.
* @return should be return a set of supported Features.
*/
virtual QSet<Feature> supportedFeatures() = 0;
/**
* @brief onStart This method invoked when service is started successful
*/
virtual void onStart() = 0;
/**
* @brief onStop This method invoked when service receive stop command from the terminal
*/
virtual void onStop() = 0;
/**
* @brief onResume This method invoked when service receive resume command from the terminal
*/
virtual void onResume() = 0;
/**
* @brief onPause This method invoked when service receive pause command from the terminal
*/
virtual void onPause() = 0;
};
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -76,14 +76,14 @@ bool Controller::send() {
return d_ptr->pause();
}
QList<Feature> sendData = {};
QSet<Feature> sendData = {};
auto userParams = QuasarAppUtils::Params::getUserParamsMap();
for (auto val = userParams.begin(); val != userParams.end(); ++val) {
if (val.key() == "verbose" || val.key() == "fileLog" || val.key() == "exec") {
continue;
}
sendData += {val.key(), val.value()};
sendData.insert(Feature{val.key(), val.value()});
}
return d_ptr->sendCmd(sendData);
@ -148,12 +148,12 @@ void Controller::printDefaultHelp() const {
auto quasarappHelp = QuasarAppUtils::Params::getparamsHelp();
QuasarAppUtils::Help::Charters help{{"General options of this controller",{
{"start", QObject::tr("Start a service")},
{"stop", QObject::tr("Stop a service")},
{"pause", QObject::tr("Pause a service")},
{"resume", QObject::tr("Resume a service")},
{"install", QObject::tr("Install a service")},
{"uninstall", QObject::tr("Uninstall a service")}
{"start", QObject::tr("Start a service")},
{"stop", QObject::tr("Stop a service")},
{"pause", QObject::tr("Pause a service")},
{"resume", QObject::tr("Resume a service")},
{"install", QObject::tr("Install a service")},
{"uninstall", QObject::tr("Uninstall a service")}
}}};
QuasarAppUtils::Help::print(quasarappHelp.unite(help));

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -11,12 +11,12 @@
namespace Patronum {
Feature::Feature(const QString &cmd, const QVariant &arg,
Feature::Feature(const QString &cmd, const QString &arg,
const QString &description, const QString &example) {
_cmd = cmd;
_arg = arg;
_description = description;
_example = example;
setCmd(cmd);
setArg(arg);
setDescription(description);
setExample(example);
}
QString Feature::cmd() const {
@ -25,13 +25,14 @@ QString Feature::cmd() const {
void Feature::setCmd(const QString &cmd) {
_cmd = cmd;
_id = qHash(_cmd);
}
QVariant Feature::arg() const {
QString Feature::arg() const {
return _arg;
}
void Feature::setArg(const QVariantList &arg) {
void Feature::setArg(const QString &arg) {
_arg = arg;
}
@ -58,6 +59,10 @@ QString Feature::toString() const {
return _cmd;
}
unsigned int Feature::id() const {
return _id;
}
QDataStream &operator<<(QDataStream &stream, const Feature &obj) {
stream << obj._cmd << obj._arg;
@ -65,8 +70,22 @@ QDataStream &operator<<(QDataStream &stream, const Feature &obj) {
}
QDataStream &operator>>(QDataStream &stream, Feature &obj) {
stream >> obj._cmd >> obj._arg;
decltype (obj._cmd) cmd;
stream >> cmd >> obj._arg;
obj.setCmd(cmd);
return stream;
}
bool operator==(const Feature &left, const Feature &right) {
return left.id() == right.id();
}
uint qHash(const Feature &feature) {
return feature.id();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -21,33 +21,83 @@ namespace Patronum {
class PATRONUM_LIBRARYSHARED_EXPORT Feature
{
public:
Feature() = default;
Feature(const QString& cmd, const QVariant& arg = {},
explicit Feature() = default;
explicit Feature(const QString& cmd, const QString& arg = {},
const QString& description = "", const QString& example = "");
/**
* @brief cmd This method return command of the feature
* @return command of the feature
*/
QString cmd() const;
/**
* @brief setCmd This method set new value of the command.
* @param cmd
*/
void setCmd(const QString &cmd);
QVariant arg() const;
void setArg(const QVariantList &arg);
/**
* @brief arg This method return argument value.
* The argument value has a qvariant type, so this object maybe have a list or array type.
* @return argument value.
*/
QString arg() const;
void setArg(const QString &arg);
friend QDataStream& operator<<(QDataStream& stream, const Feature& obj);
friend QDataStream& operator>>(QDataStream& stream, Feature& obj);
PATRONUM_LIBRARYSHARED_EXPORT friend QDataStream& operator<<(QDataStream& stream, const Feature& obj);
PATRONUM_LIBRARYSHARED_EXPORT friend QDataStream& operator>>(QDataStream& stream, Feature& obj);
PATRONUM_LIBRARYSHARED_EXPORT friend bool operator==(const Feature& left, const Feature& right);
/**
* @brief description This method return description message of the command.
* This string display in a teminal application in the help section.
* @return description message of the command
*/
QString description() const;
/**
* @brief setDescription This method sets description for command.
* @param description tihs is new value of the description command.
*/
void setDescription(const QString &description);
/**
* @brief example This is exmaple of using this command.
* @return example of use.
*/
QString example() const;
/**
* @brief setExample This method sets a new example
* @param example This is a new example value.
*/
void setExample(const QString &example);
/**
* @brief toString This is general method of the converting command to string.
* @return string of all command.
*/
QString toString() const;
/**
* @brief id This method retun id of the feature. The id is qHash from command string.
* @return id of the feature.
*/
unsigned int id() const;
private:
unsigned int _id;
QString _cmd;
QString _description;
QString _example;
QVariant _arg;
QString _arg;
};
uint PATRONUM_LIBRARYSHARED_EXPORT qHash(const Feature& feature);
}
#endif // FEaTURE_H

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -22,7 +22,7 @@ template<class Application>
* ###How to use :
* - just inherit from the Service class and override the methods you need.
*/
class PATRONUM_LIBRARYSHARED_EXPORT Service : public ServiceBase
class Service : public ServiceBase
{
public:
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -7,6 +7,7 @@
#include "PServiceBase.h"
#include <QCoreApplication>
#include <QLibraryInfo>
#include <QTimer>
#include "PController.h"
#include "serviceprivate.h"
@ -24,33 +25,42 @@ ServiceBase::~ServiceBase() {
delete d_ptr;
}
void ServiceBase::handleReceive(const QList<Feature> &data) {
void ServiceBase::handleReceiveData(const QSet<Feature> &data) {
auto list = supportedFeatures();
QStringList stringList;
for (const auto&i : list) {
stringList += i.toString();
}
QVariantMap result;
QString commandList;
for (const auto&i : data ) {
commandList += i.toString() + " ";
for (const auto& i: data) {
if (list.contains(i)) {
if (!handleReceive(i)) {
sendResuylt(QString("The process of a command %0 with argumets: %1 is failed")
.arg(i.cmd()).arg(i.arg()));
}
} else {
commandList += i.toString() + " ";
}
}
result["Error"] = "Wrong command! The commands : " + commandList + " is not supported";
result["Available commands"] = stringList;
if (commandList.size()) {
QStringList stringList;
for (const auto&i : list) {
stringList += i.toString();
}
QVariantMap result;
result["Error"] = "Wrong command! The commands : " + commandList + " is not supported";
result["Available commands"] = stringList;
sendResuylt(result);
}
sendResuylt(result);
}
QList<Feature> ServiceBase::supportedFeatures() {
QList<Feature> result;
return result;
QSet<Feature> ServiceBase::supportedFeatures() {
return {};
}
bool ServiceBase::sendResuylt(const QVariantMap &result) {
@ -61,6 +71,10 @@ bool ServiceBase::sendResuylt(const QString &result) {
return d_ptr->sendCmdResult({{"Result", result}});
}
bool ServiceBase::sendCloseeConnetion() {
return d_ptr->sendCloseConnection();
}
void ServiceBase::onStop() {
sendResuylt("Success! Use default stop function");
QCoreApplication::quit();
@ -75,12 +89,14 @@ void ServiceBase::onPause() {
sendResuylt("This function not supported");
}
Controller *ServiceBase::controller() const {
Controller *ServiceBase::controller() {
if (_controller)
return _controller;
return new Controller(_serviceName,
QuasarAppUtils::Params::getCurrentExecutable());
_controller = new Controller(_serviceName,
QuasarAppUtils::Params::getCurrentExecutable());
return _controller;
}
int ServiceBase::exec() {
@ -88,24 +104,26 @@ int ServiceBase::exec() {
createApplication();
}
if (!QuasarAppUtils::Params::customParamasSize()) {
bool fExec = QuasarAppUtils::Params::isEndable("exec") || QuasarAppUtils::Params::isDebugBuild();
if (!(QuasarAppUtils::Params::customParamasSize() || fExec)) {
return controller()->startDetached();
}
if (QuasarAppUtils::Params::isEndable("exec")) {
QTimer::singleShot(0, [this](){
if (fExec) {
QTimer::singleShot(0, nullptr, [this](){
onStart();
d_ptr->listen();
});
} else {
QTimer::singleShot(0, nullptr, [this](){
if (!controller()->send()) {
_core->exit(static_cast<int>(ControllerError::ServiceUnavailable));
}
});
}
QTimer::singleShot(0, [this](){
if (!controller()->send()) {
_core->exit(static_cast<int>(ControllerError::ServiceUnavailable));
}
});
return _core->exec();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -42,17 +42,17 @@ public:
protected:
/**
* @brief handleReceive - this method invoce when service receive new command from terminal of controller of this service
* @brief handleReceiveData - this method invoce when service receive new command from terminal of controller of this service.
* @param data - is list of commands from controller
* Default inplementation send message abount error.
* Default inplementation send message abount error, and invoke the .
*/
void handleReceive(const QList<Feature> &data) override;
void handleReceiveData(const QSet<Feature> &data) override final;
/**
* @brief supportedFeatures
* @return list of supported features of this service. override this method for correctly work of your pair (service and controller)
* @return a set supported features of this service. Override this method for correctly work of your pair (service and controller)
*/
QList<Feature> supportedFeatures() override;
QSet<Feature> supportedFeatures() override;
/**
* @brief sendResuylt - call this method for send responce from service to tour controller
@ -68,6 +68,12 @@ protected:
*/
bool sendResuylt(const QString &result);
/**
* @brief sendCloseeConnetion This method send signal that all request command processed.
* @return return true if the message sent successul.
*/
bool sendCloseeConnetion();
/**
* @brief createApplication default implementation create a Application object and parse argumnts.
*/
@ -97,11 +103,12 @@ protected:
* @brief controller
* @return own controller instance;
*/
Controller *controller() const;
Controller *controller();
QCoreApplication *_core = nullptr;
private:
ServicePrivate *d_ptr = nullptr;
Controller *_controller = nullptr;
QString _serviceName = "";

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -14,6 +14,7 @@
#include <quasarapp.h>
#include "package.h"
#include "installersystemd.h"
#include "parser.h"
namespace Patronum {
@ -23,6 +24,7 @@ ControllerPrivate::ControllerPrivate(const QString &name, const QString &service
_socket = new LocalSocket(name, this);
_serviceExe = servicePath;
_controller = controller;
_parser = new Parser();
#ifdef Q_OS_LINUX
_installer = new InstallerSystemD(name);
@ -37,6 +39,7 @@ ControllerPrivate::~ControllerPrivate() {
if (_installer) {
delete _installer;
}
delete _parser;
}
bool ControllerPrivate::sendFeaturesRequest() {
@ -47,15 +50,10 @@ bool ControllerPrivate::sendFeaturesRequest() {
return false;
}
QByteArray responce;
QDataStream stream(&responce, QIODevice::WriteOnly);
stream << static_cast<quint8>(Command::FeaturesRequest);
return _socket->send(responce);
return _socket->send(_parser->createPackage(Command::FeaturesRequest));
}
bool ControllerPrivate::sendCmd(const QList<Feature> &result) {
bool ControllerPrivate::sendCmd(const QSet<Feature> &result) {
if (!_socket->isValid()) {
QuasarAppUtils::Params::log("scoket is closed!",
QuasarAppUtils::Debug);
@ -64,13 +62,7 @@ bool ControllerPrivate::sendCmd(const QList<Feature> &result) {
return false;
}
QByteArray request;
QDataStream stream(&request, QIODevice::WriteOnly);
stream << static_cast<quint8>(Command::Feature);
stream << result;
if (_socket->send(request)) {
if (_socket->send(_parser->createPackage(Command::Feature, result))) {
_responce = false;
return true;
}
@ -190,70 +182,68 @@ bool ControllerPrivate::connectToHost() const {
void ControllerPrivate::handleReceve(QByteArray data) {
const Package package = Package::parsePackage(data);
if (!package.isValid()) {
QuasarAppUtils::Params::log("Received invalid package!",
QuasarAppUtils::Debug);
_controller->handleError(ControllerError::InvalidPackage);
if (!_controller) {
QuasarAppUtils::Params::log("System error, controller is not inited!",
QuasarAppUtils::Error);
return;
}
switch (package.cmd()) {
QList<Package> packages;
if (!_parser->parse(data, packages)) {
return;
}
case Command::Features: {
for (const auto& pkg: qAsConst(packages)) {
if (!pkg.isValid()) {
if (!_controller) {
QuasarAppUtils::Params::log("System error, controller is not inited!",
QuasarAppUtils::Params::log("Received invalid package!",
QuasarAppUtils::Debug);
_controller->handleError(ControllerError::SystemError);
_controller->handleError(ControllerError::InvalidPackage);
continue;;
}
switch (pkg.cmd()) {
case Command::Features: {
QDataStream stream(pkg.data());
QList<Feature> features;
stream >> features;
_features = features;
_controller->handleFeatures(features);
break;
}
case Command::CloseConnection: {
_responce = true;
break;
}
QDataStream stream(package.data());
case Command::FeatureResponce: {
QList<Feature> features;
stream >> features;
_features = features;
QDataStream stream(pkg.data());
_responce = true;
_controller->handleFeatures(features);
QVariantMap responce;
stream >> responce;
_controller->handleResponce(responce);
break;
break;
}
case Command::FeatureResponce: {
if (!_controller) {
QuasarAppUtils::Params::log("System error, controller is not inited!",
QuasarAppUtils::Error);
_controller->handleError(ControllerError::SystemError);
}
default: {
QuasarAppUtils::Params::log("Wrong command!",
QuasarAppUtils::Debug);
_controller->handleError(ControllerError::WrongCommand);
break;
}
QDataStream stream(package.data());
_responce = true;
QVariantMap responce;
stream >> responce;
_controller->handleResponce(responce);
break;
}
default: {
QuasarAppUtils::Params::log("Wrong command!",
QuasarAppUtils::Debug);
_controller->handleError(ControllerError::WrongCommand);
break;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -14,6 +14,7 @@ namespace Patronum {
class IController;
class LocalSocket;
class Installer;
class Parser;
class ControllerPrivate: public QObject
{
@ -23,7 +24,7 @@ public:
IController* controller = nullptr, QObject *parent = nullptr);
~ControllerPrivate();
bool sendFeaturesRequest();
bool sendCmd(const QList<Feature>& result);
bool sendCmd(const QSet<Feature> &result);
int start() const;
bool stop();
@ -44,12 +45,14 @@ signals:
void sigListFeatures(QList<Feature>);
private:
LocalSocket *_socket = nullptr;
IController *_controller = nullptr;
bool _responce = false;
QList<Feature> _features;
QString _serviceExe = "";
Installer *_installer = nullptr;
Parser * _parser;
private slots:
void handleReceve(QByteArray data);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -19,7 +19,15 @@ LocalSocket::LocalSocket(const QString &target, QObject *ptr):
}
LocalSocket::~LocalSocket() {
if (m_server) {
m_server->close();
delete m_server;
}
if (m_socket) {
m_socket->close();
delete m_socket;
}
}
bool LocalSocket::registerSokcet(QLocalSocket *socket) {
@ -34,7 +42,7 @@ bool LocalSocket::registerSokcet(QLocalSocket *socket) {
connect(m_socket, &QLocalSocket::readyRead,
this, &LocalSocket::handleReadyRead);
connect(m_socket, qOverload<QLocalSocket::LocalSocketError>(&QLocalSocket::error),
connect(m_socket, qOverload<QLocalSocket::LocalSocketError>(&QLocalSocket::errorOccurred),
this, &LocalSocket::handleSocketError);
handleStateChanged(m_socket->state());
@ -105,10 +113,11 @@ void LocalSocket::handleReadyRead() {
void LocalSocket::handleIncomming() {
if (m_socket) {
m_socket->disconnect();
m_socket->close();
m_socket->deleteLater();
m_socket = nullptr;
}
registerSokcet(m_server->nextPendingConnection());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -10,29 +10,29 @@
namespace Patronum {
Command Package::cmd() const {
return static_cast<Command>(m_cmd);
return static_cast<Command>(m_hdr.cmd);
}
QByteArray Package::data() const {
const QByteArray &Package::data() const {
return m_data;
}
bool Package::isValid() const {
return m_cmd <= static_cast<int>(Command::FeatureResponce);
return m_hdr.isValid() && m_hdr.size == m_data.size();
}
void Package::reset() {
m_hdr = {0, 0};
m_data.clear();
}
Package::Package() {
reset();
}
Package Package::parsePackage(const QByteArray &data) {
if (!data.size()) {
return {};
}
Package pkg;
pkg.m_cmd = static_cast<unsigned char>(data.at(0));
pkg.m_data = data.right(data.size() - sizeof (pkg.m_cmd));
return pkg;
bool Header::isValid() const {
return cmd && cmd <= static_cast<int>(Command::CloseConnection);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -11,16 +11,46 @@
#include <QDataStream>
#include <PFeature.h>
#include <QVariantMap>
#include <QIODevice>
namespace Patronum {
class Feature;
/**
* @brief The Command enum This is base commands for sending
*/
enum class Command: quint8 {
/// This is invalid command
Undefined,
/// This comand is request for the available command of the service
FeaturesRequest,
/// This comand is response of the FeaturesRequest command
Features,
/// This is request to execute command
Feature,
FeatureResponce
/// This is response of the execute of command
FeatureResponce,
/// This command is finished command for the terminal. after receive this command terminal will closse connection.
/// @note For Devs This commnad should be last in the enum. This commnad uses in te validation of header.
CloseConnection
};
/**
* @brief The Header struct have as size 2 byte. maximus package size is 4095 bytes.
*/
struct Header {
/**
* @brief size This is size of package data (exclude header size).
*/
unsigned short size: 12;
/**
* @brief cmd This is workCommand
*/
unsigned char cmd: 4;
bool isValid() const;
};
/**
@ -30,27 +60,36 @@ enum class Command: quint8 {
class Package
{
public:
Package();
/**
* @brief cmd This method return command of the package.
* @return command of the package.
*/
Command cmd() const;
QByteArray data() const;
/**
* @brief data This method return referense to the bytes array of the pacakge data.
* @return bytes array of the pacakge data.
*/
const QByteArray& data() const;
/**
* @brief isValid This method check this pacakge.
* @return true if the package is valid.
*/
bool isValid() const;
template<class DATA>
static QByteArray createPackage(Command cmd, const DATA &data) {
QByteArray result;
QDataStream stream(&result, QIODevice::WriteOnly);
stream << cmd;
stream << data;
return result;
}
static Package parsePackage(const QByteArray& data);
/**
* @brief reset This method reset all fields of the package to default value.
* @note after invoke this method package will be invalid.
*/
void reset();
private:
Package();
unsigned char m_cmd;
Header m_hdr;
QByteArray m_data;
friend class Parser;
};
}

View File

@ -0,0 +1,72 @@
#include "parser.h"
#include <quasarapp.h>
namespace Patronum {
Parser::Parser() { }
bool Parser::parse(const QByteArray &array,
QList<Package> &result) {
if (!array.size()) {
return false;
}
int workIndex = 0;
const int headerSize = sizeof(Header);
const auto workArray = _hdrArray + array;
const int arraySize = workArray.size();
while (arraySize > workIndex) {
int offset = arraySize - workIndex;
if (_data.m_hdr.isValid()) {
// CASE 1: The Package data is still not collected, but the header is already collected. performs full or partial filling of packet data.
int dataLength = std::min(static_cast<int>(_data.m_hdr.size - _data.m_data.size()),
arraySize - workIndex);
_data.m_data.append(array.mid(workIndex + headerSize, dataLength));
workIndex += dataLength;
} else if (offset >= headerSize) {
// CASE 2: The header and package still do not exist and the amount of data allows you to create a new header. A header is created and will fill in all or part of the package data.
_data.reset();
memcpy(&_data.m_hdr,
array.data() + workIndex, headerSize);
int dataLength = std::min(static_cast<int>(_data.m_hdr.size),
arraySize - headerSize - workIndex);
_data.m_data.append(array.mid(workIndex + headerSize, dataLength));
workIndex += headerSize + dataLength;
} else {
// CASE 3: There is not enough data to initialize the header. The data will be placed in temporary storage and will be processed the next time the data is received.
unsigned char dataLength = static_cast<unsigned char>(arraySize - workIndex);
_hdrArray += array.mid(workIndex, dataLength);
workIndex += dataLength;
}
if (_data.isValid()) {
result.push_back(_data);
_data.reset();
_hdrArray.clear();
}
if (_data.m_data.size() > _data.m_hdr.size) {
QuasarAppUtils::Params::log("Invalid Package received. ",
QuasarAppUtils::Warning);
_data.reset();
_hdrArray.clear();
}
}
return true;
}
}

View File

@ -0,0 +1,52 @@
#ifndef PARSER_H
#define PARSER_H
#include <QByteArray>
#include "package.h"
namespace Patronum {
/**
* @brief The Parser class This is package parser of the Patronum packages.
*/
class Parser
{
public:
Parser();
/**
* @brief parse This method parse input data array @a array to the @result packages.
* @param array This is input data.
* @param result This is result packages.
* @return return true if parse finished successful
*/
bool parse(const QByteArray& array, QList<Package>& result);
template<class DATA = QByteArray>
/**
* @brief createPackage This method create a custom package with @a cmd and @a data
* @param cmd This is package command.
* @param data This is data object.
* @return bytes arra of the package.
*/
QByteArray createPackage(Command cmd, const DATA &data = {}) {
QByteArray result;
QDataStream stream(&result, QIODevice::WriteOnly);
Header hdr;
hdr.cmd = static_cast<unsigned char>(cmd);
stream << data;
hdr.size = result.size();
result.insert(0, reinterpret_cast<char*>(&hdr), sizeof (hdr));
return result;
}
private:
Package _data;
QByteArray _hdrArray;
};
}
#endif // PARSER_H

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -13,6 +13,7 @@
#include <QCoreApplication>
#include <QTimer>
#include <quasarapp.h>
#include "parser.h"
namespace Patronum {
@ -22,11 +23,16 @@ Patronum::ServicePrivate::ServicePrivate(const QString &name, IService *service,
_service = service;
_parser = new Parser();
QObject::connect(_socket, &LocalSocket::sigReceve,
this, &ServicePrivate::handleReceve);
}
ServicePrivate::~ServicePrivate() {
delete _parser;
}
bool ServicePrivate::sendCmdResult(const QVariantMap &result) {
if (!_socket->isValid()) {
@ -35,7 +41,17 @@ bool ServicePrivate::sendCmdResult(const QVariantMap &result) {
return false;
}
return _socket->send(Package::createPackage(Command::FeatureResponce, result));
return _socket->send(_parser->createPackage(Command::FeatureResponce, result));
}
bool ServicePrivate::sendCloseConnection() {
if (!_socket->isValid()) {
QuasarAppUtils::Params::log("scoket is closed!",
QuasarAppUtils::Error);
return false;
}
return _socket->send(_parser->createPackage(Command::CloseConnection));
}
void ServicePrivate::listen() const {
@ -45,7 +61,7 @@ void ServicePrivate::listen() const {
};
}
bool ServicePrivate::hendleStandartCmd(QList<Feature> *cmds) {
bool ServicePrivate::handleStandartCmd(QSet<Feature> *cmds) {
if (!cmds)
return false;
@ -53,20 +69,17 @@ bool ServicePrivate::hendleStandartCmd(QList<Feature> *cmds) {
if (!_service)
return false;
for (int i = 0; i < cmds->size(); ++i) {
if (cmds->value(i).cmd() == "stop") {
_service->onStop();
cmds->removeAt(i);
i--;
} else if (cmds->value(i).cmd() == "pause") {
_service->onPause();
cmds->removeAt(i);
i--;
} else if (cmds->value(i).cmd() == "resume") {
_service->onResume();
cmds->removeAt(i);
i--;
}
if (cmds->contains(Feature{"stop"})) {
_service->onStop();
cmds->remove(Feature{"stop"});
} else if (cmds->contains(Feature{"pause"})) {
_service->onPause();
cmds->remove(Feature{"pause"});
} else if (cmds->contains(Feature{"resume"})) {
_service->onResume();
cmds->remove(Feature{"resume"});
}
@ -75,73 +88,69 @@ bool ServicePrivate::hendleStandartCmd(QList<Feature> *cmds) {
void ServicePrivate::handleReceve(QByteArray data) {
const Package package = Package::parsePackage(data);
if (!package.isValid()) {
QuasarAppUtils::Params::log("receive package is not valid!",
QuasarAppUtils::Warning);
QList<Package> packages;
if (!_parser->parse(data, packages)) {
return;
}
switch (package.cmd()) {
case Command::FeaturesRequest: {
for (const auto &pkg: qAsConst(packages)) {
if (!pkg.isValid()) {
QuasarAppUtils::Params::log("receive package is not valid!",
QuasarAppUtils::Warning);
return;
}
if (!_service) {
QuasarAppUtils::Params::log("System error, service is not inited!",
QuasarAppUtils::Error);
break;
return;;
}
if (!_socket->isValid()) {
QuasarAppUtils::Params::log("scoket is closed!",
QuasarAppUtils::Error);
return;
}
switch (pkg.cmd()) {
case Command::FeaturesRequest: {
if (!_socket->send(_parser->createPackage(Command::Features,
_service->supportedFeatures()))) {
QuasarAppUtils::Params::log("Fail to send ",
QuasarAppUtils::Error);
}
break;
}
QList<Feature> features = _service->supportedFeatures();
QByteArray sendData;
QDataStream stream(&sendData, QIODevice::WriteOnly);
case Command::Feature: {
stream << static_cast<quint8>(Command::Features);
stream << features;
QDataStream stream(pkg.data());
QSet<Feature> feature;
stream >> feature;
handleStandartCmd(&feature);
if (feature.size())
_service->handleReceiveData(feature);
break;
if (!_socket->send(sendData)) {
QuasarAppUtils::Params::log("scoket is closed!",
QuasarAppUtils::Error);
}
break;
}
case Command::Feature: {
if (!_service) {
QuasarAppUtils::Params::log("System error, service is not inited!",
default: {
QuasarAppUtils::Params::log("Wrong command!",
QuasarAppUtils::Error);
break;
}
QDataStream stream(package.data());
QList<Feature> feature;
stream >> feature;
hendleStandartCmd(&feature);
if (feature.size())
_service->handleReceive(feature);
break;
}
}
default: {
QuasarAppUtils::Params::log("Wrong command!",
QuasarAppUtils::Error);
break;
}
}
sendCloseConnection();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
@ -14,6 +14,7 @@ namespace Patronum {
class LocalSocket;
class IService;
class Parser;
class ServicePrivate: public QObject
{
@ -21,8 +22,11 @@ class ServicePrivate: public QObject
public:
ServicePrivate(const QString& name,
IService* service = nullptr, QObject *parent = nullptr);
~ServicePrivate();
bool sendCmdResult(const QVariantMap& result);
bool sendCloseConnection();
bool parseDefaultCmds();
void listen() const;
@ -30,8 +34,9 @@ public:
private:
LocalSocket *_socket = nullptr;
IService *_service = nullptr;
Parser *_parser = nullptr;
bool hendleStandartCmd(QList<Feature> *cmds);
bool handleStandartCmd(QSet<Feature> *cmds);
private slots:
void handleReceve(QByteArray data);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 QuasarApp.
* Copyright (C) 2018-2021 QuasarApp.
* Distributed under the lgplv3 software license, see the accompanying
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2018-2020 QuasarApp.
# Copyright (C) 2018-2021 QuasarApp.
# Distributed under the lgplv3 software license, see the accompanying
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed.
@ -17,14 +17,15 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core Test REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test REQUIRED)
file(GLOB SOURCE_CPP
"*.cpp"
)
add_executable(${CURRENT_PROJECT} ${SOURCE_CPP})
target_link_libraries(${CURRENT_PROJECT} PRIVATE Qt5::Test Patronum)
target_link_libraries(${CURRENT_PROJECT} PRIVATE Qt::Test Patronum )
target_include_directories(${CURRENT_PROJECT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
include(../Patronum/QuasarAppLib/CMake/QuasarAppCITargets.cmake)

View File

@ -16,22 +16,19 @@ void DefaultService::onStart() {
QuasarAppUtils::Params::log("Server started!", QuasarAppUtils::Info);
}
void DefaultService::handleReceive(const QList<Patronum::Feature> &data) {
bool DefaultService::handleReceive(const Patronum::Feature &data) {
QList<Patronum::Feature> notSupportedList;
for (const auto& i : data) {
if (i.cmd() == "ping") {
sendResuylt("pong");
} else {
notSupportedList += i;
}
if (data.cmd() == "ping") {
sendResuylt("pong");
return true;
}
Patronum::Service<QCoreApplication>::handleReceive(notSupportedList);
return false;
}
QList<Patronum::Feature> DefaultService::supportedFeatures() {
QList<Patronum::Feature> res;
QSet<Patronum::Feature> DefaultService::supportedFeatures() {
QSet<Patronum::Feature> res;
res += Patronum::Feature("ping", {}, "test ping", "ping");
return res;

View File

@ -10,12 +10,12 @@ public:
// QtServiceBase interface
protected:
void onStart();
void onStart() override;
// IService interface
public:
void handleReceive(const QList<Patronum::Feature> &data);
QList<Patronum::Feature> supportedFeatures();
bool handleReceive(const Patronum::Feature &data) override;
QSet<Patronum::Feature> supportedFeatures() override;
};
#endif // DEFAULTSERVICE_H

View File

@ -32,7 +32,9 @@ private slots:
};
testPatronum::testPatronum() {
QuasarAppUtils::Params::setArg("verbose", 3);
QuasarAppUtils::Params::setArg("verbose", "3");
QFile::remove("/tmp/PTestPatronum");
}
@ -65,7 +67,7 @@ void testPatronum::testRandomCommad() {
void testPatronum::connectTest() {
DefaultService serv;
QTimer::singleShot(10, [this]() {
QTimer::singleShot(10, this, [this]() {
testRandomCommad();
testPing();

View File

@ -703,7 +703,7 @@ FILE_VERSION_FILTER =
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
LAYOUT_FILE = /res/DoxyStyle/DoxygenLayout.xml
LAYOUT_FILE = /Patronum/QuasarAppLib/CMake/DoxyStyle/DoxygenLayout.xml
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
@ -790,7 +790,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = ./ \
INPUT = ./README.md \
Patronum/src
# This tag can be used to specify the character encoding of the source files
@ -1193,7 +1193,7 @@ HTML_STYLESHEET =
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = res/DoxyStyle/doxygenStyles.css
HTML_EXTRA_STYLESHEET = Patronum/QuasarAppLib/CMake/DoxyStyle/doxygenStyles.css
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note

5
plug.pro Normal file
View File

@ -0,0 +1,5 @@
TEMPLATE = subdirs
QMAKE_EXTRA_TARGETS += \
test

@ -1 +0,0 @@
Subproject commit 4592500f3efd49f6f404598523e09bc031368db0