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;
|
||||
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.availableCheckTime = SystemClock.elapsedRealtime();
|
||||
proxyInfo.checking = false;
|
||||
|
|
@ -69,6 +91,22 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
|
|||
if (info == SharedConfig.currentProxy || info.checking || !info.available) {
|
||||
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();
|
||||
editor.putString("proxy_ip", info.address);
|
||||
|
|
@ -116,7 +154,13 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
|
|||
|
||||
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) {
|
||||
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) {
|
||||
if (s == null || s.address == null || s.address.isEmpty()) return null;
|
||||
SharedConfig.ProxyInfo p = SharedConfig.ProxyInfo.createVless(
|
||||
|
|
|
|||
Loading…
Reference in a new issue