feat(ipc): Stop bad version existing Core process

This commit is contained in:
Nick Bolton 2026-04-08 10:31:40 +01:00
parent e9868123df
commit 10027ecc1c
11 changed files with 85 additions and 18 deletions

View file

@ -132,6 +132,9 @@ int main(int argc, char **argv)
QApplication::setApplicationName(QStringLiteral("%1 Core").arg(kAppName));
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();
QThread coreThread;

View file

@ -168,6 +168,12 @@ void App::handleScreenError() const
getEvents()->addEvent(Event(EventTypes::Quit));
}
void App::quit()
{
LOG_INFO("quitting");
getEvents()->addEvent(Event(EventTypes::Quit));
}
void App::runEventsLoop(const void *)
{
int exitCode = m_events->loop();

View file

@ -77,6 +77,7 @@ public:
}
void run(QThread &coreThread);
void quit();
void setupFileLogging();
void loggingFilterWarning() const;
void initApp() override;

View file

@ -29,8 +29,14 @@ CoreIpcServer &CoreIpcServer::instance()
void CoreIpcServer::processCommand(QLocalSocket *clientSocket, const QString &command, const QStringList &parts)
{
Q_UNUSED(clientSocket)
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());
}

View file

@ -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());
if (clientVersion != versionId) {
LOG_ERR(
LOG_WARN(
"%s ipc client version mismatch (client: %s, server: %s)", m_typeName.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->disconnectFromServer();
return;
}

View file

@ -144,6 +144,33 @@ void CoreProcess::daemonIpcClientConnected()
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)
{
using enum ProcessState;
@ -155,9 +182,10 @@ void CoreProcess::onProcessFinished(int exitCode, QProcess::ExitStatus)
if (exitCode != s_exitSuccess) {
setProcessState(Stopped);
if (exitCode == s_exitDuplicate)
qWarning("desktop process is already running");
else
if (exitCode == s_exitDuplicate) {
checkExistingProcess();
return;
}
qWarning("desktop process exited with code: %d", exitCode);
return;
}
@ -399,10 +427,15 @@ void CoreProcess::start(std::optional<ProcessMode> processModeOption)
m_coreIpcClient = new ipc::CoreIpcClient(this);
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, [] {
qWarning("failed to establish core ipc connection");
});
connect(m_coreIpcClient, &ipc::CoreIpcClient::serverShutdown, this, [] {
qDebug("core ipc server shut down cleanly");
});
m_coreIpcClient->connectToServer();
});

View file

@ -114,6 +114,7 @@ private:
void handleLogLines(const QString &text);
QString correctedAddress(const QString &address) const;
void setupDaemonLogTail(const QString &logPath);
void checkExistingProcess();
static QString makeQuotedArgs(const QString &app, const QStringList &args);
static QString processModeToString(const Settings::ProcessMode mode);
static QString processStateToString(const CoreProcess::ProcessState state);

View file

@ -20,6 +20,11 @@ CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName,
// do nothing
}
void CoreIpcClient::sendStop()
{
sendMessage(QStringLiteral("stop"));
}
void CoreIpcClient::processCommand(const QString &command, const QStringList &parts)
{
const auto args = parts.size() >= 2 ? parts.at(1) : QString();

View file

@ -19,6 +19,8 @@ class CoreIpcClient : public IpcClient
public:
explicit CoreIpcClient(QObject *parent = nullptr);
void sendStop();
Q_SIGNALS:
void commandReceived(const QString &command, const QString &args);

View file

@ -151,6 +151,13 @@ void IpcClient::handleReadyRead()
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);
}
@ -169,6 +176,17 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
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")) {
return;
}
@ -180,15 +198,6 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
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;
qDebug().noquote() << QStringLiteral("%1 ipc client connected").arg(m_typeName);
Q_EMIT connected();

View file

@ -38,6 +38,8 @@ public:
Q_SIGNALS:
void connected();
void connectionFailed();
void serverShutdown();
void versionMismatch();
private Q_SLOTS:
void handleDisconnected();