fix: дождаться готовности proxy перед загрузкой подписок и списков

При обновлении sing-box Tachyon перезапускается, запускает sing-box
и сразу пытался загрузить списки/подписки через proxy 127.0.0.1:4534,
но sing-box ещё не принял соединения на этом порту.

Исправления:
- updates.uc: dns_probe_passed теперь проверяет TCP-доступность proxy
  вместо немедленного return true; ждёт до 30s (10 попыток по 3s)
- updates.uc: download_to_file при неудаче через proxy делает fallback
  на прямой download с bootstrap DNS 8.8.8.8/1.1.1.1
- cache.uc: get_subscription_download_proxy_address проверяет что proxy-порт
  реально принимает соединения, иначе переходит на прямой download
- cache.uc: download_subscription использует bootstrap DNS при прямом
  скачивании подписок (когда proxy недоступен или не настроен)
This commit is contained in:
Dushnilin
2026-08-10 18:10:36 +03:00
parent 6379361d40
commit f5929d24f8
3 changed files with 68 additions and 3 deletions
+50 -2
View File
@@ -2051,6 +2051,24 @@ function download_to_file(url, filepath, proxy_address) {
attempt++;
}
// If a service proxy was configured but all proxy attempts failed (e.g., the
// proxy port was not yet ready after a component update restart), retry once
// directly using bootstrap DNS. This prevents a temporarily unavailable proxy
// from permanently blocking list updates.
if (as_string(proxy_address) != "" && command_exists("curl")) {
log_message("Download via service proxy failed for " + as_string(candidate) + "; retrying directly with bootstrap DNS", "warn");
let fallback_args = [
"curl", "--connect-timeout", "5", "-m", "10", "-fsSL",
"--dns-servers", "8.8.8.8,1.1.1.1",
candidate, "-o", filepath
];
if (command_success_from_args(fallback_args) && file_nonempty(filepath)) {
if (candidate != url)
log_message("Successfully downloaded " + as_string(url) + " via mirror " + candidate + " (direct, proxy unavailable)", "info");
return true;
}
}
}
if (file_nonempty(filepath)) {
@@ -2663,10 +2681,40 @@ function list_update_pid_end() {
remove_file(LIST_UPDATE_PID_FILE);
}
function service_proxy_is_ready(proxy_address) {
// Probe the service proxy by attempting a connection through it to a
// well-known public IP (no DNS resolution required). If the port is not
// yet open — e.g., sing-box is still starting after a component update —
// curl returns exit 7 (CURLE_COULDNT_CONNECT) or 28 (timeout).
// Any other result means the port is accepting connections.
let status = command_status(
command_from_args([
"curl", "-s", "--connect-timeout", "2", "-m", "4",
"-x", "http://" + as_string(proxy_address),
"http://1.1.1.1/", "-o", "/dev/null"
]) + " 2>/dev/null"
);
return status != 7 && status != 28;
}
function dns_probe_passed(proxy_address) {
if (as_string(proxy_address) != "") {
log_message("DNS check skipped because list downloads use service proxy", "info");
return true;
// When a service proxy is configured, verify it is actually accepting
// TCP connections before proceeding — sing-box may still be starting
// up after a component update or restart and the proxy port may not be
// ready even though the process is already running.
let attempt = 1;
while (attempt <= 10) {
if (service_proxy_is_ready(proxy_address)) {
log_message("Service proxy is ready", "info");
return true;
}
log_message("Service proxy not yet ready [" + attempt + "/10]", "info");
command_success_from_args([ "sleep", "3" ]);
attempt++;
}
log_message("Service proxy is not accepting connections after 10 attempts; skipping list update", "info");
return false;
}
let attempt = 1;