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