mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 11:55:13 +08:00
⛄ Sync 2026-06-30 01:11:33
This commit is contained in:
1 parent
fb3826f4ad
commit
a09508c01e
157 files changed
+78873
-73698
No files matched your search
@@ -741,13 +741,61 @@ has_mihomo_binary() {
|
||||
}
|
||||
|
||||
use_mihomo_for_ss_rust_client() {
|
||||
has_ss_rust_client_binary && return 1
|
||||
# 检查核心是否存在 (has_ss_rust_client_binary 成功返回 0,失败返回 1)
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
has_ss_rust_client_binary
|
||||
local has_ss=$?
|
||||
|
||||
has_mihomo_binary
|
||||
local has_mh=$?
|
||||
|
||||
# echolog "DEBUG: sslocal_path=[$has_ss], mihomo_path=[$has_mh], enable_mihomo=[$enable_mihomo]"
|
||||
|
||||
if [ "$enable_mihomo" = "1" ]; then
|
||||
if [ $has_mh -eq 0 ]; then
|
||||
return 0 # 使用 Mihomo
|
||||
elif [ $has_ss -eq 0 ]; then
|
||||
return 1 # Mihomo 不存在,回退到 sslocal
|
||||
fi
|
||||
else
|
||||
if [ $has_ss -eq 0 ]; then
|
||||
return 1 # 使用 sslocal
|
||||
elif [ $has_mh -eq 0 ]; then
|
||||
return 0 # sslocal 不存在,回退到 Mihomo
|
||||
fi
|
||||
fi
|
||||
|
||||
# 如果两个都不存在,默认走 sslocal 逻辑
|
||||
return 1
|
||||
}
|
||||
|
||||
use_mihomo_for_ss_rust_server() {
|
||||
has_ss_rust_server_binary && return 1
|
||||
# 检查核心是否存在 (has_ss_rust_client_binary 成功返回 0,失败返回 1)
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
has_ss_rust_server_binary
|
||||
local has_ss=$?
|
||||
|
||||
has_mihomo_binary
|
||||
local has_mh=$?
|
||||
|
||||
# echolog "DEBUG: sslocal_path=[$has_ss], mihomo_path=[$has_mh], enable_mihomo=[$enable_mihomo]"
|
||||
|
||||
if [ "$enable_mihomo" = "1" ]; then
|
||||
if [ $has_mh -eq 0 ]; then
|
||||
return 0 # 使用 Mihomo
|
||||
elif [ $has_ss -eq 0 ]; then
|
||||
return 1 # Mihomo 不存在,回退到 ssserver
|
||||
fi
|
||||
else
|
||||
if [ $has_ss -eq 0 ]; then
|
||||
return 1 # 使用 ssserver
|
||||
elif [ $has_mh -eq 0 ]; then
|
||||
return 0 # ssserver 不存在,回退到 Mihomo
|
||||
fi
|
||||
fi
|
||||
|
||||
# 如果两个都不存在,默认走 ssserver 逻辑
|
||||
return 1
|
||||
}
|
||||
|
||||
start_v2ray_with_mihomo() {
|
||||
@@ -1102,7 +1150,6 @@ start_dns() {
|
||||
fi
|
||||
}
|
||||
|
||||
# 生成 Xray 服务端配置
|
||||
# 生成 Xray 服务端配置
|
||||
generate_xray_config() {
|
||||
local type="$1"
|
||||
@@ -1388,7 +1435,7 @@ start_udp() {
|
||||
elif [ "$udp_relay_server_type" = "ss-rust" ] && use_mihomo_for_ss_rust_client; then
|
||||
redir_udp=0
|
||||
ARG_UDP=""
|
||||
echolog "UDP TPROXY Relay:ss-rust 主程序不存在,已回退到 Mihomo 主实例处理。"
|
||||
echolog "UDP TPROXY Relay:$(get_name ${type})-Rust 内核不存在,已回退到 Mihomo ($(get_name ${type})) 主实例处理。"
|
||||
else
|
||||
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
|
||||
if [ "$udp_relay_server_type" = "ssr" ]; then
|
||||
@@ -1402,18 +1449,37 @@ start_udp() {
|
||||
rm -rf "$TMP_PATH/bin/${type}-redir"
|
||||
fi
|
||||
ln_start_bin $ss_program ${type}-redir -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:$(get_name $type) Started!"
|
||||
if [ "$udp_relay_server_type" = "ssr" ] || [ "$udp_relay_server_type" = "ss" ]; then
|
||||
echolog "UDP TPROXY Relay:$(get_name $type) Started!"
|
||||
elif [ "$udp_relay_server_type" = "ss-rust" ]; then
|
||||
echolog "UDP TPROXY Relay:$(get_name $type)-Rust Started!"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
v2ray)
|
||||
if has_mihomo_binary; then
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
if [ "$enable_mihomo" = "1" ] && has_mihomo_binary; then
|
||||
redir_udp=0
|
||||
ARG_UDP=""
|
||||
echolog "UDP TPROXY Relay:V2Ray/Xray 单节点由主 Mihomo 实例处理。"
|
||||
else
|
||||
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:$($(first_type xray) version | head -1) Started!"
|
||||
# enable_mihomo=0 → 尝试 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:$($(first_type xray) version | head -1) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if has_mihomo_binary; then
|
||||
redir_udp=0
|
||||
ARG_UDP=""
|
||||
echolog "UDP TPROXY Relay:Xray 内核不存在,已回退到 Mihomo 内核启动。"
|
||||
else
|
||||
echolog "UDP TPROXY Relay:V2Ray/Xray 节点无法启动,Xray 和 Mihomo 内核均不存在。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
trojan) #client
|
||||
@@ -1440,11 +1506,24 @@ start_udp() {
|
||||
local chain_type=$(uci_get_by_name $UDP_RELAY_SERVER chain_type)
|
||||
case ${chain_type} in
|
||||
vmess)
|
||||
if start_v2ray_with_mihomo "$UDP_RELAY_SERVER" "$tmp_udp_port" "0" "${UDP_RELAY_SERVER}-shadowtls-udp" "redir" "shadowtls-vmess-udp" "UDP TPROXY Relay:shadow-tls chain-to"; then
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$UDP_RELAY_SERVER" "$tmp_udp_port" "0" "${UDP_RELAY_SERVER}-shadowtls-udp" "redir" "shadowtls-vmess-udp" "UDP TPROXY Relay:shadow-tls chain-to"; then
|
||||
:
|
||||
else
|
||||
ln_start_bin $(first_type xray) v2ray run -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:shadow-tls chain-to $($(first_type xray) --version) Started!"
|
||||
# enable_mihomo=0 或 Mihomo 启动失败 → 尝试 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
ln_start_bin $(first_type xray) v2ray run -c $udp_config_file
|
||||
echolog "UDP TPROXY Relay:shadow-tls chain-to $($(first_type xray) --version) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if start_v2ray_with_mihomo "$UDP_RELAY_SERVER" "$tmp_udp_port" "0" "${UDP_RELAY_SERVER}-shadowtls-udp" "redir" "shadowtls-vmess-udp" "UDP TPROXY Relay:shadow-tls chain-to"; then
|
||||
echolog "UDP TPROXY Relay:shadow-tls chain-to Xray 内核不存在,已回退到 Mihomo 内核启动。。"
|
||||
else
|
||||
echolog "UDP TPROXY Relay:shadow-tls chain-to Xray 和 Mihomo 内核均不存在,无法启动。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
sslocal)
|
||||
@@ -1505,9 +1584,9 @@ start_local() {
|
||||
local ss_workdir="$(get_ss_mihomo_workdir "$instance_key")"
|
||||
ln_start_bin "$mihomo_bin" ss-local -d "$ss_workdir" -f "$ss_workdir/config.yaml"
|
||||
if [ "$local_server_type" = "ss-rust" ]; then
|
||||
echolog "Global_Socks5:ss-rust 主程序不存在,已回退到 Mihomo (Shadowsocks) 启动。"
|
||||
echolog "Global_Socks5:$(get_name $type)-Rust 内核不存在,已回退到 Mihomo ($(get_name $type)-Rust) 启动。"
|
||||
else
|
||||
echolog "Global_Socks5:Mihomo (Shadowsocks) Started!"
|
||||
echolog "Global_Socks5:Mihomo ($(get_name $type)) Started!"
|
||||
fi
|
||||
else
|
||||
gen_config_file $LOCAL_SERVER $type 4 $local_port
|
||||
@@ -1518,21 +1597,34 @@ start_local() {
|
||||
rm -rf "$TMP_PATH/bin/${type}-local"
|
||||
fi
|
||||
ln_start_bin $ss_program ${type}-local -c $local_config_file
|
||||
echolog "Global_Socks5:Shadowsocks-rust Started!"
|
||||
echolog "Global_Socks5:$(get_name $type)-Rust Started!"
|
||||
fi
|
||||
;;
|
||||
v2ray)
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
local instance_key="${LOCAL_SERVER}-local"
|
||||
[ -n "$probe_instance_key" ] && instance_key="$probe_instance_key"
|
||||
if start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" "v2ray-local" "Global_Socks5"; then
|
||||
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" "v2ray-local" "Global_Socks5"; then
|
||||
:
|
||||
elif [ "$(uci_get_by_name "$LOCAL_SERVER" v2ray_protocol)" = "snell" ]; then
|
||||
echolog "Global_Socks5:Snell 需要 Mihomo 内核,且当前 Mihomo 启动失败。"
|
||||
return 1
|
||||
elif [ "$_local" == "2" ]; then
|
||||
gen_config_file $LOCAL_SERVER $type 4 0 $local_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $local_config_file
|
||||
echolog "Global_Socks5:$($(first_type xray) version | head -1) Started!"
|
||||
# 尝试 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
gen_config_file $LOCAL_SERVER $type 4 0 $local_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $local_config_file
|
||||
echolog "Global_Socks5:$($(first_type xray) version | head -1) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" "v2ray-local" "Global_Socks5"; then
|
||||
echolog "Global_Socks5:Xray 内核不存在,已回退到 Mihomo 内核启动"
|
||||
else
|
||||
echolog "Global_Socks5:Xray 和 Mihomo 内核均不存在,无法启动。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
@@ -1560,29 +1652,43 @@ start_local() {
|
||||
ln_start_bin "$mihomo_bin" tuic-local -d "$tuic_workdir" -f "$tuic_workdir/config.yaml"
|
||||
echolog "Global_Socks5:Mihomo (TUIC) Started!"
|
||||
;;
|
||||
shadowtls)
|
||||
#respective config for global socks and main node
|
||||
if [ "$_local" == "2" ]; then
|
||||
gen_config_file $LOCAL_SERVER $type 4 "10${tmp_tcp_local_port}"
|
||||
shadowtls)
|
||||
#respective config for global socks and main node
|
||||
if [ "$_local" == "2" ]; then
|
||||
gen_config_file $LOCAL_SERVER $type 4 "10${tmp_tcp_local_port}"
|
||||
gen_config_file $LOCAL_SERVER $type 4 0 $local_port chain/"10${tmp_tcp_local_port}"
|
||||
ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_local_config_file
|
||||
local chain_type=$(uci_get_by_name $LOCAL_SERVER chain_type)
|
||||
case ${chain_type} in
|
||||
vmess)
|
||||
if start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "${LOCAL_SERVER}-shadowtls-local" "socks" "shadowtls-vmess-local" "Global Socks5 Proxy:shadow-tls chain-to"; then
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
# 优先尝试 Mihomo(enable_mihomo=1 时)
|
||||
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "${LOCAL_SERVER}-shadowtls-local" "socks" "shadowtls-vmess-local" "Global Socks5 Proxy:shadow-tls chain-to"; then
|
||||
:
|
||||
else
|
||||
ln_start_bin $(first_type xray) v2ray run -c $local_config_file
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type xray) --version) Started!"
|
||||
# enable_mihomo=0 或 Mihomo 启动失败 → 尝试 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
ln_start_bin $(first_type xray) v2ray run -c $local_config_file
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type xray) --version) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "${LOCAL_SERVER}-shadowtls-local" "socks" "shadowtls-vmess-local" "Global Socks5 Proxy:shadow-tls chain-to"; then
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to Xray 内核不存在,已回退到 Mihomo 内核启动。"
|
||||
else
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to Xray 和 Mihomo 内核均不存在,无法启动。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
sslocal)
|
||||
ln_start_bin $(first_type sslocal) sslocal -c $local_config_file
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type sslocal) --version) Started!"
|
||||
echolog "Global Socks5 Proxy:shadow-tls chain-to $($(first_type sslocal) --version) Started!"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
clash)
|
||||
echolog "Global_Socks5:Clash total node is only supported when using Same as Global Server."
|
||||
return 1
|
||||
@@ -1854,9 +1960,9 @@ Start_Run() {
|
||||
local ss_workdir="$(get_ss_mihomo_workdir "$GLOBAL_SERVER")"
|
||||
ln_start_bin "$mihomo_bin" ssr-retcp -d "$ss_workdir" -f "$ss_workdir/config.yaml"
|
||||
if [ "$global_server_type" = "ss-rust" ]; then
|
||||
echolog "Main node:ss-rust 主程序不存在,已回退到 Mihomo (Shadowsocks) 启动。"
|
||||
echolog "Main node:$(get_name ${type})-Rust 内核不存在,已回退到 Mihomo ($(get_name ${type})-Rust) 启动。"
|
||||
else
|
||||
echolog "Main node:Mihomo (Shadowsocks) Started!"
|
||||
echolog "Main node:Mihomo ($(get_name ${type})) Started!"
|
||||
fi
|
||||
else
|
||||
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port
|
||||
@@ -1867,19 +1973,32 @@ Start_Run() {
|
||||
rm -rf "$TMP_PATH/bin/${type}-redir"
|
||||
fi
|
||||
ln_start_bin $ss_program ${type}-redir -c $tcp_config_file
|
||||
echolog "Main node:Shadowsocks-rust Started!"
|
||||
echolog "Main node:$(get_name ${type})-Rust Started!"
|
||||
fi
|
||||
;;
|
||||
v2ray)
|
||||
if start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "$GLOBAL_SERVER" "redir" "ssr-retcp" "Main node"; then
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "$GLOBAL_SERVER" "redir" "ssr-retcp" "Main node"; then
|
||||
:
|
||||
elif [ "$(uci_get_by_name "$GLOBAL_SERVER" v2ray_protocol)" = "snell" ]; then
|
||||
echolog "Main node:Snell 需要 Mihomo 内核,且当前 Mihomo 启动失败。"
|
||||
return 1
|
||||
else
|
||||
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file
|
||||
echolog "Main node:$($(first_type xray) version | head -1) Started!"
|
||||
# enable_mihomo=0 或 Mihomo 启动失败(非 Snell)→ 优先使用 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
|
||||
ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file
|
||||
echolog "Main node:$($(first_type xray) version | head -1) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "$GLOBAL_SERVER" "redir" "ssr-retcp" "Main node"; then
|
||||
echolog "Main node:Xray 内核不存在,已回退到 Mihomo 内核启动。"
|
||||
else
|
||||
echolog "Main node:Xray 和 Mihomo 内核均不存在,无法启动。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
trojan)
|
||||
@@ -1920,12 +2039,25 @@ Start_Run() {
|
||||
local chain_type=$(uci_get_by_name $GLOBAL_SERVER chain_type)
|
||||
case ${chain_type} in
|
||||
vmess)
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file
|
||||
if start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "${GLOBAL_SERVER}-shadowtls" "redir" "shadowtls-vmess" "Main node:shadow-tls chain-to"; then
|
||||
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "${GLOBAL_SERVER}-shadowtls" "redir" "shadowtls-vmess" "Main node:shadow-tls chain-to"; then
|
||||
:
|
||||
else
|
||||
ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file
|
||||
echolog "Mian node:shadow-tls chain-to $($(first_type xray) --version) Started!"
|
||||
# enable_mihomo=0 或 Mihomo 启动失败 → 尝试 Xray
|
||||
local xray_bin="$(first_type xray)"
|
||||
if [ -n "$xray_bin" ]; then
|
||||
ln_start_bin $(first_type xray) v2ray run -c $tcp_config_file
|
||||
echolog "Mian node:shadow-tls chain-to $($(first_type xray) --version) Started!"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "${GLOBAL_SERVER}-shadowtls" "redir" "shadowtls-vmess" "Main node:shadow-tls chain-to"; then
|
||||
echolog "Main node:shadow-tls chain-to Xray 内核不存在,已回退到 Mihomo 内核启动。"
|
||||
else
|
||||
echolog "Main node:shadow-tls chain-to Xray 和 Mihomo 内核均不存在,无法启动。"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
sslocal)
|
||||
@@ -2119,9 +2251,9 @@ start_server() {
|
||||
local ss_server_workdir="$(get_ss_server_mihomo_workdir "$1")"
|
||||
ln_start_bin "$mihomo_bin" ss-server-$server_count -d "$ss_server_workdir" -f "$ss_server_workdir/config.yaml"
|
||||
if [ "$node_type" = "ss-rust" ]; then
|
||||
echolog "Server:ss-rust 主程序不存在,已回退到 Mihomo Shadowsocks Server$server_count 启动。"
|
||||
echolog "Server:$(get_name ${type})-Rust 内核不存在,已回退到 Mihomo ($(get_name ${type})) Server$server_count 启动。"
|
||||
else
|
||||
echolog "Server:Mihomo Shadowsocks Server$server_count Started!"
|
||||
echolog "Server:Mihomo ($(get_name ${type})) Server$server_count Started!"
|
||||
fi
|
||||
else
|
||||
gen_service_file ${type} $1 $TMP_PATH/ssr-server$server_count.json
|
||||
@@ -2135,7 +2267,11 @@ start_server() {
|
||||
rm -rf "$TMP_PATH/bin/${type}-server"
|
||||
fi
|
||||
ln_start_bin $ss_program ${type}-server -c $TMP_PATH/ssr-server$server_count.json
|
||||
echolog "Server: $(get_name ${type}) Server$server_count Started!"
|
||||
if [ "$node_type" = "ssr" ] || [ "$node_type" = "ss" ]; then
|
||||
echolog "Server: $(get_name ${type}) Server$server_count Started!"
|
||||
elif [ "$node_type" = "ss-rust" ]; then
|
||||
echolog "Server: $(get_name ${type})-Rust Server$server_count Started!"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
socks5)
|
||||
@@ -2166,6 +2302,7 @@ start_server() {
|
||||
local tcp_guise=$(uci_get_by_name "$1" tcp_guise "none")
|
||||
local tcp_guise_http_host=$(uci_get_by_name "$1" tcp_guise_http_host "")
|
||||
local tcp_guise_http_path=$(uci_get_by_name "$1" tcp_guise_http_path "")
|
||||
local enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
|
||||
local mihomo_server_started=0
|
||||
|
||||
# 确定密码/UUID
|
||||
@@ -2186,36 +2323,49 @@ start_server() {
|
||||
return 1
|
||||
}
|
||||
|
||||
local mihomo_bin="$(first_type mihomo)"
|
||||
if [ -x "$mihomo_bin" ] && prepare_v2ray_server_mihomo_runtime_config "$1"; then
|
||||
local server_workdir="$(get_v2ray_server_mihomo_workdir "$1")"
|
||||
ln_start_bin "$mihomo_bin" mihomo-server-$server_count -d "$server_workdir" -f "$server_workdir/config.yaml"
|
||||
echolog "Server: Mihomo $type 服务端 Server$server_count 已启动 (端口: $port)"
|
||||
mihomo_server_started=1
|
||||
if [ "$enable_mihomo" = "1" ]; then
|
||||
local mihomo_bin="$(first_type mihomo)"
|
||||
if [ -x "$mihomo_bin" ] && prepare_v2ray_server_mihomo_runtime_config "$1"; then
|
||||
local server_workdir="$(get_v2ray_server_mihomo_workdir "$1")"
|
||||
ln_start_bin "$mihomo_bin" mihomo-server-$server_count -d "$server_workdir" -f "$server_workdir/config.yaml"
|
||||
echolog "Server: Mihomo $type 服务端 Server$server_count 已启动 (端口: $port)"
|
||||
mihomo_server_started=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$mihomo_server_started" != "1" ]; then
|
||||
|
||||
local config_file="$TMP_PATH/xray-server-$server_count.json"
|
||||
|
||||
# 生成 Xray 配置
|
||||
generate_xray_config "$type" "$port" "$password" "$security" "$method" "$network" "$ws_path" "$ws_host" "$grpc_service" "$alter_id" "$tcp_guise" "$tcp_guise_http_host" "$tcp_guise_http_path" "$config_file"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echolog "Server: Xray $type 配置生成失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local xray_bin=$(first_type xray)
|
||||
if [ -z "$xray_bin" ]; then
|
||||
echolog "Server: xray-core 未安装,无法启动 $type 服务端"
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$xray_bin" ]; then
|
||||
local config_file="$TMP_PATH/xray-server-$server_count.json"
|
||||
# 生成 Xray 配置
|
||||
generate_xray_config "$type" "$port" "$password" "$security" "$method" "$network" "$ws_path" "$ws_host" "$grpc_service" "$alter_id" "$tcp_guise" "$tcp_guise_http_host" "$tcp_guise_http_path" "$config_file"
|
||||
|
||||
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
|
||||
echolog "Server: Xray $type 服务端 Server$server_count 已启动 (端口: $port)"
|
||||
if [ $? -ne 0 ]; then
|
||||
echolog "Server: Xray $type 配置生成失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
|
||||
echolog "Server: Xray $type 服务端 Server$server_count 已启动 (端口: $port)"
|
||||
else
|
||||
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
|
||||
if [ "$enable_mihomo" != "1" ]; then
|
||||
local mihomo_bin="$(first_type mihomo)"
|
||||
if [ -x "$mihomo_bin" ] && prepare_v2ray_server_mihomo_runtime_config "$1"; then
|
||||
local server_workdir="$(get_v2ray_server_mihomo_workdir "$1")"
|
||||
ln_start_bin "$mihomo_bin" mihomo-server-$server_count -d "$server_workdir" -f "$server_workdir/config.yaml"
|
||||
echolog "Server: Xray 内核不存在,已回退到 Mihomo $type 服务端 Server$server_count (端口: $port)"
|
||||
else
|
||||
echolog "Server: Xray 和 Mihomo 内核均不可用,无法启动 $type 服务端"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echolog "Server: Xray 和 Mihomo 内核均不可用,无法启动 $type 服务端"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
;;
|
||||
esac
|
||||
server_port=$(uci_get_by_name $1 server_port)
|
||||
if [ "$USE_TABLES" = "nftables" ]; then
|
||||
|
||||
@@ -840,14 +840,26 @@ local function build_v2ray_mihomo_proxy(sid)
|
||||
proxy.down = string_or_nil(get_server_field(sid, "downlink_capacity", "")) and (get_server_field(sid, "downlink_capacity", "") .. " Mbps") or nil
|
||||
proxy.sni = string_or_nil(get_server_field(sid, "tls_host", ""))
|
||||
proxy.fingerprint = string_or_nil(get_server_field(sid, "tls_CertSha", ""))
|
||||
proxy["cert-name"] = string_or_nil(get_server_field(sid, "tls_CertByName", ""))
|
||||
proxy["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0"))
|
||||
local alpn = split_alpn(get_server_field(sid, "tls_alpn", ""))
|
||||
if #alpn > 0 then
|
||||
proxy.alpn = alpn
|
||||
end
|
||||
if get_server_field(sid, "flag_obfs", "0") == "1" then
|
||||
proxy.obfs = string_or_nil(get_server_field(sid, "obfs_type", ""))
|
||||
local obfs_type = get_server_field(sid, "obfs_type", "")
|
||||
proxy.obfs = string_or_nil(obfs_type)
|
||||
proxy["obfs-password"] = string_or_nil(get_server_field(sid, "salamander", ""))
|
||||
if obfs_type == "gecko" then
|
||||
local min = tonumber(get_server_field(sid, "obfs_MinPacketSize", "")) or 512
|
||||
local max = tonumber(get_server_field(sid, "obfs_MaxPacketSize", "")) or 1200
|
||||
if min <= 0 or min > max or max > 2048 then
|
||||
min = 512
|
||||
max = 1200
|
||||
end
|
||||
proxy["obfs-min-packet-size"] = min
|
||||
proxy["obfs-max-packet-size"] = max
|
||||
end
|
||||
end
|
||||
elseif protocol == "socks" then
|
||||
if not can_mihomo_handle_v2ray_transport(protocol, sid) then
|
||||
|
||||
@@ -11,6 +11,14 @@ local socks_port = arg[4] or "0"
|
||||
|
||||
local chain = arg[5] or "0"
|
||||
|
||||
-- trim
|
||||
local function trim(text)
|
||||
if not text or text == "" then
|
||||
return ""
|
||||
end
|
||||
return (text:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
-- 辅助函数:拆分字符串(若 luci.util 未加载则定义)
|
||||
local function split(str, pat)
|
||||
local t = {}
|
||||
@@ -54,12 +62,20 @@ if server.type == "ss-rust" then
|
||||
end
|
||||
|
||||
local function parse_realm_uri(uri)
|
||||
if type(uri) ~= "string" then return nil end
|
||||
uri = trim(uri)
|
||||
if uri == "" then return nil end
|
||||
-- realm[+http]://token@server/realm_id?query
|
||||
local scheme, token, server_url, realm_id, query = trim(uri):match("^(realm%+http|realm)://([^@]+)@([^/]+)/([^?]*)%??(.*)$")
|
||||
if not scheme or not token or not server_url or not realm_id then return nil end
|
||||
local scheme = (uri:match("^realm%+http://") and "realm+http") or (uri:match("^realm://") and "realm")
|
||||
if not scheme then return nil end
|
||||
uri = uri:gsub("^realm%+http://", ""):gsub("^realm://", "")
|
||||
local token, server_url, realm_id, query = uri:match("^([^@]+)@([^/]+)/([^?]*)%??(.*)$")
|
||||
if not token or not server_url or not realm_id then return nil end
|
||||
realm_id = realm_id:gsub("/+$", "")
|
||||
local address, port = server_url:match("^%[?([^%]]+)%]?:?(%d*)$")
|
||||
local address, port = server_url:match("^%[([^%]]+)%]:(%d+)$") --ipv6:port
|
||||
if not address then
|
||||
address, port = server_url:match("^([^:]+):(%d+)$") --ipv4[domain]:port
|
||||
end
|
||||
address = address or server_url:match("^%[([^%]]+)%]$") or server_url
|
||||
port = tonumber(port) or (scheme == "realm+http" and 80 or 443)
|
||||
local realm = {
|
||||
scheme = scheme,
|
||||
@@ -71,9 +87,9 @@ local function parse_realm_uri(uri)
|
||||
}
|
||||
-- 解析 query 中的 stun=
|
||||
local stun_servers
|
||||
for value in (query or ""):gmatch("[?&]?[Ss][Tt][Uu][Nn]=([^&]+)") do
|
||||
if not stun_servers then stun_servers = {} end
|
||||
stun_servers[#stun_servers + 1] = value
|
||||
for v in (query or ""):gmatch("[Ss][Tt][Uu][Nn]=([^&]+)") do
|
||||
stun_servers = stun_servers or {}
|
||||
stun_servers[#stun_servers + 1] = v
|
||||
end
|
||||
realm.stun_servers = stun_servers
|
||||
return realm
|
||||
@@ -646,10 +662,18 @@ Xray.outbounds = {
|
||||
local o = {
|
||||
type = "salamander",
|
||||
settings = server.salamander and {
|
||||
password = server.salamander,
|
||||
packetSize = server.obfs_type == "gecko" and "512-1200" or nil
|
||||
password = server.salamander
|
||||
} or nil
|
||||
}
|
||||
if server.obfs_type == "gecko" then
|
||||
local min = tonumber(server.obfs_MinPacketSize) or 512
|
||||
local max = tonumber(server.obfs_MaxPacketSize) or 1200
|
||||
if min <= 0 or min > max or max > 2048 then
|
||||
min = 512
|
||||
max = 1200
|
||||
end
|
||||
o.settings.packetSize = min .. "-" .. max
|
||||
end
|
||||
udp[#udp+1] = o
|
||||
end
|
||||
if server.hysteria2_realms then
|
||||
@@ -713,26 +737,11 @@ Xray.outbounds = {
|
||||
local n_maxsplit = xray_fragment.fragment_maxSplit
|
||||
--local domainstr = xray_noise.domainStrategy
|
||||
finalmask.tcp = finalmask.tcp or {}
|
||||
|
||||
-- 辅助函数:将逗号分隔的字符串拆分为数组
|
||||
local function split_to_array(str)
|
||||
if not str or str == "" then return nil end
|
||||
local result = {}
|
||||
for value in string.gmatch(str, "[^,]+") do
|
||||
value = value:gsub("^%s*(.-)%s*$", "%1") -- 去除首尾空格
|
||||
if value ~= "" then
|
||||
table.insert(result, value)
|
||||
end
|
||||
end
|
||||
return #result > 0 and result or nil
|
||||
end
|
||||
|
||||
-- 构建 fragment settings
|
||||
local fragment_settings = {
|
||||
packets = (n_packets and n_packets ~= "") and n_packets or nil,
|
||||
maxSplit = (n_maxsplit and n_maxsplit ~= "") and n_maxsplit or nil
|
||||
}
|
||||
|
||||
-- 根据 Xray 版本决定使用旧格式还是新格式
|
||||
if xray_version_val <= 260601 then
|
||||
-- 旧版本:使用 length 和 delay(单个值)
|
||||
@@ -748,18 +757,30 @@ Xray.outbounds = {
|
||||
end
|
||||
else
|
||||
-- 新版本:使用 lengths 和 delays(数组)
|
||||
-- 拆分逗号分隔的字符串
|
||||
-- 将逗号分隔的字符串拆分为数组
|
||||
local function split_to_array(str)
|
||||
if not str or str == "" then return nil end
|
||||
local result = {}
|
||||
local trimmed = trim(str)
|
||||
if trimmed and trimmed ~= "" then
|
||||
trimmed:gsub("[^,]+", function(w)
|
||||
w = w:gsub("%s+", "")
|
||||
if w ~= "" then
|
||||
result[#result + 1] = w
|
||||
end
|
||||
end)
|
||||
end
|
||||
return #result > 0 and result or nil
|
||||
end
|
||||
local lengths_array = split_to_array(n_length)
|
||||
if lengths_array then
|
||||
fragment_settings.lengths = lengths_array
|
||||
end
|
||||
|
||||
local delays_array = split_to_array(n_delay)
|
||||
if delays_array then
|
||||
fragment_settings.delays = delays_array
|
||||
end
|
||||
end
|
||||
|
||||
finalmask.tcp[#finalmask.tcp + 1] = {
|
||||
type = "fragment",
|
||||
settings = fragment_settings
|
||||
@@ -956,6 +977,9 @@ local hysteria2 = {
|
||||
up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil,
|
||||
down = tonumber(server.downlink_capacity) and tonumber(server.downlink_capacity) .. " mbps" or nil
|
||||
} or nil,
|
||||
realm = (server.hysteria2_realms and server.hysteria2_realm_stun) and {
|
||||
stunServers = server.hysteria2_realm_stun
|
||||
} or nil,
|
||||
socks5 = (proto:find("tcp") and tonumber(socks_port) and tonumber(socks_port) ~= 0) and {
|
||||
listen = "0.0.0.0:" .. tonumber(socks_port),
|
||||
disableUDP = false
|
||||
@@ -997,7 +1021,7 @@ local hysteria2 = {
|
||||
} or nil,
|
||||
obfs = (server.flag_obfs == "1") and {
|
||||
type = server.obfs_type,
|
||||
salamander = { password = server.salamander }
|
||||
[server.obfs_type] = { password = server.salamander }
|
||||
} or nil,
|
||||
quic = (server.flag_quicparam == "1" ) and {
|
||||
initStreamReceiveWindow = (server.initstreamreceivewindow and server.initstreamreceivewindow or nil),
|
||||
@@ -1046,6 +1070,16 @@ local hysteria2 = {
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
lazy = (server.lazy_mode == "1") and true or false
|
||||
}
|
||||
if hysteria2.obfs and hysteria2.obfs.type == "gecko" then
|
||||
local min = tonumber(server.obfs_MinPacketSize) or 512
|
||||
local max = tonumber(server.obfs_MaxPacketSize) or 1200
|
||||
if min <= 0 or min > max or max > 2048 then
|
||||
min = 512
|
||||
max = 1200
|
||||
end
|
||||
hysteria2.obfs.gecko.minPacketSize = min
|
||||
hysteria2.obfs.gecko.maxPacketSize = max
|
||||
end
|
||||
local shadowtls = {
|
||||
client = {
|
||||
server_addr = server.server_port and format_host_port(server.server, server.server_port) or nil,
|
||||
|
||||
@@ -29,6 +29,8 @@ local allow_insecure = ucic:get_first(name, 'server_subscribe', 'allow_insecure'
|
||||
local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期/重置/套餐/剩余/网址/QQ群/官网/防失联/回国')
|
||||
local save_words = ucic:get_first(name, 'server_subscribe', 'save_words', '')
|
||||
local user_agent = ucic:get_first(name, 'server_subscribe', 'user_agent', 'v2rayN/9.99')
|
||||
-- 读取 enable_mihomo 配置
|
||||
local enable_mihomo = ucic:get_first(name, 'server_subscribe', 'enable_mihomo', '')
|
||||
local sub_convert = ucic:get_first(name, 'server_subscribe', 'sub_convert', '0')
|
||||
local convert_address = ucic:get_first(name, 'server_subscribe', 'convert_address', 'https://api.asailor.org/sub')
|
||||
local template_url = ucic:get_first(name, 'server_subscribe', 'template_url', '')
|
||||
@@ -44,8 +46,30 @@ local log = function(...)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({...}, " "))
|
||||
end
|
||||
|
||||
-- 检查是否需要使用 Mihomo 订阅模式
|
||||
local function should_use_mihomo_mode()
|
||||
-- 如果 enable_mihomo == 1,使用 Mihomo 模式
|
||||
if enable_mihomo == "1" and has_mihomo then
|
||||
return true
|
||||
end
|
||||
-- 如果 enable_mihomo ~= 1,检查是否有其他可用核心
|
||||
if enable_mihomo ~= "1" then
|
||||
-- 有其他核心可用,使用传统模式
|
||||
if has_xray or has_ss_rust then
|
||||
return false
|
||||
end
|
||||
-- 没有其他核心,回退到 Mihomo 模式
|
||||
if has_mihomo then
|
||||
log("回退: Xray/ss-rust 不存在,使用 Mihomo 订阅模式")
|
||||
return true
|
||||
end
|
||||
end
|
||||
-- 默认:如果有 Mihomo 则使用 Mihomo 模式
|
||||
return has_mihomo
|
||||
end
|
||||
|
||||
local function preferred_ss_backend()
|
||||
if has_mihomo then
|
||||
if should_use_mihomo_mode() and has_mihomo then
|
||||
return "ss"
|
||||
end
|
||||
if has_ss_rust then
|
||||
@@ -54,6 +78,9 @@ local function preferred_ss_backend()
|
||||
if has_xray then
|
||||
return "v2ray"
|
||||
end
|
||||
if has_mihomo then
|
||||
return "ss"
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -89,6 +116,7 @@ local encrypt_methods_ss = {
|
||||
"chacha20",
|
||||
"chacha20-ietf" ]]--
|
||||
}
|
||||
|
||||
-- 分割字符串
|
||||
local function split(full, sep)
|
||||
if full == nil or type(full) ~= "string" then
|
||||
@@ -117,6 +145,7 @@ local function split(full, sep)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- urlencode
|
||||
local function get_urlencode(c)
|
||||
return sformat("%%%02X", sbyte(c))
|
||||
@@ -136,6 +165,7 @@ end
|
||||
local function get_urldecode(h)
|
||||
return schar(tonumber(h, 16))
|
||||
end
|
||||
|
||||
local function UrlDecode(szText)
|
||||
return szText:gsub("+", " "):gsub("%%(%x%x)", get_urldecode)
|
||||
end
|
||||
@@ -269,12 +299,14 @@ local function parse_host_port(value, default_port)
|
||||
|
||||
return normalize_host(value), default_port
|
||||
end
|
||||
|
||||
-- md5
|
||||
local function md5(content)
|
||||
local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1')
|
||||
-- assert(nixio.errno() == 0)
|
||||
return trim(stdout)
|
||||
end
|
||||
|
||||
-- base64 解码
|
||||
local function base64Decode(text)
|
||||
local raw = text
|
||||
@@ -296,6 +328,7 @@ local function base64Decode(text)
|
||||
return raw
|
||||
end
|
||||
end
|
||||
|
||||
-- base64 编码
|
||||
local function base64Encode(text)
|
||||
if not text or text == "" then
|
||||
@@ -309,6 +342,7 @@ local function base64Encode(text)
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
-- 检查数组(table)中是否存在某个字符值
|
||||
-- https://www.04007.cn/article/135.html
|
||||
local function checkTabValue(tab)
|
||||
@@ -318,6 +352,7 @@ local function checkTabValue(tab)
|
||||
end
|
||||
return revtab
|
||||
end
|
||||
|
||||
-- JSON完整性检查
|
||||
local function isCompleteJSON(str)
|
||||
-- 检查JSON格式
|
||||
@@ -349,7 +384,8 @@ local function processClashSubscription(url)
|
||||
return nil
|
||||
end
|
||||
|
||||
local alias = "Clash_" .. parsed.host
|
||||
local url_hash = string.sub(md5(url), 1, 8)
|
||||
local alias = "Clash_" .. parsed.host .. "_" .. url_hash
|
||||
local server_port = parsed.port or ((parsed.scheme == "http") and "80" or "443")
|
||||
local result = {
|
||||
type = "clash",
|
||||
@@ -796,6 +832,10 @@ local function can_group_into_mihomo(node)
|
||||
if not node then
|
||||
return false
|
||||
end
|
||||
-- 如果不使用 Mihomo 模式,返回 false
|
||||
if not should_use_mihomo_mode() then
|
||||
return false
|
||||
end
|
||||
if node.type == "ssr" or node.type == "ss" or node.type == "ss-rust" then
|
||||
return true
|
||||
end
|
||||
@@ -820,6 +860,11 @@ local function can_group_into_mihomo(node)
|
||||
end
|
||||
|
||||
local function buildMihomoSubscribeYaml(nodes, group_name)
|
||||
-- 如果不使用 Mihomo 模式,返回 nil
|
||||
if not should_use_mihomo_mode() then
|
||||
return nil, 0
|
||||
end
|
||||
|
||||
local proxies = {}
|
||||
local names = {}
|
||||
|
||||
@@ -943,6 +988,10 @@ local function processData(szType, content, cfgid)
|
||||
result.flag_obfs = "1"
|
||||
result.obfs_type = params.obfs
|
||||
result.salamander = params["obfs-password"] or params["obfs_password"]
|
||||
if params.obfs == "gecko" then
|
||||
result.obfs_MinPacketSize = params.minPacketSize or "512"
|
||||
result.obfs_MaxPacketSize = params.maxPacketSize or "1200"
|
||||
end
|
||||
end
|
||||
if params.allowInsecure or params.insecure then
|
||||
local insecure = params.allowInsecure or params.insecure
|
||||
@@ -2386,6 +2435,10 @@ local function is_mihomo_subscribe_node(section)
|
||||
if not section then
|
||||
return false
|
||||
end
|
||||
-- 如果不使用 Mihomo 模式,返回 false
|
||||
if not should_use_mihomo_mode() then
|
||||
return false
|
||||
end
|
||||
if section.type == "clash" and section.clash_path and tostring(section.clash_path):match("%.mihomo%.yaml$") then
|
||||
return true
|
||||
end
|
||||
@@ -2413,7 +2466,7 @@ local function is_mihomo_subscribe_node(section)
|
||||
end
|
||||
|
||||
local function group_needs_mihomo_subscribe_refresh(groupHash)
|
||||
if not has_mihomo then
|
||||
if not should_use_mihomo_mode() then
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -2446,13 +2499,26 @@ local function preserve_unselected_groups(selected_hashes)
|
||||
end)
|
||||
end
|
||||
|
||||
-- 获取 groupHash 的公共函数(预留函数)
|
||||
local function get_group_hash(url, fetch_url)
|
||||
if should_use_mihomo_mode() then
|
||||
return md5(fetch_url)
|
||||
else
|
||||
return md5(url)
|
||||
end
|
||||
end
|
||||
|
||||
local execute = function()
|
||||
local updated = false
|
||||
local selected_hashes = {}
|
||||
|
||||
for _, item in ipairs(subscribe_items) do
|
||||
local fetch_url = build_convert_url(item.url)
|
||||
selected_hashes[md5(fetch_url)] = true
|
||||
if should_use_mihomo_mode() then
|
||||
selected_hashes[md5(fetch_url)] = true
|
||||
else
|
||||
selected_hashes[md5(item.url)] = true
|
||||
end
|
||||
end
|
||||
|
||||
if target_subscribe_sid ~= "" then
|
||||
@@ -2462,24 +2528,33 @@ local execute = function()
|
||||
for _, item in ipairs(subscribe_items) do
|
||||
local url = item.url
|
||||
local fetch_url, converted = build_convert_url(url)
|
||||
local raw, new_md5 = curl(fetch_url, user_agent)
|
||||
local raw, new_md5
|
||||
local groupHash
|
||||
local yaml_removed_count = 0
|
||||
if isClashYAML(raw) then
|
||||
raw, yaml_removed_count = filterClashYamlRaw(raw)
|
||||
if yaml_removed_count and yaml_removed_count > 0 then
|
||||
new_md5 = md5_string(raw)
|
||||
|
||||
if should_use_mihomo_mode() then
|
||||
raw, new_md5 = curl(fetch_url, user_agent)
|
||||
if isClashYAML(raw) then
|
||||
raw, yaml_removed_count = filterClashYamlRaw(raw)
|
||||
if yaml_removed_count and yaml_removed_count > 0 then
|
||||
new_md5 = md5_string(raw)
|
||||
end
|
||||
end
|
||||
groupHash = md5(fetch_url)
|
||||
else
|
||||
raw, new_md5 = curl(url, user_agent)
|
||||
groupHash = md5(url)
|
||||
end
|
||||
|
||||
log("raw 长度: "..#raw)
|
||||
local groupHash = md5(fetch_url)
|
||||
local old_md5 = read_old_md5(groupHash)
|
||||
|
||||
log("处理订阅: " .. url)
|
||||
if converted then
|
||||
if should_use_mihomo_mode() and converted then
|
||||
log("使用订阅转换模板: " .. template_url)
|
||||
log("转换服务: " .. convert_address)
|
||||
end
|
||||
if yaml_removed_count and yaml_removed_count > 0 then
|
||||
if should_use_mihomo_mode() and yaml_removed_count and yaml_removed_count > 0 then
|
||||
log("Clash/Mihomo YAML 已按订阅过滤关键词移除节点数量: " .. tostring(yaml_removed_count))
|
||||
end
|
||||
log("groupHash: " .. groupHash)
|
||||
@@ -2489,110 +2564,111 @@ local execute = function()
|
||||
local backend_refresh = group_needs_ss_backend_refresh(groupHash)
|
||||
local mihomo_subscribe_refresh = group_needs_mihomo_subscribe_refresh(groupHash)
|
||||
local missing_saved_nodes = old_md5 and new_md5 == old_md5 and not group_has_saved_nodes(groupHash)
|
||||
|
||||
if #raw == 0 then
|
||||
log(url .. ': 获取内容为空')
|
||||
loadOldNodes(groupHash)
|
||||
elseif old_md5 and new_md5 == old_md5 and not backend_refresh and not mihomo_subscribe_refresh and not missing_saved_nodes then
|
||||
log("订阅未变化, 跳过无需更新的订阅: " .. url)
|
||||
-- 防止 diff 阶段误删未更新订阅节点
|
||||
loadOldNodes(groupHash)
|
||||
--ucic:foreach(name, uciType, function(s)
|
||||
-- if s.grouphashkey == groupHash and s.hashkey then
|
||||
-- cache[groupHash][s.hashkey] = s
|
||||
-- tinsert(nodeResult[index], s)
|
||||
-- end
|
||||
--end)
|
||||
log("订阅未变化, 跳过无需更新的订阅: " .. url)
|
||||
-- 防止 diff 阶段误删未更新订阅节点
|
||||
loadOldNodes(groupHash)
|
||||
--ucic:foreach(name, uciType, function(s)
|
||||
-- if s.grouphashkey == groupHash and s.hashkey then
|
||||
-- cache[groupHash][s.hashkey] = s
|
||||
-- tinsert(nodeResult[index], s)
|
||||
-- end
|
||||
--end)
|
||||
else
|
||||
if backend_refresh and old_md5 and new_md5 == old_md5 then
|
||||
log("检测到 SS 后端偏好变化,强制重建订阅节点: " .. url)
|
||||
end
|
||||
if mihomo_subscribe_refresh and old_md5 and new_md5 == old_md5 then
|
||||
log("检测到可迁移订阅节点,强制重建为 Mihomo 总节点: " .. url)
|
||||
end
|
||||
if missing_saved_nodes then
|
||||
log("订阅内容未变化但本地节点不存在,强制重建订阅节点: " .. url)
|
||||
end
|
||||
updated = true
|
||||
-- 保存更新后的 MD5 值到以 groupHash 为标识的临时文件中,用于下次订阅更新时进行对比
|
||||
write_new_md5(groupHash, new_md5)
|
||||
if backend_refresh and old_md5 and new_md5 == old_md5 then
|
||||
log("检测到 SS 后端偏好变化,强制重建订阅节点: " .. url)
|
||||
end
|
||||
if mihomo_subscribe_refresh and old_md5 and new_md5 == old_md5 then
|
||||
log("检测到可迁移订阅节点,强制重建为 Mihomo 总节点: " .. url)
|
||||
end
|
||||
if missing_saved_nodes then
|
||||
log("订阅内容未变化但本地节点不存在,强制重建订阅节点: " .. url)
|
||||
end
|
||||
updated = true
|
||||
-- 保存更新后的 MD5 值到以 groupHash 为标识的临时文件中,用于下次订阅更新时进行对比
|
||||
write_new_md5(groupHash, new_md5)
|
||||
|
||||
cache[groupHash] = {}
|
||||
tinsert(nodeResult, {})
|
||||
local index = #nodeResult
|
||||
local nodes, szType
|
||||
local is_clash_subscription = false
|
||||
cache[groupHash] = {}
|
||||
tinsert(nodeResult, {})
|
||||
local index = #nodeResult
|
||||
local nodes, szType
|
||||
local is_clash_subscription = false
|
||||
|
||||
if isClashYAML(raw) then
|
||||
is_clash_subscription = true
|
||||
local result = processClashSubscription(fetch_url)
|
||||
if result and check_filer(result) then
|
||||
log('过滤 Clash 总节点: ' .. result.alias)
|
||||
elseif result and not cache[groupHash][result.hashkey] then
|
||||
result.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], result)
|
||||
cache[groupHash][result.hashkey] = result
|
||||
log('成功导入 Clash 总节点: ' .. result.alias)
|
||||
else
|
||||
log('丢弃无效 Clash 总节点: ' .. url)
|
||||
end
|
||||
-- SSD 似乎是这种格式 ssd:// 开头的
|
||||
elseif raw:find('ssd://') then
|
||||
szType = 'ssd'
|
||||
local nEnd = select(2, raw:find('ssd://'))
|
||||
nodes = base64Decode(raw:sub(nEnd + 1, #raw))
|
||||
nodes = jsonParse(nodes)
|
||||
local extra = {
|
||||
airport = nodes.airport,
|
||||
port = nodes.port,
|
||||
encryption = nodes.encryption,
|
||||
password = nodes.password
|
||||
}
|
||||
local servers = {}
|
||||
-- SS里面包着 干脆直接这样
|
||||
for _, server in ipairs(nodes.servers or {}) do
|
||||
tinsert(servers, setmetatable(server, {__index = extra}))
|
||||
end
|
||||
nodes = servers
|
||||
-- SS SIP008 直接使用 Json 格式
|
||||
elseif jsonParse(raw) then
|
||||
nodes = jsonParse(raw).servers or jsonParse(raw)
|
||||
if nodes[1] and nodes[1].server and nodes[1].method then
|
||||
szType = 'sip008'
|
||||
end
|
||||
-- 其他 base64 格式
|
||||
if isClashYAML(raw) then
|
||||
is_clash_subscription = true
|
||||
local result = processClashSubscription(fetch_url)
|
||||
if result and check_filer(result) then
|
||||
log('过滤 Clash 总节点: ' .. result.alias)
|
||||
elseif result and not cache[groupHash][result.hashkey] then
|
||||
result.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], result)
|
||||
cache[groupHash][result.hashkey] = result
|
||||
log('成功导入 Clash 总节点: ' .. result.alias)
|
||||
else
|
||||
-- ssd 外的格式
|
||||
nodes = split(base64Decode(raw):gsub("\r\n", "\n"), "\n")
|
||||
log('丢弃无效 Clash 总节点: ' .. url)
|
||||
end
|
||||
-- SSD 似乎是这种格式 ssd:// 开头的
|
||||
elseif raw:find('ssd://') then
|
||||
szType = 'ssd'
|
||||
local nEnd = select(2, raw:find('ssd://'))
|
||||
nodes = base64Decode(raw:sub(nEnd + 1, #raw))
|
||||
nodes = jsonParse(nodes)
|
||||
local extra = {
|
||||
airport = nodes.airport,
|
||||
port = nodes.port,
|
||||
encryption = nodes.encryption,
|
||||
password = nodes.password
|
||||
}
|
||||
local servers = {}
|
||||
-- SS里面包着 干脆直接这样
|
||||
for _, server in ipairs(nodes.servers or {}) do
|
||||
tinsert(servers, setmetatable(server, {__index = extra}))
|
||||
end
|
||||
nodes = servers
|
||||
-- SS SIP008 直接使用 Json 格式
|
||||
elseif jsonParse(raw) then
|
||||
nodes = jsonParse(raw).servers or jsonParse(raw)
|
||||
if nodes[1] and nodes[1].server and nodes[1].method then
|
||||
szType = 'sip008'
|
||||
end
|
||||
-- 其他 base64 格式
|
||||
else
|
||||
-- ssd 外的格式
|
||||
nodes = split(base64Decode(raw):gsub("\r\n", "\n"), "\n")
|
||||
end
|
||||
|
||||
if not is_clash_subscription and not szType and type(nodes) == "table" then
|
||||
local anytls_nodes = {}
|
||||
local normal_nodes = {}
|
||||
for _, node in ipairs(nodes) do
|
||||
local line = trim(node or "")
|
||||
if line:match("^anytls://") then
|
||||
local parsed = parseAnytlsShare(line:gsub("^anytls://", ""))
|
||||
if parsed then
|
||||
table.insert(anytls_nodes, anytls_to_mihomo_node(parsed))
|
||||
end
|
||||
elseif line ~= "" then
|
||||
table.insert(normal_nodes, node)
|
||||
end
|
||||
end
|
||||
|
||||
if not is_clash_subscription and not szType and type(nodes) == "table" then
|
||||
local anytls_nodes = {}
|
||||
local normal_nodes = {}
|
||||
for _, node in ipairs(nodes) do
|
||||
local line = trim(node or "")
|
||||
if line:match("^anytls://") then
|
||||
local parsed = parseAnytlsShare(line:gsub("^anytls://", ""))
|
||||
if parsed then
|
||||
table.insert(anytls_nodes, anytls_to_mihomo_node(parsed))
|
||||
end
|
||||
elseif line ~= "" then
|
||||
table.insert(normal_nodes, node)
|
||||
end
|
||||
if #anytls_nodes > 0 then
|
||||
for _, parsed in ipairs(anytls_nodes) do
|
||||
table.insert(normal_nodes, parsed)
|
||||
end
|
||||
|
||||
if #anytls_nodes > 0 then
|
||||
for _, parsed in ipairs(anytls_nodes) do
|
||||
table.insert(normal_nodes, parsed)
|
||||
end
|
||||
end
|
||||
|
||||
nodes = normal_nodes
|
||||
end
|
||||
|
||||
-- 临时存储该订阅解析出的节点(带原始别名)
|
||||
local groupRawNodes = {}
|
||||
nodes = normal_nodes
|
||||
end
|
||||
|
||||
if not is_clash_subscription then
|
||||
-- 临时存储该订阅解析出的节点(带原始别名)
|
||||
local groupRawNodes = {}
|
||||
|
||||
if not is_clash_subscription then
|
||||
for _, v in ipairs(nodes) do
|
||||
if v and (type(v) == "table" or not string.match(v, "^%s*$")) then
|
||||
xpcall(function()
|
||||
@@ -2621,52 +2697,61 @@ local execute = function()
|
||||
log('跳过未知类型: ' .. szType)
|
||||
end
|
||||
-- log(result)
|
||||
if result then
|
||||
local filtered = check_filer(result)
|
||||
-- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场
|
||||
local invalid = not result.server or not result.server_port
|
||||
or (result.type ~= "clash" and result.server == "127.0.0.1")
|
||||
or result.alias == "NULL"
|
||||
or (result.type ~= "clash" and result.server:match("[^0-9a-zA-Z%-_%.%s]"))
|
||||
or cache[groupHash][result.hashkey]
|
||||
if filtered then
|
||||
log('过滤节点: ' .. result.alias)
|
||||
elseif invalid then
|
||||
log('丢弃无效节点: ' .. result.alias)
|
||||
else
|
||||
-- 暂存节点
|
||||
table.insert(groupRawNodes, result)
|
||||
end
|
||||
if result then
|
||||
local filtered = check_filer(result)
|
||||
-- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场
|
||||
local invalid = not result.server or not result.server_port
|
||||
or (result.type ~= "clash" and result.server == "127.0.0.1")
|
||||
or result.alias == "NULL"
|
||||
or (result.type ~= "clash" and result.server:match("[^0-9a-zA-Z%-_%.%s]"))
|
||||
or cache[groupHash][result.hashkey]
|
||||
if filtered then
|
||||
log('过滤节点: ' .. result.alias)
|
||||
elseif invalid then
|
||||
log('丢弃无效节点: ' .. result.alias)
|
||||
else
|
||||
-- 暂存节点
|
||||
table.insert(groupRawNodes, result)
|
||||
end
|
||||
end
|
||||
end, function(err)
|
||||
log(string.format("解析节点出错: %s\n原始数据: %s", tostring(err), tostring(v)))
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 对该组节点进行别名编号:重复节点加后缀,唯一节点不加
|
||||
-- 传统模式:对 groupRawNodes 进行组内编号
|
||||
if not should_use_mihomo_mode() then
|
||||
local freq = {}
|
||||
for _, node in ipairs(groupRawNodes) do
|
||||
local raw = node.raw_alias or ""
|
||||
freq[raw] = (freq[raw] or 0) + 1
|
||||
if raw ~= "" then
|
||||
freq[raw] = (freq[raw] or 0) + 1
|
||||
end
|
||||
end
|
||||
local aliasCount = {}
|
||||
for _, node in ipairs(groupRawNodes) do
|
||||
local raw = node.raw_alias or ""
|
||||
if freq[raw] > 1 then
|
||||
local count = (aliasCount[raw] or 0) + 1
|
||||
aliasCount[raw] = count
|
||||
node.alias = raw .. "_" .. count
|
||||
else
|
||||
node.alias = raw
|
||||
if raw ~= "" then
|
||||
if freq[raw] and freq[raw] > 1 then
|
||||
local count = (aliasCount[raw] or 0) + 1
|
||||
aliasCount[raw] = count
|
||||
node.alias = raw .. "_" .. count
|
||||
else
|
||||
node.alias = raw
|
||||
end
|
||||
end
|
||||
-- 清理临时字段
|
||||
node.raw_alias = nil
|
||||
end
|
||||
end
|
||||
|
||||
local mihomo_nodes = {}
|
||||
local legacy_nodes = {}
|
||||
local mihomo_nodes = {}
|
||||
local legacy_nodes = {}
|
||||
|
||||
-- 只有当 should_use_mihomo_mode() 为 true 时才尝试分组
|
||||
if should_use_mihomo_mode() then
|
||||
for _, node in ipairs(groupRawNodes) do
|
||||
if has_mihomo and can_group_into_mihomo(node) then
|
||||
mihomo_nodes[#mihomo_nodes + 1] = node
|
||||
@@ -2674,41 +2759,50 @@ local execute = function()
|
||||
legacy_nodes[#legacy_nodes + 1] = node
|
||||
end
|
||||
end
|
||||
else
|
||||
-- 传统模式:所有节点作为普通节点
|
||||
for _, node in ipairs(groupRawNodes) do
|
||||
legacy_nodes[#legacy_nodes + 1] = node
|
||||
end
|
||||
end
|
||||
|
||||
if #mihomo_nodes > 0 then
|
||||
local parsed_url = URL.parse(url)
|
||||
local alias = item.alias ~= "" and item.alias or ("Mihomo_" .. ((parsed_url and parsed_url.host) or groupHash))
|
||||
local local_path = string.format("%s/%s.mihomo.yaml", local_clash_dir, groupHash)
|
||||
local yaml, proxy_count = buildMihomoSubscribeYaml(mihomo_nodes, "Proxy")
|
||||
if #mihomo_nodes > 0 then
|
||||
local parsed_url = URL.parse(url)
|
||||
local alias = item.alias ~= "" and item.alias or ("Mihomo_" .. ((parsed_url and parsed_url.host) or groupHash))
|
||||
local local_path = string.format("%s/%s.mihomo.yaml", local_clash_dir, groupHash)
|
||||
local yaml, proxy_count = buildMihomoSubscribeYaml(mihomo_nodes, "Proxy")
|
||||
|
||||
if yaml and proxy_count > 0 then
|
||||
nixio.fs.mkdirr(local_clash_dir)
|
||||
nixio.fs.writefile(local_path, yaml)
|
||||
if yaml and proxy_count > 0 then
|
||||
nixio.fs.mkdirr(local_clash_dir)
|
||||
nixio.fs.writefile(local_path, yaml)
|
||||
|
||||
local result = processLocalClashSubscription(local_path, alias)
|
||||
if result and not cache[groupHash][result.hashkey] then
|
||||
result.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], result)
|
||||
cache[groupHash][result.hashkey] = result
|
||||
log('成功导入 Mihomo 总节点: ' .. result.alias .. ',包含节点数量: ' .. proxy_count)
|
||||
end
|
||||
else
|
||||
log('Mihomo 总节点生成失败,回退为普通订阅节点。')
|
||||
for _, node in ipairs(mihomo_nodes) do
|
||||
legacy_nodes[#legacy_nodes + 1] = node
|
||||
end
|
||||
local result = processLocalClashSubscription(local_path, alias)
|
||||
if result and not cache[groupHash][result.hashkey] then
|
||||
result.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], result)
|
||||
cache[groupHash][result.hashkey] = result
|
||||
log('成功导入 Mihomo 总节点: ' .. result.alias .. ',包含节点数量: ' .. proxy_count)
|
||||
end
|
||||
else
|
||||
log('Mihomo 总节点生成失败,回退为普通订阅节点。')
|
||||
for _, node in ipairs(mihomo_nodes) do
|
||||
legacy_nodes[#legacy_nodes + 1] = node
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, node in ipairs(legacy_nodes) do
|
||||
node.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], node)
|
||||
cache[groupHash][node.hashkey] = node
|
||||
end
|
||||
for _, node in ipairs(legacy_nodes) do
|
||||
node.grouphashkey = groupHash
|
||||
table.insert(nodeResult[index], node)
|
||||
cache[groupHash][node.hashkey] = node
|
||||
end
|
||||
|
||||
if not should_use_mihomo_mode() then
|
||||
log('成功解析节点数量: ' .. #groupRawNodes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 输出日志并判断是否需要进行 diff
|
||||
if not updated then
|
||||
log("订阅未变化,无需更新节点信息。")
|
||||
@@ -2729,8 +2823,8 @@ local execute = function()
|
||||
del = del + 1
|
||||
else
|
||||
local dat = nodeResult[old.grouphashkey][old.hashkey]
|
||||
ucic:tset(name, old['.name'], dat)
|
||||
-- 标记一下
|
||||
ucic:tset(name, old['.name'], dat)
|
||||
setmetatable(nodeResult[old.grouphashkey][old.hashkey], {__index = {_ignore = true}})
|
||||
end
|
||||
else
|
||||
@@ -2746,11 +2840,12 @@ local execute = function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
-- 1615-1653 行为生成 sid
|
||||
|
||||
-- 生成 sid
|
||||
-- 记录已使用编号
|
||||
local used_sid = {}
|
||||
local next_sid = 1
|
||||
-- 扫描已有 section
|
||||
-- 检查已有 section
|
||||
ucic:foreach(name, uciType, function(s)
|
||||
local num = s[".name"]:match("^cfg(%x%x)") -- 提取两位十六进制序号
|
||||
if num then
|
||||
@@ -2820,6 +2915,14 @@ if subscribe_items and #subscribe_items > 0 then
|
||||
else
|
||||
log("当前订阅模式: 不通过代理订阅")
|
||||
end
|
||||
|
||||
-- 记录当前使用的订阅模式
|
||||
if should_use_mihomo_mode() then
|
||||
log("订阅模式: Mihomo 总节点模式")
|
||||
else
|
||||
log("订阅模式: 传统节点模式")
|
||||
end
|
||||
|
||||
local direct_bypass = create_direct_subscribe_bypass()
|
||||
if direct_bypass then
|
||||
direct_bypass:apply()
|
||||
|
||||
@@ -5,6 +5,7 @@ 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"
|
||||
HELLOWORLD_RELEASE_API="https://api.github.com/repos/fw876/helloworld/releases/latest"
|
||||
XRAY_BINARY="/usr/bin/xray"
|
||||
MIHOMO_BINARY="/usr/bin/mihomo"
|
||||
NAIVEPROXY_BINARY="/usr/bin/naive"
|
||||
@@ -164,6 +165,20 @@ is_openwrt_env() {
|
||||
[ -r /etc/openwrt_release ] || command -v opkg >/dev/null 2>&1
|
||||
}
|
||||
|
||||
detect_package_manager() {
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
printf '%s' 'apk'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v opkg >/dev/null 2>&1; then
|
||||
printf '%s' 'opkg'
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
find_mihomo_binary() {
|
||||
if command -v mihomo >/dev/null 2>&1; then
|
||||
command -v mihomo
|
||||
@@ -831,6 +846,240 @@ get_naiveproxy_latest_info() {
|
||||
return 0
|
||||
}
|
||||
|
||||
get_mainprogram_current_version() {
|
||||
local pm="$1"
|
||||
local version
|
||||
|
||||
case "$pm" in
|
||||
apk)
|
||||
version="$(apk info -e luci-app-ssr-plus 2>/dev/null | sed -n 's/^luci-app-ssr-plus-\([0-9][^-[:space:]]*-[^[:space:]]*\).*$/\1/p' | sed -n '1p')"
|
||||
[ -n "$version" ] || version="$(apk list -I luci-app-ssr-plus 2>/dev/null | sed -n 's/^luci-app-ssr-plus-\([0-9][^-[:space:]]*-[^[:space:]]*\).*$/\1/p' | sed -n '1p')"
|
||||
;;
|
||||
opkg)
|
||||
version="$(opkg status luci-app-ssr-plus 2>/dev/null | sed -n 's/^Version:[[:space:]]*//p' | sed -n '1p')"
|
||||
;;
|
||||
esac
|
||||
|
||||
[ -n "$version" ] || return 1
|
||||
printf '%s' "$version"
|
||||
}
|
||||
|
||||
mainprogram_asset_suffix() {
|
||||
case "$1" in
|
||||
apk)
|
||||
printf '%s' '.apk'
|
||||
;;
|
||||
opkg)
|
||||
printf '%s' '.ipk'
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
select_mainprogram_asset() {
|
||||
local asset_list="$1"
|
||||
local pm="$2"
|
||||
local suffix candidate
|
||||
|
||||
suffix="$(mainprogram_asset_suffix "$pm")" || return 1
|
||||
candidate="$(printf '%s\n' "$asset_list" | grep -F "$suffix" | grep -E '^luci-app-ssr-plus[_-]' | sed -n '1p')"
|
||||
[ -n "$candidate" ] || return 1
|
||||
printf '%s' "$candidate"
|
||||
}
|
||||
|
||||
mainprogram_asset_version() {
|
||||
local asset="$1"
|
||||
local version
|
||||
|
||||
version="$(printf '%s' "$asset" | sed -n 's/^luci-app-ssr-plus_\([^_]*\)_.*\.ipk$/\1/p')"
|
||||
[ -n "$version" ] || version="$(printf '%s' "$asset" | sed -n 's/^luci-app-ssr-plus-\(.*\)\.apk$/\1/p')"
|
||||
[ -n "$version" ] || return 1
|
||||
printf '%s' "$version"
|
||||
}
|
||||
|
||||
get_mainprogram_latest_info() {
|
||||
local pm release_json tag version asset asset_list url
|
||||
|
||||
pm="$(detect_package_manager)" || return 2
|
||||
release_json="$(fetch_text "$HELLOWORLD_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
|
||||
asset_list="$(printf '%s\n' "$release_json" | sed -n 's/.*"name":[[:space:]]*"\([^"]*\.\(ipk\|apk\)\)".*/\1/p')"
|
||||
asset="$(select_mainprogram_asset "$asset_list" "$pm")" || return 4
|
||||
version="$(mainprogram_asset_version "$asset" 2>/dev/null || trim_version "$tag")"
|
||||
url="$(mirror_wrap_url "https://github.com/fw876/helloworld/releases/download/$tag/$asset")"
|
||||
|
||||
log_kv package_manager "$pm"
|
||||
log_kv arch "$(get_openwrt_arch)"
|
||||
log_kv asset "$asset"
|
||||
log_kv latest_version "$version"
|
||||
log_kv download_url "$url"
|
||||
return 0
|
||||
}
|
||||
|
||||
mainprogram_info() {
|
||||
local pm current installed latest_output latest_rc latest_version arch asset can_upgrade
|
||||
|
||||
installed=0
|
||||
current=""
|
||||
pm="$(detect_package_manager 2>/dev/null || true)"
|
||||
arch="$(get_openwrt_arch)"
|
||||
if [ -n "$pm" ] && current="$(get_mainprogram_current_version "$pm")" && [ -n "$current" ]; then
|
||||
installed=1
|
||||
fi
|
||||
|
||||
latest_output="$(get_mainprogram_latest_info 2>/dev/null)"
|
||||
latest_rc=$?
|
||||
|
||||
log_kv component mainprogram
|
||||
log_kv installed "$installed"
|
||||
log_kv current_version "$current"
|
||||
log_kv package_manager "$pm"
|
||||
log_kv arch "$arch"
|
||||
log_kv asset ''
|
||||
|
||||
if [ $latest_rc -ne 0 ]; then
|
||||
log_kv can_upgrade 0
|
||||
case "$latest_rc" in
|
||||
2) log_kv error 'unsupported_package_manager' ;;
|
||||
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')"
|
||||
pm="$(printf '%s\n' "$latest_output" | sed -n 's/^package_manager=//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 ''
|
||||
}
|
||||
|
||||
mainprogram_local_info() {
|
||||
local pm current installed
|
||||
|
||||
installed=0
|
||||
current=""
|
||||
pm="$(detect_package_manager 2>/dev/null || true)"
|
||||
if [ -n "$pm" ] && current="$(get_mainprogram_current_version "$pm")" && [ -n "$current" ]; then
|
||||
installed=1
|
||||
fi
|
||||
|
||||
log_kv component mainprogram
|
||||
log_kv installed "$installed"
|
||||
log_kv current_version "$current"
|
||||
log_kv latest_version ''
|
||||
log_kv package_manager "$pm"
|
||||
log_kv arch "$(get_openwrt_arch)"
|
||||
log_kv asset ''
|
||||
log_kv can_upgrade 0
|
||||
log_kv error ''
|
||||
}
|
||||
|
||||
mainprogram_install_package() {
|
||||
local pm="$1"
|
||||
local package_file="$2"
|
||||
|
||||
case "$pm" in
|
||||
apk)
|
||||
apk add --allow-untrusted "$package_file" >/dev/null 2>&1
|
||||
;;
|
||||
opkg)
|
||||
opkg install "$package_file" >/dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
mainprogram_upgrade() {
|
||||
local latest_output latest_rc latest_version download_url package_manager asset tmp_dir package_file current_before current_after
|
||||
|
||||
latest_output="$(get_mainprogram_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 package manager' ;;
|
||||
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
|
||||
|
||||
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')"
|
||||
package_manager="$(printf '%s\n' "$latest_output" | sed -n 's/^package_manager=//p' | sed -n '1p')"
|
||||
asset="$(printf '%s\n' "$latest_output" | sed -n 's/^asset=//p' | sed -n '1p')"
|
||||
current_before="$(get_mainprogram_current_version "$package_manager" 2>/dev/null || true)"
|
||||
|
||||
tmp_dir="$(mktemp -d /tmp/ssrplus-mainprogram.XXXXXX)"
|
||||
if [ -z "$tmp_dir" ] || [ ! -d "$tmp_dir" ]; then
|
||||
log_kv success 0
|
||||
log_kv message 'Failed to create temp directory'
|
||||
return 0
|
||||
fi
|
||||
|
||||
package_file="$tmp_dir/$asset"
|
||||
trap "rm -rf '$tmp_dir'" EXIT INT TERM
|
||||
|
||||
if ! download_file "$download_url" "$package_file"; then
|
||||
log_kv success 0
|
||||
log_kv message 'Download failed'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -s "$package_file" ]; then
|
||||
log_kv success 0
|
||||
log_kv message 'Download failed'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! mainprogram_install_package "$package_manager" "$package_file"; then
|
||||
log_kv success 0
|
||||
log_kv message 'Install failed'
|
||||
return 0
|
||||
fi
|
||||
|
||||
current_after="$(get_mainprogram_current_version "$package_manager" 2>/dev/null || true)"
|
||||
if [ -z "$current_after" ]; then
|
||||
log_kv success 0
|
||||
log_kv message 'Installed package check failed'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -x /etc/init.d/rpcd ]; then
|
||||
/etc/init.d/rpcd restart >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ -x /etc/init.d/uhttpd ]; then
|
||||
/etc/init.d/uhttpd reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
log_kv component mainprogram
|
||||
log_kv success 1
|
||||
log_kv previous_version "$current_before"
|
||||
log_kv current_version "$current_after"
|
||||
log_kv latest_version "$latest_version"
|
||||
log_kv package_manager "$package_manager"
|
||||
log_kv arch "$(get_openwrt_arch)"
|
||||
log_kv asset "$asset"
|
||||
log_kv can_upgrade 0
|
||||
log_kv message 'Upgrade completed'
|
||||
return 0
|
||||
}
|
||||
|
||||
xray_info() {
|
||||
local current installed latest_output latest_rc latest_version arch asset can_upgrade
|
||||
|
||||
@@ -1366,6 +1615,15 @@ naiveproxy_upgrade() {
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
mainprogram_info)
|
||||
mainprogram_info
|
||||
;;
|
||||
mainprogram_local_info)
|
||||
mainprogram_local_info
|
||||
;;
|
||||
mainprogram_upgrade)
|
||||
mainprogram_upgrade
|
||||
;;
|
||||
xray_info)
|
||||
xray_info
|
||||
;;
|
||||
@@ -1422,7 +1680,7 @@ case "${1:-}" in
|
||||
;;
|
||||
*)
|
||||
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'
|
||||
log_kv message 'Usage: update_components.sh mainprogram_info|mainprogram_local_info|mainprogram_upgrade|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
|
||||
Reference in new issue
Block a user