mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/Mapleawaa/PVE-Tools-9.git
synced 2026-09-20 08:03:35 +08:00
feat: improve bootstrap downloads for v10.2.0
This commit is contained in:
274
PVE-Tools.sh
274
PVE-Tools.sh
@@ -14,26 +14,270 @@
|
||||
PVE_TOOLS_REMOTE_BASE="${PVE_TOOLS_REMOTE_BASE:-https://raw.githubusercontent.com/PVE-Tools/PVE-Tools-9/main}"
|
||||
PVE_TOOLS_REMOTE_MIRROR_PREFIX="${PVE_TOOLS_REMOTE_MIRROR_PREFIX:-https://ghfast.top/}"
|
||||
PVE_TOOLS_REMOTE_DIST_URL="${PVE_TOOLS_REMOTE_DIST_URL:-$PVE_TOOLS_REMOTE_BASE/dist/PVE-Tools.sh}"
|
||||
PVE_TOOLS_CONNECT_TIMEOUT="${PVE_TOOLS_CONNECT_TIMEOUT:-10}"
|
||||
PVE_TOOLS_DOWNLOAD_TIMEOUT="${PVE_TOOLS_DOWNLOAD_TIMEOUT:-120}"
|
||||
PVE_TOOLS_DOWNLOAD_RETRIES="${PVE_TOOLS_DOWNLOAD_RETRIES:-2}"
|
||||
|
||||
PVE_TOOLS_RELEASE_PAGE_URL="https://github.com/PVE-Tools/PVE-Tools-9/releases/tag/v10.2.0"
|
||||
PVE_TOOLS_RELEASE_ASSET_URL="https://github.com/PVE-Tools/PVE-Tools-9/releases/download/v10.2.0/PVE-Tools.sh"
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR=""
|
||||
|
||||
pve_tools_entry_normalize_positive_integer() {
|
||||
local variable_name="$1"
|
||||
local default_value="$2"
|
||||
local value="${!variable_name:-}"
|
||||
|
||||
if [[ ! "$value" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "警告:$variable_name 必须是正整数,已使用默认值 $default_value。" >&2
|
||||
printf -v "$variable_name" '%s' "$default_value"
|
||||
fi
|
||||
}
|
||||
|
||||
pve_tools_entry_curl_error() {
|
||||
local status="$1"
|
||||
local http_code="${2:-}"
|
||||
|
||||
case "$status" in
|
||||
5|6) PVE_TOOLS_ENTRY_LAST_ERROR="DNS 解析失败(curl $status)" ;;
|
||||
7) PVE_TOOLS_ENTRY_LAST_ERROR="无法连接下载服务器(curl $status)" ;;
|
||||
18) PVE_TOOLS_ENTRY_LAST_ERROR="下载内容不完整(curl $status)" ;;
|
||||
22)
|
||||
if [[ "$http_code" =~ ^[1-9][0-9][0-9]$ ]]; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="服务器返回 HTTP $http_code(curl $status)"
|
||||
else
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="服务器返回 HTTP 错误(curl $status)"
|
||||
fi
|
||||
;;
|
||||
23) PVE_TOOLS_ENTRY_LAST_ERROR="无法写入临时文件(curl $status)" ;;
|
||||
28) PVE_TOOLS_ENTRY_LAST_ERROR="连接或下载超时(curl $status)" ;;
|
||||
35|51|60) PVE_TOOLS_ENTRY_LAST_ERROR="TLS 证书或握手失败(curl $status)" ;;
|
||||
47) PVE_TOOLS_ENTRY_LAST_ERROR="服务器重定向次数过多(curl $status)" ;;
|
||||
56) PVE_TOOLS_ENTRY_LAST_ERROR="接收下载数据失败(curl $status)" ;;
|
||||
124) PVE_TOOLS_ENTRY_LAST_ERROR="下载超过 ${PVE_TOOLS_DOWNLOAD_TIMEOUT} 秒(curl $status)" ;;
|
||||
*) PVE_TOOLS_ENTRY_LAST_ERROR="curl 下载失败(错误码 $status)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
pve_tools_entry_wget_error() {
|
||||
local status="$1"
|
||||
|
||||
case "$status" in
|
||||
3) PVE_TOOLS_ENTRY_LAST_ERROR="无法写入临时文件(wget $status)" ;;
|
||||
4) PVE_TOOLS_ENTRY_LAST_ERROR="网络连接失败(wget $status)" ;;
|
||||
5) PVE_TOOLS_ENTRY_LAST_ERROR="TLS 证书或握手失败(wget $status)" ;;
|
||||
6) PVE_TOOLS_ENTRY_LAST_ERROR="服务器认证失败(wget $status)" ;;
|
||||
7) PVE_TOOLS_ENTRY_LAST_ERROR="服务器协议错误(wget $status)" ;;
|
||||
8) PVE_TOOLS_ENTRY_LAST_ERROR="服务器返回错误状态(wget $status)" ;;
|
||||
124) PVE_TOOLS_ENTRY_LAST_ERROR="下载超过 ${PVE_TOOLS_DOWNLOAD_TIMEOUT} 秒(wget $status)" ;;
|
||||
*) PVE_TOOLS_ENTRY_LAST_ERROR="wget 下载失败(错误码 $status)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
pve_tools_entry_download_with_curl() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
local status=0
|
||||
local http_code=""
|
||||
local retry_count=$((PVE_TOOLS_DOWNLOAD_RETRIES - 1))
|
||||
local -a curl_args=(
|
||||
--fail
|
||||
--location
|
||||
--show-error
|
||||
--connect-timeout "$PVE_TOOLS_CONNECT_TIMEOUT"
|
||||
--max-time "$PVE_TOOLS_DOWNLOAD_TIMEOUT"
|
||||
--speed-limit 1
|
||||
--speed-time 20
|
||||
--retry "$retry_count"
|
||||
--retry-delay 1
|
||||
--retry-connrefused
|
||||
--output "$output"
|
||||
--write-out '%{http_code}'
|
||||
)
|
||||
|
||||
if [[ -t 2 ]]; then
|
||||
curl_args+=(--progress-bar)
|
||||
else
|
||||
curl_args+=(--silent)
|
||||
fi
|
||||
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
if http_code="$(timeout --kill-after=5s "$PVE_TOOLS_DOWNLOAD_TIMEOUT" curl "${curl_args[@]}" "$url")"; then
|
||||
return 0
|
||||
else
|
||||
status=$?
|
||||
fi
|
||||
elif http_code="$(curl "${curl_args[@]}" "$url")"; then
|
||||
return 0
|
||||
else
|
||||
status=$?
|
||||
fi
|
||||
|
||||
pve_tools_entry_curl_error "$status" "$http_code"
|
||||
return "$status"
|
||||
}
|
||||
|
||||
pve_tools_entry_download_with_wget() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
local status=0
|
||||
local -a wget_args=(
|
||||
--connect-timeout="$PVE_TOOLS_CONNECT_TIMEOUT"
|
||||
--read-timeout=20
|
||||
--dns-timeout="$PVE_TOOLS_CONNECT_TIMEOUT"
|
||||
--tries="$PVE_TOOLS_DOWNLOAD_RETRIES"
|
||||
--waitretry=1
|
||||
-O "$output"
|
||||
)
|
||||
|
||||
if [[ -t 2 ]]; then
|
||||
wget_args+=(--show-progress --progress=bar:force:noscroll)
|
||||
else
|
||||
wget_args+=(--no-verbose)
|
||||
fi
|
||||
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
if timeout --kill-after=5s "$PVE_TOOLS_DOWNLOAD_TIMEOUT" wget "${wget_args[@]}" "$url"; then
|
||||
return 0
|
||||
else
|
||||
status=$?
|
||||
fi
|
||||
elif wget "${wget_args[@]}" "$url"; then
|
||||
return 0
|
||||
else
|
||||
status=$?
|
||||
fi
|
||||
|
||||
pve_tools_entry_wget_error "$status"
|
||||
return "$status"
|
||||
}
|
||||
|
||||
pve_tools_entry_validate_script() {
|
||||
local script_path="$1"
|
||||
|
||||
if [[ ! -s "$script_path" ]]; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="下载文件为空"
|
||||
return 1
|
||||
fi
|
||||
if ! bash -n "$script_path" >/dev/null 2>&1; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="下载内容不是有效的 Bash 脚本,可能是代理错误页"
|
||||
return 1
|
||||
fi
|
||||
if ! grep -q '^CURRENT_VERSION=' "$script_path"; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="下载内容不是 PVE-Tools 主程序完整版"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
pve_tools_entry_download_file() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
local output_dir=""
|
||||
local part_file="${output}.part"
|
||||
local mirror_url=""
|
||||
local downloaded_bytes=""
|
||||
local download_status=0
|
||||
local index=0
|
||||
local source_count=0
|
||||
local source_name=""
|
||||
local source_url=""
|
||||
local -a source_names=("GitHub 原始源")
|
||||
local -a source_urls=("$url")
|
||||
|
||||
mkdir -p "$(dirname "$output")"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$url" -o "$output" && return 0
|
||||
curl -fsSL "${PVE_TOOLS_REMOTE_MIRROR_PREFIX}${url}" -o "$output" && return 0
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$output" "$url" && return 0
|
||||
wget -qO "$output" "${PVE_TOOLS_REMOTE_MIRROR_PREFIX}${url}" && return 0
|
||||
else
|
||||
echo "错误:未找到 curl 或 wget,无法下载 PVE-Tools。" >&2
|
||||
output_dir="$(dirname "$output")"
|
||||
if ! mkdir -p "$output_dir"; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="无法创建临时下载目录:$output_dir"
|
||||
echo "错误:$PVE_TOOLS_ENTRY_LAST_ERROR" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -n "$PVE_TOOLS_REMOTE_MIRROR_PREFIX" && "$url" != "${PVE_TOOLS_REMOTE_MIRROR_PREFIX}"* ]]; then
|
||||
mirror_url="${PVE_TOOLS_REMOTE_MIRROR_PREFIX}${url}"
|
||||
source_names+=("GitHub 加速源")
|
||||
source_urls+=("$mirror_url")
|
||||
fi
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="未找到 curl 或 wget"
|
||||
echo "错误:未找到 curl 或 wget,无法下载 PVE-Tools。" >&2
|
||||
echo "请先执行:apt update && apt install -y curl" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
source_count="${#source_urls[@]}"
|
||||
for ((index = 0; index < source_count; index++)); do
|
||||
source_name="${source_names[$index]}"
|
||||
source_url="${source_urls[$index]}"
|
||||
rm -f -- "$part_file"
|
||||
|
||||
echo "[$((index + 1))/$source_count] 正在通过${source_name}下载主程序完整版..."
|
||||
echo "下载地址:$source_url"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if pve_tools_entry_download_with_curl "$source_url" "$part_file"; then
|
||||
download_status=0
|
||||
else
|
||||
download_status=$?
|
||||
fi
|
||||
elif pve_tools_entry_download_with_wget "$source_url" "$part_file"; then
|
||||
download_status=0
|
||||
else
|
||||
download_status=$?
|
||||
fi
|
||||
|
||||
if [[ "$download_status" -eq 0 ]]; then
|
||||
echo "下载完成,正在校验脚本完整性..."
|
||||
if pve_tools_entry_validate_script "$part_file"; then
|
||||
if ! mv -f -- "$part_file" "$output"; then
|
||||
PVE_TOOLS_ENTRY_LAST_ERROR="无法保存已下载的主程序"
|
||||
else
|
||||
downloaded_bytes="$(wc -c < "$output")"
|
||||
downloaded_bytes="${downloaded_bytes//[[:space:]]/}"
|
||||
echo "${source_name}下载成功:${downloaded_bytes:-未知} 字节。"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f -- "$part_file"
|
||||
echo "${source_name}下载失败:$PVE_TOOLS_ENTRY_LAST_ERROR" >&2
|
||||
if ((index + 1 < source_count)); then
|
||||
echo "将自动切换到下一个下载源..." >&2
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
pve_tools_entry_print_release_help() {
|
||||
cat >&2 <<EOF
|
||||
|
||||
错误:PVE-Tools 主程序单文件完整版下载失败,程序尚未启动。
|
||||
以上 GitHub 原始源和加速源均未能完成下载。
|
||||
|
||||
请在另一台能够访问 GitHub 的设备或网络中打开:
|
||||
$PVE_TOOLS_RELEASE_PAGE_URL
|
||||
|
||||
展开 Assets,下载 PVE-Tools.sh(请勿下载 Source code 的 zip 或 tar.gz 压缩包)。
|
||||
直接下载地址:$PVE_TOOLS_RELEASE_ASSET_URL
|
||||
|
||||
下载后可通过 SCP、WinSCP 或 U 盘传到 PVE 主机,然后执行:
|
||||
chmod +x PVE-Tools.sh
|
||||
sudo ./PVE-Tools.sh
|
||||
EOF
|
||||
}
|
||||
|
||||
pve_tools_entry_cleanup() {
|
||||
if [[ -n "${tmp_dir:-}" && -d "$tmp_dir" ]]; then
|
||||
rm -rf -- "$tmp_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
pve_tools_entry_normalize_positive_integer PVE_TOOLS_CONNECT_TIMEOUT 10
|
||||
pve_tools_entry_normalize_positive_integer PVE_TOOLS_DOWNLOAD_TIMEOUT 120
|
||||
pve_tools_entry_normalize_positive_integer PVE_TOOLS_DOWNLOAD_RETRIES 2
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if [[ -f "$SCRIPT_DIR/lib/config.sh" && -d "$SCRIPT_DIR/src/modules" ]]; then
|
||||
@@ -65,16 +309,20 @@ if [[ -f "$SCRIPT_DIR/lib/config.sh" && -d "$SCRIPT_DIR/src/modules" ]]; then
|
||||
done
|
||||
else
|
||||
# 远程模式:下载 dist 单文件并执行
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
tmp_dir=""
|
||||
if ! tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/pve-tools-entry.XXXXXX")"; then
|
||||
echo "错误:无法创建 PVE-Tools 临时目录,程序尚未启动。" >&2
|
||||
exit 1
|
||||
fi
|
||||
trap pve_tools_entry_cleanup EXIT
|
||||
|
||||
if pve_tools_entry_download_file "$PVE_TOOLS_REMOTE_DIST_URL" "$tmp_dir/PVE-Tools.sh"; then
|
||||
echo "主程序校验通过,正在启动 PVE-Tools..."
|
||||
bash "$tmp_dir/PVE-Tools.sh" "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
echo "错误:无法下载 PVE-Tools。请检查网络连接或稍后重试。" >&2
|
||||
echo "下载地址: $PVE_TOOLS_REMOTE_DIST_URL" >&2
|
||||
pve_tools_entry_print_release_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
8
dist/PVE-Tools.sh
vendored
8
dist/PVE-Tools.sh
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# PVE-Tools Pro v10.1.0
|
||||
# Build: 2026-07-08T07:56:40Z
|
||||
# PVE-Tools Pro v10.2.0
|
||||
# Build: 2026-07-11T12:09:24Z
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
# Copyright (C) 2026 Ciriu Networks
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# Copyright (C) 2026 Ciriu Networks
|
||||
|
||||
# 版本信息
|
||||
CURRENT_VERSION="10.1.0"
|
||||
CURRENT_VERSION="10.2.0"
|
||||
BUILD_NICKNAME="Evanescia"
|
||||
VERSION_FILE_URL="https://raw.githubusercontent.com/PVE-Tools/PVE-Tools-9/main/VERSION"
|
||||
UPDATE_FILE_URL="https://raw.githubusercontent.com/PVE-Tools/PVE-Tools-9/main/UPDATE"
|
||||
@@ -1386,6 +1386,8 @@ show_menu() {
|
||||
show_menu_footer
|
||||
echo
|
||||
echo -e " ${YELLOW}Tips: ${SESSION_TIP:-一言获取失败,本次会话不再重试。}${NC}"
|
||||
echo -e "本项目正在收集用户意见,如您愿意,请前往填写问卷,这能帮到整个项目!"
|
||||
echo -e "-> https://wj.qq.com/s2/27286538/9d9d/"
|
||||
echo
|
||||
echo -ne " ${PRIMARY}请输入您的选择 [0-10]: ${NC}"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Copyright (C) 2026 Ciriu Networks
|
||||
|
||||
# 版本信息
|
||||
CURRENT_VERSION="10.1.0"
|
||||
CURRENT_VERSION="10.2.0"
|
||||
BUILD_NICKNAME="Evanescia"
|
||||
VERSION_FILE_URL="https://raw.githubusercontent.com/PVE-Tools/PVE-Tools-9/main/VERSION"
|
||||
UPDATE_FILE_URL="https://raw.githubusercontent.com/PVE-Tools/PVE-Tools-9/main/UPDATE"
|
||||
|
||||
@@ -158,6 +158,8 @@ show_menu() {
|
||||
show_menu_footer
|
||||
echo
|
||||
echo -e " ${YELLOW}Tips: ${SESSION_TIP:-一言获取失败,本次会话不再重试。}${NC}"
|
||||
echo -e "本项目正在收集用户意见,如您愿意,请前往填写问卷,这能帮到整个项目!"
|
||||
echo -e "-> https://wj.qq.com/s2/27286538/9d9d/"
|
||||
echo
|
||||
echo -ne " ${PRIMARY}请输入您的选择 [0-10]: ${NC}"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user