feat(diagnostics): автоматическая загрузка и обновление профилей сервисов из репозитория с зеркалами и правами доступа

This commit is contained in:
Dushnilin
2026-08-16 15:07:07 +03:00
parent 18be28ec03
commit 61b34bb949
2 changed files with 107 additions and 6 deletions
@@ -202,17 +202,107 @@ function number_value(value) {
} }
function temp_path(suffix) { function temp_path(suffix) {
return sprintf("/tmp/.forkop-sc-%d-%d.%s", now_seconds(), int(now_ms() % 1000000), as_string(suffix)); return sprintf("/tmp/.tachyon-sc-%d-%d.%s", now_seconds(), int(now_ms() % 1000000), as_string(suffix));
} }
function ensure_state_dir() { function ensure_state_dir() {
run_quiet([ "mkdir", "-p", STATE_DIR ]); run_quiet([ "mkdir", "-p", STATE_DIR ]);
} }
function download_profiles_from_repo() {
const RAW_URL = "https://raw.githubusercontent.com/Dushnilin/tachyon/main/tachyon/files/usr/share/tachyon/servicecheck_profiles.json";
const MIRRORS = [
RAW_URL,
"https://gh-proxy.com/" + RAW_URL,
"https://ghfast.top/" + RAW_URL,
"https://ghproxy.net/" + RAW_URL
];
let proxy_address = trim(as_string(common.command_output("/usr/lib/tachyon/singbox/runtime.uc service-proxy-address components 2>/dev/null") || ""));
let content = "";
for (let mirror in MIRRORS) {
// 1. Попытка через локальный прокси
if (proxy_address != "") {
let proxy_cmd = [ "curl", "-sS", "-x", "http://" + proxy_address, "--connect-timeout", "5", "--max-time", "15", "-L", mirror ];
if (!command_exists("curl")) {
proxy_cmd = [ "uclient-fetch", "-q", "-O", "-", "--timeout=15", mirror ];
}
let res = capture_args(proxy_cmd, false);
if (res.status == 0 && length(trim(res.output)) > 100 && index(res.output, "profiles") >= 0) {
content = res.output;
break;
}
}
// 2. Прямое скачивание
let direct_cmd = [ "curl", "-sS", "--connect-timeout", "5", "--max-time", "15", "-L", mirror ];
if (!command_exists("curl")) {
direct_cmd = [ "uclient-fetch", "-q", "-O", "-", "--timeout=15", mirror ];
}
let res = capture_args(direct_cmd, false);
if (res.status == 0 && length(trim(res.output)) > 100 && index(res.output, "profiles") >= 0) {
content = res.output;
break;
}
}
if (content == "")
return null;
let parsed = parse_json(content);
if (type(parsed) != "object" || type(parsed.profiles) != "array" || length(parsed.profiles) == 0)
return null;
// Сохранение в /usr/share/tachyon или /etc/tachyon
let target_file = PROFILES_DEFAULT;
let target_dir = "/usr/share/tachyon";
run_quiet([ "mkdir", "-p", target_dir ]);
let tmp = target_file + ".tmp";
if (fs.stat(target_dir) == null || fs.writefile(tmp, content) == null) {
target_file = PROFILES_OVERRIDE;
target_dir = "/etc/tachyon";
run_quiet([ "mkdir", "-p", target_dir ]);
tmp = target_file + ".tmp";
if (fs.writefile(tmp, content) == null) {
return null;
}
}
run_quiet([ "mv", "-f", tmp, target_file ]);
run_quiet([ "chmod", "0644", target_file ]);
return content;
}
function load_profiles_data() {
let override = getenv("TACHYON_SC_PROFILES") || getenv("FORKOP_SC_PROFILES");
if (as_string(override) != "") {
let data = fs.readfile(as_string(override));
if (data != null && length(trim(data)) > 0) return data;
}
if (fs.stat(PROFILES_OVERRIDE) != null) {
let data = fs.readfile(PROFILES_OVERRIDE);
if (data != null && length(trim(data)) > 0) return data;
}
if (fs.stat(PROFILES_DEFAULT) != null) {
let data = fs.readfile(PROFILES_DEFAULT);
if (data != null && length(trim(data)) > 0) return data;
}
return download_profiles_from_repo();
}
function profiles_file() { function profiles_file() {
let override = getenv("FORKOP_SC_PROFILES"); let override = getenv("TACHYON_SC_PROFILES") || getenv("FORKOP_SC_PROFILES");
if (as_string(override) != "") if (as_string(override) != "")
return as_string(override); return as_string(override);
if (fs.stat(PROFILES_OVERRIDE) != null)
return PROFILES_OVERRIDE;
if (fs.stat(PROFILES_DEFAULT) != null)
return PROFILES_DEFAULT;
download_profiles_from_repo();
if (fs.stat(PROFILES_OVERRIDE) != null) if (fs.stat(PROFILES_OVERRIDE) != null)
return PROFILES_OVERRIDE; return PROFILES_OVERRIDE;
return PROFILES_DEFAULT; return PROFILES_DEFAULT;
@@ -1826,7 +1916,7 @@ function gemini_key_status() {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function tachyon_get_targets(all_mode) { function tachyon_get_targets(all_mode) {
let all_profiles_json = fs.readfile(PROFILES_OVERRIDE) || fs.readfile(PROFILES_DEFAULT); let all_profiles_json = load_profiles_data();
let all_profiles = object_or_empty(parse_json(all_profiles_json)); let all_profiles = object_or_empty(parse_json(all_profiles_json));
if (type(all_profiles.profiles) != "array") all_profiles.profiles = []; if (type(all_profiles.profiles) != "array") all_profiles.profiles = [];
let profiles_map = {}; let profiles_map = {};
@@ -2074,6 +2164,17 @@ if (mode == "get-targets") {
expect: [200, 301, 302, 307, 400, 403, 404, 405, 426] expect: [200, 301, 302, 307, 400, 403, 404, 405, 426]
}; };
tachyon_check_target(sprintf("%J", custom_target)); tachyon_check_target(sprintf("%J", custom_target));
} else if (mode == "update-profiles" || mode == "download-profiles") {
let data = download_profiles_from_repo();
let parsed = object_or_empty(parse_json(data));
let count = length(array_or_empty(parsed.profiles));
write_json({ success: data != null, count: count, message: data != null ? "Профили успешно загружены и обновлены" : "Не удалось загрузить профили" });
} else if (mode == "get-profiles") {
profiles_get();
} else if (mode == "save-profiles" && ARGV[1]) {
profiles_save(ARGV[1]);
} else if (mode == "reset-profiles") {
profiles_reset();
} else { } else {
warn("Unknown mode: ", mode, "\n"); warn("Unknown mode: ", mode, "\n");
exit(1); exit(1);
+3 -3
View File
@@ -19,8 +19,8 @@ targets_json="$(ucode -L "$TACHYON_LIB" "$SERVICE_CHECK_UC" get-targets)"
targets_all_json="$(ucode -L "$TACHYON_LIB" "$SERVICE_CHECK_UC" get-targets all)" targets_all_json="$(ucode -L "$TACHYON_LIB" "$SERVICE_CHECK_UC" get-targets all)"
[ -n "$targets_all_json" ] || fail "service_check get-targets all returned empty output" [ -n "$targets_all_json" ] || fail "service_check get-targets all returned empty output"
# 3. Test check-custom parses and returns structured result # 4. Test get-profiles
check_json="$(ucode -L "$TACHYON_LIB" "$SERVICE_CHECK_UC" check-custom 127.0.0.1 2>/dev/null || true)" profiles_json="$(ucode -L "$TACHYON_LIB" "$SERVICE_CHECK_UC" get-profiles)"
[ -n "$check_json" ] || fail "service_check check-custom returned empty output" [ -n "$profiles_json" ] || fail "service_check get-profiles returned empty output"
printf 'service check diagnostics passed\n' printf 'service check diagnostics passed\n'