Skip to content

Commit 31487d6

Browse files
committed
refactor(scripts): 重构脚本架构
- 重写 CLI 为分组命令,统一服务、节点、订阅、模式、API、应用和透明代理入口 - 抽离 common/config/api/nodes 公共工具,减少重复的配置读写、节点解析和 Clash API 逻辑 - 重构 service/runtime/switch/subscription 逻辑 - 优化日志输出,避免内部脚本调用时重复写入 service.log - 统一 gms_fix/ipset 脚本风格,修正中文注释和日志文案
1 parent 293d37b commit 31487d6

11 files changed

Lines changed: 1647 additions & 1050 deletions

File tree

src/module/scripts/cli

Lines changed: 521 additions & 617 deletions
Large diffs are not rendered by default.

src/module/scripts/core/runtime.sh

Lines changed: 87 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,129 @@
11
#!/system/bin/sh
22
# sing-box 运行时配置辅助函数
33

4+
CUR_OUTBOUND_CONFIG=""
5+
CUR_OUTBOUND_DIR=""
6+
CUR_OUTBOUND_MODE=""
7+
CUR_SELECTOR_MODE=""
8+
CUR_CURRENT_TAG=""
9+
10+
RUNTIME_OUTBOUNDS_FILE=""
11+
RUNTIME_NODE_PATHS=""
12+
RUNTIME_NODE_TAGS_JSON=""
13+
RUNTIME_NODE_COUNT=0
14+
RUNTIME_SKIPPED_COUNT=0
15+
416
#######################################
5-
# 获取当前节点所在目录
17+
# 初始化运行时上下文
618
#######################################
7-
get_current_outbounds_dir() {
8-
local current_config="$1"
9-
local current_dir
19+
initialize_runtime_context() {
20+
require_file "${MODULE_CONF:-}" "模块配置文件不存在: ${MODULE_CONF:-未定义}"
21+
require_dir "${SINGBOX_DIR:-}" "sing-box 配置目录不存在: ${SINGBOX_DIR:-未定义}"
22+
require_dir "${CONFDIR:-}" "通用配置目录不存在: ${CONFDIR:-未定义}"
23+
require_dir "${RUNTIME_DIR:-}" "运行时目录不存在: ${RUNTIME_DIR:-未定义}"
1024

11-
current_dir="${current_config%/*}"
12-
[ "$current_dir" != "$current_config" ] || die "无法解析当前节点目录: $current_config"
13-
[ -d "$current_dir" ] || die "当前节点目录不存在: $current_dir"
25+
CUR_OUTBOUND_CONFIG="$(read_conf "$MODULE_CONF" "CURRENT_CONFIG" "")"
26+
CUR_OUTBOUND_MODE="$(read_conf "$MODULE_CONF" "OUTBOUND_MODE" "rule")"
27+
CUR_SELECTOR_MODE="$(read_conf "$MODULE_CONF" "SELECTOR_MODE" "urltest")"
1428

15-
echo "$current_dir"
16-
}
29+
[ -n "$CUR_OUTBOUND_CONFIG" ] || die "CURRENT_CONFIG 未定义,请先选择节点"
30+
require_file "$CUR_OUTBOUND_CONFIG" "当前节点配置文件不存在: $CUR_OUTBOUND_CONFIG"
1731

18-
#######################################
19-
# 判断是否为节点配置文件
20-
#######################################
21-
is_node_config_file() {
22-
local file="$1"
32+
CUR_OUTBOUND_DIR="${CUR_OUTBOUND_CONFIG%/*}"
33+
[ "$CUR_OUTBOUND_DIR" != "$CUR_OUTBOUND_CONFIG" ] || die "无法解析当前节点目录: $CUR_OUTBOUND_CONFIG"
34+
require_dir "$CUR_OUTBOUND_DIR" "当前节点目录不存在: $CUR_OUTBOUND_DIR"
35+
36+
CUR_CURRENT_TAG="$(detect_outbound_tag "$CUR_OUTBOUND_CONFIG" || true)"
37+
[ -n "$CUR_CURRENT_TAG" ] || die "无法读取当前节点标签: $CUR_OUTBOUND_CONFIG"
2338

24-
[ -f "$file" ] || return 1
25-
[ "${file##*/}" != "_meta.json" ] || return 1
39+
RUNTIME_OUTBOUNDS_FILE="$RUNTIME_DIR/outbounds.json"
2640
}
2741

2842
#######################################
29-
# 转义 JSON 字符串
43+
# 清空运行时节点缓存
3044
#######################################
31-
json_escape() {
32-
printf "%s" "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
45+
reset_runtime_nodes() {
46+
RUNTIME_NODE_PATHS=""
47+
RUNTIME_NODE_TAGS_JSON=""
48+
RUNTIME_NODE_COUNT=0
49+
RUNTIME_SKIPPED_COUNT=0
3350
}
3451

3552
#######################################
36-
# 追加出站标签到 JSON 数组片段
53+
# 追加运行时节点缓存
3754
#######################################
38-
append_selector_tag() {
39-
local tags="$1"
55+
append_runtime_node() {
56+
local file="$1"
4057
local tag="$2"
41-
local escaped
58+
local escaped_tag
4259

43-
escaped="$(json_escape "$tag")"
44-
if [ -n "$tags" ]; then
45-
printf "%s, \"%s\"" "$tags" "$escaped"
60+
if [ -n "$RUNTIME_NODE_PATHS" ]; then
61+
RUNTIME_NODE_PATHS="${RUNTIME_NODE_PATHS}
62+
$file"
4663
else
47-
printf "\"%s\"" "$escaped"
64+
RUNTIME_NODE_PATHS="$file"
4865
fi
49-
}
5066

51-
# 运行时上下文(由 initialize_runtime_context 填充)
52-
CUR_OUTBOUND_CONFIG=""
53-
CUR_OUTBOUND_DIR=""
54-
CUR_OUTBOUND_MODE=""
55-
CUR_SELECTOR_MODE=""
67+
if ! is_reserved_outbound_tag "$tag"; then
68+
escaped_tag="$(json_escape "$tag")"
69+
if [ -n "$RUNTIME_NODE_TAGS_JSON" ]; then
70+
RUNTIME_NODE_TAGS_JSON="$RUNTIME_NODE_TAGS_JSON, \"$escaped_tag\""
71+
else
72+
RUNTIME_NODE_TAGS_JSON="\"$escaped_tag\""
73+
fi
74+
fi
5675

57-
# 节点扫描结果(由 write_runtime_outbounds 填充)
58-
SCAN_NODE_ARGS=""
59-
SCAN_NODE_COUNT=0
60-
SCAN_SKIPPED_COUNT=0
76+
RUNTIME_NODE_COUNT=$((RUNTIME_NODE_COUNT + 1))
77+
}
6178

6279
#######################################
63-
# 初始化启动环境与基础配置
80+
# 扫描当前节点目录
6481
#######################################
65-
initialize_runtime_context() {
66-
# 基础环境检查
67-
[ -x "${SING_BOX_BIN:-}" ] || die "sing-box 二进制不存在或不可执行"
68-
[ -f "${MODULE_CONF:-}" ] || die "模块配置文件不存在"
69-
[ -f "${TPROXY_CONF_DIR:-}/tproxy.conf" ] || die "透明代理配置文件不存在"
82+
scan_runtime_nodes() {
83+
local current_dir="${1:-$CUR_OUTBOUND_DIR}"
84+
local file tag
7085

71-
# 加载模块与透明代理配置
72-
. "$MODULE_CONF"
73-
. "$TPROXY_CONF_DIR/tproxy.conf"
86+
require_dir "$current_dir" "节点目录不存在: $current_dir"
87+
reset_runtime_nodes
7488

75-
# 提取并验证当前节点路径
76-
CUR_OUTBOUND_CONFIG="$(strip_quotes "${CURRENT_CONFIG:-}")"
77-
[ -n "$CUR_OUTBOUND_CONFIG" ] || die "CURRENT_CONFIG 未定义,请先选择节点"
78-
[ -f "$CUR_OUTBOUND_CONFIG" ] || die "指定的节点配置文件不存在: $CUR_OUTBOUND_CONFIG"
79-
80-
# 确定运行模式与选择器模式
81-
CUR_OUTBOUND_MODE="${OUTBOUND_MODE:-rule}"
82-
CUR_SELECTOR_MODE="${SELECTOR_MODE:-urltest}"
83-
84-
# 获取当前节点目录
85-
CUR_OUTBOUND_DIR="$(get_current_outbounds_dir "$CUR_OUTBOUND_CONFIG")" || return 1
89+
for file in "$current_dir"/*.json; do
90+
is_node_config_file "$file" || continue
91+
tag="$(detect_outbound_tag "$file" || true)"
92+
93+
if [ -z "$tag" ]; then
94+
RUNTIME_SKIPPED_COUNT=$((RUNTIME_SKIPPED_COUNT + 1))
95+
continue
96+
fi
97+
98+
append_runtime_node "$file" "$tag"
99+
done
86100
}
87101

88102
#######################################
89-
# 扫描节点并生成运行时出站配置
103+
# 生成运行时出站配置
90104
#######################################
91105
write_runtime_outbounds() {
92-
local output="${RUNTIME_DIR:?RUNTIME_DIR 未定义}/outbounds.json"
93106
local current_config="${1:-$CUR_OUTBOUND_CONFIG}"
94-
local current_dir="${CUR_OUTBOUND_DIR:-$(get_current_outbounds_dir "$current_config")}"
95107
local selector_mode="${2:-$CUR_SELECTOR_MODE}"
96-
local current_tag current_tag_json tags="" f tag
97-
98-
SCAN_NODE_ARGS=""
99-
SCAN_NODE_COUNT=0
100-
SCAN_SKIPPED_COUNT=0
108+
local tags="$RUNTIME_NODE_TAGS_JSON"
101109

102-
current_tag="$(detect_outbound_tag "$current_config")"
103-
[ -n "$current_tag" ] || die "无法从当前出站配置读取标签: $current_config"
104-
current_tag_json="$(json_escape "$current_tag")"
110+
[ -n "$current_config" ] || die "当前节点配置未初始化"
111+
[ -n "$selector_mode" ] || selector_mode="urltest"
105112

106-
mkdir -p "$RUNTIME_DIR" || die "无法创建运行时配置目录: $RUNTIME_DIR"
107-
108-
log "INFO" "正在扫描节点目录: $current_dir"
109-
110-
# 扫描当前节点目录
111-
for f in "$current_dir"/*.json; do
112-
is_node_config_file "$f" || continue
113-
tag="$(detect_outbound_tag "$f")"
114-
115-
if [ -z "$tag" ]; then
116-
SCAN_SKIPPED_COUNT=$((SCAN_SKIPPED_COUNT + 1))
117-
continue
118-
fi
119-
120-
# 收集启动参数(所有节点都加载)
121-
SCAN_NODE_ARGS="$SCAN_NODE_ARGS -c \"$f\""
122-
SCAN_NODE_COUNT=$((SCAN_NODE_COUNT + 1))
113+
if [ "$RUNTIME_NODE_COUNT" -eq 0 ] && [ -z "$RUNTIME_NODE_PATHS" ]; then
114+
scan_runtime_nodes "$CUR_OUTBOUND_DIR"
115+
tags="$RUNTIME_NODE_TAGS_JSON"
116+
fi
123117

124-
# 收集可切换标签(过滤掉 default 以防止抢占测速组)
125-
if [ "$tag" != "default" ]; then
126-
tags="$(append_selector_tag "$tags" "$tag")"
127-
fi
128-
done
118+
if [ -z "$tags" ] && ! is_reserved_outbound_tag "$CUR_CURRENT_TAG"; then
119+
tags="\"$(json_escape "$CUR_CURRENT_TAG")\""
120+
fi
129121

130-
# 未发现可切换节点时,至少保留当前节点供测速/选择
131-
[ -n "$tags" ] || tags="$(append_selector_tag "" "$current_tag")"
122+
[ -n "$tags" ] || die "当前节点目录没有可用的出站标签: $CUR_OUTBOUND_DIR"
132123

133124
case "$selector_mode" in
134125
urltest | auto | 动态测速)
135-
cat > "$output" << EOF
126+
cat > "$RUNTIME_OUTBOUNDS_FILE" << EOF
136127
{
137128
"outbounds": [
138129
{
@@ -169,7 +160,7 @@ write_runtime_outbounds() {
169160
EOF
170161
;;
171162
manual | selector | 手动选择 | 手动)
172-
cat > "$output" << EOF
163+
cat > "$RUNTIME_OUTBOUNDS_FILE" << EOF
173164
{
174165
"outbounds": [
175166
{
@@ -187,7 +178,7 @@ EOF
187178
"direct",
188179
$tags
189180
],
190-
"default": "$current_tag_json",
181+
"default": "$(json_escape "$CUR_CURRENT_TAG")",
191182
"interrupt_exist_connections": true
192183
}
193184
]
@@ -199,5 +190,5 @@ EOF
199190
;;
200191
esac
201192

202-
echo "$output"
193+
printf "%s\n" "$RUNTIME_OUTBOUNDS_FILE"
203194
}

0 commit comments

Comments
 (0)