mirror of
https://github.com/chenx-dust/EZ4Connect.git
synced 2026-09-20 10:23:33 +08:00
feat: 改进的状态指示
This commit is contained in:
@@ -21,7 +21,11 @@ ConnectionSession::ConnectionSession(CoreProcess *coreProcess, QObject *parent)
|
||||
});
|
||||
connect(coreProcess, &CoreProcess::started, this, [this]()
|
||||
{
|
||||
sessionState.processStarted();
|
||||
emit stateChanged(sessionState.state());
|
||||
});
|
||||
connect(coreProcess, &CoreProcess::connectionEstablished, this, [this]()
|
||||
{
|
||||
sessionState.connectionEstablished();
|
||||
emit stateChanged(sessionState.state());
|
||||
});
|
||||
connect(coreProcess, &CoreProcess::finished,
|
||||
|
||||
@@ -30,6 +30,7 @@ signals:
|
||||
void ssoAuth();
|
||||
void askSudoPass();
|
||||
void started();
|
||||
void connectionEstablished();
|
||||
void finished();
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ bool ConnectionSessionState::requestStart(const ReconnectPolicy &policy)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConnectionSessionState::processStarted()
|
||||
void ConnectionSessionState::connectionEstablished()
|
||||
{
|
||||
if (currentState == ConnectionState::Starting)
|
||||
{
|
||||
@@ -76,6 +76,7 @@ bool ConnectionSessionState::requestStop()
|
||||
|
||||
ProcessFinishAction ConnectionSessionState::processFinished()
|
||||
{
|
||||
const bool connectionWasEstablished = currentState == ConnectionState::Running;
|
||||
if (desiredConnected
|
||||
&& reconnectPolicy.enabled
|
||||
&& isReconnectable(currentError))
|
||||
@@ -85,9 +86,16 @@ ProcessFinishAction ConnectionSessionState::processFinished()
|
||||
}
|
||||
|
||||
desiredConnected = false;
|
||||
currentState = currentError == ZJU_ERROR::NONE
|
||||
? ConnectionState::Disconnected
|
||||
: ConnectionState::Failed;
|
||||
if (connectionWasEstablished)
|
||||
{
|
||||
currentState = ConnectionState::Interrupted;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentState = currentError == ZJU_ERROR::NONE
|
||||
? ConnectionState::Disconnected
|
||||
: ConnectionState::Failed;
|
||||
}
|
||||
return ProcessFinishAction::Complete;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ enum class ConnectionState
|
||||
Running,
|
||||
Stopping,
|
||||
Reconnecting,
|
||||
Interrupted,
|
||||
Failed,
|
||||
};
|
||||
|
||||
@@ -35,7 +36,7 @@ public:
|
||||
int reconnectDelayMs() const;
|
||||
|
||||
bool requestStart(const ReconnectPolicy &policy);
|
||||
void processStarted();
|
||||
void connectionEstablished();
|
||||
void recordError(ZJU_ERROR error);
|
||||
bool requestStop();
|
||||
ProcessFinishAction processFinished();
|
||||
|
||||
@@ -26,6 +26,10 @@ CoreOutputEvent CoreOutputParser::parse(const QString &output)
|
||||
{
|
||||
return CoreOutputEvent::SsoCallback;
|
||||
}
|
||||
if (output.contains("VPN client started"))
|
||||
{
|
||||
return CoreOutputEvent::ClientStarted;
|
||||
}
|
||||
if (output.contains("graph check code still required after second login attempt") ||
|
||||
output.contains("The characters are incorrect or has expired!"))
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ enum class CoreOutputEvent
|
||||
SmsCode,
|
||||
TotpCode,
|
||||
SsoCallback,
|
||||
ClientStarted,
|
||||
CaptchaFailed,
|
||||
AccessDenied,
|
||||
ListenFailed,
|
||||
|
||||
@@ -104,6 +104,9 @@ void ZjuConnectProcess::processOutputLines(const QList<QByteArray> &lines)
|
||||
case CoreOutputEvent::SsoCallback:
|
||||
emit ssoAuth();
|
||||
break;
|
||||
case CoreOutputEvent::ClientStarted:
|
||||
emit connectionEstablished();
|
||||
break;
|
||||
case CoreOutputEvent::CaptchaFailed:
|
||||
emit error(ZJU_ERROR::CAPTCHA_FAILED);
|
||||
break;
|
||||
|
||||
@@ -133,7 +133,10 @@ ConnectionUiController::ConnectionUiController(
|
||||
this->connectButton->setText("连接服务器");
|
||||
this->trayConnectAction->setText("连接服务器");
|
||||
this->proxyButton->hide();
|
||||
showConnectionError(error);
|
||||
if (this->connectionSession->state() != ConnectionState::Interrupted)
|
||||
{
|
||||
showConnectionError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
connect(
|
||||
|
||||
@@ -482,6 +482,11 @@ void MainWindow::updateConnectionState(ConnectionState state)
|
||||
title = "正在重连";
|
||||
detail = "连接中断,正在按当前策略重新尝试。";
|
||||
break;
|
||||
case ConnectionState::Interrupted:
|
||||
propertyValue = "failed";
|
||||
title = "连接已断开";
|
||||
detail = "VPN 核心意外退出,请查看右侧日志。";
|
||||
break;
|
||||
case ConnectionState::Failed:
|
||||
propertyValue = "failed";
|
||||
title = "连接失败";
|
||||
|
||||
@@ -76,7 +76,7 @@ QMenu::item:selected {
|
||||
}
|
||||
|
||||
#statusIndicator[connectionState="running"] {
|
||||
background: #55b9e7;
|
||||
background: #5acb83;
|
||||
}
|
||||
|
||||
#statusIndicator[connectionState="stopping"] {
|
||||
|
||||
@@ -76,7 +76,7 @@ QMenu::item:selected {
|
||||
}
|
||||
|
||||
#statusIndicator[connectionState="running"] {
|
||||
background: #278bb9;
|
||||
background: #2e8b57;
|
||||
}
|
||||
|
||||
#statusIndicator[connectionState="stopping"] {
|
||||
|
||||
@@ -33,6 +33,11 @@ public:
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void establishConnection()
|
||||
{
|
||||
emit connectionEstablished();
|
||||
}
|
||||
|
||||
void requestSudoPassword()
|
||||
{
|
||||
emit askSudoPass();
|
||||
@@ -53,7 +58,7 @@ bool delegatesProcessLifecycleThroughPort()
|
||||
|
||||
if (!session.start(profile, {})
|
||||
|| coreProcess->startCalls != 1
|
||||
|| session.state() != ConnectionState::Running
|
||||
|| session.state() != ConnectionState::Starting
|
||||
|| !session.isActive()
|
||||
|| session.start(profile, {}))
|
||||
{
|
||||
@@ -61,6 +66,13 @@ bool delegatesProcessLifecycleThroughPort()
|
||||
return false;
|
||||
}
|
||||
|
||||
coreProcess->establishConnection();
|
||||
if (session.state() != ConnectionState::Running)
|
||||
{
|
||||
qCritical() << "connection establishment was not reflected";
|
||||
return false;
|
||||
}
|
||||
|
||||
session.submitInput("input");
|
||||
session.stop();
|
||||
if (coreProcess->lastInput != "input"
|
||||
@@ -82,6 +94,25 @@ bool delegatesProcessLifecycleThroughPort()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool distinguishesInterruptedConnectionFromStartupFailure()
|
||||
{
|
||||
auto *coreProcess = new FakeCoreProcess();
|
||||
ConnectionSession session(coreProcess);
|
||||
ConnectionProfile profile;
|
||||
|
||||
session.start(profile, {});
|
||||
coreProcess->establishConnection();
|
||||
emit coreProcess->error(ZJU_ERROR::OTHER);
|
||||
coreProcess->complete();
|
||||
|
||||
if (session.state() != ConnectionState::Interrupted)
|
||||
{
|
||||
qCritical() << "established connection was reported as startup failure";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emptySudoPasswordStopsTheSession()
|
||||
{
|
||||
auto *coreProcess = new FakeCoreProcess();
|
||||
@@ -133,6 +164,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication application(argc, argv);
|
||||
return delegatesProcessLifecycleThroughPort()
|
||||
&& distinguishesInterruptedConnectionFromStartupFailure()
|
||||
&& emptySudoPasswordStopsTheSession()
|
||||
&& cancelledInteractiveInputSubmitsNewlineBeforeStopping() ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ bool normalLifecycle()
|
||||
return false;
|
||||
}
|
||||
|
||||
session.processStarted();
|
||||
session.connectionEstablished();
|
||||
if (session.state() != ConnectionState::Running)
|
||||
{
|
||||
qCritical() << "normalLifecycle failed at running";
|
||||
@@ -43,7 +43,7 @@ bool reconnectsOnlyEligibleFailures()
|
||||
{
|
||||
ConnectionSessionState session;
|
||||
session.requestStart({true, 2500});
|
||||
session.processStarted();
|
||||
session.connectionEstablished();
|
||||
session.recordError(ZJU_ERROR::AUTH_EXPIRED);
|
||||
|
||||
if (session.processFinished() != ProcessFinishAction::Reconnect
|
||||
@@ -61,7 +61,6 @@ bool reconnectsOnlyEligibleFailures()
|
||||
return false;
|
||||
}
|
||||
|
||||
session.processStarted();
|
||||
session.recordError(ZJU_ERROR::INVALID_DETAIL);
|
||||
if (session.processFinished() != ProcessFinishAction::Complete
|
||||
|| session.state() != ConnectionState::Failed)
|
||||
@@ -76,7 +75,7 @@ bool keepsFirstErrorAndCancelsPendingReconnect()
|
||||
{
|
||||
ConnectionSessionState session;
|
||||
session.requestStart({true, 1000});
|
||||
session.processStarted();
|
||||
session.connectionEstablished();
|
||||
session.recordError(ZJU_ERROR::AUTH_EXPIRED);
|
||||
session.recordError(ZJU_ERROR::OTHER);
|
||||
if (session.error() != ZJU_ERROR::AUTH_EXPIRED)
|
||||
@@ -95,6 +94,22 @@ bool keepsFirstErrorAndCancelsPendingReconnect()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool establishedConnectionEndsAsInterrupted()
|
||||
{
|
||||
ConnectionSessionState session;
|
||||
session.requestStart({false, 1000});
|
||||
session.connectionEstablished();
|
||||
session.recordError(ZJU_ERROR::OTHER);
|
||||
|
||||
if (session.processFinished() != ProcessFinishAction::Complete
|
||||
|| session.state() != ConnectionState::Interrupted)
|
||||
{
|
||||
qCritical() << "establishedConnectionEndsAsInterrupted failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -103,6 +118,7 @@ int main(int argc, char *argv[])
|
||||
return normalLifecycle()
|
||||
&& reconnectsOnlyEligibleFailures()
|
||||
&& keepsFirstErrorAndCancelsPendingReconnect()
|
||||
&& establishedConnectionEndsAsInterrupted()
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ bool recognizesCoreProtocol()
|
||||
{"Please enter your SMS code:", CoreOutputEvent::SmsCode},
|
||||
{"Please enter your TOTP code:", CoreOutputEvent::TotpCode},
|
||||
{"Please enter the callback url:", CoreOutputEvent::SsoCallback},
|
||||
{"VPN client started", CoreOutputEvent::ClientStarted},
|
||||
{"graph check code still required after second login attempt", CoreOutputEvent::CaptchaFailed},
|
||||
{"Access is denied.", CoreOutputEvent::AccessDenied},
|
||||
{"listen failed on 127.0.0.1", CoreOutputEvent::ListenFailed},
|
||||
|
||||
Reference in New Issue
Block a user