# Workflow ```mermaid flowchart TD %% ========================= %% Entry points %% ========================= A1[systemd timer 触发
OnBootSec=2min / OnUnitActiveSec=interval] --> A2[vmess-domain-rotator.service] A2 --> A3[run_update_and_commit.sh config.json] A4[手动执行
bash scripts/run_update_and_commit.sh config.json] --> A3 A5[仅手动更新不走服务提交
python3 scripts/domain_updater.py --config config.json] --> B1 %% ========================= %% domain_updater.py pipeline %% ========================= subgraph U["domain_updater.py(域名选择主流程)"] direction TB B1[读取 config.json
解析 output.runtime_dir] --> B2[读取 runtime/state.json
last_good_domain] B2 --> B3[请求 API
api.url/method/headers/params/body/timeout] B3 --> B4[解析候选域名
parser.field_paths/json_paths/regex fallback] B4 --> B5[域名过滤
domain_filter.include_suffixes/exclude_regex] B5 --> B6[记录级过滤
record_filter.exclude_if_any
contains/equals/regex] B6 --> B7[解析评分记录
scoring.records_path/ip_field/created_time_field/score_fields] B7 --> B8[排序
within_hours + prefer_lower/use_api_order] B8 --> B9{healthcheck.enabled?} B9 -- 是 --> B10[TLS 探测候选
attempts/timeout_ms/port/tls_verify] B9 -- 否 --> B11[跳过 healthcheck] B10 --> B12[choose_domain] B11 --> B12 B12 --> B13{是否选出域名?} B13 -- 是 --> B16[status=ok] B13 -- 否 --> B14{last_good_domain 存在?} B14 -- 是 --> B15[使用 last_good_domain
status=fallback_last_good] B14 -- 否 --> BE1[报错并退出] B15 --> B17[写 runtime/current_domain.txt] B16 --> B17 B17 --> B18[写 runtime/current_domain.json] B18 --> B19[写 runtime/substore_vars.json] B19 --> B20[可选渲染 v2ray 模板
v2ray.template_file/output_file/replace_token] B20 --> B21[写 runtime/state.json] B21 --> B22[可选 notify.command] B22 --> B23[stdout 输出本次 JSON 结果] BE1 --> BE2[写 state.json status=error] BE2 --> BE3{last_good_domain 存在?} BE3 -- 是 --> BE4[写 current_domain*.json/txt
status=error_use_last_good] BE4 --> BE5[notify.command + 输出 error_use_last_good] BE3 -- 否 --> BE6[stderr 输出 error 并 exit 1] end %% updater 结果回到 wrapper B23 --> C1 BE5 --> C1 %% ========================= %% run_update_and_commit.sh pipeline %% ========================= subgraph W["run_update_and_commit.sh(runtime-state 自动提交/推送)"] direction TB C1[检查 runtime/current_domain.txt 存在且非空] --> C2{满足 git 环境?
git存在+在仓库+HEAD有效} C2 -- 否 --> C0[仅完成本地 runtime 更新并退出] C2 -- 是 --> C3[确定 runtime_branch / push_remote / auth 选项] C3 --> C4{当前分支是 runtime-state?} C4 -- 是 --> C5[直接在当前仓库操作] C4 -- 否 --> C6[创建临时 worktree] C6 --> C7{runtime-state 分支存在?} C7 -- 本地存在 --> C8[checkout 本地 runtime-state] C7 -- 仅远程存在 --> C9[fetch 后 checkout] C7 -- 都不存在 --> C10[创建 orphan runtime-state] C8 --> C11 C9 --> C11 C10 --> C11 C5 --> C11[读取 runtime-state HEAD 的 runtime/current_domain.txt] C11 --> C12{force_commit!=1 且 新旧域名相同?} C12 -- 是 --> C13[skip git commit/push] C12 -- 否 --> C14[同步 4 个 runtime 文件到目标 worktree] C14 --> C15[git add runtime/*.txt/json] C15 --> C16{有 staged 变化?} C16 -- 否 且 force=0 --> C17[skip commit] C16 -- 否 且 force=1 --> C18[allow-empty commit] C16 -- 是 --> C19[正常 commit] C18 --> C20[提交信息 manual: ...] C19 --> C21[提交信息 chore: rotate preferred domain ...] C20 --> C22{GIT_PUSH_ENABLED=1?} C21 --> C22 C22 -- 否 --> C23[结束(仅本地提交)] C22 -- 是 --> C24{有可用 remote?} C24 -- 否且required=1 --> C25[exit 1] C24 -- 否且required=0 --> C26[跳过 push] C24 -- 是 --> C27[按认证方式 push
credential helper 或 HTTP header/token] C27 --> C28{push 成功?} C28 -- 是 --> C29[结束] C28 -- 否且required=1 --> C30[exit 1] C28 -- 否且required=0 --> C31[记录失败并结束] end %% ========================= %% Consumers %% ========================= B18 --> D1[runtime/current_domain.json 对外可读] D1 --> D2[substore/operator_template.js 拉取 JSON] D2 --> D3[scriptResourceCache 缓存 domain(默认 5 分钟)] D3 --> D4[重写匹配节点 vmess server] C29 --> E1[runtime-state 分支更新] E1 --> E2[下游通过 raw/runtime-state/runtime/*.json 消费] ```