4
0
mirror of https://github.com/QuasarApp/Patronum.git synced 2025-05-10 22:19:35 +00:00

added daemon option

This commit is contained in:
Andrei Yankovich 2021-04-28 17:32:45 +03:00
parent 05eb4c7479
commit 5fc1abab33
13 changed files with 179 additions and 55 deletions

@ -33,7 +33,8 @@ enum class ControllerError {
};
/**
* @brief The IController class
* @brief The IController class This is base interface for the handling network events.
*
*/
class PATRONUM_LIBRARYSHARED_EXPORT IController
{
@ -43,14 +44,31 @@ public:
/**
* @brief errorToString This method convert the ControllerError to QString.
* @param error - Error id.
* @param error This is error id.
* @return return text of error.
*/
QString errorToString(ControllerError error) const;
/**
* @brief handleFeatures This method should be handle all Command::Features resuests.
* This method will invoked when controller receive commands list for execute (features) from controller or terminal.
* @param features This is list of the requests (@a features)
*/
virtual void handleFeatures(const QList<Feature>& features) = 0;
virtual void handleResponce(const QVariantMap& feature) = 0;
virtual void handleError(ControllerError) = 0;
/**
* @brief handleResponce This method should be handle all responces of the service.
* This method will invoked when controller receive responce from service.
* @param responce This is responce message.
*/
virtual void handleResponce(const QVariantMap& responce) = 0;
/**
* @brief handleError This method shold be handle all error messages.
* This method will invoked when a controlee receive a error responce from a service.
* @param errorCode This is code of a error.
*/
virtual void handleError(ControllerError errorCode) = 0;
};
}

@ -26,14 +26,14 @@ public:
/**
* @brief handleReceiveData This method get all received commnads and process its.
* For each command will invoke the handleReceive method.
* @param data
* For each command will invoke the IService::handleReceive method.
* @param data This is array of the incomming requests (commands)
*/
virtual void handleReceiveData(const QSet<Feature>& data) = 0;
/**
* @brief handleReceive This method invoked when service receive a request from terminal.
* Override this method for work service.
* Override this method for work your service.
* @param data This is input data.
* @return This method should be return true if the @a data command is supported and processed successful.
* IF you return false then a negative message will be sent to a terminal app.
@ -41,7 +41,8 @@ public:
virtual bool handleReceive(const Feature &data) = 0;
/**
* @brief supportedFeatures Override this method for add your features for the service.
* @brief supportedFeatures This method should be return the list of the supported fetures.
* Override this method for add your features for the service.
* @return should be return a set of supported features.
*/
virtual QSet<Feature> supportedFeatures() = 0;

