fix: DNS петля + watchdog автоисправление + централизация file_is_usable

Ключевые изменения:

1. core/helpers.uc: file_is_usable(path, min_bytes) + file_size_value(path)
   для единообразной проверки файлов (минимальный размер порог).

2. singbox/dns.uc: WAN fallback DNS серверы (fallback_wan_main) теперь
   используют прямой UDP без detour — исправлена петля когда
   DNS шёл через мёртвую прокси-секцию.
   Health probes для ВСЕХ DNS серверов (включая DoH) идут direct —
   failover может определить доступность DNS серверов.

3. watchdog.uc: ai_heal_empty_sections() — автообнаружение пустых
   proxy-секций с подписками → запуск subscription_update_async.
   ai_heal_dns_loop() — при обнаружении DNS-петли (dead proxy +
   dead DNS) → временно отключает DNS detour → загружает подписку →
   восстанавливает настройки.

4. Единая file_is_usable: nft/apply.uc, generator_routes.uc,
   components/{updates,action}.uc, config/validator.uc,
   subscription/cache.uc — все используют helpers.file_is_usable.

5. Тест tests/file_usable.sh для проверки helpers CLI.

6. Исправлен components_updater_job.sh mock lib — добавлен core/helpers.uc
This commit is contained in:
Dushnilin
2026-08-03 14:07:57 +03:00
parent 9b956e1bb4
commit 5eef78b877
11 changed files with 279 additions and 25 deletions
+2
View File
@@ -191,6 +191,7 @@ package_runtime_bin="$WORK_DIR/package-runtime-bin"
mkdir -p "$package_runtime_lib/components" "$package_runtime_lib/core" "$package_runtime_lib/singbox" "$package_runtime_bin"
cp "$UPDATER" "$package_runtime_lib/components/updater.uc"
cp "$TACHYON_LIB/core/common.uc" "$package_runtime_lib/core/common.uc"
cp "$TACHYON_LIB/core/helpers.uc" "$package_runtime_lib/core/helpers.uc"
cat >"$package_runtime_lib/core/constants.uc" <<'UCODE'
function module_exports() {
return {};
@@ -380,6 +381,7 @@ cp "$UPDATES_UC" "$fake_lib/components/updates.uc"
cp "$TACHYON_LIB/config/connections.uc" "$fake_lib/config/connections.uc"
cp "$TACHYON_LIB/core/uci.uc" "$fake_lib/core/uci.uc"
cp "$TACHYON_LIB/core/common.uc" "$fake_lib/core/common.uc"
cp "$TACHYON_LIB/core/helpers.uc" "$fake_lib/core/helpers.uc"
cat >"$fake_lib/components/action.uc" <<'UCODE'
#!/usr/bin/env ucode
if ((ARGV[0] || "") == "component-action") {
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
HELPERS_UC="$ROOT_DIR/tachyon/files/usr/lib/core/helpers.uc"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
TMP_DIR="$ROOT_DIR/tmp_file_usable_test"
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
ucode() {
command ucode -L "$TACHYON_LIB" "$@"
}
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
assert() {
local expected="$1"
local actual="$2"
local label="$3"
[ "$actual" = "$expected" ] || fail "$label: expected '$expected', got '$actual'"
}
# --- file-is-usable CLI tests ---
# Nonexistent file
assert 1 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/nonexistent.srs" 100 2>/dev/null; echo $?)" "nonexistent file not usable"
# Empty file
touch "$TMP_DIR/empty.srs"
assert 1 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/empty.srs" 100 2>/dev/null; echo $?)" "empty file not usable"
# 1-byte file
printf x > "$TMP_DIR/1byte.srs"
assert 1 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/1byte.srs" 100 2>/dev/null; echo $?)" "1-byte file not usable at min 100"
# 49-byte file
dd if=/dev/urandom of="$TMP_DIR/49byte.srs" bs=1 count=49 2>/dev/null
assert 1 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/49byte.srs" 50 2>/dev/null; echo $?)" "49-byte file not usable at min 50"
assert 0 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/49byte.srs" 0 2>/dev/null; echo $?)" "49-byte file usable at min 0"
# 50-byte file
dd if=/dev/urandom of="$TMP_DIR/50byte.srs" bs=1 count=50 2>/dev/null
assert 0 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/50byte.srs" 50 2>/dev/null; echo $?)" "50-byte file usable at min 50"
# 100-byte file
dd if=/dev/urandom of="$TMP_DIR/100byte.srs" bs=1 count=100 2>/dev/null
assert 0 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/100byte.srs" 100 2>/dev/null; echo $?)" "100-byte file usable at min 100"
assert 1 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/100byte.srs" 200 2>/dev/null; echo $?)" "100-byte file not usable at min 200"
# No min_bytes = always usable if exists
assert 0 "$(ucode "$HELPERS_UC" file-is-usable "$TMP_DIR/1byte.srs" 2>/dev/null; echo $?)" "1-byte file usable with no min"
# --- file-size CLI tests ---
assert "-1" "$(ucode "$HELPERS_UC" file-size "$TMP_DIR/nonexistent.srs" 2>/dev/null)" "nonexistent file size is -1"
assert "0" "$(ucode "$HELPERS_UC" file-size "$TMP_DIR/empty.srs" 2>/dev/null)" "empty file size is 0"
assert "49" "$(ucode "$HELPERS_UC" file-size "$TMP_DIR/49byte.srs" 2>/dev/null)" "49-byte file size is 49"
assert "100" "$(ucode "$HELPERS_UC" file-size "$TMP_DIR/100byte.srs" 2>/dev/null)" "100-byte file size is 100"
# Clean up
rm -rf "$TMP_DIR"
printf 'file_usable checks passed\n'