feat(gui): Retry mechanism for Windows Daemon IPC client
This commit is contained in:
@ -289,7 +289,9 @@ void MainWindow::connectSlots()
|
||||
connect(&m_coreProcess, &CoreProcess::processStateChanged, this, &MainWindow::coreProcessStateChanged);
|
||||
connect(&m_coreProcess, &CoreProcess::connectionStateChanged, this, &MainWindow::coreConnectionStateChanged);
|
||||
connect(&m_coreProcess, &CoreProcess::secureSocket, this, &MainWindow::secureSocket);
|
||||
connect(&m_coreProcess, &CoreProcess::daemonIpcClientConnectFailed, this, &MainWindow::daemonIpcClientConnectFailed);
|
||||
connect(
|
||||
&m_coreProcess, &CoreProcess::daemonIpcClientConnectionFailed, this, &MainWindow::daemonIpcClientConnectionFailed
|
||||
);
|
||||
|
||||
connect(m_actionAbout, &QAction::triggered, this, &MainWindow::openAboutDialog);
|
||||
connect(m_actionClearSettings, &QAction::triggered, this, &MainWindow::clearSettings);
|
||||
@ -1145,7 +1147,7 @@ bool MainWindow::regenerateLocalFingerprints()
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::daemonIpcClientConnectFailed()
|
||||
void MainWindow::daemonIpcClientConnectionFailed()
|
||||
{
|
||||
if (deskflow::gui::messages::showDaemonOffline(this)) {
|
||||
m_coreProcess.retryDaemon();
|
||||
|
||||
@ -158,7 +158,7 @@ private:
|
||||
void showAndActivate();
|
||||
void showHostNameEditor();
|
||||
void setHostName();
|
||||
void daemonIpcClientConnectFailed();
|
||||
void daemonIpcClientConnectionFailed();
|
||||
void toggleCanRunCore(bool enableButtons);
|
||||
void remoteHostChanged(const QString newRemoteHost);
|
||||
|
||||
|
||||
@ -140,7 +140,9 @@ CoreProcess::CoreProcess(const IServerConfig &serverConfig, std::shared_ptr<Deps
|
||||
m_daemonIpcClient{new ipc::DaemonIpcClient(this)}
|
||||
{
|
||||
connect(m_daemonIpcClient, &ipc::DaemonIpcClient::connected, this, &CoreProcess::daemonIpcClientConnected);
|
||||
connect(m_daemonIpcClient, &ipc::DaemonIpcClient::connectFailed, this, &CoreProcess::daemonIpcClientConnectFailed);
|
||||
connect(
|
||||
m_daemonIpcClient, &ipc::DaemonIpcClient::connectionFailed, this, &CoreProcess::daemonIpcClientConnectionFailed
|
||||
);
|
||||
|
||||
connect(&m_pDeps->process(), &QProcessProxy::finished, this, &CoreProcess::onProcessFinished);
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ signals:
|
||||
void connectionStateChanged(ConnectionState state);
|
||||
void processStateChanged(ProcessState state);
|
||||
void secureSocket(bool enabled);
|
||||
void daemonIpcClientConnectFailed();
|
||||
void daemonIpcClientConnectionFailed();
|
||||
|
||||
private slots:
|
||||
void onProcessFinished(int exitCode, QProcess::ExitStatus);
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
namespace deskflow::gui::ipc {
|
||||
|
||||
const auto kTimeout = 1000;
|
||||
const auto kRetryLimit = 3;
|
||||
|
||||
DaemonIpcClient::DaemonIpcClient(QObject *parent)
|
||||
: QObject(parent),
|
||||
@ -27,54 +28,95 @@ DaemonIpcClient::DaemonIpcClient(QObject *parent)
|
||||
|
||||
bool DaemonIpcClient::connectToServer()
|
||||
{
|
||||
if (m_connecting) {
|
||||
qDebug() << "daemon ipc client already connecting to server";
|
||||
if (m_state == State::Connecting) {
|
||||
qWarning() << "daemon ipc client already connecting to server";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "daemon ipc client connecting to server:" << kDaemonIpcName;
|
||||
m_connecting = true;
|
||||
m_socket->connectToServer(kDaemonIpcName);
|
||||
|
||||
if (!m_socket->waitForConnected(kTimeout)) {
|
||||
qWarning() << "daemon ipc client failed to connect";
|
||||
m_connecting = false;
|
||||
Q_EMIT connectFailed();
|
||||
return false;
|
||||
if (m_state != State::Unconnected) {
|
||||
qDebug() << "daemon ipc client not in unconnected state, disconnecting";
|
||||
disconnectFromServer();
|
||||
}
|
||||
|
||||
if (!sendMessage("hello", "hello", false)) {
|
||||
qWarning() << "daemon ipc client failed to send hello";
|
||||
m_connecting = false;
|
||||
Q_EMIT connectFailed();
|
||||
return false;
|
||||
if (m_socket->state() != QLocalSocket::UnconnectedState) {
|
||||
qWarning() << "daemon ipc client socket not in unconnected state, disconnecting";
|
||||
disconnectFromServer();
|
||||
}
|
||||
|
||||
m_connecting = false;
|
||||
m_connected = true;
|
||||
for (int i = 0; i < kRetryLimit; ++i) {
|
||||
if (i == 0) {
|
||||
qDebug() << "daemon ipc client connecting to server:" << kDaemonIpcName;
|
||||
} else {
|
||||
qDebug() << "daemon ipc client retrying connection, attempt:" << i + 1;
|
||||
}
|
||||
|
||||
qDebug() << "daemon ipc client connected";
|
||||
Q_EMIT connected();
|
||||
m_state = State::Connecting;
|
||||
m_socket->connectToServer(kDaemonIpcName);
|
||||
|
||||
return true;
|
||||
if (!m_socket->waitForConnected(kTimeout)) {
|
||||
qWarning() << "daemon ipc client failed to connect";
|
||||
disconnectFromServer();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sendMessage("hello", "hello", false)) {
|
||||
qWarning() << "daemon ipc client failed to send hello";
|
||||
disconnectFromServer();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_state = State::Connected;
|
||||
qDebug() << "daemon ipc client connected";
|
||||
Q_EMIT connected();
|
||||
return true;
|
||||
}
|
||||
|
||||
qWarning() << "daemon ipc client failed to connect after" << kRetryLimit << "attempts";
|
||||
disconnectFromServer();
|
||||
Q_EMIT connectionFailed();
|
||||
return false;
|
||||
}
|
||||
|
||||
void DaemonIpcClient::disconnectFromServer()
|
||||
{
|
||||
m_state = State::Disconnecting;
|
||||
qDebug() << "daemon ipc client disconnecting from server";
|
||||
m_socket->disconnectFromServer();
|
||||
|
||||
if (m_socket->state() != QLocalSocket::UnconnectedState) {
|
||||
qDebug() << "daemon ipc client waiting for socket to disconnect";
|
||||
m_socket->waitForDisconnected(kTimeout);
|
||||
qDebug() << "daemon ipc client disconnected from server";
|
||||
} else {
|
||||
qDebug() << "daemon ipc client socket already disconnected";
|
||||
}
|
||||
|
||||
m_state = State::Unconnected;
|
||||
}
|
||||
|
||||
void DaemonIpcClient::handleDisconnected()
|
||||
{
|
||||
qWarning() << "daemon ipc client disconnected from server";
|
||||
m_connected = false;
|
||||
Q_EMIT connectFailed();
|
||||
qDebug() << "daemon ipc client disconnected from server";
|
||||
if (m_state == State::Connected) {
|
||||
Q_EMIT connectionFailed();
|
||||
}
|
||||
|
||||
m_state = State::Unconnected;
|
||||
}
|
||||
|
||||
void DaemonIpcClient::handleErrorOccurred()
|
||||
{
|
||||
qWarning() << "daemon ipc client error:" << m_socket->errorString();
|
||||
m_connected = false;
|
||||
disconnectFromServer();
|
||||
|
||||
if (m_state == State::Connected) {
|
||||
Q_EMIT connectionFailed();
|
||||
}
|
||||
}
|
||||
|
||||
bool DaemonIpcClient::sendMessage(const QString &message, const QString &expectAck, const bool expectConnected)
|
||||
{
|
||||
if (expectConnected && !m_connected) {
|
||||
if (expectConnected && !isConnected()) {
|
||||
qWarning() << "cannot send command, ipc client not connected";
|
||||
return false;
|
||||
}
|
||||
@ -90,7 +132,7 @@ bool DaemonIpcClient::sendMessage(const QString &message, const QString &expectA
|
||||
qDebug() << "daemon ipc client waiting for ack: " << expectAck;
|
||||
|
||||
if (!m_socket->waitForReadyRead(kTimeout)) {
|
||||
qWarning() << "daemon ipc client failed to read response";
|
||||
qWarning() << "daemon ipc client socket ready read timed out";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -124,8 +166,8 @@ bool DaemonIpcClient::keepAlive()
|
||||
}
|
||||
|
||||
if (!sendMessage("noop")) {
|
||||
qWarning() << "daemon ipc client keep alive ping failed";
|
||||
m_connected = false;
|
||||
qWarning() << "daemon ipc client keep alive ping failed, reconnecting";
|
||||
connectToServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -16,9 +16,19 @@ class DaemonIpcClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
// Represents underlying socket state and whether the server responded to the hello message.
|
||||
enum class State
|
||||
{
|
||||
Unconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
Disconnecting,
|
||||
};
|
||||
|
||||
public:
|
||||
explicit DaemonIpcClient(QObject *parent = nullptr);
|
||||
bool connectToServer();
|
||||
void disconnectFromServer();
|
||||
bool sendLogLevel(const QString &logLevel);
|
||||
bool sendStartProcess(const QString &command, bool elevate);
|
||||
bool sendStopProcess();
|
||||
@ -27,12 +37,12 @@ public:
|
||||
|
||||
bool isConnected() const
|
||||
{
|
||||
return m_connected;
|
||||
return m_state == State::Connected;
|
||||
}
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void connectFailed();
|
||||
void connectionFailed();
|
||||
|
||||
private slots:
|
||||
void handleDisconnected();
|
||||
@ -44,8 +54,7 @@ private:
|
||||
|
||||
private:
|
||||
QLocalSocket *m_socket;
|
||||
bool m_connected{false};
|
||||
bool m_connecting{false};
|
||||
State m_state{State::Unconnected};
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui::ipc
|
||||
|
||||
@ -246,7 +246,7 @@ void MSWindowsWatchdog::mainLoop(void *)
|
||||
LOG_DEBUG("watchdog main loop finished");
|
||||
|
||||
if (m_process != nullptr) {
|
||||
LOG_DEBUG("terminated running process on exit");
|
||||
LOG_DEBUG("terminating running process on exit");
|
||||
m_process->shutdown();
|
||||
m_process.reset();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user