refactor: Run legacy daemon loop in thread
This commit is contained in:
@ -5,6 +5,9 @@
|
||||
* 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 "arch/Arch.h"
|
||||
@ -20,10 +23,13 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#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));
|
||||
#endif
|
||||
|
||||
@ -33,8 +39,24 @@ int main(int argc, char **argv)
|
||||
Log log;
|
||||
EventQueue events;
|
||||
|
||||
DaemonApp app(&events, __argc, __argv);
|
||||
return DaemonApp::exec();
|
||||
LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion));
|
||||
|
||||
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
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include "base/Log.h"
|
||||
#include "base/TMethodEventJob.h"
|
||||
#include "base/log_outputters.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/ipc.h"
|
||||
#include "deskflow/App.h"
|
||||
#include "deskflow/ArgParser.h"
|
||||
@ -42,6 +43,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@ -96,16 +101,13 @@ int winMainLoopStatic(int, const char **)
|
||||
}
|
||||
#endif
|
||||
|
||||
DaemonApp::DaemonApp(IEventQueue *events, int argc, char **argv)
|
||||
: QCoreApplication(argc, argv),
|
||||
m_events(events),
|
||||
m_ipcServer{new ipc::DaemonIpcServer(this)}
|
||||
DaemonApp::DaemonApp(IEventQueue *events) : m_ipcServer{new ipc::DaemonIpcServer(this)}
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
connect(m_ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, this, &DaemonApp::handleElevateModeChanged);
|
||||
connect(m_ipcServer, &ipc::DaemonIpcServer::commandChanged, this, &DaemonApp::handleCommandChanged);
|
||||
connect(m_ipcServer, &ipc::DaemonIpcServer::restartRequested, this, &DaemonApp::handleRestartRequested);
|
||||
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
DaemonApp::~DaemonApp()
|
||||
@ -113,6 +115,25 @@ DaemonApp::~DaemonApp()
|
||||
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)
|
||||
{
|
||||
LOG_DEBUG("elevate mode changed: %d", mode);
|
||||
@ -135,61 +156,50 @@ void DaemonApp::handleRestartRequested()
|
||||
#endif
|
||||
}
|
||||
|
||||
void DaemonApp::startAsync()
|
||||
void DaemonApp::init(int argc, char **argv)
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
m_watchdog->startAsync();
|
||||
#endif
|
||||
}
|
||||
|
||||
int DaemonApp::init(int argc, char **argv)
|
||||
{
|
||||
bool uninstall = false;
|
||||
bool isUninstalling = false;
|
||||
try {
|
||||
// default log level to system setting.
|
||||
if (string logLevel = ARCH->setting("LogLevel"); logLevel != "")
|
||||
CLOG->setFilter(logLevel.c_str());
|
||||
|
||||
bool foreground = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
string arg(argv[i]);
|
||||
|
||||
if (arg == "-f") {
|
||||
foreground = true;
|
||||
m_foreground = true;
|
||||
}
|
||||
#if SYSAPI_WIN32
|
||||
else if (arg == "--install" || arg == "/install") {
|
||||
LOG((CLOG_NOTE "installing windows daemon"));
|
||||
uninstall = true;
|
||||
ARCH->installDaemon();
|
||||
return kExitSuccess;
|
||||
Q_EMIT serviceInstalled();
|
||||
} else if (arg == "--uninstall" || arg == "/uninstall") {
|
||||
LOG((CLOG_NOTE "uninstalling windows daemon"));
|
||||
isUninstalling = true;
|
||||
ARCH->uninstallDaemon();
|
||||
return kExitSuccess;
|
||||
Q_EMIT serviceUninstalled();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
stringstream ss;
|
||||
ss << "Unrecognized argument: " << arg;
|
||||
foregroundError(ss.str().c_str());
|
||||
return kExitArgs;
|
||||
Q_EMIT fatalError();
|
||||
}
|
||||
}
|
||||
|
||||
if (!foreground) {
|
||||
if (!m_foreground) {
|
||||
#if SYSAPI_WIN32
|
||||
// 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.
|
||||
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR - Adopted by `Log`
|
||||
#endif
|
||||
}
|
||||
|
||||
return kExitSuccess;
|
||||
} catch (XArch &e) {
|
||||
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?!).
|
||||
// HACK: this message happens intermittently, not sure where from but
|
||||
// it's quite misleading for the user. they thing something has gone
|
||||
@ -198,13 +208,13 @@ int DaemonApp::init(int argc, char **argv)
|
||||
} else {
|
||||
foregroundError(message.c_str());
|
||||
}
|
||||
return kExitFailed;
|
||||
Q_EMIT fatalError();
|
||||
} catch (std::exception &e) {
|
||||
foregroundError(e.what());
|
||||
return kExitFailed;
|
||||
Q_EMIT fatalError();
|
||||
} catch (...) {
|
||||
foregroundError("Unrecognized error.");
|
||||
return kExitFailed;
|
||||
Q_EMIT fatalError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
@ -20,6 +20,7 @@ class IEventQueue;
|
||||
class IpcLogOutputter;
|
||||
class FileLogOutputter;
|
||||
class QLocalServer;
|
||||
class QCoreApplication;
|
||||
|
||||
namespace deskflow::core::ipc {
|
||||
class DaemonIpcServer;
|
||||
@ -31,15 +32,22 @@ class MSWindowsWatchdog;
|
||||
|
||||
extern const char *const kLogFilename;
|
||||
|
||||
class DaemonApp : public QCoreApplication
|
||||
class DaemonApp : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DaemonApp(IEventQueue *events, int argc, char **argv);
|
||||
DaemonApp(IEventQueue *events);
|
||||
~DaemonApp();
|
||||
int init(int argc, char **argv);
|
||||
void startAsync();
|
||||
void init(int argc, char **argv);
|
||||
void run();
|
||||
void mainLoop(bool logToFile, bool foreground = false);
|
||||
|
||||
signals:
|
||||
void fatalError();
|
||||
void serviceInstalled();
|
||||
void serviceUninstalled();
|
||||
|
||||
private:
|
||||
void daemonize();
|
||||
void foregroundError(const char *message);
|
||||
@ -65,4 +73,5 @@ private:
|
||||
deskflow::core::ipc::DaemonIpcServer *m_ipcServer = nullptr;
|
||||
std::string m_command = "";
|
||||
int m_elevateMode = 0;
|
||||
bool m_foreground = false;
|
||||
};
|
||||
|
||||
@ -108,7 +108,7 @@ void DaemonIpcServer::processMessage(QLocalSocket *clientSocket, const QString &
|
||||
return;
|
||||
} else {
|
||||
LOG_DEBUG("ipc server got new elevate mode: %d", elevateMode);
|
||||
Q_SIGNAL elevateModeChanged(elevateMode);
|
||||
Q_EMIT elevateModeChanged(elevateMode);
|
||||
clientSocket->write(kAckMessage);
|
||||
}
|
||||
} else if (message.startsWith("command=")) {
|
||||
@ -118,12 +118,12 @@ void DaemonIpcServer::processMessage(QLocalSocket *clientSocket, const QString &
|
||||
clientSocket->write(kErrorMessage);
|
||||
} else {
|
||||
LOG_DEBUG("ipc server got new command: %s", command.toUtf8().constData());
|
||||
Q_SIGNAL commandChanged(command);
|
||||
Q_EMIT commandChanged(command);
|
||||
clientSocket->write(kAckMessage);
|
||||
}
|
||||
} else if (message == "restart") {
|
||||
LOG_DEBUG("ipc server got restart message");
|
||||
Q_SIGNAL restartRequested();
|
||||
Q_EMIT restartRequested();
|
||||
clientSocket->write(kAckMessage);
|
||||
} else {
|
||||
LOG_WARN("ipc server got unknown message: %s", message.toUtf8().constData());
|
||||
|
||||
Reference in New Issue
Block a user