feat: 一条 curl 自动装/升(未装安装、已装升级)
This commit is contained in:
Executable
+256
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env bash
|
||||
# 仅下载/安装 sing-box(轻量核心)
|
||||
# 优先级:local → 系统已有 → Gitea Release(整包/分片)→ GitHub 代理 → 直连 GitHub
|
||||
set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT_DIR/scripts/lib.sh"
|
||||
load_config
|
||||
need_root
|
||||
ensure_dirs
|
||||
mkdir -p /var/lib/cellular-proxy
|
||||
|
||||
ARCH="$(arch_go)"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
GITHUB_PROXY="${GITHUB_PROXY:-https://git.86482425.xyz}"
|
||||
GITEA_BASE="${GITEA_BASE:-https://gitea.chickliu.fun}"
|
||||
GITEA_OWNER="${GITEA_OWNER:-Hermes}"
|
||||
GITEA_REPO="${GITEA_REPO:-cellular-proxy}"
|
||||
SING_BOX_RELEASE_TAG="${SING_BOX_RELEASE_TAG:-bin-v${SING_BOX_VERSION}}"
|
||||
# gitea | github | auto | local | release
|
||||
SING_BOX_SOURCE="${SING_BOX_SOURCE:-auto}"
|
||||
|
||||
github_url() {
|
||||
local raw="$1"
|
||||
local proxy="${GITHUB_PROXY:-}"
|
||||
if [[ -z "$proxy" ]]; then
|
||||
echo "$raw"
|
||||
return
|
||||
fi
|
||||
proxy="${proxy%/}"
|
||||
case "$raw" in
|
||||
"${proxy}"/*) echo "$raw"; return ;;
|
||||
esac
|
||||
echo "${proxy}/${raw}"
|
||||
}
|
||||
|
||||
download() {
|
||||
local url="$1" dest="$2"
|
||||
info "下载: $url"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fL --retry 3 --connect-timeout 20 --max-time 300 -o "$dest" "$url"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -O "$dest" "$url"
|
||||
else
|
||||
die "需要 curl 或 wget"
|
||||
fi
|
||||
}
|
||||
|
||||
# 静默探测 URL 是否可下(不写盘)
|
||||
url_ok() {
|
||||
local url="$1"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSIL --connect-timeout 8 --max-time 20 -o /dev/null "$url" 2>/dev/null
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
download_github() {
|
||||
local raw="$1" dest="$2"
|
||||
local proxied
|
||||
proxied="$(github_url "$raw")"
|
||||
if [[ "$proxied" != "$raw" ]]; then
|
||||
info "经 GitHub 代理下载: $proxied"
|
||||
if download "$proxied" "$dest"; then
|
||||
return 0
|
||||
fi
|
||||
warn "代理下载失败,尝试直连 GitHub: $raw"
|
||||
fi
|
||||
download "$raw" "$dest"
|
||||
}
|
||||
|
||||
install_from_tarball() {
|
||||
local tgz="$1" ver="$2" arch="$3"
|
||||
local name="sing-box-${ver}-linux-${arch}"
|
||||
tar -xzf "$tgz" -C "$TMP"
|
||||
if [[ -x "$TMP/${name}/sing-box" ]]; then
|
||||
install -m 0755 "$TMP/${name}/sing-box" "$INSTALL_DIR/bin/sing-box"
|
||||
elif [[ -x "$TMP/sing-box" ]]; then
|
||||
install -m 0755 "$TMP/sing-box" "$INSTALL_DIR/bin/sing-box"
|
||||
else
|
||||
local found
|
||||
found="$(find "$TMP" -type f -name sing-box 2>/dev/null | head -1)"
|
||||
[[ -n "$found" && -x "$found" ]] || die "压缩包内未找到 sing-box 可执行文件"
|
||||
install -m 0755 "$found" "$INSTALL_DIR/bin/sing-box"
|
||||
fi
|
||||
}
|
||||
|
||||
gitea_asset_url() {
|
||||
local fname="$1"
|
||||
echo "${GITEA_BASE%/}/${GITEA_OWNER}/${GITEA_REPO}/releases/download/${SING_BOX_RELEASE_TAG}/${fname}"
|
||||
}
|
||||
|
||||
# 从 Gitea 拉整包 tar.gz
|
||||
try_download_gitea_whole() {
|
||||
local ver="$1" arch="$2" dest="$3"
|
||||
local name url
|
||||
name="sing-box-${ver}-linux-${arch}.tar.gz"
|
||||
url="$(gitea_asset_url "$name")"
|
||||
info "尝试 Gitea 预置整包: $url"
|
||||
if download "$url" "$dest"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# 代理 504 时可能只提供分片:name.tar.gz.part-00.. + name.tar.gz.SHA256SUMS
|
||||
try_download_gitea_parts() {
|
||||
local ver="$1" arch="$2" dest="$3"
|
||||
local base name sums_url part_url part_dir i max
|
||||
name="sing-box-${ver}-linux-${arch}.tar.gz"
|
||||
base="${GITEA_BASE%/}/${GITEA_OWNER}/${GITEA_REPO}/releases/download/${SING_BOX_RELEASE_TAG}"
|
||||
sums_url="${base}/${name}.SHA256SUMS"
|
||||
# 兼容旧名 SHA256SUMS(仅 armv7 曾用)
|
||||
part_dir="$TMP/parts_${arch}"
|
||||
mkdir -p "$part_dir"
|
||||
|
||||
if download "$sums_url" "$part_dir/SHA256SUMS" 2>/dev/null; then
|
||||
info "发现分片清单: $sums_url"
|
||||
elif [[ "$arch" == "armv7" ]] && download "$(gitea_asset_url SHA256SUMS)" "$part_dir/SHA256SUMS" 2>/dev/null; then
|
||||
info "使用兼容清单 SHA256SUMS"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 从清单提取 part 文件名(去掉路径前缀)
|
||||
mapfile -t parts < <(awk '{print $2}' "$part_dir/SHA256SUMS" | sed 's|^\./||' | grep -E '\.part-[0-9]+$' || true)
|
||||
if [[ ${#parts[@]} -eq 0 ]]; then
|
||||
# 无清单文件名时按 part-00..99 探测
|
||||
parts=()
|
||||
for i in $(seq -w 0 99); do
|
||||
part_url="${base}/${name}.part-${i}"
|
||||
if url_ok "$part_url"; then
|
||||
parts+=("${name}.part-${i}")
|
||||
else
|
||||
[[ ${#parts[@]} -gt 0 ]] && break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
[[ ${#parts[@]} -gt 0 ]] || return 1
|
||||
|
||||
info "Gitea 分片下载 ${#parts[@]} 片 → 合并 $name"
|
||||
: >"$dest"
|
||||
for p in "${parts[@]}"; do
|
||||
p="${p#./}"
|
||||
# 若清单里只有 basename part-xx,补全前缀
|
||||
case "$p" in
|
||||
*.part-*) ;;
|
||||
*) p="${name}.part-${p##*-}" ;;
|
||||
esac
|
||||
# 清单可能是 relative part name only like sing-box-...part-00
|
||||
if [[ "$p" != *"/"* && "$p" != ${name}.part-* && "$p" == *.part-* ]]; then
|
||||
:
|
||||
fi
|
||||
part_url="${base}/${p}"
|
||||
if ! download "$part_url" "$part_dir/$p"; then
|
||||
# 尝试无前缀名
|
||||
local bn
|
||||
bn="$(basename "$p")"
|
||||
part_url="${base}/${bn}"
|
||||
download "$part_url" "$part_dir/$bn" || return 1
|
||||
p="$bn"
|
||||
fi
|
||||
cat "$part_dir/$p" >>"$dest"
|
||||
done
|
||||
|
||||
# 可选校验
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
(
|
||||
cd "$part_dir"
|
||||
# 规范化清单路径
|
||||
sed 's| \./| |; s|^\([a-f0-9]*\) \./|\1 |' SHA256SUMS > SHA256SUMS.norm || cp SHA256SUMS SHA256SUMS.norm
|
||||
if sha256sum -c SHA256SUMS.norm --status 2>/dev/null; then
|
||||
info "分片 SHA256 校验通过"
|
||||
else
|
||||
warn "分片 SHA256 校验跳过/未严格通过(已合并,继续)"
|
||||
fi
|
||||
) || true
|
||||
fi
|
||||
|
||||
# 快速完整性:tar 列表
|
||||
tar -tzf "$dest" >/dev/null
|
||||
return 0
|
||||
}
|
||||
|
||||
try_download_gitea() {
|
||||
local ver="$1" arch="$2" dest="$3"
|
||||
if try_download_gitea_whole "$ver" "$arch" "$dest"; then
|
||||
return 0
|
||||
fi
|
||||
warn "Gitea 整包不可用,尝试分片合并(大文件/代理 504 兜底)"
|
||||
if try_download_gitea_parts "$ver" "$arch" "$dest"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
try_download_github_release() {
|
||||
local ver="$1" arch="$2" dest="$3"
|
||||
local name raw_url
|
||||
name="sing-box-${ver}-linux-${arch}"
|
||||
raw_url="https://github.com/SagerNet/sing-box/releases/download/v${ver}/${name}.tar.gz"
|
||||
download_github "$raw_url" "$dest"
|
||||
}
|
||||
|
||||
if [[ "$SING_BOX_SOURCE" == "local" ]]; then
|
||||
[[ -n "$SING_BOX_BIN" && -x "$SING_BOX_BIN" ]] || die "SING_BOX_SOURCE=local 但 SING_BOX_BIN 无效"
|
||||
install -m 0755 "$SING_BOX_BIN" "$INSTALL_DIR/bin/sing-box"
|
||||
info "已安装本地 sing-box"
|
||||
elif command -v sing-box >/dev/null 2>&1 && [[ -z "${FORCE_DOWNLOAD:-}" && "$SING_BOX_SOURCE" != "gitea" && "$SING_BOX_SOURCE" != "github" ]]; then
|
||||
install -m 0755 "$(command -v sing-box)" "$INSTALL_DIR/bin/sing-box"
|
||||
info "复用系统 sing-box: $(command -v sing-box)"
|
||||
else
|
||||
ver="$SING_BOX_VERSION"
|
||||
tgz="$TMP/sb.tgz"
|
||||
ok=0
|
||||
case "$SING_BOX_SOURCE" in
|
||||
gitea)
|
||||
try_download_gitea "$ver" "$ARCH" "$tgz" || die "Gitea 预置包下载失败(tag=$SING_BOX_RELEASE_TAG arch=$ARCH)"
|
||||
ok=1
|
||||
;;
|
||||
github|release)
|
||||
try_download_github_release "$ver" "$ARCH" "$tgz"
|
||||
ok=1
|
||||
;;
|
||||
auto|*)
|
||||
if try_download_gitea "$ver" "$ARCH" "$tgz"; then
|
||||
ok=1
|
||||
info "已从 Gitea Release 获取 sing-box"
|
||||
else
|
||||
warn "Gitea 预置包不可用,回退 GitHub(经 ${GITHUB_PROXY:-直连})"
|
||||
try_download_github_release "$ver" "$ARCH" "$tgz"
|
||||
ok=1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
[[ "$ok" -eq 1 ]] || die "无法下载 sing-box"
|
||||
install_from_tarball "$tgz" "$ver" "$ARCH"
|
||||
info "已安装 sing-box v${ver} (${ARCH})"
|
||||
"$INSTALL_DIR/bin/sing-box" version 2>/dev/null | head -3 || true
|
||||
fi
|
||||
|
||||
# 安装中文静态 UI
|
||||
mkdir -p "$INSTALL_DIR/ui"
|
||||
if [[ -f "$ROOT_DIR/ui/index.html" ]]; then
|
||||
cp -a "$ROOT_DIR/ui/." "$INSTALL_DIR/ui/"
|
||||
info "已安装内置中文面板 -> $INSTALL_DIR/ui"
|
||||
else
|
||||
warn "未找到 ui/index.html"
|
||||
fi
|
||||
|
||||
info "二进制就绪:"
|
||||
ls -la "$INSTALL_DIR/bin"
|
||||
du -sh "$INSTALL_DIR/bin" "$INSTALL_DIR/ui" 2>/dev/null || true
|
||||
Reference in New Issue
Block a user