Rotate to another server on stuck proxy connection
- ProxyRotationController now probes VLESS+Reality servers with a real TCP latency check (the MTProto check always failed for them), so rotation can actually find a working server - Switching to a built-in VLESS server now starts Xray and points Telegram at the local SOCKS5 listener via XrayController.switchToBuiltinProxy, instead of pointing at the raw server address - Skip built-in servers that don't match the current network when rotating - Trigger rotation not only on ConnectingToProxy but also on prolonged Connecting/WaitingForNetwork states, covering the infinite-connecting case
This commit is contained in:
parent
cf44ff32b9
commit
a807fa9db6
2 changed files with 76 additions and 1 deletions
|
|
@ -31,6 +31,28 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
|
||||||
}
|
}
|
||||||
startedCheck = true;
|
startedCheck = true;
|
||||||
proxyInfo.checking = true;
|
proxyInfo.checking = true;
|
||||||
|
if (proxyInfo.isVless()) {
|
||||||
|
// VLESS+Reality servers don't speak the MTProto proxy protocol,
|
||||||
|
// so Telegram's checkProxy always fails. Use a real TCP-connect
|
||||||
|
// latency probe to the server endpoint instead.
|
||||||
|
final SharedConfig.ProxyInfo info = proxyInfo;
|
||||||
|
new Thread(() -> {
|
||||||
|
long latency = XrayController.measureTcpLatency(info.address, info.port, 4000);
|
||||||
|
AndroidUtilities.runOnUIThread(() -> {
|
||||||
|
info.availableCheckTime = SystemClock.elapsedRealtime();
|
||||||
|
info.checking = false;
|
||||||
|
if (latency < 0) {
|
||||||
|
info.available = false;
|
||||||
|
info.ping = 0;
|
||||||
|
} else {
|
||||||
|
info.ping = latency;
|
||||||
|
info.available = true;
|
||||||
|
}
|
||||||
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, info);
|
||||||
|
});
|
||||||
|
}, "vless-rotation-ping").start();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> {
|
proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> {
|
||||||
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime();
|
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime();
|
||||||
proxyInfo.checking = false;
|
proxyInfo.checking = false;
|
||||||
|
|
@ -69,6 +91,22 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
|
||||||
if (info == SharedConfig.currentProxy || info.checking || !info.available) {
|
if (info == SharedConfig.currentProxy || info.checking || !info.available) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Don't switch to a built-in server that doesn't match the current
|
||||||
|
// network (e.g. a Wi-Fi server while we're on mobile data).
|
||||||
|
if (info.builtin && !XrayController.matchesCurrentNetwork(info)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.builtin && info.isVless()) {
|
||||||
|
// Built-in VLESS proxy: start Xray and point Telegram at the
|
||||||
|
// local SOCKS5 listener. switchToBuiltinProxy persists the
|
||||||
|
// selection and applies the proxy settings itself.
|
||||||
|
SharedConfig.currentProxy = info;
|
||||||
|
XrayController.switchToBuiltinProxy(info);
|
||||||
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
|
||||||
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyChangedByRotation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit();
|
SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit();
|
||||||
editor.putString("proxy_ip", info.address);
|
editor.putString("proxy_ip", info.address);
|
||||||
|
|
@ -116,7 +154,13 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
|
||||||
|
|
||||||
int state = ConnectionsManager.getInstance(account).getConnectionState();
|
int state = ConnectionsManager.getInstance(account).getConnectionState();
|
||||||
|
|
||||||
if (state == ConnectionsManager.ConnectionStateConnectingToProxy) {
|
// Treat any prolonged "not connected" state as a stuck connection
|
||||||
|
// that should trigger a rotation to another server after the
|
||||||
|
// configured timeout. This covers the "infinite connecting" case
|
||||||
|
// where Telegram keeps trying a dead proxy without ever failing.
|
||||||
|
if (state == ConnectionsManager.ConnectionStateConnectingToProxy
|
||||||
|
|| state == ConnectionsManager.ConnectionStateConnecting
|
||||||
|
|| state == ConnectionsManager.ConnectionStateWaitingForNetwork) {
|
||||||
if (!isCurrentlyChecking) {
|
if (!isCurrentlyChecking) {
|
||||||
AndroidUtilities.runOnUIThread(checkProxyAndSwitchRunnable, ROTATION_TIMEOUTS.get(SharedConfig.proxyRotationTimeout) * 1000L);
|
AndroidUtilities.runOnUIThread(checkProxyAndSwitchRunnable, ROTATION_TIMEOUTS.get(SharedConfig.proxyRotationTimeout) * 1000L);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,37 @@ public class XrayController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** All built-in proxies that match the current network, in declaration order. */
|
||||||
|
public static java.util.List<SharedConfig.ProxyInfo> builtinProxiesForCurrentNetwork() {
|
||||||
|
java.util.List<SharedConfig.ProxyInfo> list = new java.util.ArrayList<>();
|
||||||
|
for (XrayServers.Server s : XrayServers.SERVERS) {
|
||||||
|
SharedConfig.ProxyInfo p = fromServer(s);
|
||||||
|
if (p != null && matchesCurrentNetwork(p)) list.add(p);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the active built-in proxy: (re)start Xray with the given server,
|
||||||
|
* persist the selection and point Telegram at the local SOCKS5 listener.
|
||||||
|
* Runs the heavy work on a background thread. Safe to call from any thread.
|
||||||
|
*/
|
||||||
|
public static void switchToBuiltinProxy(SharedConfig.ProxyInfo proxy) {
|
||||||
|
if (proxy == null || !proxy.isVless()) return;
|
||||||
|
final VlessConfig cfg = proxy.toVlessConfig();
|
||||||
|
new Thread(() -> {
|
||||||
|
boolean ok = start(cfg);
|
||||||
|
if (ok) {
|
||||||
|
SharedConfig.currentProxy = proxy;
|
||||||
|
persistBuiltinProxySelection(proxy);
|
||||||
|
try { Thread.sleep(300); } catch (InterruptedException ignored) {}
|
||||||
|
ConnectionsManager.setProxySettings(true, "127.0.0.1", cfg.localPort, "", "", "");
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "switchToBuiltinProxy: Xray failed to start for " + proxy.builtinName);
|
||||||
|
}
|
||||||
|
}, "xray-switch").start();
|
||||||
|
}
|
||||||
|
|
||||||
private static SharedConfig.ProxyInfo fromServer(XrayServers.Server s) {
|
private static SharedConfig.ProxyInfo fromServer(XrayServers.Server s) {
|
||||||
if (s == null || s.address == null || s.address.isEmpty()) return null;
|
if (s == null || s.address == null || s.address.isEmpty()) return null;
|
||||||
SharedConfig.ProxyInfo p = SharedConfig.ProxyInfo.createVless(
|
SharedConfig.ProxyInfo p = SharedConfig.ProxyInfo.createVless(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue