feat(ipc): Stop bad version existing Core process
This commit is contained in:
parent
e9868123df
commit
10027ecc1c
11 changed files with 85 additions and 18 deletions
|
|
@ -132,6 +132,9 @@ int main(int argc, char **argv)
|
||||||
QApplication::setApplicationName(QStringLiteral("%1 Core").arg(kAppName));
|
QApplication::setApplicationName(QStringLiteral("%1 Core").arg(kAppName));
|
||||||
|
|
||||||
const auto ipcServer = new deskflow::core::ipc::CoreIpcServer(&app); // NOSONAR - Qt managed
|
const auto ipcServer = new deskflow::core::ipc::CoreIpcServer(&app); // NOSONAR - Qt managed
|
||||||
|
QObject::connect(
|
||||||
|
ipcServer, &deskflow::core::ipc::IpcServer::stopProcessRequested, coreApp, &App::quit, Qt::DirectConnection
|
||||||
|
);
|
||||||
ipcServer->listen();
|
ipcServer->listen();
|
||||||
|
|
||||||
QThread coreThread;
|
QThread coreThread;
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,12 @@ void App::handleScreenError() const
|
||||||
getEvents()->addEvent(Event(EventTypes::Quit));
|
getEvents()->addEvent(Event(EventTypes::Quit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::quit()
|
||||||
|
{
|
||||||
|
LOG_INFO("quitting");
|
||||||
|
getEvents()->addEvent(Event(EventTypes::Quit));
|
||||||
|
}
|
||||||
|
|
||||||
void App::runEventsLoop(const void *)
|
void App::runEventsLoop(const void *)
|
||||||
{
|
{
|
||||||
int exitCode = m_events->loop();
|
int exitCode = m_events->loop();
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(QThread &coreThread);
|
void run(QThread &coreThread);
|
||||||
|
void quit();
|
||||||
void setupFileLogging();
|
void setupFileLogging();
|
||||||
void loggingFilterWarning() const;
|
void loggingFilterWarning() const;
|
||||||
void initApp() override;
|
void initApp() override;
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,14 @@ CoreIpcServer &CoreIpcServer::instance()
|
||||||
|
|
||||||
void CoreIpcServer::processCommand(QLocalSocket *clientSocket, const QString &command, const QStringList &parts)
|
void CoreIpcServer::processCommand(QLocalSocket *clientSocket, const QString &command, const QStringList &parts)
|
||||||
{
|
{
|
||||||
Q_UNUSED(clientSocket)
|
|
||||||
Q_UNUSED(parts)
|
Q_UNUSED(parts)
|
||||||
|
if (command == QStringLiteral("stop")) {
|
||||||
|
LOG_DEBUG("core ipc server got stop message");
|
||||||
|
writeToClientSocket(clientSocket, QStringLiteral("ok"));
|
||||||
|
broadcastCommand(QStringLiteral("bye"));
|
||||||
|
Q_EMIT stopProcessRequested();
|
||||||
|
return;
|
||||||
|
}
|
||||||
LOG_WARN("core ipc server got unknown command: %s", command.toUtf8().constData());
|
LOG_WARN("core ipc server got unknown command: %s", command.toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,13 +125,12 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
|
||||||
LOG_DEBUG("%s ipc server got hello message (version: %s)", m_typeName.constData(), versionId.toUtf8().constData());
|
LOG_DEBUG("%s ipc server got hello message (version: %s)", m_typeName.constData(), versionId.toUtf8().constData());
|
||||||
|
|
||||||
if (clientVersion != versionId) {
|
if (clientVersion != versionId) {
|
||||||
LOG_ERR(
|
LOG_WARN(
|
||||||
"%s ipc client version mismatch (client: %s, server: %s)", m_typeName.constData(),
|
"%s ipc client version mismatch (client: %s, server: %s)", m_typeName.constData(),
|
||||||
clientVersion.toUtf8().constData(), versionId.toUtf8().constData()
|
clientVersion.toUtf8().constData(), versionId.toUtf8().constData()
|
||||||
);
|
);
|
||||||
writeToClientSocket(clientSocket, QStringLiteral("error=version mismatch, expected: %1").arg(versionId));
|
writeToClientSocket(clientSocket, QStringLiteral("versionMismatch=%1").arg(versionId));
|
||||||
clientSocket->flush();
|
clientSocket->flush();
|
||||||
clientSocket->disconnectFromServer();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,33 @@ void CoreProcess::daemonIpcClientConnected()
|
||||||
m_daemonIpcClient->requestLogPath();
|
m_daemonIpcClient->requestLogPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoreProcess::checkExistingProcess()
|
||||||
|
{
|
||||||
|
qInfo("checking existing core");
|
||||||
|
|
||||||
|
auto *client = new ipc::CoreIpcClient(this);
|
||||||
|
connect(client, &ipc::CoreIpcClient::connected, this, [client] {
|
||||||
|
qInfo("existing core has matching version, leaving it running");
|
||||||
|
client->deleteLater();
|
||||||
|
});
|
||||||
|
connect(client, &ipc::CoreIpcClient::versionMismatch, this, [client] {
|
||||||
|
qInfo("existing core has mismatched version, asking it to stop");
|
||||||
|
client->sendStop();
|
||||||
|
});
|
||||||
|
connect(client, &ipc::CoreIpcClient::serverShutdown, this, [this, client] {
|
||||||
|
qInfo("existing core stopped successfully");
|
||||||
|
client->deleteLater();
|
||||||
|
setProcessState(ProcessState::RetryPending);
|
||||||
|
m_retryTimer.setSingleShot(true);
|
||||||
|
m_retryTimer.start(kRetryDelay);
|
||||||
|
});
|
||||||
|
connect(client, &ipc::CoreIpcClient::connectionFailed, this, [client] {
|
||||||
|
qCritical("could not contact existing core");
|
||||||
|
client->deleteLater();
|
||||||
|
});
|
||||||
|
client->connectToServer();
|
||||||
|
}
|
||||||
|
|
||||||
void CoreProcess::onProcessFinished(int exitCode, QProcess::ExitStatus)
|
void CoreProcess::onProcessFinished(int exitCode, QProcess::ExitStatus)
|
||||||
{
|
{
|
||||||
using enum ProcessState;
|
using enum ProcessState;
|
||||||
|
|
@ -155,10 +182,11 @@ void CoreProcess::onProcessFinished(int exitCode, QProcess::ExitStatus)
|
||||||
|
|
||||||
if (exitCode != s_exitSuccess) {
|
if (exitCode != s_exitSuccess) {
|
||||||
setProcessState(Stopped);
|
setProcessState(Stopped);
|
||||||
if (exitCode == s_exitDuplicate)
|
if (exitCode == s_exitDuplicate) {
|
||||||
qWarning("desktop process is already running");
|
checkExistingProcess();
|
||||||
else
|
return;
|
||||||
qWarning("desktop process exited with code: %d", exitCode);
|
}
|
||||||
|
qWarning("desktop process exited with code: %d", exitCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,10 +427,15 @@ void CoreProcess::start(std::optional<ProcessMode> processModeOption)
|
||||||
|
|
||||||
m_coreIpcClient = new ipc::CoreIpcClient(this);
|
m_coreIpcClient = new ipc::CoreIpcClient(this);
|
||||||
connect(m_coreIpcClient, &ipc::CoreIpcClient::commandReceived, this, &CoreProcess::onCoreIpcMessageReceived);
|
connect(m_coreIpcClient, &ipc::CoreIpcClient::commandReceived, this, &CoreProcess::onCoreIpcMessageReceived);
|
||||||
connect(m_coreIpcClient, &ipc::CoreIpcClient::connected, this, [] { qInfo("connected to core ipc server"); });
|
connect(m_coreIpcClient, &ipc::CoreIpcClient::connected, this, [] {
|
||||||
|
qDebug("connected to core ipc server");
|
||||||
|
});
|
||||||
connect(m_coreIpcClient, &ipc::CoreIpcClient::connectionFailed, this, [] {
|
connect(m_coreIpcClient, &ipc::CoreIpcClient::connectionFailed, this, [] {
|
||||||
qWarning("failed to establish core ipc connection");
|
qWarning("failed to establish core ipc connection");
|
||||||
});
|
});
|
||||||
|
connect(m_coreIpcClient, &ipc::CoreIpcClient::serverShutdown, this, [] {
|
||||||
|
qDebug("core ipc server shut down cleanly");
|
||||||
|
});
|
||||||
|
|
||||||
m_coreIpcClient->connectToServer();
|
m_coreIpcClient->connectToServer();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ private:
|
||||||
void handleLogLines(const QString &text);
|
void handleLogLines(const QString &text);
|
||||||
QString correctedAddress(const QString &address) const;
|
QString correctedAddress(const QString &address) const;
|
||||||
void setupDaemonLogTail(const QString &logPath);
|
void setupDaemonLogTail(const QString &logPath);
|
||||||
|
void checkExistingProcess();
|
||||||
static QString makeQuotedArgs(const QString &app, const QStringList &args);
|
static QString makeQuotedArgs(const QString &app, const QStringList &args);
|
||||||
static QString processModeToString(const Settings::ProcessMode mode);
|
static QString processModeToString(const Settings::ProcessMode mode);
|
||||||
static QString processStateToString(const CoreProcess::ProcessState state);
|
static QString processStateToString(const CoreProcess::ProcessState state);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@ CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName,
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoreIpcClient::sendStop()
|
||||||
|
{
|
||||||
|
sendMessage(QStringLiteral("stop"));
|
||||||
|
}
|
||||||
|
|
||||||
void CoreIpcClient::processCommand(const QString &command, const QStringList &parts)
|
void CoreIpcClient::processCommand(const QString &command, const QStringList &parts)
|
||||||
{
|
{
|
||||||
const auto args = parts.size() >= 2 ? parts.at(1) : QString();
|
const auto args = parts.size() >= 2 ? parts.at(1) : QString();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ class CoreIpcClient : public IpcClient
|
||||||
public:
|
public:
|
||||||
explicit CoreIpcClient(QObject *parent = nullptr);
|
explicit CoreIpcClient(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void sendStop();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void commandReceived(const QString &command, const QString &args);
|
void commandReceived(const QString &command, const QString &args);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,13 @@ void IpcClient::handleReadyRead()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parts.at(0) == QStringLiteral("bye")) {
|
||||||
|
qDebug().noquote() << QStringLiteral("%1 ipc server is shutting down").arg(m_typeName);
|
||||||
|
disconnectFromServer();
|
||||||
|
Q_EMIT serverShutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
processCommand(parts.at(0), parts);
|
processCommand(parts.at(0), parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +176,17 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
|
||||||
|
|
||||||
|
if (parts.at(0) == QStringLiteral("versionMismatch")) {
|
||||||
|
const auto serverVersion = parts.size() >= 2 ? parts.at(1) : QStringLiteral("unknown");
|
||||||
|
qWarning().noquote(
|
||||||
|
) << QStringLiteral("%1 ipc version mismatch (client: %2, server: %3)").arg(m_typeName, versionId, serverVersion);
|
||||||
|
m_state = State::Connected;
|
||||||
|
Q_EMIT versionMismatch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (parts.at(0) != QStringLiteral("hello")) {
|
if (parts.at(0) != QStringLiteral("hello")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -180,15 +198,6 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
|
|
||||||
if (const auto serverVersion = parts.at(1); serverVersion != versionId) {
|
|
||||||
qCritical().noquote(
|
|
||||||
) << QStringLiteral("%1 ipc version mismatch (client: %2 , server: %3)").arg(m_typeName, versionId, serverVersion);
|
|
||||||
disconnectFromServer();
|
|
||||||
Q_EMIT connectionFailed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_state = State::Connected;
|
m_state = State::Connected;
|
||||||
qDebug().noquote() << QStringLiteral("%1 ipc client connected").arg(m_typeName);
|
qDebug().noquote() << QStringLiteral("%1 ipc client connected").arg(m_typeName);
|
||||||
Q_EMIT connected();
|
Q_EMIT connected();
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void connected();
|
void connected();
|
||||||
void connectionFailed();
|
void connectionFailed();
|
||||||
|
void serverShutdown();
|
||||||
|
void versionMismatch();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void handleDisconnected();
|
void handleDisconnected();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue