small-packages/luci-app-ssr-plus/root/usr/share/shadowsocksr/update_components.sh
2026-05-10 09:48:30 +08:00

1429 lines
36 KiB
Bash

#!/bin/sh
set -u
XRAY_RELEASE_PAGE="https://github.com/XTLS/Xray-core/releases/latest"
MIHOMO_RELEASE_PAGE="https://github.com/MetaCubeX/mihomo/releases/latest"
NAIVEPROXY_RELEASE_API="https://api.github.com/repos/klzgrad/naiveproxy/releases/latest"
XRAY_BINARY="/usr/bin/xray"
MIHOMO_BINARY="/usr/bin/mihomo"
NAIVEPROXY_BINARY="/usr/bin/naive"
COUNTRY_MMDB_URL="https://testingcf.jsdelivr.net/gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
GEOSITE_URL="https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
GEOIP_DAT_URL="https://testingcf.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
COUNTRY_MMDB_FILE="/usr/share/shadowsocksr/Country.mmdb"
GEOIP_DAT_FILE="/usr/share/v2ray/geoip.dat"
GEOSITE_DAT_FILE="/usr/share/v2ray/geosite.dat"
OPENCLASH_GEOSITE_FILE="/etc/openclash/GeoSite.dat"
OPENCLASH_GEOIP_DAT_FILE="/etc/openclash/geoip.dat"
OPENCLASH_GEOSITE_DAT_FILE="/etc/openclash/geosite.dat"
log_kv() {
key="$1"
shift
printf '%s=%s\n' "$key" "$*"
}
file_mtime() {
local path="$1"
[ -f "$path" ] || {
printf '%s' 'File Not Exist'
return 0
}
date -r "$path" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || printf '%s' 'Unknown'
}
file_size() {
local path="$1"
[ -f "$path" ] || {
printf '%s' '0'
return 0
}
wc -c < "$path" 2>/dev/null | tr -d '[:space:]'
}
resolve_existing_geo_file() {
local primary="$1"
local fallback="$2"
if [ -f "$primary" ]; then
printf '%s' "$primary"
elif [ -n "$fallback" ] && [ -f "$fallback" ]; then
printf '%s' "$fallback"
else
printf '%s' "$primary"
fi
}
resolve_geosite_file() {
resolve_existing_geo_file "$GEOSITE_DAT_FILE" "$OPENCLASH_GEOSITE_FILE"
}
resolve_v2ray_geoip_file() {
resolve_existing_geo_file "$GEOIP_DAT_FILE" "$OPENCLASH_GEOIP_DAT_FILE"
}
resolve_v2ray_geosite_file() {
resolve_existing_geo_file "$GEOSITE_DAT_FILE" "$OPENCLASH_GEOSITE_DAT_FILE"
}
trim_version() {
printf '%s' "$1" | sed 's/^v//'
}
get_component_mirror() {
if [ -n "${COMPONENT_MIRROR:-}" ]; then
echo "$COMPONENT_MIRROR"
return 0
fi
uci -q get shadowsocksr.@global[0].component_mirror 2>/dev/null || echo "direct"
}
mirror_wrap_url() {
local raw_url="$1"
local mirror
mirror="$(get_component_mirror)"
case "$mirror" in
direct|"")
printf '%s' "$raw_url"
;;
ghproxy)
printf 'https://mirror.ghproxy.com/%s' "$raw_url"
;;
ghproxy_cc)
printf 'https://ghproxy.cc/%s' "$raw_url"
;;
ghfast)
printf 'https://ghfast.top/%s' "$raw_url"
;;
jsdelivr)
case "$raw_url" in
https://github.com/XTLS/Xray-core/releases/download/*)
printf '%s' "$raw_url" | sed 's#https://github.com/XTLS/Xray-core/releases/download/\(v[^/]*\)/\(.*\)#https://fastly.jsdelivr.net/gh/XTLS/Xray-core@\1/\2#'
;;
https://github.com/MetaCubeX/mihomo/releases/download/*)
printf '%s' "$raw_url" | sed 's#https://github.com/MetaCubeX/mihomo/releases/download/\(v[^/]*\)/\(.*\)#https://fastly.jsdelivr.net/gh/MetaCubeX/mihomo@\1/\2#'
;;
*)
printf '%s' "$raw_url"
;;
esac
;;
*)
printf '%s' "$raw_url"
;;
esac
}
version_gt() {
local left right first
left="$(trim_version "${1:-}")"
right="$(trim_version "${2:-}")"
[ -n "$left" ] || return 1
[ -n "$right" ] || return 1
[ "$left" = "$right" ] && return 1
first="$(printf '%s\n%s\n' "$left" "$right" | sort -V | tail -n 1)"
[ "$first" = "$left" ]
}
naiveproxy_versions_equal() {
local left right
left="$(trim_version "${1:-}")"
right="$(trim_version "${2:-}")"
[ -n "$left" ] || return 1
[ -n "$right" ] || return 1
[ "$left" = "$right" ] && return 0
[ "${left%%-*}" = "${right%%-*}" ]
}
get_openwrt_arch() {
local arch
arch=""
if [ -r /etc/openwrt_release ]; then
arch="$(. /etc/openwrt_release 2>/dev/null; printf '%s' "${DISTRIB_ARCH:-}")"
fi
if [ -z "$arch" ] && command -v opkg >/dev/null 2>&1; then
arch="$(opkg print-architecture 2>/dev/null | awk '$2 != "all" && $2 != "noarch" { print $2 }' | tail -n 1)"
fi
if [ -z "$arch" ] && command -v uname >/dev/null 2>&1; then
arch="$(uname -m 2>/dev/null)"
fi
printf '%s' "$arch"
}
is_openwrt_env() {
[ -r /etc/openwrt_release ] || command -v opkg >/dev/null 2>&1
}
find_mihomo_binary() {
if command -v mihomo >/dev/null 2>&1; then
command -v mihomo
return 0
fi
for path in /usr/bin/mihomo /usr/libexec/mihomo /etc/ssrplus/bin/mihomo; do
if [ -x "$path" ]; then
printf '%s' "$path"
return 0
fi
done
return 1
}
find_naiveproxy_binary() {
if command -v naive >/dev/null 2>&1; then
command -v naive
return 0
fi
for path in /usr/bin/naive /usr/libexec/naive /etc/ssrplus/bin/naive; do
if [ -x "$path" ]; then
printf '%s' "$path"
return 0
fi
done
return 1
}
get_xray_current_version() {
if [ ! -x "$XRAY_BINARY" ]; then
return 1
fi
"$XRAY_BINARY" version 2>/dev/null | sed -n 's/^Xray[[:space:]]\+\([^[:space:]]\+\).*$/\1/p' | sed -n '1p'
return 0
}
get_mihomo_current_version() {
local binary
binary="$(find_mihomo_binary)" || return 1
"$binary" -v 2>/dev/null | sed -n 's/.* v\([0-9][0-9.]*\).*/\1/p' | sed -n '1p'
return 0
}
get_naiveproxy_current_version() {
local binary
binary="$(find_naiveproxy_binary)" || return 1
"$binary" --version 2>&1 | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?' | sed -n '1p'
return 0
}
map_xray_asset() {
case "$1" in
x86_64*|amd64*)
printf '%s' 'Xray-linux-64.zip'
;;
i386*|i486*|i586*|i686*|x86*)
printf '%s' 'Xray-linux-32.zip'
;;
aarch64*|arm64*)
printf '%s' 'Xray-linux-arm64-v8a.zip'
;;
*armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*)
printf '%s' 'Xray-linux-arm32-v7a.zip'
;;
*armv6*|*arm1176*)
printf '%s' 'Xray-linux-arm32-v6.zip'
;;
*armv5*|*arm926*|*xscale*)
printf '%s' 'Xray-linux-arm32-v5.zip'
;;
mips64el*|mips64le*)
printf '%s' 'Xray-linux-mips64le.zip'
;;
mips64*)
printf '%s' 'Xray-linux-mips64.zip'
;;
mipsel*|mips32el*|mips32le*)
printf '%s' 'Xray-linux-mips32le.zip'
;;
mips*)
printf '%s' 'Xray-linux-mips32.zip'
;;
riscv64*)
printf '%s' 'Xray-linux-riscv64.zip'
;;
loongarch64*|loong64*)
printf '%s' 'Xray-linux-loong64.zip'
;;
powerpc64*|ppc64*)
printf '%s' 'Xray-linux-ppc64.zip'
;;
s390x*)
printf '%s' 'Xray-linux-s390x.zip'
;;
*)
return 1
;;
esac
}
require_cmd() {
command -v "$1" >/dev/null 2>&1
}
select_unzip_cmd() {
if require_cmd unzip; then
printf '%s' 'unzip -oq'
return 0
fi
if busybox unzip >/dev/null 2>&1; then
printf '%s' 'busybox unzip -o'
return 0
fi
return 1
}
select_gzip_cmd() {
if require_cmd gzip; then
printf '%s' 'gzip -dc'
return 0
fi
if busybox gzip >/dev/null 2>&1; then
printf '%s' 'busybox gzip -dc'
return 0
fi
return 1
}
select_xz_cmd() {
if require_cmd xz; then
printf '%s' 'xz -dc'
return 0
fi
if busybox xz >/dev/null 2>&1; then
printf '%s' 'busybox xz -dc'
return 0
fi
return 1
}
select_tar_cmd() {
if require_cmd tar; then
printf '%s' 'tar'
return 0
fi
if busybox tar --help >/dev/null 2>&1; then
printf '%s' 'busybox tar'
return 0
fi
return 1
}
select_wget_cmd() {
if require_cmd wget-ssl; then
printf '%s' 'wget-ssl'
return 0
fi
if require_cmd wget; then
printf '%s' 'wget'
return 0
fi
return 1
}
curl_effective_url() {
local target="$1"
local effective=""
local headers=""
local location=""
headers="$(curl -kfsSI --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' "$target" 2>/dev/null || true)"
location="$(printf '%s\n' "$headers" | sed -n 's/^[Ll]ocation:[[:space:]]*//p' | sed 's/\r$//' | sed 's/[[:space:]]\+\[following\]$//' | sed -n '1p')"
[ -n "$location" ] && effective="$location"
[ -n "$effective" ] || effective="$(curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' -o /dev/null -w '%{url_effective}' "$target" 2>/dev/null || true)"
[ -n "$effective" ] || return 1
printf '%s' "$effective"
}
wget_effective_url() {
local target="$1"
local wget_cmd output location
wget_cmd="$(select_wget_cmd)" || return 1
output="$($wget_cmd --server-response --max-redirect=0 --spider --timeout=20 --tries=3 --no-check-certificate "$target" 2>&1 || true)"
location="$(printf '%s\n' "$output" | sed -n 's/^[Ll]ocation:[[:space:]]*//p' | sed 's/\r$//' | sed 's/[[:space:]]\+\[following\]$//' | sed -n '1p')"
if [ -n "$location" ]; then
printf '%s' "$location"
return 0
fi
printf '%s\n' "$output" | grep -qE 'HTTP/[0-9.]+ 200' || return 1
printf '%s' "$target"
}
effective_url() {
local target="$1"
local url=""
url="$(curl_effective_url "$target" 2>/dev/null || true)"
[ -n "$url" ] || url="$(wget_effective_url "$target" 2>/dev/null || true)"
[ -n "$url" ] || return 1
printf '%s' "$url"
}
fetch_text() {
local url="$1"
local wget_cmd
if curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept: application/vnd.github+json' "$url" 2>/dev/null; then
return 0
fi
wget_cmd="$(select_wget_cmd)" || return 1
"$wget_cmd" --header='Accept: application/vnd.github+json' --timeout=20 --tries=3 --no-check-certificate -O - "$url" 2>/dev/null
}
download_file() {
local url="$1"
local output="$2"
local wget_cmd
if curl -kfsSL --http1.1 --connect-timeout 10 --retry 2 -A 'curl/8.0' -H 'Accept-Encoding: identity' -o "$output" "$url" 2>/dev/null; then
return 0
fi
wget_cmd="$(select_wget_cmd)" || return 1
"$wget_cmd" --no-check-certificate --timeout=20 --tries=3 -O "$output" "$url" >/dev/null 2>&1
}
geo_validate_download() {
local new_file="$1"
local current_file="$2"
local new_size current_size
new_size="$(file_size "$new_file")"
[ "${new_size:-0}" -gt 0 ] 2>/dev/null || return 1
if [ -f "$current_file" ]; then
current_size="$(file_size "$current_file")"
[ "${new_size:-0}" -ge "${current_size:-0}" ] 2>/dev/null || return 1
fi
return 0
}
geo_safe_replace() {
local new_file="$1"
local current_file="$2"
local backup_file="$3"
mkdir -p "$(dirname "$current_file")" || return 1
[ -f "$current_file" ] && cp -fp "$current_file" "$backup_file" 2>/dev/null || true
if ! cp -f "$new_file" "$current_file"; then
[ -f "$backup_file" ] && cp -f "$backup_file" "$current_file" 2>/dev/null || true
return 1
fi
return 0
}
geo_local_info() {
local geo="$1"
local file1=""
local file2=""
case "$geo" in
country_mmdb)
file1="$COUNTRY_MMDB_FILE"
;;
geosite)
file1="$(resolve_geosite_file)"
;;
v2ray_geo)
file1="$(resolve_v2ray_geoip_file)"
file2="$(resolve_v2ray_geosite_file)"
;;
*)
log_kv error 'unsupported_component'
return 1
;;
esac
log_kv component "$geo"
log_kv installed "$([ -f "$file1" ] && echo 1 || echo 0)"
log_kv current_version "$(file_mtime "$file1")"
log_kv current_version_extra "$([ -n "$file2" ] && file_mtime "$file2" || echo '')"
log_kv latest_version ''
log_kv can_upgrade 0
log_kv error ''
}
geo_upgrade() {
local geo="$1"
local tmp_dir file_a url_a file_b url_b msg
tmp_dir="$(mktemp -d /tmp/ssrplus-geo.XXXXXX)"
[ -n "$tmp_dir" ] && [ -d "$tmp_dir" ] || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Failed to create temp directory'
return 0
}
trap "rm -rf '$tmp_dir'" EXIT INT TERM
case "$geo" in
country_mmdb)
file_a="$COUNTRY_MMDB_FILE"
url_a="$(mirror_wrap_url "$COUNTRY_MMDB_URL")"
download_file "$url_a" "$tmp_dir/file_a" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Download failed'
return 0
}
geo_validate_download "$tmp_dir/file_a" "$file_a" || {
log_kv component "$geo"
log_kv success 1
log_kv current_version "$(file_mtime "$file_a")"
log_kv current_version_extra ''
log_kv latest_version "$(file_mtime "$file_a")"
log_kv can_upgrade 0
log_kv message 'Already up to date'
return 0
}
geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Install failed'
return 0
}
msg='Upgrade completed'
;;
geosite)
file_a="$(resolve_geosite_file)"
url_a="$(mirror_wrap_url "$GEOSITE_URL")"
download_file "$url_a" "$tmp_dir/file_a" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Download failed'
return 0
}
geo_validate_download "$tmp_dir/file_a" "$file_a" || {
log_kv component "$geo"
log_kv success 1
log_kv current_version "$(file_mtime "$file_a")"
log_kv current_version_extra ''
log_kv latest_version "$(file_mtime "$file_a")"
log_kv can_upgrade 0
log_kv message 'Already up to date'
return 0
}
geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Install failed'
return 0
}
msg='Upgrade completed'
;;
v2ray_geo)
file_a="$(resolve_v2ray_geoip_file)"
url_a="$(mirror_wrap_url "$GEOIP_DAT_URL")"
file_b="$(resolve_v2ray_geosite_file)"
url_b="$(mirror_wrap_url "$GEOSITE_URL")"
download_file "$url_a" "$tmp_dir/file_a" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Download failed'
return 0
}
download_file "$url_b" "$tmp_dir/file_b" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Download failed'
return 0
}
geo_validate_download "$tmp_dir/file_a" "$file_a" || {
log_kv component "$geo"
log_kv success 1
log_kv current_version "$(file_mtime "$file_a")"
log_kv current_version_extra "$(file_mtime "$file_b")"
log_kv latest_version "$(file_mtime "$file_a")"
log_kv can_upgrade 0
log_kv message 'Already up to date'
return 0
}
geo_validate_download "$tmp_dir/file_b" "$file_b" || {
log_kv component "$geo"
log_kv success 1
log_kv current_version "$(file_mtime "$file_a")"
log_kv current_version_extra "$(file_mtime "$file_b")"
log_kv latest_version "$(file_mtime "$file_a")"
log_kv can_upgrade 0
log_kv message 'Already up to date'
return 0
}
geo_safe_replace "$tmp_dir/file_a" "$file_a" "$tmp_dir/file_a.bak" || {
log_kv component "$geo"
log_kv success 0
log_kv message 'Install failed'
return 0
}
geo_safe_replace "$tmp_dir/file_b" "$file_b" "$tmp_dir/file_b.bak" || {
[ -f "$tmp_dir/file_a.bak" ] && cp -f "$tmp_dir/file_a.bak" "$file_a" 2>/dev/null || true
log_kv component "$geo"
log_kv success 0
log_kv message 'Install failed'
return 0
}
msg='Upgrade completed'
;;
*)
log_kv component "$geo"
log_kv success 0
log_kv message 'Unsupported component'
return 0
;;
esac
log_kv component "$geo"
log_kv success 1
log_kv current_version "$(file_mtime "$file_a")"
log_kv current_version_extra "$([ -n "${file_b:-}" ] && file_mtime "$file_b" || echo '')"
log_kv latest_version "$(file_mtime "$file_a")"
log_kv can_upgrade 0
log_kv message "$msg"
return 0
}
get_xray_latest_tag() {
local location tag
location="$(effective_url "$XRAY_RELEASE_PAGE")" || return 1
tag="$(printf '%s' "$location" | sed -n 's#.*/tag/\(v[0-9][^/]*\)$#\1#p' | sed -n '1p')"
[ -n "$tag" ] || return 1
printf '%s' "$tag"
}
get_xray_latest_info() {
local tag version asset url arch
arch="$(get_openwrt_arch)"
asset="$(map_xray_asset "$arch")" || return 2
tag="$(get_xray_latest_tag)" || return 3
version="$(trim_version "$tag")"
url="$(mirror_wrap_url "https://github.com/XTLS/Xray-core/releases/download/$tag/$asset")"
[ -n "$tag" ] && [ -n "$version" ] && [ -n "$url" ] || return 4
log_kv arch "$arch"
log_kv asset "$asset"
log_kv latest_version "$version"
log_kv download_url "$url"
return 0
}
get_mihomo_latest_tag() {
local location tag
location="$(effective_url "$MIHOMO_RELEASE_PAGE")" || return 1
tag="$(printf '%s' "$location" | sed -n 's#.*/tag/\(v[0-9][^/]*\)$#\1#p' | sed -n '1p')"
[ -n "$tag" ] || return 1
printf '%s' "$tag"
}
map_mihomo_asset() {
local arch="$1"
local version="$2"
case "$arch" in
x86_64*|amd64*)
printf 'mihomo-linux-amd64-compatible-v%s.gz' "$version"
;;
i386*|i486*|i586*|i686*|x86*)
printf 'mihomo-linux-386-v%s.gz' "$version"
;;
aarch64*|arm64*)
printf 'mihomo-linux-arm64-v%s.gz' "$version"
;;
*armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*)
printf 'mihomo-linux-armv7-v%s.gz' "$version"
;;
*armv6*|*arm1176*)
printf 'mihomo-linux-armv6-v%s.gz' "$version"
;;
*armv5*|*arm926*|*xscale*)
printf 'mihomo-linux-armv5-v%s.gz' "$version"
;;
mips64el*|mips64le*)
printf 'mihomo-linux-mips64le-v%s.gz' "$version"
;;
mips64*)
printf 'mihomo-linux-mips64-v%s.gz' "$version"
;;
mipsel*|mips32el*|mips32le*)
printf 'mihomo-linux-mipsle-softfloat-v%s.gz' "$version"
;;
mips*)
printf 'mihomo-linux-mips-softfloat-v%s.gz' "$version"
;;
riscv64*)
printf 'mihomo-linux-riscv64-v%s.gz' "$version"
;;
loongarch64*|loong64*)
printf 'mihomo-linux-loong64-abi1-v%s.gz' "$version"
;;
powerpc64le*|ppc64le*)
printf 'mihomo-linux-ppc64le-v%s.gz' "$version"
;;
s390x*)
printf 'mihomo-linux-s390x-v%s.gz' "$version"
;;
*)
return 1
;;
esac
}
get_mihomo_latest_info() {
local arch tag version asset url
arch="$(get_openwrt_arch)"
tag="$(get_mihomo_latest_tag)" || return 3
version="$(trim_version "$tag")"
asset="$(map_mihomo_asset "$arch" "$version")" || return 2
url="$(mirror_wrap_url "https://github.com/MetaCubeX/mihomo/releases/download/$tag/$asset")"
log_kv arch "$arch"
log_kv asset "$asset"
log_kv latest_version "$version"
log_kv download_url "$url"
return 0
}
map_naiveproxy_linux_asset() {
case "$1" in
x86_64*|amd64*)
printf '%s' 'x64'
;;
i386*|i486*|i586*|i686*|x86*)
printf '%s' 'x86'
;;
aarch64*|arm64*)
printf '%s' 'arm64'
;;
*armv7*|*cortex-a*|*neon*|*vfpv3*|*vfpv4*)
printf '%s' 'arm'
;;
mips64el*|mips64le*)
printf '%s' 'mips64el'
;;
mipsel*|mips32el*|mips32le*)
printf '%s' 'mipsel'
;;
riscv64*)
printf '%s' 'riscv64'
;;
loongarch64*|loong64*)
printf '%s' 'loong64'
;;
*)
return 1
;;
esac
}
normalize_naiveproxy_openwrt_arch() {
local arch="${1%%+*}"
printf '%s' "$arch"
}
naiveproxy_openwrt_arch_candidates() {
local normalized
normalized="$(normalize_naiveproxy_openwrt_arch "$1")"
printf '%s\n' "$normalized"
case "$normalized" in
aarch64_*)
[ "$normalized" = "aarch64_generic" ] || printf '%s\n' 'aarch64_generic'
;;
x86|i386|i486|i586|i686)
printf '%s\n' 'x86'
;;
esac
}
asset_list_has() {
local asset_list="$1"
local candidate="$2"
printf '%s\n' "$asset_list" | grep -Fx "$candidate" >/dev/null 2>&1
}
select_naiveproxy_asset() {
local asset_list="$1"
local tag="$2"
local arch="$3"
local candidate linux_arch candidate_arch
if is_openwrt_env; then
for candidate_arch in $(naiveproxy_openwrt_arch_candidates "$arch"); do
candidate="naiveproxy-${tag}-openwrt-${candidate_arch}-static.tar.xz"
if asset_list_has "$asset_list" "$candidate"; then
printf '%s' "$candidate"
return 0
fi
candidate="naiveproxy-${tag}-openwrt-${candidate_arch}.tar.xz"
if asset_list_has "$asset_list" "$candidate"; then
printf '%s' "$candidate"
return 0
fi
done
fi
linux_arch="$(map_naiveproxy_linux_asset "$arch" 2>/dev/null || true)"
if [ -n "$linux_arch" ]; then
candidate="naiveproxy-${tag}-linux-${linux_arch}.tar.xz"
if asset_list_has "$asset_list" "$candidate"; then
printf '%s' "$candidate"
return 0
fi
fi
return 1
}
get_naiveproxy_latest_info() {
local arch release_json tag version asset asset_list url
arch="$(get_openwrt_arch)"
release_json="$(fetch_text "$NAIVEPROXY_RELEASE_API")" || return 3
tag="$(printf '%s\n' "$release_json" | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | sed -n '1p')"
[ -n "$tag" ] || return 3
version="$(trim_version "$tag")"
asset_list="$(printf '%s\n' "$release_json" | sed -n 's/.*"name":[[:space:]]*"\([^"]*\.tar\.xz\)".*/\1/p')"
asset="$(select_naiveproxy_asset "$asset_list" "$tag" "$arch")" || return 4
url="$(mirror_wrap_url "https://github.com/klzgrad/naiveproxy/releases/download/$tag/$asset")"
log_kv arch "$arch"
log_kv asset "$asset"
log_kv latest_version "$version"
log_kv download_url "$url"
return 0
}
xray_info() {
local current installed latest_output latest_rc latest_version arch asset can_upgrade
installed=0
current=""
arch="$(get_openwrt_arch)"
asset="$(map_xray_asset "$arch" 2>/dev/null || true)"
if current="$(get_xray_current_version)" && [ -n "$current" ]; then
installed=1
fi
latest_output="$(get_xray_latest_info 2>/dev/null)"
latest_rc=$?
log_kv component xray
log_kv installed "$installed"
log_kv current_version "$current"
log_kv arch "$arch"
log_kv asset "$asset"
if [ $latest_rc -ne 0 ]; then
log_kv can_upgrade 0
case "$latest_rc" in
2) log_kv error 'unsupported_arch' ;;
3) log_kv error 'fetch_failed' ;;
4) log_kv error 'asset_not_found' ;;
*) log_kv error 'unknown_error' ;;
esac
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')"
asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')"
can_upgrade=0
if [ -z "$current" ] || version_gt "$latest_version" "$current"; then
can_upgrade=1
fi
printf '%s\n' "$latest_output" | sed '/^download_url=/d'
log_kv can_upgrade "$can_upgrade"
log_kv error ''
}
mihomo_info() {
local current installed latest_output latest_rc latest_version arch asset can_upgrade
installed=0
current=""
arch="$(get_openwrt_arch)"
if current="$(get_mihomo_current_version)" && [ -n "$current" ]; then
installed=1
asset="$(map_mihomo_asset "$arch" "$current" 2>/dev/null || true)"
else
asset=""
fi
latest_output="$(get_mihomo_latest_info 2>/dev/null)"
latest_rc=$?
log_kv component mihomo
log_kv installed "$installed"
log_kv current_version "$current"
log_kv arch "$arch"
log_kv asset "$asset"
if [ $latest_rc -ne 0 ]; then
log_kv can_upgrade 0
case "$latest_rc" in
2) log_kv error 'unsupported_arch' ;;
3) log_kv error 'fetch_failed' ;;
4) log_kv error 'asset_not_found' ;;
*) log_kv error 'unknown_error' ;;
esac
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')"
asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')"
can_upgrade=0
if [ -z "$current" ] || version_gt "$latest_version" "$current"; then
can_upgrade=1
fi
printf '%s\n' "$latest_output" | sed '/^download_url=/d'
log_kv can_upgrade "$can_upgrade"
log_kv error ''
}
naiveproxy_info() {
local current installed latest_output latest_rc latest_version arch asset can_upgrade
installed=0
current=""
arch="$(get_openwrt_arch)"
if current="$(get_naiveproxy_current_version)" && [ -n "$current" ]; then
installed=1
fi
latest_output="$(get_naiveproxy_latest_info 2>/dev/null)"
latest_rc=$?
log_kv component naiveproxy
log_kv installed "$installed"
log_kv current_version "$current"
log_kv arch "$arch"
log_kv asset ''
if [ $latest_rc -ne 0 ]; then
log_kv can_upgrade 0
case "$latest_rc" in
3) log_kv error 'fetch_failed' ;;
4) log_kv error 'asset_not_found' ;;
*) log_kv error 'unknown_error' ;;
esac
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
arch="$(printf '%s\n' "$latest_output" | sed -n 's/^arch=//p' | sed -n '1p')"
asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')"
can_upgrade=0
if [ -z "$current" ]; then
can_upgrade=1
elif ! naiveproxy_versions_equal "$latest_version" "$current" && version_gt "$latest_version" "$current"; then
can_upgrade=1
fi
printf '%s\n' "$latest_output" | sed '/^download_url=/d'
log_kv can_upgrade "$can_upgrade"
log_kv error ''
}
xray_local_info() {
local current installed arch asset
installed=0
current=""
arch="$(get_openwrt_arch)"
asset="$(map_xray_asset "$arch" 2>/dev/null || true)"
if current="$(get_xray_current_version)" && [ -n "$current" ]; then
installed=1
fi
log_kv component xray
log_kv installed "$installed"
log_kv current_version "$current"
log_kv latest_version ''
log_kv arch "$arch"
log_kv asset "$asset"
log_kv can_upgrade 0
log_kv error ''
}
mihomo_local_info() {
local current installed arch asset
installed=0
current=""
arch="$(get_openwrt_arch)"
if current="$(get_mihomo_current_version)" && [ -n "$current" ]; then
installed=1
asset="$(map_mihomo_asset "$arch" "$current" 2>/dev/null || true)"
else
asset=""
fi
log_kv component mihomo
log_kv installed "$installed"
log_kv current_version "$current"
log_kv latest_version ''
log_kv arch "$arch"
log_kv asset "$asset"
log_kv can_upgrade 0
log_kv error ''
}
naiveproxy_local_info() {
local current installed arch
installed=0
current=""
arch="$(get_openwrt_arch)"
if current="$(get_naiveproxy_current_version)" && [ -n "$current" ]; then
installed=1
fi
log_kv component naiveproxy
log_kv installed "$installed"
log_kv current_version "$current"
log_kv latest_version ''
log_kv arch "$arch"
log_kv asset ''
log_kv can_upgrade 0
log_kv error ''
}
xray_upgrade() {
local latest_output latest_rc latest_version download_url tmp_dir zip_file unzip_cmd backup_file current_before current_after
latest_output="$(get_xray_latest_info 2>/dev/null)"
latest_rc=$?
if [ $latest_rc -ne 0 ]; then
log_kv success 0
case "$latest_rc" in
2) log_kv message 'Unsupported ARCH' ;;
3) log_kv message 'Failed to fetch release metadata' ;;
4) log_kv message 'Matching release asset not found' ;;
*) log_kv message 'Unknown error' ;;
esac
return 0
fi
if ! unzip_cmd="$(select_unzip_cmd)"; then
log_kv success 0
log_kv message 'Missing unzip support'
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')"
current_before="$(get_xray_current_version 2>/dev/null || true)"
if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_before"
log_kv latest_version "$latest_version"
log_kv message 'Already up to date'
return 0
fi
tmp_dir="$(mktemp -d /tmp/ssrplus-xray.XXXXXX)"
if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then
log_kv success 0
log_kv message 'Failed to create temp directory'
return 0
fi
zip_file="$tmp_dir/xray.zip"
backup_file="$tmp_dir/xray.backup"
trap "rm -rf '$tmp_dir'" EXIT INT TERM
if ! download_file "$download_url" "$zip_file"; then
log_kv success 0
log_kv message 'Download failed'
return 0
fi
if ! sh -c "$unzip_cmd \"$zip_file\" -d \"$tmp_dir\" >/dev/null 2>&1"; then
log_kv success 0
log_kv message 'Extract failed'
return 0
fi
if [ ! -f "$tmp_dir/xray" ]; then
log_kv success 0
log_kv message 'xray binary not found in archive'
return 0
fi
chmod 0755 "$tmp_dir/xray" || true
if [ -x "$XRAY_BINARY" ]; then
cp -fp "$XRAY_BINARY" "$backup_file" 2>/dev/null || true
fi
if ! cp -f "$tmp_dir/xray" "$XRAY_BINARY"; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$XRAY_BINARY" 2>/dev/null || true
fi
log_kv success 0
log_kv message 'Install failed'
return 0
fi
chmod 0755 "$XRAY_BINARY" || true
current_after="$(get_xray_current_version 2>/dev/null || true)"
if [ -z "$current_after" ]; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$XRAY_BINARY" 2>/dev/null || true
chmod 0755 "$XRAY_BINARY" || true
fi
log_kv success 0
log_kv message 'Installed binary failed to run'
return 0
fi
if [ -x /etc/init.d/shadowsocksr ]; then
/etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true
fi
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_after"
log_kv latest_version "$latest_version"
log_kv message 'Upgrade completed'
return 0
}
mihomo_upgrade() {
local latest_output latest_rc latest_version download_url tmp_dir gz_file gzip_cmd backup_file current_before current_after target_binary extracted_binary
latest_output="$(get_mihomo_latest_info 2>/dev/null)"
latest_rc=$?
if [ $latest_rc -ne 0 ]; then
log_kv success 0
case "$latest_rc" in
2) log_kv message 'Unsupported ARCH' ;;
3) log_kv message 'Failed to fetch release metadata' ;;
4) log_kv message 'Matching release asset not found' ;;
*) log_kv message 'Unknown error' ;;
esac
return 0
fi
if ! gzip_cmd="$(select_gzip_cmd)"; then
log_kv success 0
log_kv message 'Missing gzip support'
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')"
current_before="$(get_mihomo_current_version 2>/dev/null || true)"
if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_before"
log_kv latest_version "$latest_version"
log_kv message 'Already up to date'
return 0
fi
target_binary="$(find_mihomo_binary 2>/dev/null || true)"
[ -n "$target_binary" ] || target_binary="$MIHOMO_BINARY"
tmp_dir="$(mktemp -d /tmp/ssrplus-mihomo.XXXXXX)"
if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then
log_kv success 0
log_kv message 'Failed to create temp directory'
return 0
fi
gz_file="$tmp_dir/mihomo.gz"
backup_file="$tmp_dir/mihomo.backup"
extracted_binary="$tmp_dir/mihomo"
trap "rm -rf '$tmp_dir'" EXIT INT TERM
if ! download_file "$download_url" "$gz_file"; then
log_kv success 0
log_kv message 'Download failed'
return 0
fi
if ! sh -c "$gzip_cmd \"$gz_file\" > \"$extracted_binary\""; then
log_kv success 0
log_kv message 'Extract failed'
return 0
fi
if [ ! -s "$extracted_binary" ]; then
log_kv success 0
log_kv message 'mihomo binary not found in archive'
return 0
fi
mkdir -p "$(dirname "$target_binary")" || true
chmod 0755 "$extracted_binary" || true
if [ -x "$target_binary" ]; then
cp -fp "$target_binary" "$backup_file" 2>/dev/null || true
fi
if ! cp -f "$extracted_binary" "$target_binary"; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$target_binary" 2>/dev/null || true
fi
log_kv success 0
log_kv message 'Install failed'
return 0
fi
chmod 0755 "$target_binary" || true
if [ "$target_binary" != "$MIHOMO_BINARY" ] && [ ! -x "$MIHOMO_BINARY" ]; then
ln -sf "$target_binary" "$MIHOMO_BINARY" 2>/dev/null || true
fi
current_after="$(get_mihomo_current_version 2>/dev/null || true)"
if [ -z "$current_after" ]; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$target_binary" 2>/dev/null || true
chmod 0755 "$target_binary" || true
fi
log_kv success 0
log_kv message 'Installed binary failed to run'
return 0
fi
if [ -x /etc/init.d/shadowsocksr ]; then
/etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true
fi
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_after"
log_kv latest_version "$latest_version"
log_kv message 'Upgrade completed'
return 0
}
naiveproxy_upgrade() {
local latest_output latest_rc latest_version download_url tmp_dir archive_file xz_cmd tar_cmd backup_file current_before current_after target_binary extracted_binary
latest_output="$(get_naiveproxy_latest_info 2>/dev/null)"
latest_rc=$?
if [ $latest_rc -ne 0 ]; then
log_kv success 0
case "$latest_rc" in
3) log_kv message 'Failed to fetch release metadata' ;;
4) log_kv message 'Matching release asset not found' ;;
*) log_kv message 'Unknown error' ;;
esac
return 0
fi
if ! xz_cmd="$(select_xz_cmd)"; then
log_kv success 0
log_kv message 'Missing xz support'
return 0
fi
if ! tar_cmd="$(select_tar_cmd)"; then
log_kv success 0
log_kv message 'Extract failed'
return 0
fi
latest_version="$(printf '%s\n' "$latest_output" | sed -n 's/^latest_version=//p' | sed -n '1p')"
download_url="$(printf '%s\n' "$latest_output" | sed -n 's/^download_url=//p' | sed -n '1p')"
current_before="$(get_naiveproxy_current_version 2>/dev/null || true)"
if [ -n "$current_before" ] && ! version_gt "$latest_version" "$current_before"; then
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_before"
log_kv latest_version "$latest_version"
log_kv message 'Already up to date'
return 0
fi
target_binary="$(find_naiveproxy_binary 2>/dev/null || true)"
[ -n "$target_binary" ] || target_binary="$NAIVEPROXY_BINARY"
tmp_dir="$(mktemp -d /tmp/ssrplus-naiveproxy.XXXXXX)"
if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then
log_kv success 0
log_kv message 'Failed to create temp directory'
return 0
fi
archive_file="$tmp_dir/naiveproxy.tar.xz"
backup_file="$tmp_dir/naive.backup"
extracted_binary=""
trap "rm -rf '$tmp_dir'" EXIT INT TERM
if ! download_file "$download_url" "$archive_file"; then
log_kv success 0
log_kv message 'Download failed'
return 0
fi
mkdir -p "$tmp_dir/extract" || {
log_kv success 0
log_kv message 'Failed to create temp directory'
return 0
}
if ! sh -c "cd \"$tmp_dir/extract\" && $xz_cmd \"$archive_file\" | $tar_cmd -xf - >/dev/null 2>&1"; then
log_kv success 0
log_kv message 'Extract failed'
return 0
fi
extracted_binary="$(find "$tmp_dir/extract" -type f -name naive | sed -n '1p')"
if [ -z "$extracted_binary" ] || [ ! -s "$extracted_binary" ]; then
log_kv success 0
log_kv message 'naive binary not found in archive'
return 0
fi
mkdir -p "$(dirname "$target_binary")" || true
chmod 0755 "$extracted_binary" || true
if [ -x "$target_binary" ]; then
cp -fp "$target_binary" "$backup_file" 2>/dev/null || true
fi
if ! cp -f "$extracted_binary" "$target_binary"; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$target_binary" 2>/dev/null || true
fi
log_kv success 0
log_kv message 'Install failed'
return 0
fi
chmod 0755 "$target_binary" || true
if [ "$target_binary" != "$NAIVEPROXY_BINARY" ] && [ ! -x "$NAIVEPROXY_BINARY" ]; then
ln -sf "$target_binary" "$NAIVEPROXY_BINARY" 2>/dev/null || true
fi
current_after="$(get_naiveproxy_current_version 2>/dev/null || true)"
if [ -z "$current_after" ]; then
if [ -f "$backup_file" ]; then
cp -f "$backup_file" "$target_binary" 2>/dev/null || true
chmod 0755 "$target_binary" || true
fi
log_kv success 0
log_kv message 'Installed binary failed to run'
return 0
fi
if [ -x /etc/init.d/shadowsocksr ]; then
/etc/init.d/shadowsocksr restart >/dev/null 2>&1 || true
fi
log_kv success 1
log_kv previous_version "$current_before"
log_kv current_version "$current_after"
log_kv latest_version "$latest_version"
log_kv message 'Upgrade completed'
return 0
}
case "${1:-}" in
xray_info)
xray_info
;;
xray_local_info)
xray_local_info
;;
xray_upgrade)
xray_upgrade
;;
mihomo_info)
mihomo_info
;;
mihomo_local_info)
mihomo_local_info
;;
mihomo_upgrade)
mihomo_upgrade
;;
naiveproxy_info)
naiveproxy_info
;;
naiveproxy_local_info)
naiveproxy_local_info
;;
naiveproxy_upgrade)
naiveproxy_upgrade
;;
country_mmdb_info)
geo_local_info country_mmdb
;;
country_mmdb_local_info)
geo_local_info country_mmdb
;;
country_mmdb_upgrade)
geo_upgrade country_mmdb
;;
geosite_info)
geo_local_info geosite
;;
geosite_local_info)
geo_local_info geosite
;;
geosite_upgrade)
geo_upgrade geosite
;;
v2ray_geo_info)
geo_local_info v2ray_geo
;;
v2ray_geo_local_info)
geo_local_info v2ray_geo
;;
v2ray_geo_upgrade)
geo_upgrade v2ray_geo
;;
*)
log_kv success 0
log_kv message 'Usage: update_components.sh xray_info|xray_local_info|xray_upgrade|mihomo_info|mihomo_local_info|mihomo_upgrade|naiveproxy_info|naiveproxy_local_info|naiveproxy_upgrade|country_mmdb_info|country_mmdb_local_info|country_mmdb_upgrade|geosite_info|geosite_local_info|geosite_upgrade|v2ray_geo_info|v2ray_geo_local_info|v2ray_geo_upgrade'
return 1 2>/dev/null || exit 1
;;
esac