refactor: Run legacy daemon loop in thread
This commit is contained in:
parent
e72faf1446
commit
24c57e46e2
4 changed files with 81 additions and 40 deletions
|
|
@ -5,6 +5,9 @@
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "arch/Arch.h"
|
||||||
|
#include "base/EventQueue.h"
|
||||||
|
#include "base/Log.h"
|
||||||
#include "deskflow/DaemonApp.h"
|
#include "deskflow/DaemonApp.h"
|
||||||
|
|
||||||
#include "arch/Arch.h"
|
#include "arch/Arch.h"
|
||||||
|
|
@ -20,10 +23,13 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
// win32 instance needed for threading, etc.
|
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
||||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -33,8 +39,24 @@ int main(int argc, char **argv)
|
||||||
Log log;
|
Log log;
|
||||||
EventQueue events;
|
EventQueue events;
|
||||||
|
|
||||||
DaemonApp app(&events, __argc, __argv);
|
LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion));
|
||||||
return DaemonApp::exec();
|
|
||||||
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
|
// Must be on the heap, as we're moving it to a thread.
|
||||||
|
DaemonApp *pDaemon = new DaemonApp(&events);
|
||||||
|
QObject::connect(pDaemon, &DaemonApp::serviceInstalled, &app, &QCoreApplication::quit);
|
||||||
|
QObject::connect(pDaemon, &DaemonApp::serviceUninstalled, &app, &QCoreApplication::quit);
|
||||||
|
pDaemon->init(argc, argv);
|
||||||
|
|
||||||
|
QThread *thread = new QThread();
|
||||||
|
pDaemon->moveToThread(thread);
|
||||||
|
QObject::connect(thread, &QThread::started, pDaemon, &DaemonApp::run);
|
||||||
|
QObject::connect(thread, &QThread::finished, pDaemon, &QObject::deleteLater);
|
||||||
|
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
thread->start();
|
||||||
|
|
||||||
|
return QCoreApplication::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/log_outputters.h"
|
#include "base/log_outputters.h"
|
||||||
|
#include "common/constants.h"
|
||||||
#include "common/ipc.h"
|
#include "common/ipc.h"
|
||||||
#include "deskflow/App.h"
|
#include "deskflow/App.h"
|
||||||
#include "deskflow/ArgParser.h"
|
#include "deskflow/ArgParser.h"
|
||||||
|
|
@ -42,6 +43,10 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -96,16 +101,13 @@ int winMainLoopStatic(int, const char **)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DaemonApp::DaemonApp(IEventQueue *events, int argc, char **argv)
|
DaemonApp::DaemonApp(IEventQueue *events) : m_ipcServer{new ipc::DaemonIpcServer(this)}
|
||||||
: QCoreApplication(argc, argv),
|
|
||||||
m_events(events),
|
|
||||||
m_ipcServer{new ipc::DaemonIpcServer(this)}
|
|
||||||
{
|
{
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
connect(m_ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, this, &DaemonApp::handleElevateModeChanged);
|
connect(m_ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, this, &DaemonApp::handleElevateModeChanged);
|
||||||
connect(m_ipcServer, &ipc::DaemonIpcServer::commandChanged, this, &DaemonApp::handleCommandChanged);
|
connect(m_ipcServer, &ipc::DaemonIpcServer::commandChanged, this, &DaemonApp::handleCommandChanged);
|
||||||
connect(m_ipcServer, &ipc::DaemonIpcServer::restartRequested, this, &DaemonApp::handleRestartRequested);
|
connect(m_ipcServer, &ipc::DaemonIpcServer::restartRequested, this, &DaemonApp::handleRestartRequested);
|
||||||
|
|
||||||
s_instance = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DaemonApp::~DaemonApp()
|
DaemonApp::~DaemonApp()
|
||||||
|
|
@ -113,6 +115,25 @@ DaemonApp::~DaemonApp()
|
||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DaemonApp::run()
|
||||||
|
{
|
||||||
|
if (m_foreground) {
|
||||||
|
LOG((CLOG_NOTE "starting daemon in foreground"));
|
||||||
|
|
||||||
|
// run process in foreground instead of daemonizing.
|
||||||
|
// useful for debugging.
|
||||||
|
mainLoop(false, m_foreground);
|
||||||
|
} else {
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
LOG((CLOG_NOTE "daemonizing windows service"));
|
||||||
|
ARCH->daemonize(kAppName, winMainLoopStatic);
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
LOG((CLOG_NOTE "daemonizing unix service"));
|
||||||
|
ARCH->daemonize(kAppName, unixMainLoopStatic);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DaemonApp::handleElevateModeChanged(int mode)
|
void DaemonApp::handleElevateModeChanged(int mode)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("elevate mode changed: %d", mode);
|
LOG_DEBUG("elevate mode changed: %d", mode);
|
||||||
|
|
@ -135,61 +156,50 @@ void DaemonApp::handleRestartRequested()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void DaemonApp::startAsync()
|
void DaemonApp::init(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
bool isUninstalling = false;
|
||||||
m_watchdog->startAsync();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int DaemonApp::init(int argc, char **argv)
|
|
||||||
{
|
|
||||||
bool uninstall = false;
|
|
||||||
try {
|
try {
|
||||||
// default log level to system setting.
|
// default log level to system setting.
|
||||||
if (string logLevel = ARCH->setting("LogLevel"); logLevel != "")
|
if (string logLevel = ARCH->setting("LogLevel"); logLevel != "")
|
||||||
CLOG->setFilter(logLevel.c_str());
|
CLOG->setFilter(logLevel.c_str());
|
||||||
|
|
||||||
bool foreground = false;
|
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
string arg(argv[i]);
|
string arg(argv[i]);
|
||||||
|
|
||||||
if (arg == "-f") {
|
if (arg == "-f") {
|
||||||
foreground = true;
|
m_foreground = true;
|
||||||
}
|
}
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
else if (arg == "--install" || arg == "/install") {
|
else if (arg == "--install" || arg == "/install") {
|
||||||
LOG((CLOG_NOTE "installing windows daemon"));
|
LOG((CLOG_NOTE "installing windows daemon"));
|
||||||
uninstall = true;
|
|
||||||
ARCH->installDaemon();
|
ARCH->installDaemon();
|
||||||
return kExitSuccess;
|
Q_EMIT serviceInstalled();
|
||||||
} else if (arg == "--uninstall" || arg == "/uninstall") {
|
} else if (arg == "--uninstall" || arg == "/uninstall") {
|
||||||
LOG((CLOG_NOTE "uninstalling windows daemon"));
|
LOG((CLOG_NOTE "uninstalling windows daemon"));
|
||||||
|
isUninstalling = true;
|
||||||
ARCH->uninstallDaemon();
|
ARCH->uninstallDaemon();
|
||||||
return kExitSuccess;
|
Q_EMIT serviceUninstalled();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
ss << "Unrecognized argument: " << arg;
|
ss << "Unrecognized argument: " << arg;
|
||||||
foregroundError(ss.str().c_str());
|
foregroundError(ss.str().c_str());
|
||||||
return kExitArgs;
|
Q_EMIT fatalError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foreground) {
|
if (!m_foreground) {
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
|
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
|
||||||
// in that case, but is accessible when running in the foreground.
|
// in that case, but is accessible when running in the foreground.
|
||||||
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR - Adopted by `Log`
|
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR - Adopted by `Log`
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return kExitSuccess;
|
|
||||||
} catch (XArch &e) {
|
} catch (XArch &e) {
|
||||||
std::string message = e.what();
|
std::string message = e.what();
|
||||||
if (uninstall && (message.find("The service has not been started") != std::string::npos)) {
|
if (isUninstalling && (message.find("The service has not been started") != std::string::npos)) {
|
||||||
// TODO: if we're keeping this use error code instead (what is it?!).
|
// TODO: if we're keeping this use error code instead (what is it?!).
|
||||||
// HACK: this message happens intermittently, not sure where from but
|
// HACK: this message happens intermittently, not sure where from but
|
||||||
// it's quite misleading for the user. they thing something has gone
|
// it's quite misleading for the user. they thing something has gone
|
||||||
|
|
@ -198,13 +208,13 @@ int DaemonApp::init(int argc, char **argv)
|
||||||
} else {
|
} else {
|
||||||
foregroundError(message.c_str());
|
foregroundError(message.c_str());
|
||||||
}
|
}
|
||||||
return kExitFailed;
|
Q_EMIT fatalError();
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
foregroundError(e.what());
|
foregroundError(e.what());
|
||||||
return kExitFailed;
|
Q_EMIT fatalError();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
foregroundError("Unrecognized error.");
|
foregroundError("Unrecognized error.");
|
||||||
return kExitFailed;
|
Q_EMIT fatalError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QObject>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
|
||||||
|
|
@ -20,6 +20,7 @@ class IEventQueue;
|
||||||
class IpcLogOutputter;
|
class IpcLogOutputter;
|
||||||
class FileLogOutputter;
|
class FileLogOutputter;
|
||||||
class QLocalServer;
|
class QLocalServer;
|
||||||
|
class QCoreApplication;
|
||||||
|
|
||||||
namespace deskflow::core::ipc {
|
namespace deskflow::core::ipc {
|
||||||
class DaemonIpcServer;
|
class DaemonIpcServer;
|
||||||
|
|
@ -31,15 +32,22 @@ class MSWindowsWatchdog;
|
||||||
|
|
||||||
extern const char *const kLogFilename;
|
extern const char *const kLogFilename;
|
||||||
|
|
||||||
class DaemonApp : public QCoreApplication
|
class DaemonApp : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DaemonApp(IEventQueue *events, int argc, char **argv);
|
DaemonApp(IEventQueue *events);
|
||||||
~DaemonApp();
|
~DaemonApp();
|
||||||
int init(int argc, char **argv);
|
void init(int argc, char **argv);
|
||||||
void startAsync();
|
void run();
|
||||||
void mainLoop(bool logToFile, bool foreground = false);
|
void mainLoop(bool logToFile, bool foreground = false);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void fatalError();
|
||||||
|
void serviceInstalled();
|
||||||
|
void serviceUninstalled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void daemonize();
|
void daemonize();
|
||||||
void foregroundError(const char *message);
|
void foregroundError(const char *message);
|
||||||
|
|
@ -65,4 +73,5 @@ private:
|
||||||
deskflow::core::ipc::DaemonIpcServer *m_ipcServer = nullptr;
|
deskflow::core::ipc::DaemonIpcServer *m_ipcServer = nullptr;
|
||||||
std::string m_command = "";
|
std::string m_command = "";
|
||||||
int m_elevateMode = 0;
|
int m_elevateMode = 0;
|
||||||
|
bool m_foreground = false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ void DaemonIpcServer::processMessage(QLocalSocket *clientSocket, const QString &
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("ipc server got new elevate mode: %d", elevateMode);
|
LOG_DEBUG("ipc server got new elevate mode: %d", elevateMode);
|
||||||
Q_SIGNAL elevateModeChanged(elevateMode);
|
Q_EMIT elevateModeChanged(elevateMode);
|
||||||
clientSocket->write(kAckMessage);
|
clientSocket->write(kAckMessage);
|
||||||
}
|
}
|
||||||
} else if (message.startsWith("command=")) {
|
} else if (message.startsWith("command=")) {
|
||||||
|
|
@ -118,12 +118,12 @@ void DaemonIpcServer::processMessage(QLocalSocket *clientSocket, const QString &
|
||||||
clientSocket->write(kErrorMessage);
|
clientSocket->write(kErrorMessage);
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("ipc server got new command: %s", command.toUtf8().constData());
|
LOG_DEBUG("ipc server got new command: %s", command.toUtf8().constData());
|
||||||
Q_SIGNAL commandChanged(command);
|
Q_EMIT commandChanged(command);
|
||||||
clientSocket->write(kAckMessage);
|
clientSocket->write(kAckMessage);
|
||||||
}
|
}
|
||||||
} else if (message == "restart") {
|
} else if (message == "restart") {
|
||||||
LOG_DEBUG("ipc server got restart message");
|
LOG_DEBUG("ipc server got restart message");
|
||||||
Q_SIGNAL restartRequested();
|
Q_EMIT restartRequested();
|
||||||
clientSocket->write(kAckMessage);
|
clientSocket->write(kAckMessage);
|
||||||
} else {
|
} else {
|
||||||
LOG_WARN("ipc server got unknown message: %s", message.toUtf8().constData());
|
LOG_WARN("ipc server got unknown message: %s", message.toUtf8().constData());
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue