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