refactor: 统一管理连接会话生命周期

This commit is contained in:
Chenx Dust
2026-07-27 16:30:23 +08:00
parent a160d383e9
commit 9e6d741ab6
12 changed files with 550 additions and 134 deletions

View File

@@ -35,8 +35,10 @@ set(SOURCE_FILES
main.cpp
mainwindow.cpp
zjuconnectmode.cpp
application/connectionsession.cpp
core/corecommandbuilder.cpp
core/coreoutputparser.cpp
core/connectionsessionstate.cpp
infrastructure/settingsprofileloader.cpp
zjuconnectcontroller/zjuconnectcontroller.cpp
extrasettingwindow/extrasettingwindow.cpp
@@ -136,4 +138,12 @@ if(BUILD_TESTING)
target_include_directories(settingsprofileloader_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(settingsprofileloader_test Qt::Core)
add_test(NAME settingsprofileloader_test COMMAND settingsprofileloader_test)
add_executable(connectionsessionstate_test
tests/connectionsessionstate_test.cpp
core/connectionsessionstate.cpp
)
target_include_directories(connectionsessionstate_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(connectionsessionstate_test Qt::Core)
add_test(NAME connectionsessionstate_test COMMAND connectionsessionstate_test)
endif()

View File

@@ -0,0 +1,141 @@
#include "connectionsession.h"
ConnectionSession::ConnectionSession(QObject *parent)
: QObject(parent),
controller(new ZjuConnectController(this))
{
reconnectTimer.setSingleShot(true);
connect(controller, &ZjuConnectController::outputRead, this, &ConnectionSession::outputRead);
connect(controller, &ZjuConnectController::graphCaptcha, this, &ConnectionSession::graphCaptcha);
connect(controller, &ZjuConnectController::smsCode, this, &ConnectionSession::smsCode);
connect(controller, &ZjuConnectController::totpCode, this, &ConnectionSession::totpCode);
connect(controller, &ZjuConnectController::ssoAuth, this, &ConnectionSession::ssoAuth);
connect(controller, &ZjuConnectController::askSudoPass,
this, &ConnectionSession::handleSudoPasswordRequest);
connect(controller, &ZjuConnectController::error, this, [this](ZJU_ERROR error)
{
sessionState.recordError(error);
});
connect(controller, &ZjuConnectController::started, this, [this]()
{
sessionState.processStarted();
emit stateChanged(sessionState.state());
});
connect(controller, &ZjuConnectController::finished,
this, &ConnectionSession::handleCoreFinished);
connect(&reconnectTimer, &QTimer::timeout, this, [this]()
{
if (sessionState.state() != ConnectionState::Reconnecting)
{
return;
}
sessionState.beginReconnect();
emit stateChanged(sessionState.state());
startCore();
});
}
bool ConnectionSession::start(const ConnectionProfile &profile, const ReconnectPolicy &policy)
{
if (!sessionState.requestStart(policy))
{
return false;
}
currentProfile = profile;
emit stateChanged(sessionState.state());
startCore();
return true;
}
void ConnectionSession::stop()
{
const ConnectionState previousState = sessionState.state();
const bool processNeedsStop = sessionState.requestStop();
if (previousState == ConnectionState::Reconnecting)
{
reconnectTimer.stop();
emit stateChanged(sessionState.state());
emit finished(sessionState.error());
return;
}
if (processNeedsStop)
{
emit stateChanged(sessionState.state());
controller->stop();
}
}
void ConnectionSession::submitInput(const QByteArray &data)
{
controller->writeInput(data);
}
void ConnectionSession::submitSudoPassword(const QString &password, bool remember)
{
if (password.isEmpty())
{
stop();
return;
}
if (remember)
{
savedSudoPassword = password;
}
sudoPasswordSubmitted = true;
submitInput(password.toUtf8() + "\n");
}
ConnectionState ConnectionSession::state() const
{
return sessionState.state();
}
bool ConnectionSession::isActive() const
{
return sessionState.isActive();
}
void ConnectionSession::startCore()
{
sudoPasswordSubmitted = false;
controller->start(currentProfile);
}
void ConnectionSession::handleCoreFinished()
{
if (sessionState.processFinished() == ProcessFinishAction::Reconnect)
{
emit stateChanged(sessionState.state());
emit reconnectScheduled(sessionState.reconnectDelayMs());
reconnectTimer.start(sessionState.reconnectDelayMs());
return;
}
emit stateChanged(sessionState.state());
emit finished(sessionState.error());
}
void ConnectionSession::handleSudoPasswordRequest()
{
if (savedSudoPassword.isEmpty())
{
emit askSudoPass();
return;
}
if (sudoPasswordSubmitted)
{
savedSudoPassword.clear();
emit savedSudoPasswordRejected();
emit askSudoPass();
return;
}
sudoPasswordSubmitted = true;
submitInput(savedSudoPassword.toUtf8() + "\n");
}

View File

@@ -0,0 +1,51 @@
#ifndef CONNECTIONSESSION_H
#define CONNECTIONSESSION_H
#include <QObject>
#include <QTimer>
#include "core/connectionprofile.h"
#include "core/connectionsessionstate.h"
#include "zjuconnectcontroller/zjuconnectcontroller.h"
class ConnectionSession : public QObject
{
Q_OBJECT
public:
explicit ConnectionSession(QObject *parent = nullptr);
bool start(const ConnectionProfile &profile, const ReconnectPolicy &policy);
void stop();
void submitInput(const QByteArray &data);
void submitSudoPassword(const QString &password, bool remember);
ConnectionState state() const;
bool isActive() const;
signals:
void stateChanged(ConnectionState state);
void outputRead(const QString &output);
void graphCaptcha(const QString &graphFile);
void smsCode(bool showSkipSecondaryAuthOption);
void totpCode();
void ssoAuth();
void askSudoPass();
void savedSudoPasswordRejected();
void reconnectScheduled(int delayMs);
void finished(ZJU_ERROR error);
private:
void startCore();
void handleCoreFinished();
void handleSudoPasswordRequest();
ZjuConnectController *controller;
QTimer reconnectTimer;
ConnectionSessionState sessionState;
ConnectionProfile currentProfile;
QString savedSudoPassword;
bool sudoPasswordSubmitted = false;
};
#endif // CONNECTIONSESSION_H

21
core/connectionerror.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef CONNECTIONERROR_H
#define CONNECTIONERROR_H
enum class ZJU_ERROR
{
NONE,
INVALID_DETAIL,
BRUTE_FORCE,
OTHER_LOGIN_FAILED,
ACCESS_DENIED,
LISTEN_FAILED,
CLIENT_FAILED,
CAPTCHA_FAILED,
PROGRAM_NOT_FOUND,
INTERACTIVE_ERROR,
AUTH_NOT_AVAILABLE,
AUTH_EXPIRED,
OTHER,
};
#endif // CONNECTIONERROR_H

View File

@@ -0,0 +1,106 @@
#include "connectionsessionstate.h"
ConnectionState ConnectionSessionState::state() const
{
return currentState;
}
ZJU_ERROR ConnectionSessionState::error() const
{
return currentError;
}
bool ConnectionSessionState::isActive() const
{
return currentState == ConnectionState::Starting
|| currentState == ConnectionState::Running
|| currentState == ConnectionState::Stopping
|| currentState == ConnectionState::Reconnecting;
}
bool ConnectionSessionState::wantsConnection() const
{
return desiredConnected;
}
int ConnectionSessionState::reconnectDelayMs() const
{
return reconnectPolicy.delayMs;
}
bool ConnectionSessionState::requestStart(const ReconnectPolicy &policy)
{
if (isActive())
{
return false;
}
reconnectPolicy = policy;
desiredConnected = true;
currentError = ZJU_ERROR::NONE;
currentState = ConnectionState::Starting;
return true;
}
void ConnectionSessionState::processStarted()
{
if (currentState == ConnectionState::Starting)
{
currentState = ConnectionState::Running;
}
}
void ConnectionSessionState::recordError(ZJU_ERROR error)
{
if (currentError == ZJU_ERROR::NONE)
{
currentError = error;
}
}
bool ConnectionSessionState::requestStop()
{
desiredConnected = false;
if (currentState == ConnectionState::Reconnecting)
{
currentState = ConnectionState::Disconnected;
return false;
}
if (currentState == ConnectionState::Starting || currentState == ConnectionState::Running)
{
currentState = ConnectionState::Stopping;
return true;
}
return currentState == ConnectionState::Stopping;
}
ProcessFinishAction ConnectionSessionState::processFinished()
{
if (desiredConnected
&& reconnectPolicy.enabled
&& isReconnectable(currentError))
{
currentState = ConnectionState::Reconnecting;
return ProcessFinishAction::Reconnect;
}
desiredConnected = false;
currentState = currentError == ZJU_ERROR::NONE
? ConnectionState::Disconnected
: ConnectionState::Failed;
return ProcessFinishAction::Complete;
}
void ConnectionSessionState::beginReconnect()
{
if (currentState == ConnectionState::Reconnecting && desiredConnected)
{
currentError = ZJU_ERROR::NONE;
currentState = ConnectionState::Starting;
}
}
bool ConnectionSessionState::isReconnectable(ZJU_ERROR error)
{
return error == ZJU_ERROR::AUTH_EXPIRED || error == ZJU_ERROR::OTHER;
}

View File

@@ -0,0 +1,53 @@
#ifndef CONNECTIONSESSIONSTATE_H
#define CONNECTIONSESSIONSTATE_H
#include "connectionerror.h"
enum class ConnectionState
{
Disconnected,
Starting,
Running,
Stopping,
Reconnecting,
Failed,
};
struct ReconnectPolicy
{
bool enabled = false;
int delayMs = 1000;
};
enum class ProcessFinishAction
{
Complete,
Reconnect,
};
class ConnectionSessionState
{
public:
ConnectionState state() const;
ZJU_ERROR error() const;
bool isActive() const;
bool wantsConnection() const;
int reconnectDelayMs() const;
bool requestStart(const ReconnectPolicy &policy);
void processStarted();
void recordError(ZJU_ERROR error);
bool requestStop();
ProcessFinishAction processFinished();
void beginReconnect();
private:
static bool isReconnectable(ZJU_ERROR error);
ConnectionState currentState = ConnectionState::Disconnected;
ZJU_ERROR currentError = ZJU_ERROR::NONE;
ReconnectPolicy reconnectPolicy;
bool desiredConnected = false;
};
#endif // CONNECTIONSESSIONSTATE_H

View File

@@ -37,9 +37,7 @@ MainWindow::MainWindow(QWidget *parent) :
upgradeSettings();
isFirstTimeSetMode = true;
isZjuConnectLinked = false;
isSystemProxySet = false;
zjuConnectError = ZJU_ERROR::NONE;
ui->setupUi(this);
setupTrayIcon();
@@ -353,7 +351,7 @@ MainWindow::MainWindow(QWidget *parent) :
void MainWindow::closeEvent(QCloseEvent *event)
{
if (isZjuConnectLinked)
if (connectionSession != nullptr && connectionSession->isActive())
{
event->ignore();
hide();
@@ -402,8 +400,6 @@ void MainWindow::clearLog()
void MainWindow::resetZjuConnectUi()
{
isZjuConnectLinked = false;
zjuConnectError = ZJU_ERROR::NONE;
ui->pushButton1->setText("连接服务器");
trayConnectAction->setText("连接服务器");
ui->pushButton2->setText("设置系统代理");
@@ -581,7 +577,7 @@ bool MainWindow::switchProfile(const QString &profileId)
return true;
}
if (isZjuConnectLinked)
if (connectionSession != nullptr && connectionSession->isActive())
{
QMessageBox::warning(this, "切换失败", "请先断开 VPN 连接,再切换配置。");
refreshProfileMenu();
@@ -657,7 +653,7 @@ void MainWindow::renameCurrentProfile()
{
return;
}
if (isZjuConnectLinked)
if (connectionSession != nullptr && connectionSession->isActive())
{
QMessageBox::warning(this, "重命名失败", "请先断开 VPN 连接,再重命名配置。");
return;
@@ -824,9 +820,10 @@ void MainWindow::cleanUpWhenQuit()
void MainWindow::gracefullyQuit()
{
if (isZjuConnectLinked)
if (connectionSession != nullptr && connectionSession->isActive())
{
connect(zjuConnectController, &ZjuConnectController::finished, qApp, QApplication::quit);
connect(connectionSession, &ConnectionSession::finished, qApp,
[](ZJU_ERROR) { QApplication::quit(); });
ui->pushButton1->click();
}
else
@@ -848,10 +845,11 @@ MainWindow::~MainWindow()
delete profileManager;
}
if (zjuConnectController != nullptr)
if (connectionSession != nullptr)
{
disconnect(zjuConnectController, &ZjuConnectController::finished, nullptr, nullptr);
delete zjuConnectController;
disconnect(connectionSession, nullptr, this, nullptr);
delete connectionSession;
connectionSession = nullptr;
}
delete ui;

View File

@@ -9,6 +9,7 @@
#include <QSettings>
#include <QPointer>
#include "application/connectionsession.h"
#include "loginwindow/loginwindow.h"
#include "sudowindow/sudowindow.h"
#include "ssologinwebview/ssologinwebview.h"
@@ -41,8 +42,6 @@ signals:
void SetModeFinished();
void WriteToProcess(const QByteArray &data);
protected:
void closeEvent(QCloseEvent *e) override;
@@ -98,7 +97,7 @@ private:
QAction *newProfileAction;
QAction *renameProfileAction;
QAction *deleteProfileAction;
ZjuConnectController *zjuConnectController = nullptr;
ConnectionSession *connectionSession = nullptr;
QNetworkAccessManager *checkUpdateNAM;
QNetworkAccessManager *checkCoreUpdateNAM;
QSettings *settings;
@@ -115,10 +114,7 @@ private:
bool isFirstTimeSetMode;
bool isZjuConnectLinked;
bool isSystemProxySet;
bool isAutoReconnecting = false;
ZJU_ERROR zjuConnectError;
};
#endif //MAINWINDOW_H

View File

@@ -0,0 +1,108 @@
#include <QCoreApplication>
#include <QDebug>
#include "core/connectionsessionstate.h"
namespace
{
bool normalLifecycle()
{
ConnectionSessionState session;
if (!session.requestStart({false, 1000})
|| session.state() != ConnectionState::Starting
|| !session.isActive())
{
qCritical() << "normalLifecycle failed at start";
return false;
}
session.processStarted();
if (session.state() != ConnectionState::Running)
{
qCritical() << "normalLifecycle failed at running";
return false;
}
if (!session.requestStop() || session.state() != ConnectionState::Stopping)
{
qCritical() << "normalLifecycle failed at stopping";
return false;
}
if (session.processFinished() != ProcessFinishAction::Complete
|| session.state() != ConnectionState::Disconnected
|| session.isActive())
{
qCritical() << "normalLifecycle failed at completion";
return false;
}
return true;
}
bool reconnectsOnlyEligibleFailures()
{
ConnectionSessionState session;
session.requestStart({true, 2500});
session.processStarted();
session.recordError(ZJU_ERROR::AUTH_EXPIRED);
if (session.processFinished() != ProcessFinishAction::Reconnect
|| session.state() != ConnectionState::Reconnecting
|| session.reconnectDelayMs() != 2500)
{
qCritical() << "reconnectsOnlyEligibleFailures failed at scheduling";
return false;
}
session.beginReconnect();
if (session.state() != ConnectionState::Starting || session.error() != ZJU_ERROR::NONE)
{
qCritical() << "reconnectsOnlyEligibleFailures failed at restart";
return false;
}
session.processStarted();
session.recordError(ZJU_ERROR::INVALID_DETAIL);
if (session.processFinished() != ProcessFinishAction::Complete
|| session.state() != ConnectionState::Failed)
{
qCritical() << "reconnectsOnlyEligibleFailures reconnected an ineligible error";
return false;
}
return true;
}
bool keepsFirstErrorAndCancelsPendingReconnect()
{
ConnectionSessionState session;
session.requestStart({true, 1000});
session.processStarted();
session.recordError(ZJU_ERROR::AUTH_EXPIRED);
session.recordError(ZJU_ERROR::OTHER);
if (session.error() != ZJU_ERROR::AUTH_EXPIRED)
{
qCritical() << "keepsFirstErrorAndCancelsPendingReconnect did not keep first error";
return false;
}
session.processFinished();
if (session.requestStop()
|| session.state() != ConnectionState::Disconnected
|| session.wantsConnection())
{
qCritical() << "keepsFirstErrorAndCancelsPendingReconnect failed to cancel reconnect";
return false;
}
return true;
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
return normalLifecycle()
&& reconnectsOnlyEligibleFailures()
&& keepsFirstErrorAndCancelsPendingReconnect()
? 0
: 1;
}

View File

@@ -1,5 +1,4 @@
#include "zjuconnectcontroller.h"
#include "mainwindow.h"
#include "core/corecommandbuilder.h"
#include "core/coreoutputparser.h"
#include "utils/utils.h"
@@ -10,7 +9,7 @@
#include <QFileInfo>
#include <QStandardPaths>
ZjuConnectController::ZjuConnectController(QWidget* parent) : QObject(parent)
ZjuConnectController::ZjuConnectController(QObject *parent) : QObject(parent)
{
zjuConnectProcess = new QProcess(this);
@@ -21,7 +20,7 @@ ZjuConnectController::ZjuConnectController(QWidget* parent) : QObject(parent)
logStream = new QTextStream(logFile);
logStream->setEncoding(QStringConverter::Utf8);
QString startMsg = "=== Log started at " + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") +
" with " + QApplication::applicationDisplayName() + " " + QApplication::applicationVersion() +
" with " + QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion() +
" ===\n";
*logStream << startMsg;
logStream->flush();
@@ -138,10 +137,6 @@ ZjuConnectController::ZjuConnectController(QWidget* parent) : QObject(parent)
emit outputRead(timeString + " 退出原因:" "进程已结束");
emit finished();
});
connect(qobject_cast<MainWindow *>(parent), &MainWindow::WriteToProcess, this,
[&](const QByteArray &data) { zjuConnectProcess->write(data); });
}
QString ZjuConnectController::copyCoreForAppImage(const QString &programPath)
@@ -232,7 +227,6 @@ void ZjuConnectController::start(const ConnectionProfile &profile)
sudoArgs << programToStart << finalArgs;
programToStart = "sudo";
finalArgs = sudoArgs;
enteredSudoPassword = false;
}
#endif
@@ -242,6 +236,10 @@ void ZjuConnectController::start(const ConnectionProfile &profile)
{
emit finished();
}
else
{
emit started();
}
}
void ZjuConnectController::stop()
@@ -262,6 +260,11 @@ void ZjuConnectController::stop()
}
}
void ZjuConnectController::writeInput(const QByteArray &data)
{
zjuConnectProcess->write(data);
}
ZjuConnectController::~ZjuConnectController()
{
stop();

View File

@@ -3,31 +3,15 @@
#include <QtCore>
#include "core/connectionerror.h"
#include "core/connectionprofile.h"
enum class ZJU_ERROR
{
NONE,
INVALID_DETAIL,
BRUTE_FORCE,
OTHER_LOGIN_FAILED,
ACCESS_DENIED,
LISTEN_FAILED,
CLIENT_FAILED,
CAPTCHA_FAILED,
PROGRAM_NOT_FOUND,
INTERACTIVE_ERROR,
AUTH_NOT_AVAILABLE,
AUTH_EXPIRED,
OTHER,
};
class ZjuConnectController : public QObject
{
Q_OBJECT
public:
ZjuConnectController(QWidget* parent);
explicit ZjuConnectController(QObject *parent = nullptr);
~ZjuConnectController() override;
@@ -35,6 +19,7 @@ public:
void stop();
void writeInput(const QByteArray &data);
signals:
@@ -52,9 +37,9 @@ signals:
void askSudoPass();
void finished();
void started();
void write(const QByteArray &data);
void finished();
private:
QString copyCoreForAppImage(const QString &programPath);
@@ -69,10 +54,6 @@ private:
QTextStream *logStream = nullptr;
bool stopRequested = false;
public:
bool savedSudoPassword;
bool enteredSudoPassword;
QString sudoPassword;
};
#endif //ZJUCONNECTCONTROLLER_H

View File

@@ -17,72 +17,38 @@
void MainWindow::initZjuConnect()
{
if (zjuConnectController != nullptr)
if (connectionSession != nullptr)
{
return;
}
clearLog();
zjuConnectController = new ZjuConnectController(this);
connectionSession = new ConnectionSession(this);
resetZjuConnectUi();
// 连接服务器
connect(zjuConnectController, &ZjuConnectController::outputRead, this,
connect(connectionSession, &ConnectionSession::outputRead, this,
[&](const QString &output)
{
ui->logPlainTextEdit->appendPlainText(output.trimmed());
});
connect(zjuConnectController, &ZjuConnectController::error, this,
[&](ZJU_ERROR err)
{
if (zjuConnectError == ZJU_ERROR::NONE)
{
zjuConnectError = err;
}
});
connect(connectionSession, &ConnectionSession::savedSudoPasswordRejected, this,
[&]() { addLog("sudo 密码可能有误,不使用记住的密码"); });
connect(zjuConnectController, &ZjuConnectController::askSudoPass, this,
connect(connectionSession, &ConnectionSession::askSudoPass, this,
[&]()
{
if (zjuConnectController->savedSudoPassword)
{
if (zjuConnectController->enteredSudoPassword)
{
addLog("sudo 密码可能有误,不使用记住的密码");
zjuConnectController->savedSudoPassword = false;
zjuConnectController->sudoPassword.clear();
}
else
{
zjuConnectController->enteredSudoPassword = true;
emit WriteToProcess(zjuConnectController->sudoPassword.toUtf8() + "\n");
return;
}
}
sudoWindow = new SudoWindow(this);
connect(sudoWindow, &SudoWindow::sudo, this, [&](const QString &password, bool save)
{
if (password.isEmpty())
{
zjuConnectController->stop();
}
else
{
if (save)
{
zjuConnectController->savedSudoPassword = true;
zjuConnectController->sudoPassword = password;
}
zjuConnectController->enteredSudoPassword = true;
emit WriteToProcess(password.toUtf8() + "\n");
}
connectionSession->submitSudoPassword(password, save);
});
sudoWindow->show();
});
connect(zjuConnectController, &ZjuConnectController::graphCaptcha, this,
connect(connectionSession, &ConnectionSession::graphCaptcha, this,
[&](const QString &graphFile) {
addLog("需要图形验证码");
graphCaptchaWindow = new GraphCaptchaWindow(this);
@@ -90,11 +56,11 @@ void MainWindow::initZjuConnect()
graphCaptchaWindow->show();
connect(graphCaptchaWindow, &GraphCaptchaWindow::finishCaptcha, this, [&](const QByteArray &captcha) {
addLog("图形验证码用户输入:" + captcha);
emit WriteToProcess(captcha + "\n");
connectionSession->submitInput(captcha + "\n");
});
});
connect(zjuConnectController, &ZjuConnectController::smsCode, this, [&](bool showSkipSecondaryAuthOption) {
connect(connectionSession, &ConnectionSession::smsCode, this, [&](bool showSkipSecondaryAuthOption) {
addLog("需要短信验证码");
QDialog smsCodeDialog(this);
@@ -130,20 +96,20 @@ void MainWindow::initZjuConnect()
{
smsCodeInput.prepend('$');
}
emit WriteToProcess(smsCodeInput + "\n");
connectionSession->submitInput(smsCodeInput + "\n");
});
connect(zjuConnectController, &ZjuConnectController::totpCode, this, [&]() {
connect(connectionSession, &ConnectionSession::totpCode, this, [&]() {
addLog("需要 TOTP 验证码");
QString totp = QInputDialog::getText(this, "TOTP 验证码", "请输入 TOTP 验证码:");
addLog("TOTP 验证码用户输入:" + totp);
emit WriteToProcess(totp.toLocal8Bit() + "\n");
connectionSession->submitInput(totp.toLocal8Bit() + "\n");
});
connect(zjuConnectController, &ZjuConnectController::ssoAuth, this, [&]() {
connect(connectionSession, &ConnectionSession::ssoAuth, this, [&]() {
ssoLoginWebView = new SsoLoginWebView(this);
connect(ssoLoginWebView, &SsoLoginWebView::loginCompleted,
[=](const QString &url) { emit WriteToProcess(url.toLocal8Bit() + "\n"); });
[=](const QString &url) { connectionSession->submitInput(url.toLocal8Bit() + "\n"); });
QString serverHost = settings->value("ZJUConnect/ServerAddress", "trust.hitsz.edu.cn").toString();
int serverPort = settings->value("ZJUConnect/ServerPort", 443).toInt();
@@ -164,36 +130,18 @@ void MainWindow::initZjuConnect()
ssoLoginWebView->show();
});
connect(zjuConnectController, &ZjuConnectController::finished, this, [&]()
{
addLog("VPN 断开!");
if (
(zjuConnectError == ZJU_ERROR::AUTH_EXPIRED || zjuConnectError == ZJU_ERROR::OTHER) &&
settings->value("Common/AutoReconnect", false).toBool() &&
isZjuConnectLinked
)
{
QTimer::singleShot(settings->value("Common/ReconnectTime", 1).toInt() * 1000, this, [&]()
{
if (isZjuConnectLinked)
connect(connectionSession, &ConnectionSession::reconnectScheduled, this, [&](int)
{
addLog("正在尝试重新连接...");
zjuConnectController->stop();
isZjuConnectLinked = false;
isAutoReconnecting = true;
ui->pushButton1->click();
}
});
return;
}
if (zjuConnectError != ZJU_ERROR::NONE)
connect(connectionSession, &ConnectionSession::finished, this, [&](ZJU_ERROR error)
{
addLog("VPN 断开!");
if (error != ZJU_ERROR::NONE)
{
showNotification("VPN", "VPN 意外断开!", QSystemTrayIcon::MessageIcon::Warning);
}
isZjuConnectLinked = false;
ui->pushButton1->setText("连接服务器");
trayConnectAction->setText("连接服务器");
if (isSystemProxySet)
@@ -202,7 +150,7 @@ void MainWindow::initZjuConnect()
}
ui->pushButton2->hide();
switch (zjuConnectError)
switch (error)
{
case ZJU_ERROR::INVALID_DETAIL:
QMessageBox::critical(this, "错误", "登录失败!\n请检查设置中的网络账号和密码是否设置正确。");
@@ -244,13 +192,12 @@ void MainWindow::initZjuConnect()
default:
break;
}
zjuConnectError = ZJU_ERROR::NONE;
});
connect(ui->pushButton1, &QPushButton::clicked,
[&]()
{
if (!isZjuConnectLinked)
if (!connectionSession->isActive())
{
if (settings->contains("ZJUConnect/ServerAddress") &&
settings->value("ZJUConnect/ServerAddress").toString().isEmpty())
@@ -281,22 +228,23 @@ void MainWindow::initZjuConnect()
#endif
auto startZjuConnect = [this](const QString &username, const QString &password) {
isZjuConnectLinked = true;
zjuConnectError = ZJU_ERROR::NONE;
ui->pushButton1->setText("断开服务器");
trayConnectAction->setText("断开服务器");
ui->pushButton2->show();
if (!isAutoReconnecting && settings->value("Common/AutoSetProxy", false).toBool())
if (settings->value("Common/AutoSetProxy", false).toBool())
{
ui->pushButton2->click();
}
isAutoReconnecting = false;
ConnectionProfile profile =
SettingsProfileLoader::load(*settings, currentProfileId, username, password);
profile.program = Utils::getCorePath();
zjuConnectController->start(profile);
const ReconnectPolicy reconnectPolicy{
settings->value("Common/AutoReconnect", false).toBool(),
settings->value("Common/ReconnectTime", 1).toInt() * 1000
};
connectionSession->start(profile, reconnectPolicy);
};
if (((protocol == "atrust" && authtype == "psw") ||
@@ -327,7 +275,7 @@ void MainWindow::initZjuConnect()
}
else
{
zjuConnectController->stop();
connectionSession->stop();
}
});
@@ -377,7 +325,7 @@ void MainWindow::initZjuConnect()
Utils::clearSystemProxy();
ui->pushButton2->setText("设置系统代理");
isSystemProxySet = false;
if (!isZjuConnectLinked)
if (!connectionSession->isActive())
{
ui->pushButton2->hide();
}