This commit is contained in:
Arvin
2026-03-21 13:58:10 +08:00
parent f62ea80d43
commit dda67b180d
72 changed files with 848 additions and 1181 deletions

View File

@ -1,119 +1,214 @@
#!/bin/bash
resolve_clash_arch() {
local raw_arch="$1"
case "$raw_arch" in
x86_64|amd64)
echo "linux-amd64"
;;
aarch64|arm64)
echo "linux-arm64"
;;
armv7*|armv7l)
echo "linux-armv7"
;;
*)
echo "linux-${raw_arch}"
;;
x86_64|amd64) echo "linux-amd64" ;;
aarch64|arm64) echo "linux-arm64" ;;
armv7*|armv7l) echo "linux-armv7" ;;
*) echo "linux-${raw_arch}" ;;
esac
}
get_latest_mihomo_version() {
local url="https://api.github.com/repos/MetaCubeX/mihomo/releases/latest"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$url" \
| grep '"tag_name"' \
| sed -E 's/.*"([^"]+)".*/\1/' \
| head -n 1
elif command -v wget >/dev/null 2>&1; then
wget -qO- "$url" \
| grep '"tag_name"' \
| sed -E 's/.*"([^"]+)".*/\1/' \
| head -n 1
fi
}
download_clash_bin() {
local server_dir="$1"
local detected_arch="$2"
local resolved_arch
local version
local download_url
local download_target
local archive_file
local tmp_bin
resolved_arch="$(resolve_clash_arch "$detected_arch")"
resolved_arch=$(resolve_clash_arch "$detected_arch")
if [ -z "$resolved_arch" ]; then
echo -e "\033[33m[WARN] 无法识别 CPU 架构,跳过 Clash 内核自动下载\033[0m"
echo "[WARN] 无法识别 CPU 架构" >&2
return 1
fi
if [ "${CLASH_AUTO_DOWNLOAD:-auto}" = "false" ]; then
version="${MIHOMO_VERSION:-}"
if [ -z "$version" ]; then
version="$(get_latest_mihomo_version || true)"
fi
if [ -z "$version" ]; then
echo "[ERROR] 无法获取 Mihomo 版本" >&2
return 1
fi
local _default_url="https://github.com/Dreamacro/clash/releases/latest/download/clash-{arch}.gz"
download_url="${CLASH_DOWNLOAD_URL_TEMPLATE:-$_default_url}"
if [ -z "$download_url" ]; then
echo -e "\033[33m[WARN] 未设置 CLASH_DOWNLOAD_URL_TEMPLATE跳过 Clash 内核自动下载\033[0m"
if [ -z "${CLASH_DOWNLOAD_URL_TEMPLATE:-}" ]; then
echo "[ERROR] CLASH_DOWNLOAD_URL_TEMPLATE 未设置" >&2
return 1
fi
download_url="${download_url//\{arch\}/${resolved_arch}}"
download_url="${CLASH_DOWNLOAD_URL_TEMPLATE//\{arch\}/${resolved_arch}}"
download_url="${download_url//\{version\}/${version}}"
download_target="${server_dir}/bin/clash-${resolved_arch}"
archive_file="${server_dir}/temp/clash-${resolved_arch}.download"
archive_file="${server_dir}/runtime/.clash_download.tmp"
tmp_bin="${server_dir}/runtime/.clash_bin.tmp"
mkdir -p "${server_dir}/bin" "${server_dir}/temp"
mkdir -p "${server_dir}/bin" "${server_dir}/runtime"
rm -f "$archive_file" "$tmp_bin"
echo "[INFO] downloading: $download_url"
# =========================
# 下载
# =========================
if command -v curl >/dev/null 2>&1; then
curl -L -sS -o "${archive_file}" "${download_url}"
if ! curl -fL -sS -o "$archive_file" "$download_url"; then
echo "[ERROR] 下载失败: $download_url" >&2
return 1
fi
elif command -v wget >/dev/null 2>&1; then
wget -q -O "${archive_file}" "${download_url}"
if ! wget -q -O "$archive_file" "$download_url"; then
echo "[ERROR] 下载失败: $download_url" >&2
return 1
fi
else
echo -e "\033[33m[WARN] 未找到 curl 或 wget无法自动下载 Clash 内核\033[0m"
echo "[ERROR] 未找到 curl 或 wget" >&2
return 1
fi
if [ -f "${archive_file}" ]; then
if gzip -t "${archive_file}" >/dev/null 2>&1; then
gzip -dc "${archive_file}" >"${download_target}"
else
mv "${archive_file}" "${download_target}"
fi
chmod +x "${download_target}"
echo "${download_target}"
return 0
# =========================
# 基础校验(防 404 / HTML
# =========================
if [ ! -s "$archive_file" ]; then
echo "[ERROR] 下载文件为空" >&2
return 1
fi
echo -e "\033[33m[WARN] Clash 内核自动下载失败\033[0m"
return 1
if head -c 200 "$archive_file" | grep -qiE "not found|html"; then
echo "[ERROR] 下载内容疑似错误页面404/HTML" >&2
return 1
fi
# =========================
# 解压 / 直写
# =========================
if gzip -t "$archive_file" >/dev/null 2>&1; then
if ! gzip -dc "$archive_file" > "$tmp_bin"; then
echo "[ERROR] gzip 解压失败" >&2
return 1
fi
else
cp "$archive_file" "$tmp_bin"
fi
# =========================
# ELF 校验(关键)
# =========================
if ! file "$tmp_bin" | grep -q "ELF"; then
echo "[ERROR] 非有效 ELF 二进制" >&2
echo "[DEBUG] file result: $(file "$tmp_bin")" >&2
return 1
fi
chmod +x "$tmp_bin"
mv "$tmp_bin" "$download_target"
rm -f "$archive_file"
echo "[OK] downloaded: $download_target"
echo "$download_target"
}
resolve_clash_bin() {
local server_dir="$1"
local detected_arch="$2"
local resolved_arch
local candidates=()
local candidate
local downloaded_bin
local mode
if [ -n "${CLASH_BIN:-}" ]; then
if [ -x "$CLASH_BIN" ]; then
echo "$CLASH_BIN"
return 0
fi
echo -e "\033[31m[ERROR] CLASH_BIN 指定的文件不可执行: $CLASH_BIN\033[0m"
echo "[ERROR] CLASH_BIN 不可执行: $CLASH_BIN" >&2
return 1
fi
resolved_arch=$(resolve_clash_arch "$detected_arch")
resolved_arch="$(resolve_clash_arch "$detected_arch")"
if [ -n "$resolved_arch" ]; then
candidates+=("${server_dir}/bin/clash-${resolved_arch}")
fi
candidates+=(
"${server_dir}/bin/clash-${detected_arch}"
"${server_dir}/bin/clash"
)
for candidate in "${candidates[@]}"; do
if [ -x "$candidate" ]; then
echo "$candidate"
return 0
fi
done
mode="${CLASH_AUTO_DOWNLOAD:-auto}"
if downloaded_bin=$(download_clash_bin "$server_dir" "$detected_arch"); then
echo "$downloaded_bin"
return 0
fi
case "$mode" in
false)
for candidate in "${candidates[@]}"; do
if [ -x "$candidate" ]; then
echo "$candidate"
return 0
fi
done
;;
echo -e "\033[31m\n[ERROR] 未找到可用的 Clash 二进制。\033[0m"
echo -e "请将对应架构的二进制放入: $server_dir/bin/"
echo -e "可用命名示例: clash-${resolved_arch} 或 clash-${detected_arch}"
echo -e "或通过 CLASH_BIN 指定自定义路径。"
auto)
for candidate in "${candidates[@]}"; do
if [ -x "$candidate" ]; then
echo "$candidate"
return 0
fi
done
if downloaded_bin="$(download_clash_bin "$server_dir" "$detected_arch")"; then
echo "$downloaded_bin"
return 0
fi
;;
true)
if downloaded_bin="$(download_clash_bin "$server_dir" "$detected_arch")"; then
echo "$downloaded_bin"
return 0
fi
for candidate in "${candidates[@]}"; do
if [ -x "$candidate" ]; then
echo "$candidate"
return 0
fi
done
;;
*)
echo "[ERROR] CLASH_AUTO_DOWNLOAD 非法值: $mode" >&2
return 1
;;
esac
echo "[ERROR] 未找到可用 Mihomo 内核" >&2
echo "请放入: ${server_dir}/bin/" >&2
return 1
}
}