#!/usr/bin/env bash # 将 sing-box 官方 release 预下载并上传到本仓库 Gitea Release # 用法(维护机): # set -a; source ~/.hermes/env/gitea.env; set +a # ./scripts/publish-binaries-to-gitea.sh # SING_BOX_VERSION=1.11.7 ARCHS='amd64 arm64 armv7' ./scripts/publish-binaries-to-gitea.sh # # GitHub 下载默认经 https://git.86482425.xyz # 上传走 multipart;>约 8MB 可能被反向代理 504,自动改 1MB 分片上传 set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" : "${GITEA_URL:?请先 source ~/.hermes/env/gitea.env}" : "${GITEA_TOKEN:?请先 source ~/.hermes/env/gitea.env}" OWNER="${GITEA_OWNER:-Hermes}" REPO="${GITEA_REPO:-cellular-proxy}" VER="${SING_BOX_VERSION:-1.11.7}" TAG="${SING_BOX_RELEASE_TAG:-bin-v${VER}}" ARCHS="${ARCHS:-amd64 arm64 armv7}" GITHUB_PROXY="${GITHUB_PROXY:-https://git.86482425.xyz}" PART_BYTES="${PART_BYTES:-1048576}" # 经验阈值:整包上传超时则分片(nginx 常见 ~80s) WHOLE_MAX_BYTES="${WHOLE_MAX_BYTES:-9000000}" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*" >&2; } download() { local url="$1" dest="$2" log "下载 $url" curl -fL --retry 3 --connect-timeout 20 --max-time 300 -o "$dest" "$url" } github_fetch() { local raw="$1" dest="$2" local proxied="${GITHUB_PROXY%/}/${raw}" if [[ -n "${GITHUB_PROXY:-}" ]]; then if download "$proxied" "$dest"; then return 0 fi log "代理失败,直连" fi download "$raw" "$dest" } API="$GITEA_URL/api/v1/repos/$OWNER/$REPO" auth=(-H "Authorization: token $GITEA_TOKEN") delete_asset() { local id="$1" # Gitea 正确路径:/releases/{id}/assets/{asset_id} curl -sS -X DELETE "${auth[@]}" -o /dev/null -w "DEL %{http_code}\n" \ "$API/releases/$REL_ID/assets/$id" || true } upload_file() { local fpath="$1" fname="$2" local code code=$(curl -sS --http1.1 --max-time 300 \ "${auth[@]}" \ -F "attachment=@${fpath};filename=${fname}" \ -o "$TMP/up_${fname}.json" \ -w '%{http_code}' \ "$API/releases/$REL_ID/assets?name=${fname}" || echo 000) if [[ "$code" != "201" && "$code" != "200" ]]; then log "上传失败 $fname HTTP $code" head -c 300 "$TMP/up_${fname}.json" 2>/dev/null || true return 1 fi python3 - < $WHOLE_MAX_BYTES,直接分片上传 $fname" fi local pdir="$TMP/parts_${fname}" rm -rf "$pdir" mkdir -p "$pdir" split -b "$PART_BYTES" -d -a 2 "$fpath" "$pdir/${fname}.part-" ( cd "$pdir" # 清单使用纯文件名,便于客户端校验 sha256sum "${fname}.part-"* > "${fname}.SHA256SUMS" ) local p for p in "$pdir/${fname}.part-"* "$pdir/${fname}.SHA256SUMS"; do bn=$(basename "$p") log "分片上传 $bn ($(stat -c%s "$p") bytes)" upload_file "$p" "$bn" done } # 1) 下载 for arch in $ARCHS; do name="sing-box-${VER}-linux-${arch}" raw="https://github.com/SagerNet/sing-box/releases/download/v${VER}/${name}.tar.gz" dest="$TMP/${name}.tar.gz" github_fetch "$raw" "$dest" tar -tzf "$dest" | head -3 >/dev/null ls -lh "$dest" done # 2) release ensure_release # 3) 上传 for arch in $ARCHS; do fname="sing-box-${VER}-linux-${arch}.tar.gz" upload_whole_or_parts "$TMP/$fname" "$fname" done # 4) 公开下载自检 for arch in $ARCHS; do fname="sing-box-${VER}-linux-${arch}.tar.gz" url="$GITEA_URL/$OWNER/$REPO/releases/download/$TAG/$fname" code=$(curl -sS -o /dev/null -w '%{http_code}' -L --max-time 30 "$url" || true) if [[ "$code" == "200" || "$code" == "206" ]]; then log "公开整包 OK $url -> $code" else # 分片? p0="$GITEA_URL/$OWNER/$REPO/releases/download/$TAG/${fname}.part-00" code2=$(curl -sS -o /dev/null -w '%{http_code}' -L --max-time 30 "$p0" || true) log "整包 $code,分片 part-00 -> $code2 ($p0)" fi done log "完成。安装端优先:" log " $GITEA_URL/$OWNER/$REPO/releases/download/$TAG/sing-box-${VER}-linux-.tar.gz" log " 或分片: .../${fname}.part-XX + .../${fname}.SHA256SUMS"