@ -33,15 +33,11 @@ bool Controller::send(int argc, char **argv) {
bool Controller::send() {
if (QuasarAppUtils::Params::isEndable("start")) {
return !d_ptr->start();
}
if (QuasarAppUtils::Params::isEndable("install")) {
if (QuasarAppUtils::Params::isEndable("install") || QuasarAppUtils::Params::isEndable("i")) {
return d_ptr->install();
}
if (QuasarAppUtils::Params::isEndable("uninstall")) {
if (QuasarAppUtils::Params::isEndable("uninstall") || QuasarAppUtils::Params::isEndable("u")) {
return d_ptr->uninstall();
}
@ -98,6 +94,28 @@ bool Controller::waitForResponce(int msec) {
return d_ptr->waitForResponce(msec);
}
QuasarAppUtils::Help::Section Controller::help() const {
QuasarAppUtils::Help::Section help {
{QObject::tr("Options that available after start"), {
{"stop", QObject::tr("Stop a service")},
{"pause", QObject::tr("Pause a service")},
{"resume", QObject::tr("Resume a service")},
{"uninstall / u", QObject::tr("Uninstall a service")}
}
},
{QObject::tr("Options that available after instalation"),
{
{"uninstall / u", QObject::tr("Uninstall a service")},
{"start / s", QObject::tr("Start a service as a daemon")},
}
}
};
return help;
}
void Controller::handleError(ControllerError error) {
QuasarAppUtils::Params::log(errorToString(error),
QuasarAppUtils::Error);
@ -146,17 +164,7 @@ QList<Feature> Controller::features() {
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")}
}}};
QuasarAppUtils::Help::print(quasarappHelp.unite(help));
QuasarAppUtils::Help::print(quasarappHelp.unite(help()));
}
}

@ -10,6 +10,7 @@
#include "Patronum_global.h"
#include <IPController.h>
#include "PFeature.h"
#include <quasarapp.h>
namespace Patronum {
@ -29,21 +30,23 @@ public:
/**
* @brief Controller - Base constructor.
* @param name - Name of you service.
* @param servicePath - Path to service executable. @note If servicePath argument well be empty then 'start' commnad not working
* @param servicePath - Path to service executable.
* @note If servicePath argument will set to empty then 'start' and install commands will not working
*/
Controller(const QString& name, const QString& servicePath = "");
~Controller() override;
/**
* @brief send - This method send request to service.
* @param argc - Count of arguments.
* @param argv - Arguments list.
* @brief send This method send request to service.
* @param argc This is count of arguments.
* @param argv This is arguments list.
* @return true if all sendet successful.
*/
bool send(int argc, char **argv);
/**
* @brief send - This method send request to service. @warning Invoke this method if you invoked QuasarAppUtils::Params::parse() before invoke this method else use send(int argc, char **argv).
* @brief send - This method send request to service.
* @warning Invoke this method if you invoked QuasarAppUtils::Params::parse() before invoke this method else use send(int argc, char **argv).
* @return true if all sendet successful.
*/
bool send();
@ -61,6 +64,12 @@ public:
*/
bool waitForResponce(int msec = 10000);
/**
* @brief help This method return help of the Controller.
* @return Available otions list.
*/
QuasarAppUtils::Help::Section help() const;
// IControler interface
protected:

@ -94,23 +94,52 @@ Controller *ServiceBase::controller() {
return _controller;
_controller = new Controller(_serviceName,
QuasarAppUtils::Params::getCurrentExecutable());
QuasarAppUtils::Params::getCurrentExecutable());
return _controller;
}
void ServiceBase::printDefaultHelp() {
auto serviceHelp = controller()->help();
serviceHelp.unite(QuasarAppUtils::Params::getParamsHelp());
serviceHelp.unite({{QObject::tr("Options that available befor install"),{
{"start / s", QObject::tr("Start a service in console")},
{"daemon / d", QObject::tr("Start a service as a daemon")},
{"install / i", QObject::tr("Install a service")},
}}});
const auto features = supportedFeatures();
QuasarAppUtils::Help::Options optionsList;
for (const auto& cmd : features) {
optionsList.insert(cmd.cmd(), cmd.description());
}
serviceHelp.unite({{"Available commands of the service:", optionsList}});
QuasarAppUtils::Help::print(serviceHelp);
}
int ServiceBase::exec() {
if (!_core) {
createApplication();
}
bool fExec = QuasarAppUtils::Params::isEndable("exec") || QuasarAppUtils::Params::isDebugBuild();
if (!(QuasarAppUtils::Params::size() || fExec)) {
return controller()->startDetached();
if (!QuasarAppUtils::Params::size()) {
printDefaultHelp();
return 0;
}
if (fExec) {
bool fStart = QuasarAppUtils::Params::isEndable("start") || QuasarAppUtils::Params::isEndable("s");
bool fDaemon = QuasarAppUtils::Params::isEndable("daemon") || QuasarAppUtils::Params::isEndable("d");
if (fStart || fDaemon) {
if (fDaemon) {
return controller()->startDetached();
}
QTimer::singleShot(0, nullptr, [this](){
onStart();
d_ptr->listen();

@ -108,6 +108,7 @@ protected:
QCoreApplication *_core = nullptr;
private:
void printDefaultHelp();
ServicePrivate *d_ptr = nullptr;
Controller *_controller = nullptr;

@ -5,7 +5,7 @@ Description=Automatet generated service of %0
Type=forking
User=root
Group=root
ExecStart=%0
ExecStart=%0 start
ExecStop=%0 stop
[Install]

@ -6,33 +6,42 @@
*/
#include "baseinstaller.h"
#include <QFile>
#include <QSettings>
#include <quasarapp.h>
namespace Patronum {
BaseInstaller::BaseInstaller(const QString &name):
Installer(name)
{
Installer(name) {
}
bool BaseInstaller::install(const QString &executable) {
if (!QFile::exists(executable)) {
QuasarAppUtils::Params::log(QObject::tr("The service executable file is not exists %0\n").arg(executable),
QuasarAppUtils::Error);
return false;
}
_executable = executable;
if (isInstalled()) {
QuasarAppUtils::Params::log(QString("the service %0 alredy installed \n").
QuasarAppUtils::Params::log(QObject::tr("the service %0 alredy installed \n").
arg(serviceName()),
QuasarAppUtils::Info);
return true;
}
return false;
savePath();
return true;
}
bool BaseInstaller::uninstall() {
if (!isInstalled()) {
QuasarAppUtils::Params::log(QString("the service %0 alredy uninstalled \n").
QuasarAppUtils::Params::log(QObject::tr("the service %0 alredy uninstalled \n").
arg(serviceName()),
QuasarAppUtils::Info);
return true;
@ -43,7 +52,7 @@ bool BaseInstaller::uninstall() {
bool BaseInstaller::enable() {
if (!isInstalled()) {
QuasarAppUtils::Params::log(QString("Cannot enabled the service %0 not installed, run install command befor enable. \n").
QuasarAppUtils::Params::log(QObject::tr("Cannot enabled the service %0 not installed, run install command befor enable. \n").
arg(serviceName()),
QuasarAppUtils::Info);
return false;
@ -54,7 +63,7 @@ bool BaseInstaller::enable() {
bool BaseInstaller::disable() {
if (!isInstalled()) {
QuasarAppUtils::Params::log(QString("Cannot disabled the service %0 not installed, run install command befor enable. \n").
QuasarAppUtils::Params::log(QObject::tr("Cannot disabled the service %0 not installed, run install command befor enable. \n").
arg(serviceName()),
QuasarAppUtils::Info);
return false;

@ -10,6 +10,7 @@
#include "localsocket.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QFile>
#include <QProcess>
#include <quasarapp.h>
#include "package.h"
@ -73,12 +74,9 @@ bool ControllerPrivate::sendCmd(const QSet<Feature> &result) {
int ControllerPrivate::start() const {
QProcess proc;
proc.setProgram(_serviceExe);
if (_installer && _installer->isInstalled() && _installer->getExecutable().size()) {
proc.setProgram(_installer->getExecutable());
}
proc.setProgram(getExecutable());
proc.setArguments({"exec"});
proc.setArguments({"d"});
proc.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
proc.setProcessChannelMode(QProcess::SeparateChannels);
@ -104,7 +102,7 @@ bool ControllerPrivate::install() const {
return false;
}
if (!_installer->install(_serviceExe)) {
if (!_installer->install(getExecutable())) {
return false;
}
@ -126,7 +124,7 @@ bool ControllerPrivate::uninstall() const {
_controller->handleResponce({{"Result", "Uninstall service successful"}});
return _installer->uninstall();
return true;
}
bool ControllerPrivate::pause() {
@ -249,4 +247,16 @@ void ControllerPrivate::handleReceve(QByteArray data) {
}
}
QString ControllerPrivate::getExecutable() const {
if (QFile::exists(_serviceExe)) {
return _serviceExe;
}
if (!_installer) {
return "";
}
return _installer->getExecutable();
}
}

@ -44,8 +44,14 @@ public:
signals:
void sigListFeatures(QList<Feature>);
private slots:
void handleReceve(QByteArray data);
private:
QString getExecutable() const;
LocalSocket *_socket = nullptr;
IController *_controller = nullptr;
bool _responce = false;
@ -54,8 +60,6 @@ private:
Installer *_installer = nullptr;
Parser * _parser;
private slots:
void handleReceve(QByteArray data);
};
}

@ -12,7 +12,7 @@
#include <QProcess>
namespace Patronum {
const QString systemDPath = "/etc/systemd/system/";
#define SYSTEMD_PATH "/etc/systemd/system/"
InstallerSystemD::InstallerSystemD(const QString& name):
BaseInstaller(name) {
@ -106,7 +106,7 @@ bool InstallerSystemD::isInstalled() const {
}
QString InstallerSystemD::absaluteServicePath() const {
return systemDPath + serviceName() + ".service";
return SYSTEMD_PATH + serviceName() + ".service";
}
}

@ -13,6 +13,39 @@
/**
* @brief The Patronum namespace - It is main name space of Patronum Library.
* The Patronum library support the two work mode
* 1. Single executable mode.
* 2. Service-terminal mode.
*
* ## Single executable mode
* In this case you have a service with single executable file. All service operations (instalation deinstalation, send commnad and another) will sends from the one executable.
*
* Fits one you need to start service executable as a daemon.
* @code{bash}
* myservice daemon
* @endcode
*
* For send any command to service use the service command.
*
* @code{bash}
* myservice myCommand
* @endcode
*
* ## Service-terminal mode.
* In this mode you create two executable file.
* 1. Service is Patronum::Service
* 2. Terminal is Patronum::Controller
*
* Fits one you need to start service executable as a daemon.
* @code{bash}
* myservice daemon
* @endcode
*
* For send any command to service use the terminal executable.
*
* @code{bash}
* terminal myCommand
* @endcode
*/
namespace Patronum {}
#endif // PATRONUM_H

@ -74,6 +74,8 @@ void testPatronum::connectTest() {
QCoreApplication::exit(0);
});
QuasarAppUtils::Params::parseParams({"s"});
QVERIFY(serv.exec() == 0);
}