fix(vpn): arm bypass proactively on detected tunnel, drop post-failure fallback

This commit is contained in:
klockky
2026-07-14 12:31:23 +03:00
parent a87b61248c
commit 5f3ebb2ade
2 changed files with 7 additions and 31 deletions
+4 -28
View File
@@ -90,9 +90,6 @@ class Api {
int get sessionEpoch => _sessionEpoch; int get sessionEpoch => _sessionEpoch;
/// Залипает на время сессии: VPN-путь не сработал — идём мимо туннеля.
bool _bypassActive = false;
int _nextSeq() => _seq = (_seq + 1) & 0xFFFF; int _nextSeq() => _seq = (_seq + 1) & 0xFFFF;
// Публичное API // Публичное API
@@ -110,20 +107,17 @@ class Api {
_armConnectWatchdog(gen); _armConnectWatchdog(gen);
try { try {
bool bypassArmed; bool useBypass;
try { try {
bypassArmed = await VpnBypassService.instance.shouldArm().timeout( useBypass = await VpnBypassService.instance.shouldArm().timeout(
_shouldArmTimeout, _shouldArmTimeout,
); );
} catch (e) { } catch (e) {
logger.w('connect: shouldArm завис/упал ($e) — без обхода VPN'); logger.w('connect: shouldArm завис/упал ($e) — без обхода VPN');
bypassArmed = false; useBypass = false;
} }
if (gen != _connectGen) return; if (gen != _connectGen) return;
if (!bypassArmed) _bypassActive = false;
final useBypass = _bypassActive && bypassArmed;
({String host, int port}) endpoint; ({String host, int port}) endpoint;
try { try {
endpoint = await ServerConfig.loadEndpoint().timeout(_endpointTimeout); endpoint = await ServerConfig.loadEndpoint().timeout(_endpointTimeout);
@@ -168,13 +162,7 @@ class Api {
info = await session.connect(); info = await session.connect();
} catch (e) { } catch (e) {
if (gen != _connectGen) return; if (gen != _connectGen) return;
await _handleConnectFailure( await _handleConnectFailure(e, phase: 'Ошибка хэндшейка');
e,
phase: 'Ошибка хэндшейка',
bypassArmed: bypassArmed,
useBypass: useBypass,
bypassWhy: 'хэндшейк не прошёл',
);
return; return;
} finally { } finally {
if (useBypass) { if (useBypass) {
@@ -242,31 +230,19 @@ class Api {
Future<void> _handleConnectFailure( Future<void> _handleConnectFailure(
Object error, { Object error, {
required String phase, required String phase,
required bool bypassArmed,
required bool useBypass,
required String bypassWhy,
}) async { }) async {
logger.e('$phase: $error'); logger.e('$phase: $error');
_cancelConnectWatchdog(); _cancelConnectWatchdog();
if (_sessionState != SessionState.disconnected) { if (_sessionState != SessionState.disconnected) {
_cleanup(); _cleanup();
_setSessionState(SessionState.disconnected); _setSessionState(SessionState.disconnected);
_armBypassIfPossible(bypassArmed, useBypass, bypassWhy);
_scheduleReconnect(); _scheduleReconnect();
} }
} }
void _armBypassIfPossible(bool armed, bool alreadyBypassing, String why) {
if (armed && !alreadyBypassing && !_bypassActive) {
_bypassActive = true;
logger.w('VPN bypass: $why — следующая попытка мимо VPN');
}
}
/// Отключается без автореконнекта. /// Отключается без автореконнекта.
Future<void> disconnect() async { Future<void> disconnect() async {
_autoReconnect = false; _autoReconnect = false;
_bypassActive = false;
_connectGen++; _connectGen++;
_reconnectTimer?.cancel(); _reconnectTimer?.cancel();
_cleanup(); _cleanup();
+3 -3
View File
@@ -428,9 +428,9 @@ class KometAppState extends State<KometApp>
_vpnBypassSub = VpnBypassService.instance.events.listen((r) { _vpnBypassSub = VpnBypassService.instance.events.listen((r) {
final msg = r.bound final msg = r.bound
? 'Соединение через VPN не работает — ' ? 'Обход VPN включён — прямое подключение через '
'используется ${r.boundInterface ?? r.transport ?? 'прямое подключение'}' '${r.boundInterface ?? r.transport ?? 'сеть без VPN'}'
: 'Соединение через VPN не работает, обойти не удалось' : 'Обход VPN не удался, подключение через туннель'
'${r.reason != null ? ' (${r.reason})' : ''}'; '${r.reason != null ? ' (${r.reason})' : ''}';
final now = DateTime.now(); final now = DateTime.now();