mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
feat: add auto switch from AWG to Xray (only premium)
This commit is contained in:
@@ -436,6 +436,7 @@ bool SubscriptionUiController::updateServiceFromGateway(const QString &serverId,
|
|||||||
} else {
|
} else {
|
||||||
emit changeApiCountryFinished(tr("Successfully changed the country of connection to %1").arg(newCountryName));
|
emit changeApiCountryFinished(tr("Successfully changed the country of connection to %1").arg(newCountryName));
|
||||||
}
|
}
|
||||||
|
emit updateServiceFromGatewayCompleted(true, serverId);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (errorCode == ErrorCode::ApiSubscriptionExpiredError) {
|
if (errorCode == ErrorCode::ApiSubscriptionExpiredError) {
|
||||||
@@ -443,6 +444,7 @@ bool SubscriptionUiController::updateServiceFromGateway(const QString &serverId,
|
|||||||
} else {
|
} else {
|
||||||
emit errorOccurred(errorCode);
|
emit errorOccurred(errorCode);
|
||||||
}
|
}
|
||||||
|
emit updateServiceFromGatewayCompleted(false, serverId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ signals:
|
|||||||
void changeApiCountryFinished(const QString &message);
|
void changeApiCountryFinished(const QString &message);
|
||||||
void reloadServerFromApiFinished(const QString &message);
|
void reloadServerFromApiFinished(const QString &message);
|
||||||
void updateServerFromApiFinished();
|
void updateServerFromApiFinished();
|
||||||
|
void updateServiceFromGatewayCompleted(bool success, const QString &serverId);
|
||||||
void subscriptionRefreshNeeded();
|
void subscriptionRefreshNeeded();
|
||||||
|
|
||||||
void apiConfigRemoved(const QString &message);
|
void apiConfigRemoved(const QString &message);
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ void ConnectionUiController::onConnectionStateChanged(Vpn::ConnectionState state
|
|||||||
m_connectionStateText = tr("Connecting...");
|
m_connectionStateText = tr("Connecting...");
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case Vpn::ConnectionState::Connected: {
|
case Vpn::ConnectionState::Connected: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
amnApp->networkManager()->clearConnectionCache();
|
amnApp->networkManager()->clearConnectionCache();
|
||||||
|
|
||||||
m_isConnectionInProgress = false;
|
m_isConnectionInProgress = false;
|
||||||
@@ -69,54 +71,55 @@ void ConnectionUiController::onConnectionStateChanged(Vpn::ConnectionState state
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Connecting: {
|
case Vpn::ConnectionState::Connecting: {
|
||||||
{
|
checkAndStartAwgStateTimer();
|
||||||
const QString serverId = m_serversController->getDefaultServerId();
|
|
||||||
if (!serverId.isEmpty()) {
|
|
||||||
const DockerContainer container = m_serversController->getDefaultContainer(serverId);
|
|
||||||
const Proto proto = ContainerUtils::defaultProtocol(container);
|
|
||||||
if (proto == Proto::Awg) {
|
|
||||||
m_awgStateTimer.start(10000);
|
|
||||||
} else {
|
|
||||||
m_awgStateTimer.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_isConnectionInProgress = true;
|
m_isConnectionInProgress = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Reconnecting: {
|
case Vpn::ConnectionState::Reconnecting: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = true;
|
m_isConnectionInProgress = true;
|
||||||
m_connectionStateText = tr("Reconnecting...");
|
m_connectionStateText = tr("Reconnecting...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Disconnected: {
|
case Vpn::ConnectionState::Disconnected: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = false;
|
m_isConnectionInProgress = false;
|
||||||
m_connectionStateText = tr("Connect");
|
m_connectionStateText = tr("Connect");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Disconnecting: {
|
case Vpn::ConnectionState::Disconnecting: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = true;
|
m_isConnectionInProgress = true;
|
||||||
m_connectionStateText = tr("Disconnecting...");
|
m_connectionStateText = tr("Disconnecting...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Preparing: {
|
case Vpn::ConnectionState::Preparing: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = true;
|
m_isConnectionInProgress = true;
|
||||||
m_connectionStateText = tr("Preparing...");
|
m_connectionStateText = tr("Preparing...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Error: {
|
case Vpn::ConnectionState::Error: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = false;
|
m_isConnectionInProgress = false;
|
||||||
m_connectionStateText = tr("Connect");
|
m_connectionStateText = tr("Connect");
|
||||||
emit connectionErrorOccurred(getLastConnectionError());
|
emit connectionErrorOccurred(getLastConnectionError());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Vpn::ConnectionState::Unknown: {
|
case Vpn::ConnectionState::Unknown: {
|
||||||
m_awgStateTimer.stop();
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
m_isConnectionInProgress = false;
|
m_isConnectionInProgress = false;
|
||||||
m_connectionStateText = tr("Connect");
|
m_connectionStateText = tr("Connect");
|
||||||
emit connectionErrorOccurred(getLastConnectionError());
|
emit connectionErrorOccurred(getLastConnectionError());
|
||||||
@@ -167,6 +170,32 @@ bool ConnectionUiController::isConnected() const
|
|||||||
return m_isConnected;
|
return m_isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionUiController::checkAndStartAwgStateTimer()
|
||||||
|
{
|
||||||
|
const QString serverId = m_serversController->getDefaultServerId();
|
||||||
|
if (serverId.isEmpty()) {
|
||||||
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DockerContainer container = m_serversController->getDefaultContainer(serverId);
|
||||||
|
const Proto proto = ContainerUtils::defaultProtocol(container);
|
||||||
|
if (proto == Proto::Awg) {
|
||||||
|
const auto v2Config = m_serversController->apiV2Config(serverId);
|
||||||
|
if (v2Config.has_value() && v2Config->isPremium()) {
|
||||||
|
if (!m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.start(10000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_awgStateTimer.isActive()) {
|
||||||
|
m_awgStateTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionUiController::onAwgStateTimeout()
|
void ConnectionUiController::onAwgStateTimeout()
|
||||||
{
|
{
|
||||||
if (m_state != Vpn::ConnectionState::Connecting) {
|
if (m_state != Vpn::ConnectionState::Connecting) {
|
||||||
@@ -184,22 +213,48 @@ void ConnectionUiController::onAwgStateTimeout()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMap<DockerContainer, ContainerConfig> containersMap = m_serversController->getServerContainersMap(serverId);
|
closeConnection();
|
||||||
if (!containersMap.contains(DockerContainer::Xray)) {
|
|
||||||
qDebug().noquote() << "AWG connect timeout: no Xray container available";
|
QTimer::singleShot(1000, this, [this, serverId]() {
|
||||||
|
if (m_isConnected || m_isConnectionInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug().noquote() << "AWG connect timeout: trying to switch API protocol to VLESS and reload config from gateway";
|
||||||
|
|
||||||
|
m_pendingApiServerId = serverId;
|
||||||
|
m_apiSwitched = false;
|
||||||
|
m_waitingForApiUpdate = true;
|
||||||
|
|
||||||
|
emit requestSetCurrentProtocol(QStringLiteral("vless"));
|
||||||
|
emit requestUpdateServiceFromGateway(serverId, QString(), QString(), true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionUiController::onUpdateServiceFromGatewayCompleted(bool success, const QString &serverId)
|
||||||
|
{
|
||||||
|
if (!m_waitingForApiUpdate || m_pendingApiServerId != serverId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug().noquote() << "AWG connect timeout (10s), switching default container to Xray and reconnecting";
|
m_waitingForApiUpdate = false;
|
||||||
|
m_apiSwitched = success;
|
||||||
|
|
||||||
m_serversController->setDefaultContainer(serverId, DockerContainer::Xray);
|
if (success) {
|
||||||
emit requestSetCurrentProtocol(QStringLiteral("vless"));
|
const QMap<DockerContainer, ContainerConfig> containersMap = m_serversController->getServerContainersMap(serverId);
|
||||||
|
if (containersMap.contains(DockerContainer::Xray)) {
|
||||||
|
qDebug().noquote() << "AWG connect timeout (10s), switching default container to Xray and reconnecting";
|
||||||
|
m_serversController->setDefaultContainer(serverId, DockerContainer::Xray);
|
||||||
|
m_pendingApiServerId.clear();
|
||||||
|
|
||||||
closeConnection();
|
if (!m_isConnected && !m_isConnectionInProgress) {
|
||||||
|
emit prepareConfig();
|
||||||
QTimer::singleShot(500, this, [this]() {
|
}
|
||||||
if (!m_isConnected && !m_isConnectionInProgress) {
|
return;
|
||||||
emit prepareConfig();
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
qDebug().noquote() << "AWG connect timeout: no Xray available (API switch success ="
|
||||||
|
<< (m_apiSwitched ? "YES" : "NO") << ")";
|
||||||
|
m_pendingApiServerId.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ public slots:
|
|||||||
|
|
||||||
void onTranslationsUpdated();
|
void onTranslationsUpdated();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void checkAndStartAwgStateTimer();
|
||||||
|
void onUpdateServiceFromGatewayCompleted(bool success, const QString &serverId);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onAwgStateTimeout();
|
void onAwgStateTimeout();
|
||||||
|
|
||||||
@@ -54,6 +58,8 @@ signals:
|
|||||||
void prepareConfig();
|
void prepareConfig();
|
||||||
|
|
||||||
void requestSetCurrentProtocol(const QString &protocol);
|
void requestSetCurrentProtocol(const QString &protocol);
|
||||||
|
void requestUpdateServiceFromGateway(const QString &serverId, const QString &newCountryCode,
|
||||||
|
const QString &newCountryName, bool reloadServiceConfig);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vpn::ConnectionState getCurrentConnectionState();
|
Vpn::ConnectionState getCurrentConnectionState();
|
||||||
@@ -67,6 +73,10 @@ private:
|
|||||||
QString m_connectionStateText = tr("Connect");
|
QString m_connectionStateText = tr("Connect");
|
||||||
|
|
||||||
Vpn::ConnectionState m_state;
|
Vpn::ConnectionState m_state;
|
||||||
|
|
||||||
|
QString m_pendingApiServerId;
|
||||||
|
bool m_apiSwitched = false;
|
||||||
|
bool m_waitingForApiUpdate = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user