mirror of
https://github.com/Gloridust/WechatOnCloud.git
synced 2026-09-20 03:23:32 +08:00
fix(install): 微信下载支持断点续传 + 并发锁 + 完整性校验(修反复卡进度退出)
用户反馈安装卡在 ~28% 反复退出、多次重试无效(诊断包实证:panel.log 里短时间连点多次「触发下载安装」)。 do_install 有两处放大网络抖动的缺陷: - 每次触发都先 rm -rf $WORK_DIR:用户重试时把上一次下到一半的包删掉; - curl 不带 -C -:每次从 0 重下,网络稍差就永远下不完,且反复停在相近百分比。 修: - 并发锁($STATE_DIR/.install.lock,mkdir 原子 + pid 存活判定):已有安装在跑则跳过本次触发, 让它续着下完,不再互相踩。 - curl -C - 断点续传 + --retry-all-errors + 外层最多 6 轮,重试前【绝不删】部分文件 → 从断点继续。 - 下载后 dpkg-deb -f 完整性校验:半包/损坏才删了重下,否则不白费已下的量。 - 全程写 $STATE_DIR/install.log,便于线上定位(此前安装失败在诊断包里完全看不到原因)。 注:待 Docker 恢复后补端到端验证(真拉一次微信 deb + 并发锁)再考虑发版。
This commit is contained in:
@@ -52,51 +52,85 @@ print_status() {
|
||||
fi
|
||||
}
|
||||
|
||||
log() { echo "[$(date '+%F %T')] $*" >> "$STATE_DIR/install.log" 2>/dev/null; }
|
||||
|
||||
do_install() {
|
||||
local file url tmp pid total cur pct rc=1
|
||||
local file tmp pid total cur pct rc=1 attempt=0
|
||||
file="$(deb_filename)"
|
||||
if [ -z "$file" ]; then
|
||||
write_status error 0 "不支持的架构:微信仅提供 x86_64 / arm64"
|
||||
return
|
||||
fi
|
||||
|
||||
rm -rf "$WORK_DIR"
|
||||
mkdir -p "$WORK_DIR"
|
||||
mkdir -p "$STATE_DIR" "$WORK_DIR"
|
||||
# 并发保护(issue:反复点安装会互相踩):锁目录 mkdir 原子。已有【活着的】安装在跑 → 直接返回,
|
||||
# 让它继续(下面的 curl 支持断点续传,会自己下完);否则每次触发都 rm 掉下到一半的包 → 永远装不完。
|
||||
local lock="$STATE_DIR/.install.lock"
|
||||
if ! mkdir "$lock" 2>/dev/null; then
|
||||
local lpid; lpid="$(cat "$lock/pid" 2>/dev/null || echo)"
|
||||
if [ -n "$lpid" ] && kill -0 "$lpid" 2>/dev/null; then
|
||||
log "已有安装进行中(pid=$lpid),本次触发跳过"
|
||||
return
|
||||
fi
|
||||
rm -rf "$lock"; mkdir "$lock" 2>/dev/null || { log "抢锁失败,跳过"; return; }
|
||||
fi
|
||||
echo "$$" > "$lock/pid"
|
||||
trap 'rm -rf "$lock" 2>/dev/null' EXIT # 本次 exec 短命,退出即释放锁
|
||||
log "开始安装 file=$file"
|
||||
|
||||
tmp="$WORK_DIR/wechat.deb"
|
||||
|
||||
# 取总大小用于进度(HEAD 可能失败,失败则进度走不确定值 -1)
|
||||
# 取总大小用于进度 + 完整性判断(HEAD 可能失败,失败则进度走不确定值 -1)
|
||||
for base in "$CDN_MAIN" "$CDN_FALLBACK"; do
|
||||
total="$(curl -fsSLI -A "$UA" "$base/$file" 2>/dev/null | tr -d '\r' \
|
||||
| awk 'tolower($1)=="content-length:"{v=$2} END{print v}')"
|
||||
[ -n "${total:-}" ] && url="$base/$file" && break
|
||||
[ -n "${total:-}" ] && break
|
||||
done
|
||||
: "${total:=0}" "${url:=$CDN_MAIN/$file}"
|
||||
: "${total:=0}"
|
||||
|
||||
write_status downloading 0 "正在下载微信安装包"
|
||||
# 后台下载 + 轮询已下字节算百分比(下载占 0~90)
|
||||
for base in "$CDN_MAIN" "$CDN_FALLBACK"; do
|
||||
curl -fSL --retry 3 -A "$UA" -o "$tmp" "$base/$file" & pid=$!
|
||||
while kill -0 "$pid" 2>/dev/null; do
|
||||
if [ "${total:-0}" -gt 0 ] 2>/dev/null; then
|
||||
cur="$(stat -c%s "$tmp" 2>/dev/null || echo 0)"
|
||||
pct=$(( cur * 90 / total ))
|
||||
[ "$pct" -gt 90 ] && pct=90
|
||||
write_status downloading "$pct" "正在下载微信安装包"
|
||||
else
|
||||
write_status downloading -1 "正在下载微信安装包"
|
||||
fi
|
||||
sleep 1
|
||||
# 断点续传下载(-C -):网络半路中断/被中间设备掐断时,下次从已下字节【继续】而非从 0 重来
|
||||
#(这正是"反复卡在同一百分比退出"的解药)。--retry-all-errors 对传输中断也重试;外层再多轮兜底。
|
||||
# 关键:绝不在重试前删 $tmp —— 保留部分文件才能续传。
|
||||
while [ "$attempt" -lt 6 ]; do
|
||||
attempt=$((attempt+1))
|
||||
for base in "$CDN_MAIN" "$CDN_FALLBACK"; do
|
||||
curl -fSL -C - --retry 3 --retry-all-errors --retry-delay 2 --connect-timeout 20 \
|
||||
-A "$UA" -o "$tmp" "$base/$file" & pid=$!
|
||||
while kill -0 "$pid" 2>/dev/null; do
|
||||
if [ "${total:-0}" -gt 0 ] 2>/dev/null; then
|
||||
cur="$(stat -c%s "$tmp" 2>/dev/null || echo 0)"
|
||||
pct=$(( cur * 90 / total )); [ "$pct" -gt 90 ] && pct=90
|
||||
write_status downloading "$pct" "正在下载微信安装包"
|
||||
else
|
||||
write_status downloading -1 "正在下载微信安装包"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
wait "$pid"; rc=$?
|
||||
[ "$rc" -eq 0 ] && break 2
|
||||
log "curl 退出码 $rc(base=$base,attempt=$attempt),已下 $(stat -c%s "$tmp" 2>/dev/null || echo 0) 字节"
|
||||
done
|
||||
wait "$pid"; rc=$?
|
||||
[ "$rc" -eq 0 ] && break
|
||||
write_status downloading -1 "主线路失败,尝试备用线路"
|
||||
# 已下满(校验用 total)也算成功——防某些实现在收尾时给非 0 退出码
|
||||
cur="$(stat -c%s "$tmp" 2>/dev/null || echo 0)"
|
||||
if [ "${total:-0}" -gt 0 ] && [ "$cur" -ge "$total" ]; then rc=0; break; fi
|
||||
write_status downloading -1 "下载中断,正在续传重试($attempt/6)"
|
||||
sleep 2
|
||||
done
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
write_status error 0 "下载失败,请检查网络后重试"
|
||||
rm -rf "$WORK_DIR"; return
|
||||
log "下载最终失败 rc=$rc,已下 $(stat -c%s "$tmp" 2>/dev/null || echo 0)/$total"
|
||||
write_status error 0 "下载失败(多次续传仍未完成,请检查网络/镜像后重试)"
|
||||
return
|
||||
fi
|
||||
|
||||
write_status extracting 92 "正在解压安装"
|
||||
# 完整性校验:能被 dpkg-deb 读出版本才算完整包;半包/损坏包会解压失败或装出坏微信。
|
||||
if ! dpkg-deb -f "$tmp" Version >/dev/null 2>&1; then
|
||||
log "包不完整/损坏,删除重下"
|
||||
rm -f "$tmp"
|
||||
write_status error 0 "安装包不完整或损坏,已清理,请再次点击安装(将重新下载)"
|
||||
return
|
||||
fi
|
||||
local newroot="$WORK_DIR/new"
|
||||
rm -rf "$newroot"; mkdir -p "$newroot"
|
||||
if ! dpkg-deb -x "$tmp" "$newroot" 2>/dev/null; then
|
||||
|
||||
Reference in New Issue
Block a user