feat(vps-xray): 重启计划配置解析与旧字段迁移
新增 normalize_restart_time / resolve_restart_config, XRAY_RESTART_EVERY_DAYS 缺失时才回退读 XRAY_DAILY_RESTART。 附单元测试,不需要 root 与 systemd。
This commit is contained in:
+54
-6
@@ -74,12 +74,60 @@ if [[ "$MODE" != "reality" && "$MODE" != "fast" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 布尔开关归一化:容忍 true/TRUE/True/yes/on/1 等写法,
|
||||
# 避免用户按直觉写了 TRUE 却被静默当成关闭
|
||||
case "$(printf '%s' "${XRAY_DAILY_RESTART:-false}" | tr '[:upper:]' '[:lower:]')" in
|
||||
true|yes|on|1) DAILY_RESTART=1 ;;
|
||||
*) DAILY_RESTART=0 ;;
|
||||
esac
|
||||
# ===== 定时重启配置 =====
|
||||
# 可覆盖路径,测试时指向临时目录
|
||||
SYSTEMD_DIR="${SYSTEMD_DIR:-/etc/systemd/system}"
|
||||
GUARD_BIN="${GUARD_BIN:-/usr/local/bin/xray-restart-guard}"
|
||||
RESTART_STATE_FILE="${RESTART_STATE_FILE:-/var/lib/xray/last-restart}"
|
||||
|
||||
RESTART_EVERY_DAYS=0
|
||||
RESTART_TIME="04:00"
|
||||
RESTART_TZ="Asia/Shanghai"
|
||||
|
||||
# 把 4:00 / 04:00 统一成两位小时的 HH:MM,不合法返回 1。
|
||||
# 归一化的意义:OnCalendar 字符串格式统一,.env 内容可预测。
|
||||
normalize_restart_time() {
|
||||
local t="${1:-}"
|
||||
[[ "$t" =~ ^([01]?[0-9]|2[0-3]):([0-5][0-9])$ ]] || return 1
|
||||
# 10# 前缀避免 08/09 被当成八进制
|
||||
printf '%02d:%s' "$((10#${BASH_REMATCH[1]}))" "${BASH_REMATCH[2]}"
|
||||
}
|
||||
|
||||
resolve_restart_config() {
|
||||
local days="${XRAY_RESTART_EVERY_DAYS:-}"
|
||||
|
||||
# 旧字段迁移:仅当新字段完全未设置时才回退去读,
|
||||
# 这样 .env 里显式写 0 能覆盖遗留的 XRAY_DAILY_RESTART=true
|
||||
if [ -z "$days" ]; then
|
||||
case "$(printf '%s' "${XRAY_DAILY_RESTART:-false}" | tr '[:upper:]' '[:lower:]')" in
|
||||
true|yes|on|1) days=1 ;;
|
||||
*) days=0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ! [[ "$days" =~ ^[0-9]+$ ]]; then
|
||||
error "XRAY_RESTART_EVERY_DAYS 必须是非负整数,当前为 '${days}'"
|
||||
return 1
|
||||
fi
|
||||
RESTART_EVERY_DAYS="$days"
|
||||
|
||||
local t
|
||||
if ! t=$(normalize_restart_time "${XRAY_RESTART_TIME:-04:00}"); then
|
||||
error "XRAY_RESTART_TIME 必须是 HH:MM(00:00~23:59),当前为 '${XRAY_RESTART_TIME:-}'"
|
||||
return 1
|
||||
fi
|
||||
RESTART_TIME="$t"
|
||||
|
||||
RESTART_TZ="${XRAY_RESTART_TIMEZONE-Asia/Shanghai}"
|
||||
if [ -z "$RESTART_TZ" ]; then
|
||||
error "XRAY_RESTART_TIMEZONE 不能为空"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
resolve_restart_config || exit 1
|
||||
|
||||
XRAY_PORT="${XRAY_PORT:-443}"
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh 中重启计划相关逻辑的单元测试
|
||||
#
|
||||
# 用法: bash vps-xray/tests/test-restart-schedule.sh
|
||||
#
|
||||
# 不需要 root,不接触真实 systemd:所有写入路径都被重定向到临时目录,
|
||||
# systemctl 用 PATH 打桩拦截。
|
||||
#
|
||||
# 加载方式说明:deploy.sh 结尾会直接调用 main,且顶层有 root 检查与参数解析,
|
||||
# 不能整份 source。这里只抽取「多行函数定义」(形如 `name() {` 开头、`}` 结尾)。
|
||||
# 单行函数(log/warn/error/step)抽不到,正好由下面的桩覆盖。
|
||||
|
||||
set -u
|
||||
|
||||
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEPLOY="${TEST_DIR}/../deploy.sh"
|
||||
|
||||
if [ ! -f "$DEPLOY" ]; then
|
||||
echo "找不到 $DEPLOY" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval "$(sed -n '/^[a-z_][a-z_]*() {$/,/^}$/p' "$DEPLOY")"
|
||||
|
||||
# 日志桩:error 保留输出便于断言,其余静音
|
||||
log() { :; }
|
||||
warn() { :; }
|
||||
step() { :; }
|
||||
error() { echo "ERROR: $*" >&2; }
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
ok() { PASS=$((PASS + 1)); echo " ok - $1"; }
|
||||
bad() { FAIL=$((FAIL + 1)); echo " FAIL - $1"; echo " 期望: $2"; echo " 实际: $3"; }
|
||||
# is <描述> <实际值> <期望值>
|
||||
is() { if [ "$2" = "$3" ]; then ok "$1"; else bad "$1" "$3" "$2"; fi; }
|
||||
|
||||
echo "== normalize_restart_time =="
|
||||
is "04:00 原样通过" "$(normalize_restart_time 04:00)" "04:00"
|
||||
is "4:00 补零" "$(normalize_restart_time 4:00)" "04:00"
|
||||
is "08:30 不被当八进制" "$(normalize_restart_time 08:30)" "08:30"
|
||||
is "23:59 边界" "$(normalize_restart_time 23:59)" "23:59"
|
||||
is "00:00 边界" "$(normalize_restart_time 00:00)" "00:00"
|
||||
|
||||
normalize_restart_time "24:00" >/dev/null 2>&1
|
||||
is "24:00 被拒" "$?" "1"
|
||||
normalize_restart_time "04:60" >/dev/null 2>&1
|
||||
is "04:60 被拒" "$?" "1"
|
||||
normalize_restart_time "abc" >/dev/null 2>&1
|
||||
is "abc 被拒" "$?" "1"
|
||||
normalize_restart_time "" >/dev/null 2>&1
|
||||
is "空串被拒" "$?" "1"
|
||||
|
||||
echo "== resolve_restart_config =="
|
||||
|
||||
reset_env() {
|
||||
unset XRAY_RESTART_EVERY_DAYS XRAY_RESTART_TIME XRAY_RESTART_TIMEZONE XRAY_DAILY_RESTART
|
||||
RESTART_EVERY_DAYS=""; RESTART_TIME=""; RESTART_TZ=""
|
||||
}
|
||||
|
||||
reset_env
|
||||
resolve_restart_config
|
||||
is "全空时天数默认 0" "$RESTART_EVERY_DAYS" "0"
|
||||
is "全空时时间默认" "$RESTART_TIME" "04:00"
|
||||
is "全空时时区默认" "$RESTART_TZ" "Asia/Shanghai"
|
||||
|
||||
reset_env; XRAY_RESTART_EVERY_DAYS=7; XRAY_RESTART_TIME=5:30
|
||||
resolve_restart_config
|
||||
is "读取新字段天数" "$RESTART_EVERY_DAYS" "7"
|
||||
is "读取新字段时间并补零" "$RESTART_TIME" "05:30"
|
||||
|
||||
reset_env; XRAY_DAILY_RESTART=true
|
||||
resolve_restart_config
|
||||
is "迁移 true → 1" "$RESTART_EVERY_DAYS" "1"
|
||||
|
||||
reset_env; XRAY_DAILY_RESTART=TRUE
|
||||
resolve_restart_config
|
||||
is "迁移 TRUE → 1" "$RESTART_EVERY_DAYS" "1"
|
||||
|
||||
reset_env; XRAY_DAILY_RESTART=false
|
||||
resolve_restart_config
|
||||
is "迁移 false → 0" "$RESTART_EVERY_DAYS" "0"
|
||||
|
||||
reset_env; XRAY_DAILY_RESTART=true; XRAY_RESTART_EVERY_DAYS=3
|
||||
resolve_restart_config
|
||||
is "新字段优先于旧字段" "$RESTART_EVERY_DAYS" "3"
|
||||
|
||||
reset_env; XRAY_DAILY_RESTART=true; XRAY_RESTART_EVERY_DAYS=0
|
||||
resolve_restart_config
|
||||
is "新字段显式 0 覆盖旧 true" "$RESTART_EVERY_DAYS" "0"
|
||||
|
||||
reset_env; XRAY_RESTART_EVERY_DAYS=abc
|
||||
resolve_restart_config 2>/dev/null
|
||||
is "天数非数字报错" "$?" "1"
|
||||
|
||||
reset_env; XRAY_RESTART_EVERY_DAYS=-1
|
||||
resolve_restart_config 2>/dev/null
|
||||
is "天数负数报错" "$?" "1"
|
||||
|
||||
reset_env; XRAY_RESTART_TIME=25:00
|
||||
resolve_restart_config 2>/dev/null
|
||||
is "时间非法报错" "$?" "1"
|
||||
|
||||
reset_env; XRAY_RESTART_TIMEZONE=""
|
||||
resolve_restart_config 2>/dev/null
|
||||
is "时区空串报错" "$?" "1"
|
||||
|
||||
echo ""
|
||||
echo "通过 ${PASS},失败 ${FAIL}"
|
||||
[ "$FAIL" -eq 0 ]
|
||||
Reference in New Issue
Block a user