diff --git a/_setup.deb.sh b/_setup.deb.sh index 4f93f8a..e0a2343 100755 --- a/_setup.deb.sh +++ b/_setup.deb.sh @@ -2,4 +2,4 @@ # Debian sudo apt update -sudo apt install libsqlite3-dev libboost-all-dev libcurl4-gnutls-dev python3 python3-venv python3-pip g++ patchelf golang-go libportaudio-ocaml-dev libfreetype-dev +sudo apt install libsqlite3-dev libboost-all-dev libcurl4-gnutls-dev python3 python3-venv python3-pip g++ patchelf golang-go libportaudio-ocaml-dev libfreetype-dev libyaml-cpp-dev diff --git a/_setup.rhel.sh b/_setup.rhel.sh index 885a9d6..78a25bd 100755 --- a/_setup.rhel.sh +++ b/_setup.rhel.sh @@ -1,4 +1,4 @@ #!/bin/bash # RHEL / CentOS / Rocky / Fedora -sudo dnf install -y boost-devel libcurl-devel python3 python3-pip gcc-c++ patchelf golang sqlite-devel freetype-devel +sudo dnf install -y boost-devel libcurl-devel python3 python3-pip gcc-c++ patchelf golang sqlite-devel freetype-devel yaml-cpp-devel diff --git a/ai_review/_run.sh b/ai_review/_run.sh index 90fc521..1e58925 100644 --- a/ai_review/_run.sh +++ b/ai_review/_run.sh @@ -2,5 +2,5 @@ cd "$(dirname "$0")" || exit source ./venv/bin/activate #exec ./dnfs.bin -exec python3 ai_review.py +exec python3 ai_review.py "$@" diff --git a/aibox/_run.sh b/aibox/_run.sh index b465f80..d206b5f 100644 --- a/aibox/_run.sh +++ b/aibox/_run.sh @@ -3,6 +3,6 @@ cd "$(dirname "$0")" || exit source ./_setenv.sh source ./venv/bin/activate export PATH=${PATH}:~/.aibox/skills -exec python aibox.py $@ +exec python aibox.py "$@" diff --git a/ca/_run.sh b/ca/_run.sh index 8c24dde..67da3b7 100755 --- a/ca/_run.sh +++ b/ca/_run.sh @@ -4,7 +4,5 @@ # 启动时从 confs(CONFS_HOST:CONFS_PORT,默认 127.0.0.1:8010)拉取配置。 cd "$(dirname "$0")" || exit -# 等待依赖服务启动(confs/db) -sleep 2 - +# sleep 已移至 services.yaml 的 sleep_before 字段统一管理 exec ./build/ca.out "$@" diff --git a/captcha2/_run.sh b/captcha2/_run.sh index 280ce23..cfb6f83 100755 --- a/captcha2/_run.sh +++ b/captcha2/_run.sh @@ -1,4 +1,3 @@ #!/bin/bash cd "$(dirname "$0")" || exit -sleep 1 -exec ./captcha2.bin +exec ./captcha2.bin "$@" diff --git a/core/Makefile b/core/Makefile index 7e888e6..fd88b6f 100644 --- a/core/Makefile +++ b/core/Makefile @@ -4,7 +4,7 @@ APP_NAME := nidus INSTL_DIRS := /usr/local/bin -CONF_NAME := init.txt +CONF_NAME := services.yaml CONF_DIR := /etc/Nidus @@ -17,7 +17,7 @@ CPP:= g++ INCS:= -I include/ MY_LIBS := -L/usr/lib -lus_th -lus_http -lus_httpclient -lus_msg -lcurl -LIBS := -lpthread -lssl -lcrypto -lboost_program_options -lboost_json -lboost_thread -lboost_filesystem +LIBS := -lpthread -lssl -lcrypto -lboost_program_options -lboost_json -lboost_thread -lboost_filesystem -lyaml-cpp CPPFLAGS := --std=c++20 -O3 -pipe #-Wall -Werror @@ -26,7 +26,7 @@ $(shell mkdir -p $(BUILD_DIR)) #-------- all: ${APP_NAME}.out -${APP_NAME}.out: $(BUILD_DIR)/main.o $(BUILD_DIR)/PPool.o $(BUILD_DIR)/ProcessTask.o $(BUILD_DIR)/HttpTask.o $(BUILD_DIR)/ConfsTask.o $(BUILD_DIR)/Tttask.o $(BUILD_DIR)/pmc_mtd.o $(BUILD_DIR)/subsys_call.o +${APP_NAME}.out: $(BUILD_DIR)/main.o $(BUILD_DIR)/PPool.o $(BUILD_DIR)/ProcessTask.o $(BUILD_DIR)/HttpTask.o $(BUILD_DIR)/ConfsTask.o $(BUILD_DIR)/Tttask.o $(BUILD_DIR)/pmc_mtd.o $(BUILD_DIR)/subsys_call.o $(BUILD_DIR)/InitParser.o $(CPP) $^ $(MY_LIBS) $(LIBS) -o $@ $(BUILD_DIR)/main.o: src/main.cpp @@ -53,6 +53,9 @@ $(BUILD_DIR)/pmc_mtd.o: src/main/pmc_mtd.cpp $(BUILD_DIR)/subsys_call.o: src/main/subsys_call.cpp $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ +$(BUILD_DIR)/InitParser.o: src/registry/InitParser.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + install: $(APP_NAME).out @@ -65,6 +68,7 @@ install: $(APP_NAME).out @echo "正在配置 $(APP_NAME)" @mkdir -p $(CONF_DIR) @cp $(CONF_NAME) $(CONF_DIR)/$(CONF_NAME) + @cp init.txt $(CONF_DIR)/init.txt @cp $(SRV_NAME) $(SRV_DIR)/$(SRV_NAME) @systemctl daemon-reload @systemctl enable $(SRV_NAME) @@ -77,6 +81,7 @@ uninstall: @ @rm -f $(INSTL_DIRS)/$(APP_NAME) @rm -f $(CONF_DIRS)/$(CONF_NAME) + @rm -f $(CONF_DIRS)/init.txt @rm -f -d ${CONF_DIRS} @ @systemctl stop $(SRV_NAME) diff --git a/core/_run.sh b/core/_run.sh index dde1669..87a2704 100644 --- a/core/_run.sh +++ b/core/_run.sh @@ -1,4 +1,4 @@ #!/bin/bash cd "$(dirname "$0")" || exit export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH -./nidus.out -i init.txt --serve 5200 --confs 8010 +./nidus.out -i . --serve 5200 --confs 8010 diff --git a/core/include/registry/InitParser.hh b/core/include/registry/InitParser.hh new file mode 100644 index 0000000..f40939e --- /dev/null +++ b/core/include/registry/InitParser.hh @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include + +namespace qing::registry { + +/* 服务启动配置项 + * + * 从 services.yaml 或 init.txt 解析出的单个服务声明。 + * YAML 模式下包含完整的元数据;TXT 模式下仅 cmd 有值。 + */ +struct ServiceConfig { + std::string name; /* 服务唯一标识 */ + std::string cmd; /* 启动命令(如 bash /opt/.../_run.sh) */ + std::vector args; /* 传递给 _run.sh 的命令行参数 */ + std::map env; /* 启动前设置的环境变量 */ + std::vector depends_on; /* 依赖的服务名列表(未来 DAG 排序用) */ + int sleep_before = 0; /* 启动前等待秒数 */ + + /* 拼接完整命令:cmd + " " + args... */ + std::string toCommand() const; +}; + +/* 启动配置解析器 + * + * 优先读 services.yaml(结构化声明),不存在则回退 init.txt(纯命令列表)。 + * 两种格式都输出 std::vector,调用方无需关心来源。 + */ +class InitParser { +public: + /* 入口:传入配置目录(如 /etc/Nidus) + * + * 查找顺序: + * 1. /services.yaml → parseYaml() + * 2. /init.txt → parseTxt() + * 3. 都不存在 → 返回空 vector,调用方自行处理 + */ + static std::vector load(const std::string& dir); + + /* 解析 services.yaml */ + static std::vector parseYaml(const std::string& path); + + /* 解析 init.txt(向后兼容,每行一条命令,# 开头为注释) */ + static std::vector parseTxt(const std::string& path); +}; + +} // namespace qing::registry diff --git a/core/services.yaml b/core/services.yaml new file mode 100644 index 0000000..0ea5489 --- /dev/null +++ b/core/services.yaml @@ -0,0 +1,87 @@ +# core/services.yaml +# 声明式服务启动配置(替代 init.txt) +# 如果本文件存在则优先使用,否则回退 init.txt +# +# 字段说明: +# name 服务唯一标识(用于日志和未来注册中心) +# cmd 启动命令(与 init.txt 每行格式一致) +# args 传递给 _run.sh 的命令行参数列表(可选) +# env 启动前设置的环境变量(可选) +# depends_on 依赖的服务名列表(未来 DAG 拓扑排序用,当前仅记录) +# sleep_before 启动前等待秒数(替代散落在 _run.sh 中的 sleep) + +services: + # --- 数据层(最先启动) --- + - name: db2 + cmd: bash /opt/micro_servers/db2/_run.sh + args: [] + depends_on: [] + sleep_before: 0 + + # --- AI 审核 --- + - name: ai_review + cmd: bash /opt/micro_servers/ai_review/_run.sh + args: [] + depends_on: [db2] + sleep_before: 2 + + # --- 文件服务 --- + - name: dnfs2 + cmd: bash /opt/micro_servers/dnfs2/_run.sh + args: [] + depends_on: [db2, ai_review] + sleep_before: 0 + + # --- 邮件服务 --- + - name: smtp + cmd: bash /opt/micro_servers/smtp/_run.sh + args: [] + depends_on: [] + sleep_before: 2 + + # --- 前端静态资源 --- + - name: fsys + cmd: bash /opt/micro_servers/fsys/_run.sh + args: [] + depends_on: [] + sleep_before: 0 + + # --- 安全链路 --- + - name: waf + cmd: bash /opt/micro_servers/waf/_run.sh + args: [] # -c config.yaml 保留在 _run.sh 作为默认值 + depends_on: [ca, gateway] + sleep_before: 0 + + - name: ca + cmd: bash /opt/micro_servers/ca/_run.sh + args: [] + depends_on: [db2] + sleep_before: 2 + + - name: gateway + cmd: bash /opt/micro_servers/gateway/_run.sh + args: [] + depends_on: [db2] + sleep_before: 2 + + # --- 验证码 --- + - name: captcha2 + cmd: bash /opt/micro_servers/captcha2/_run.sh + args: [] + depends_on: [] + sleep_before: 1 + + # --- AI 工具箱 --- + - name: aibox + cmd: bash /opt/micro_servers/aibox/_run.sh + args: [] + depends_on: [] + sleep_before: 0 + + # --- 端口重定向(最后启动) --- + - name: redirect80 + cmd: bash /opt/micro_servers/redirect80/_run.sh + args: [] + depends_on: [waf] + sleep_before: 0 diff --git a/core/src/main.cpp b/core/src/main.cpp index b6ec8c0..6500642 100644 --- a/core/src/main.cpp +++ b/core/src/main.cpp @@ -149,7 +149,7 @@ int main(int argc, char** argv) { ("list", "list process all run") /* 列出运行中的进程 */ ("kill", po::value(), "kill a process") /* 杀死一个进程 */ /********* 子系统服务模式 ********/ - ("init,i", po::value(), "self-init list") /* 输入自启动列表 */ + ("init,i", po::value(), "self-init config (dir or .yaml/.txt file)") /* 输入自启动配置 */ ("serve", po::value(), "Run as http server") /* 启用http伺服器 */ ("confs", po::value(), "Run embedded confs rpc server"); /* 启用内嵌confs配置服务 */ diff --git a/core/src/main/pmc_mtd.cpp b/core/src/main/pmc_mtd.cpp index 936c126..68a264a 100644 --- a/core/src/main/pmc_mtd.cpp +++ b/core/src/main/pmc_mtd.cpp @@ -5,6 +5,12 @@ #include #include "main/PPool.hh" #include "main/pmc_mtd.hh" +#include "registry/InitParser.hh" + +#include +#include +#include +#include namespace qing { @@ -87,37 +93,61 @@ catch(std::exception& exp) { /* 解析自启动列表、添加自启动项 * - * 如果在解析过程中出错,只是打印异常? */ -void parse_self_init_list(std::string &path) + * 兼容两种格式: + * - services.yaml(结构化声明,含 args/env/depends_on/sleep_before) + * - init.txt(纯命令列表,每行一条 bash 命令,# 开头为注释) + * + * path 可以是: + * - 目录路径 → 自动查找 services.yaml 或 init.txt + * - .yaml 文件 → 按 YAML 解析 + * - 其他文件 → 按 TXT 解析(向后兼容 init.txt) + * + * 如果在解析过程中出错,只是打印异常 */ +void parse_self_init_list(std::string &path) try { + namespace fs = std::filesystem; - std::ifstream file(path); - if (!file.is_open()) { /* ---- 没能打开自启动文件 ---- */ - std::cerr << "Failed to open self-init list" << std::endl; + std::vector services; + + if (fs::is_directory(path)) { + /* 目录模式:InitParser::load 自动查找 services.yaml → init.txt */ + services = registry::InitParser::load(path); + } else if (path.size() > 5 && path.substr(path.size() - 5) == ".yaml") { + /* YAML 文件模式 */ + services = registry::InitParser::parseYaml(path); + } else { + /* TXT 文件模式(向后兼容 init.txt) */ + services = registry::InitParser::parseTxt(path); + } + + if (services.empty()) { + std::cerr << "parse_self_init_list: 没有可启动的服务" << std::endl; return; } - std::string row = ""; - char ch; - while (file.get(ch)) - - if (ch == '\n') { - - auto pos = row.find("#"); - if (pos != -1) - row = row.substr(0, pos); - if (row != "") { /* trim() */ - ppool.clr(); - ppool.crtp(row); /* 创建进程 */ - row = ""; - } + for (const auto& svc : services) { + /* 启动前等待(替代散落在 _run.sh 中的 sleep) */ + if (svc.sleep_before > 0) { + std::cerr << "[pmc] " << svc.name + << " 等待 " << svc.sleep_before << "s..." << std::endl; + std::this_thread::sleep_for( + std::chrono::seconds(svc.sleep_before)); } - else row += ch; + /* 设置环境变量 */ + for (const auto& [k, v] : svc.env) + setenv(k.c_str(), v.c_str(), 1); - file.close(); + /* 清理已停止的进程,然后创建新进程 */ + ppool.clr(); + std::string full_cmd = svc.toCommand(); + std::cerr << "[pmc] 启动: " << svc.name + << " -> " << full_cmd << std::endl; + ppool.crtp(full_cmd); + } } + catch (std::exception &exp) { std::cerr << "Exception at: parse_self_init_list()" << std::endl; std::cerr << "Exception type: " << typeid(exp).name() << std::endl; diff --git a/core/src/registry/InitParser.cpp b/core/src/registry/InitParser.cpp new file mode 100644 index 0000000..4320fd0 --- /dev/null +++ b/core/src/registry/InitParser.cpp @@ -0,0 +1,131 @@ +#include "registry/InitParser.hh" + +#include +#include +#include +#include +#include + +namespace qing::registry { + +/* -------- ServiceConfig -------- */ + +std::string ServiceConfig::toCommand() const { + std::ostringstream oss; + oss << cmd; + for (const auto& a : args) { + oss << ' ' << a; + } + return oss.str(); +} + +/* -------- InitParser -------- */ + +std::vector InitParser::load(const std::string& dir) { + namespace fs = std::filesystem; + + auto yaml_path = fs::path(dir) / "services.yaml"; + auto txt_path = fs::path(dir) / "init.txt"; + + /* 优先 services.yaml */ + if (fs::exists(yaml_path)) { + std::cerr << "[InitParser] 使用 services.yaml: " << yaml_path << std::endl; + return parseYaml(yaml_path.string()); + } + + /* 回退 init.txt */ + if (fs::exists(txt_path)) { + std::cerr << "[InitParser] 回退 init.txt: " << txt_path << std::endl; + return parseTxt(txt_path.string()); + } + + std::cerr << "[InitParser] 未找到 services.yaml 或 init.txt 于 " << dir << std::endl; + return {}; +} + +std::vector InitParser::parseYaml(const std::string& path) { + std::vector result; + + YAML::Node root; + try { + root = YAML::LoadFile(path); + } catch (const std::exception& e) { + std::cerr << "[InitParser] YAML 解析失败: " << e.what() << std::endl; + return {}; + } + + if (!root["services"] || !root["services"].IsSequence()) { + std::cerr << "[InitParser] services.yaml 缺少 services 序列" << std::endl; + return {}; + } + + for (const auto& node : root["services"]) { + ServiceConfig svc; + + if (node["name"]) + svc.name = node["name"].as(); + + if (node["cmd"]) + svc.cmd = node["cmd"].as(); + + if (node["args"] && node["args"].IsSequence()) + for (const auto& a : node["args"]) + svc.args.push_back(a.as()); + + if (node["env"] && node["env"].IsMap()) + for (const auto& kv : node["env"]) + svc.env[kv.first.as()] = kv.second.as(); + + if (node["depends_on"] && node["depends_on"].IsSequence()) + for (const auto& d : node["depends_on"]) + svc.depends_on.push_back(d.as()); + + if (node["sleep_before"]) + svc.sleep_before = node["sleep_before"].as(0); + + if (svc.cmd.empty()) { + std::cerr << "[InitParser] 跳过缺少 cmd 的服务: " << svc.name << std::endl; + continue; + } + + result.push_back(std::move(svc)); + } + + std::cerr << "[InitParser] 解析完成,共 " << result.size() << " 个服务" << std::endl; + return result; +} + +std::vector InitParser::parseTxt(const std::string& path) { + std::vector result; + + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "[InitParser] 无法打开 init.txt: " << path << std::endl; + return {}; + } + + std::string line; + while (std::getline(file, line)) { + /* 去除注释(# 之后的内容) */ + auto pos = line.find('#'); + if (pos != std::string::npos) + line = line.substr(0, pos); + + /* trim 空白 */ + auto first = line.find_first_not_of(" \t\r\n"); + if (first == std::string::npos) + continue; /* 空行 */ + auto last = line.find_last_not_of(" \t\r\n"); + line = line.substr(first, last - first + 1); + + ServiceConfig svc; + svc.cmd = line; + /* init.txt 模式下 name/args/env/depends_on/sleep_before 均为空/默认 */ + result.push_back(std::move(svc)); + } + + std::cerr << "[InitParser] init.txt 解析完成,共 " << result.size() << " 个服务" << std::endl; + return result; +} + +} // namespace qing::registry diff --git a/docs/reports/core_services_yaml_dev_doc.md b/docs/reports/core_services_yaml_dev_doc.md new file mode 100644 index 0000000..7e2e13e --- /dev/null +++ b/docs/reports/core_services_yaml_dev_doc.md @@ -0,0 +1,806 @@ +# Core 启动配置 YAML 化与 CLI 参数标准化 · 开发文档 + +> 文档类型:功能开发计划 +> 模块:core(PMC / Nidus)+ 全部子服务 +> 作者:自动生成 +> 日期:2026-08-10 +> 前置关系:本文档是 `core_service_registry_dev_doc.md` P7 阶段(services.yaml)的前置拆分,聚焦"配置格式迁移 + 参数透传 + CLI 标准化"三步基础设施改造 + +--- + +## 1. 概述 + +### 1.1 背景与动机 + +当前 core 通过 `init.txt`(纯命令列表)拉起 11 个子服务,存在以下问题: + +| 现状 | 问题 | +|------|------| +| `init.txt` 每行一条 bash 命令,无结构化字段 | 无法为每个服务指定命令行参数、环境变量、依赖关系 | +| 5/11 个 `_run.sh` 不转发 `"$@"` | core 即便想传参也传不进去 | +| `sleep 2` 等依赖等待逻辑散落在各 `_run.sh` 中 | 无统一管理,调整需逐个脚本修改 | +| waf 的 `-c config.yaml` 硬编码在 `_run.sh` | 参数不可外部覆盖 | +| 各服务 CLI 接口不统一 | ca/gateway 仅有 `--help/--version`,waf 有 `-c/-list/-test/-check`,其余 8 个服务零 CLI 支持 | + +**本方案目标**:通过三步改造,让 core 能够以结构化 YAML 声明每个服务的启动命令和参数,参数能透传到各服务二进制/脚本,并建立统一的 CLI 参数规范——为注册中心 `services.yaml` + `depends_on` DAG 拓扑排序打下基础。 + +### 1.2 设计目标 + +1. **结构化启动声明**:`init.txt` → `services.yaml`,每个服务可声明 `cmd`、`args`、`env`、`depends_on`、`sleep_before` +2. **参数透传**:全部 11 个 `_run.sh` 统一转发 `"$@"`,消除硬编码参数 +3. **CLI 标准化**:定义通用参数约定(`--host`/`--port`/`--config`/`--log-level`/`--instance`),各服务逐步适配 +4. **向后兼容**:`services.yaml` 不存在时回退 `init.txt`,现有部署零中断 +5. **yaml-cpp 引入**:vendored 到 `core/third_party/yaml-cpp/`,不依赖系统包管理器 + +### 1.3 与注册中心计划的关系 + +``` +本文档(三步改造) 注册中心计划(core_service_registry_dev_doc.md) +┌─────────────────────┐ ┌─────────────────────────────┐ +│ Step 1: services.yaml│ ──────▶ │ P7: services.yaml DAG 排序 │ +│ Step 2: _run.sh 透传 │ ──────▶ │ P2: init 解析后自动填充注册表 │ +│ Step 3: CLI 标准化 │ ──────▶ │ P5: RegistrationClient SDK │ +└─────────────────────┘ └─────────────────────────────┘ +``` + +本方案是注册中心的**基础设施前置**——做完这三步,P2/P5/P7 的工作量直接减半。 + +--- + +## 2. 现状分析 + +### 2.1 init.txt 当前内容 + +``` +bash /opt/micro_servers/db2/_run.sh +bash /opt/micro_servers/ai_review/_run.sh +bash /opt/micro_servers/dnfs2/_run.sh +bash /opt/micro_servers/smtp/_run.sh +bash /opt/micro_servers/fsys/_run.sh +bash /opt/micro_servers/waf/_run.sh +bash /opt/micro_servers/ca/_run.sh +bash /opt/micro_servers/gateway/_run.sh +bash /opt/micro_servers/captcha2/_run.sh +bash /opt/micro_servers/aibox/_run.sh +bash /opt/micro_servers/redirect80/_run.sh +``` + +纯命令列表,无参数、无元数据、无依赖声明。 + +### 2.2 各服务 _run.sh 现状 + +| 服务 | 语言 | `"$@"` 转发 | 硬编码参数 | 特殊处理 | sleep 等待 | +|------|------|-------------|-----------|----------|------------| +| db2 | C++ | ✅ `"$@"` | — | `set -e` | — | +| dnfs2 | C++ | ✅ `"$@"` | — | `set -e` | — | +| fsys | C++ | ✅ `"$@"` | — | `set -e` | — | +| ca | C++ | ✅ `"$@"` | — | — | `sleep 2` | +| gateway | C++ | ✅ `"$@"` | — | — | `sleep 2` | +| waf | Go | ❌ | `-c config.yaml` | — | — | +| captcha2 | C++ | ❌ | — | — | `sleep 1` | +| aibox | Python | ⚠️ `$@`(未加引号) | — | `_setenv.sh` + venv | — | +| ai_review | Python | ❌ | — | venv | — | +| smtp | Python | ❌ | — | venv | `sleep 2` | +| redirect80 | Python | ❌ | — | setcap + venv | — | + +**统计**:5 个已转发、1 个半转发(未加引号)、5 个未转发。3 个脚本含 `sleep` 硬编码。 + +### 2.3 各服务 CLI 参数支持现状 + +| 服务 | 语言 | CLI 框架 | 实际参数 | 配置来源 | +|------|------|----------|----------|----------| +| db2 | C++ | 无 | 无 | 硬编码常量 | +| dnfs2 | C++ | 无 | 无 | 硬编码 + confs | +| fsys | C++ | 无 | 无 | 硬编码 | +| captcha2 | C++ | 无 | 无 | 硬编码 | +| ca | C++ | `boost::program_options` | `--help` `--version`(仅此) | confs (ca.ini) + 环境变量 | +| gateway | C++ | `boost::program_options` | `--help` `--version`(仅此) | confs (gateway.ini) + 环境变量 | +| waf | Go | `flag` | `-c` `-list` `-test` `-check` | YAML 配置文件 | +| aibox | Python | `argparse`(已 import 未使用) | 无 | `_setenv.sh` + 硬编码 | +| ai_review | Python | 无 | 无 | 硬编码 | +| smtp | Python | 无 | 无 | 硬编码 | +| redirect80 | Python | 无 | 无 | 硬编码 | + +**关键发现**: +- ca 和 gateway 已引入 `boost::program_options` 但只实现了 `--help`/`--version`,实际配置全走 confs + 环境变量 +- aibox 已 `import argparse` 但从未调用,是死代码 +- waf 是唯一有完整 CLI 接口的服务(Go `flag` 包) +- 8/11 个服务零 CLI 参数支持 + +### 2.4 配置加载模式分类 + +当前各服务的配置获取有三种模式: + +| 模式 | 服务 | 说明 | +|------|------|------| +| **confs + 环境变量** | ca, gateway, dnfs2 | 从 confs 服务拉取 ini 配置,环境变量可覆盖;`CONFS_HOST`/`CONFS_PORT` 引导 | +| **本地配置文件** | waf | `-c config.yaml` 指定 YAML 配置 | +| **硬编码** | db2, fsys, captcha2, aibox, ai_review, smtp, redirect80 | 常量直接写在源码中 | + +CLI 标准化后,三种模式可统一为:**CLI 参数(最高优先级)> 环境变量 > confs/配置文件 > 硬编码默认值**。 + +--- + +## 3. 三步改造方案 + +### 3.1 总览 + +``` +Step 1: init.txt → services.yaml Step 2: _run.sh 参数透传 Step 3: CLI 参数标准化 +┌──────────────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ +│ • 引入 yaml-cpp (vendored) │ │ • 11 个 _run.sh 统一 │ │ • 定义通用参数约定 │ +│ • 设计 services.yaml 格式 │ ──▶ │ 末尾 exec 加 "$@" │ ──▶ │ • _run.sh 注入默认值 │ +│ • core 解析 YAML 并启动 │ │ • 移除硬编码参数 │ │ • 各服务逐步适配 │ +│ • 回退兼容 init.txt │ │ • sleep 移至 YAML │ │ • 环境变量桥接 │ +└──────────────────────────────┘ └──────────────────────┘ └──────────────────────┘ +``` + +--- + +## 4. Step 1:init.txt → services.yaml + +### 4.1 yaml-cpp 引入 + +采用系统包安装方式(已写入 `_setup.deb.sh` 和 `_setup.rhel.sh`): + +| 发行版 | 包名 | 安装命令 | +|--------|------|----------| +| Debian/Ubuntu | `libyaml-cpp-dev` | `apt install libyaml-cpp-dev` | +| RHEL/CentOS/Rocky | `yaml-cpp-devel` | `dnf install yaml-cpp-devel` | + +**Makefile 集成**(已完成): + +```makefile +# 链接 yaml-cpp 系统库 +LIBS := ... -lyaml-cpp + +# InitParser 编译目标 +$(BUILD_DIR)/InitParser.o: src/registry/InitParser.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +# 链接时追加 +$(APP_NAME).out: ... $(BUILD_DIR)/InitParser.o +``` + +### 4.2 services.yaml 格式设计 + +```yaml +# core/services.yaml +# 声明式服务启动配置(替代 init.txt) +# 如果本文件存在则优先使用,否则回退 init.txt + +services: + # --- 数据层 --- + - name: db2 + cmd: bash /opt/micro_servers/db2/_run.sh + args: [] + env: {} + depends_on: [] + sleep_before: 0 + + # --- AI 服务 --- + - name: ai_review + cmd: bash /opt/micro_servers/ai_review/_run.sh + args: ["--port", "8007", "--log-level", "info"] + env: + PYTHONUNBUFFERED: "1" + depends_on: [db2] + sleep_before: 2 + + # --- 文件服务 --- + - name: dnfs2 + cmd: bash /opt/micro_servers/dnfs2/_run.sh + args: [] + env: {} + depends_on: [db2, ai_review] + sleep_before: 0 + + # --- 邮件服务 --- + - name: smtp + cmd: bash /opt/micro_servers/smtp/_run.sh + args: [] + env: {} + depends_on: [] + sleep_before: 2 + + # --- 前端静态资源 --- + - name: fsys + cmd: bash /opt/micro_servers/fsys/_run.sh + args: [] + env: {} + depends_on: [] + sleep_before: 0 + + # --- 安全链路 --- + - name: waf + cmd: bash /opt/micro_servers/waf/_run.sh + args: ["-c", "config.yaml"] + env: {} + depends_on: [ca, gateway] + sleep_before: 0 + + - name: ca + cmd: bash /opt/micro_servers/ca/_run.sh + args: [] + env: {} + depends_on: [db2] + sleep_before: 2 + + - name: gateway + cmd: bash /opt/micro_servers/gateway/_run.sh + args: [] + env: {} + depends_on: [db2] + sleep_before: 2 + + # --- 验证码 --- + - name: captcha2 + cmd: bash /opt/micro_servers/captcha2/_run.sh + args: [] + env: {} + depends_on: [] + sleep_before: 1 + + # --- AI 工具箱 --- + - name: aibox + cmd: bash /opt/micro_servers/aibox/_run.sh + args: [] + env: + PATH: "${PATH}:~/.aibox/skills" + depends_on: [] + sleep_before: 0 + + # --- 端口重定向 --- + - name: redirect80 + cmd: bash /opt/micro_servers/redirect80/_run.sh + args: [] + env: {} + depends_on: [waf] + sleep_before: 0 +``` + +**字段说明**: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `name` | string | 是 | 服务唯一标识,用于日志和未来注册表 | +| `cmd` | string | 是 | 启动命令(与 init.txt 每行格式一致) | +| `args` | string[] | 否 | 传递给 `_run.sh` 的命令行参数列表 | +| `env` | map | 否 | 启动前设置的环境变量 | +| `depends_on` | string[] | 否 | 依赖的服务名列表(未来 DAG 排序用,当前仅记录) | +| `sleep_before` | int | 否 | 启动前等待秒数(替代散落在 _run.sh 中的 sleep) | + +### 4.3 core 解析逻辑 + +新增 `include/registry/InitParser.hh` + `src/registry/InitParser.cpp`: + +```cpp +// include/registry/InitParser.hh +#pragma once +#include +#include +#include + +namespace qing::registry { + +struct ServiceConfig { + std::string name; + std::string cmd; + std::vector args; + std::map env; + std::vector depends_on; + int sleep_before = 0; +}; + +class InitParser { +public: + // 优先读 services.yaml,不存在则回退 init.txt + static std::vector load(const std::string& conf_dir); + + // 解析 services.yaml + static std::vector parseYaml(const std::string& path); + + // 解析 init.txt(向后兼容) + static std::vector parseTxt(const std::string& path); + + // 将 ServiceConfig 拼成完整命令字符串(cmd + " " + args.join(" ")) + static std::string toCommand(const ServiceConfig& svc); +}; + +} // namespace qing::registry +``` + +**解析流程**: + +``` +load(conf_dir): + 1. 检查 conf_dir/services.yaml 是否存在 + 2. 存在 → parseYaml() → 返回 ServiceConfig 列表 + 3. 不存在 → 检查 conf_dir/init.txt + 4. 存在 → parseTxt() → 每行作为 ServiceConfig{name="", cmd=line, args=[]} + 5. 都不存在 → 报错退出 +``` + +**parseYaml 核心逻辑**(使用 yaml-cpp): + +```cpp +#include + +std::vector InitParser::parseYaml(const std::string& path) { + YAML::Node root = YAML::LoadFile(path); + std::vector result; + + for (const auto& node : root["services"]) { + ServiceConfig svc; + svc.name = node["name"].as(""); + svc.cmd = node["cmd"].as(); + + if (node["args"]) + for (const auto& a : node["args"]) + svc.args.push_back(a.as()); + + if (node["env"]) + for (const auto& kv : node["env"]) + svc.env[kv.first.as()] = kv.second.as(); + + if (node["depends_on"]) + for (const auto& d : node["depends_on"]) + svc.depends_on.push_back(d.as()); + + if (node["sleep_before"]) + svc.sleep_before = node["sleep_before"].as(0); + + result.push_back(std::move(svc)); + } + return result; +} +``` + +**启动执行逻辑**(改动 `pmc_mtd::parse_self_init_list`): + +```cpp +// pmc_mtd.cpp 中改造 +void pmc_mtd::init_from_config(const std::string& conf_dir) { + auto services = InitParser::load(conf_dir); + + for (const auto& svc : services) { + // 1. sleep_before 等待 + if (svc.sleep_before > 0) + std::this_thread::sleep_for(std::chrono::seconds(svc.sleep_before)); + + // 2. 设置环境变量 + for (const auto& [k, v] : svc.env) + setenv(k.c_str(), v.c_str(), 1); + + // 3. 拼接完整命令并启动 + std::string full_cmd = InitParser::toCommand(svc); + // full_cmd = "bash /opt/micro_servers/db2/_run.sh --port 8007 --log-level info" + ppool.crtp(full_cmd); + } +} +``` + +### 4.4 向后兼容策略 + +``` + services.yaml 存在? + │ + ┌─── 是 ──┤── 否 ───┐ + ▼ ▼ + parseYaml() init.txt 存在? + │ │ + │ ┌── 是 ──┤── 否 ───┐ + │ ▼ ▼ + │ parseTxt() 报错退出 + │ │ + └─────┬─────┘ + ▼ + ServiceConfig[] + 逐个启动 +``` + +- `init.txt` 模式下,每行解析为 `{name="", cmd=line, args=[], sleep_before=0}`,行为与当前完全一致 +- `services.yaml` 模式下,享受参数透传和 sleep 管理能力 +- Makefile 的 `CONF_NAME` 可逐步从 `init.txt` 切换为 `services.yaml` + +--- + +## 5. Step 2:_run.sh 参数透传 + +### 5.1 改造规则 + +每个 `_run.sh` 的末尾 `exec` 行必须带 `"$@"`,同时移除硬编码参数和散落的 `sleep`。 + +**改造模板**: + +```bash +#!/bin/bash +# /_run.sh — 标准化启动脚本 +cd "$(dirname "$0")" || exit + +# --- 服务特有前置(venv / setcap 等)保持不变 --- + +# 启动:"$@" 透传 core/services.yaml 传入的参数 +exec "$@" +``` + +### 5.2 逐服务改造清单 + +| 服务 | 当前 exec 行 | 改造后 | 额外改动 | +|------|-------------|--------|----------| +| db2 | `exec ./build/db2 "$@"` | ✅ 无需改 | — | +| dnfs2 | `exec ./build/dnfs2 "$@"` | ✅ 无需改 | — | +| fsys | `exec ./build/fsys "$@"` | ✅ 无需改 | — | +| ca | `exec ./build/ca.out "$@"` | ✅ 无需改 | 移除 `sleep 2`(移交 YAML) | +| gateway | `exec ./build/gateway.out "$@"` | ✅ 无需改 | 移除 `sleep 2`(移交 YAML) | +| waf | `exec ./waf.bin -c config.yaml` | `exec ./waf.bin -c config.yaml "$@"` | 保留 `-c config.yaml` 作为脚本默认值,services.yaml `args: []` | +| captcha2 | `exec ./captcha2.bin` | `exec ./captcha2.bin "$@"` | 移除 `sleep 1`(移交 YAML) | +| aibox | `exec python aibox.py $@` | `exec python aibox.py "$@"` | `$@` → `"$@"` 加引号 | +| ai_review | `exec python3 ai_review.py` | `exec python3 ai_review.py "$@"` | — | +| smtp | `exec python3 smtp_v2.py` | `exec python3 smtp_v2.py "$@"` | 移除 `sleep 2`(移交 YAML) | +| redirect80 | `exec python3 redirect80.py` | `exec python3 redirect80.py "$@"` | — | + +**统计**:6 个无需改、5 个需改 exec 行、4 个需移除 sleep。 + +### 5.3 sleep 迁移对照 + +| 服务 | 当前 sleep 位置 | 迁移到 services.yaml | +|------|----------------|---------------------| +| ca | `_run.sh` 中 `sleep 2` | `sleep_before: 2` | +| gateway | `_run.sh` 中 `sleep 2` | `sleep_before: 2` | +| captcha2 | `_run.sh` 中 `sleep 1` | `sleep_before: 1` | +| smtp | `_run.sh` 中 `sleep 2` | `sleep_before: 2` | + +移除后 `_run.sh` 只负责"切换目录 + 前置准备 + exec",不负责时序控制。 + +--- + +## 6. Step 3:CLI 参数标准化 + +### 6.1 通用参数约定 + +定义一组所有服务都应支持的通用 CLI 参数: + +| 参数 | 短选项 | 类型 | 默认值 | 说明 | +|------|--------|------|--------|------| +| `--host` | `-H` | string | `127.0.0.1` | 绑定地址 | +| `--port` | `-p` | int | 服务特定 | 监听端口 | +| `--config` | `-c` | string | 服务特定 | 配置文件路径 | +| `--log-level` | `-l` | enum | `info` | `debug\|info\|warn\|error` | +| `--instance` | `-i` | string | 服务名 | 实例标识(未来多实例/注册中心用) | +| `--help` | `-h` | flag | — | 输出帮助 | +| `--version` | `-v` | flag | — | 输出版本 | + +**优先级规则**:`CLI 参数 > 环境变量 > confs/配置文件 > 硬编码默认值` + +### 6.2 _run.sh 默认值注入 + +在服务二进制还不支持所有参数的过渡期,`_run.sh` 可注入默认值: + +```bash +#!/bin/bash +# waf/_run.sh — 标准化后 +cd "$(dirname "$0")" || exit + +# 默认参数(可被 services.yaml args 覆盖) +DEFAULT_ARGS=(-c config.yaml) + +exec ./waf.bin "${DEFAULT_ARGS[@]}" "$@" +``` + +```bash +#!/bin/bash +# db2/_run.sh — 标准化后 +cd "$(dirname "$0")" || exit +set -e + +# 默认参数 +DEFAULT_ARGS=(--host 127.0.0.1 --port 8005 --log-level info) + +exec ./build/db2 "${DEFAULT_ARGS[@]}" "$@" +``` + +**原理**:`"$@"` 追加在 `DEFAULT_ARGS` 之后,如果用户通过 services.yaml 传了同名参数,取决于各服务的解析逻辑(`boost::program_options` 默认后者覆盖前者;Python `argparse` 同理)。 + +### 6.3 各语言适配指南 + +#### C++ 服务(db2, dnfs2, fsys, captcha2) + +当前这 4 个服务无 CLI 框架。建议引入 `boost::program_options`(ca/gateway 已有先例): + +```cpp +// db2/src/db2.cpp — 新增 CLI 解析 +#include +namespace po = boost::program_options; + +int main(int argc, char** argv) { + po::options_description desc("db2 — database RPC service"); + desc.add_options() + ("help,h", "output help message") + ("version,v", "output version message") + ("host,H", po::value()->default_value("127.0.0.1"), "bind address") + ("port,p", po::value()->default_value(8005), "listen port") + ("log-level,l", po::value()->default_value("info"), + "debug|info|warn|error") + ("instance,i", po::value()->default_value("db2"), "instance name") + ; + + po::variables_map vm; + try { + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << desc << std::endl; + return 1; + } + + if (vm.count("help")) { std::cout << desc << std::endl; return 0; } + if (vm.count("version")) { std::cout << "db2 1.0.0" << std::endl; return 0; } + + std::string host = vm["host"].as(); + int port = vm["port"].as(); + std::string log_level = vm["log-level"].as(); + + // 后续使用 host/port/log_level 启动服务... +} +``` + +#### C++ 服务(ca, gateway)— 扩展现有 program_options + +ca 和 gateway已有 `po::options_description` 但只注册了 `--help`/`--version`,需追加通用参数: + +```cpp +// ca/src/main.cpp — 扩展 +desc.add_options() + ("help,h", "output help message") + ("version,v", "output version message") + // 新增通用参数 + ("host,H", po::value()->default_value("127.0.0.1"), "bind address") + ("port,p", po::value()->default_value(8443), "listen port") + ("log-level,l", po::value()->default_value("info"), + "debug|info|warn|error") + ("instance,i", po::value()->default_value("ca"), "instance name") +; +``` + +注意:ca/gateway 当前配置走 confs + 环境变量,CLI 参数应作为**覆盖层**,不替换 confs 机制。 + +#### Go 服务(waf)— 扩展现有 flag + +waf 已有 `flag` 包,追加通用参数: + +```go +func main() { + var ( + configFile = flag.String("c", "config.yaml", "配置文件路径") + host = flag.String("H", "127.0.0.1", "绑定地址") + port = flag.Int("p", 443, "监听端口") + logLevel = flag.String("l", "info", "debug|info|warn|error") + instance = flag.String("i", "waf", "实例名") + doList = flag.Bool("list", false, "列出所有规则后退出") + doTest = flag.String("test", "", "校验单个规则文件语法后退出") + doCheck = flag.String("check", "", "用当前规则测试输入字符串后退出") + ) + flag.Parse() + // ... +} +``` + +注意:Go `flag` 包不支持短选项连写(`-H 127.0.0.1`),与 C++ `program_options` 的 `-H` 语法兼容。 + +#### Python 服务(aibox, ai_review, smtp, redirect80) + +建议统一使用 `argparse`: + +```python +#!/usr/bin/env python3 +"""ai_review — AI 审核服务""" +import argparse + +def parse_args(): + parser = argparse.ArgumentParser(description="ai_review — AI 审核服务") + parser.add_argument("-H", "--host", default="127.0.0.1", help="绑定地址") + parser.add_argument("-p", "--port", type=int, default=8007, help="监听端口") + parser.add_argument("-l", "--log-level", default="info", + choices=["debug", "info", "warn", "error"], help="日志级别") + parser.add_argument("-i", "--instance", default="ai_review", help="实例名") + return parser.parse_args() + +if __name__ == "__main__": + args = parse_args() + # 后续使用 args.host, args.port, args.log_level... +``` + +aibox 已有 `import argparse`(死代码),激活即可。 + +### 6.4 环境变量桥接 + +对于走 confs + 环境变量的服务(ca, gateway, dnfs2),CLI 参数应映射到环境变量,保持与现有 confs 机制兼容: + +```bash +# ca/_run.sh — 环境变量桥接模式 +cd "$(dirname "$0")" || exit + +# 从命令行参数提取并导出环境变量(供 confs 加载逻辑使用) +while [[ $# -gt 0 ]]; do + case "$1" in + -H|--host) export CA_HOST="$2"; shift 2 ;; + -p|--port) export CA_PORT="$2"; shift 2 ;; + -l|--log-level) export LOG_LEVEL="$2"; shift 2 ;; + *) EXTRA_ARGS+=("$1"); shift ;; + esac +done + +exec ./build/ca.out "${EXTRA_ARGS[@]}" +``` + +这种桥接方式不需要立刻改 ca 的 C++ 源码——`_run.sh` 先把 CLI 参数翻译成环境变量,ca 现有的环境变量读取逻辑自然生效。 + +--- + +## 7. 实施计划 + +### 7.1 分步交付 + +| 步骤 | 改动范围 | 涉及文件 | 预估工时 | 风险 | +|------|----------|----------|----------|------| +| **S1-a** | yaml-cpp vendored + Makefile 集成 | `core/third_party/yaml-cpp/`、`core/Makefile` | 1h | 低 | +| **S1-b** | InitParser 实现 | `core/include/registry/InitParser.hh`、`core/src/registry/InitParser.cpp` | 2h | 低 | +| **S1-c** | pmc_mtd 改造(调用 InitParser) | `core/src/main/pmc_mtd.cpp` | 1h | 中(改核心启动路径) | +| **S1-d** | 创建 services.yaml | `core/services.yaml` | 0.5h | 低 | +| **S1-e** | 回退测试(删除 services.yaml 验证 init.txt 兼容) | — | 0.5h | 低 | +| **S2-a** | 5 个 _run.sh 改 exec 行 | `waf/`、`captcha2/`、`aibox/`、`ai_review/`、`smtp/`、`redirect80/` 的 `_run.sh` | 0.5h | 极低 | +| **S2-b** | 4 个 _run.sh 移除 sleep | `ca/`、`gateway/`、`captcha2/`、`smtp/` 的 `_run.sh` | 0.2h | 低(sleep 已移交 YAML) | +| **S3-a** | 定义 CLI 标准文档(本文档 §6) | — | 0h(已完成) | — | +| **S3-b** | C++ 服务适配(ca/gateway 扩展,db2/dnfs2/fsys/captcha2 新增) | 各服务 `src/*.cpp` | 4h | 中 | +| **S3-c** | Python 服务适配(argparse) | `aibox.py`、`ai_review.py`、`smtp_v2.py`、`redirect80.py` | 2h | 低 | +| **S3-d** | Go 服务适配(waf flag 扩展) | `waf/waf.go` | 0.5h | 低 | +| **S3-e** | _run.sh 默认值注入 | 各服务 `_run.sh` | 0.5h | 低 | +| **S4** | 端到端测试 | — | 1h | — | + +**总计预估:~14 小时** + +### 7.2 推荐实施顺序 + +``` +S1-a (yaml-cpp 集成) + └─▶ S1-b (InitParser) + └─▶ S1-c (pmc_mtd 改造) + └─▶ S1-d (services.yaml) + └─▶ S1-e (回退测试) ──▶ Step 1 完成 + │ + ▼ + S2-a + S2-b ( _run.sh 改造) ──▶ Step 2 完成 + │ + ▼ + S3-b/c/d (各服务 CLI 适配) + └─▶ S3-e (默认值注入) ──▶ Step 3 完成 + │ + ▼ + S4 (端到端测试) +``` + +### 7.3 新增/改动文件清单 + +``` +core/ +├── include/registry/ +│ └── InitParser.hh # 【新增】YAML/TXT 解析器头文件 +├── src/registry/ +│ └── InitParser.cpp # 【新增】YAML/TXT 解析器实现 +├── src/main/pmc_mtd.cpp # 【改动】调用 InitParser 替代 parse_self_init_list +├── src/main.cpp # 【改动】--init 帮助文本更新 +├── Makefile # 【改动】追加 InitParser.o 编译目标 + -lyaml-cpp 链接 +├── _run.sh # 【改动】-i init.txt → -i .(目录模式自动查找) +├── services.yaml # 【新增】声明式服务启动配置 +└── init.txt # 【保留】向后兼容回退 + +项目根目录/ +├── _setup.deb.sh # 【改动】追加 libyaml-cpp-dev +└── _setup.rhel.sh # 【改动】追加 yaml-cpp-devel + +各服务 _run.sh(11 个) # 【已完成】Step 2 统一 "$@" 透传 + 移除 sleep + +C++ 服务源码(6 个) # 【待改】Step 3 新增/扩展 program_options +Python 服务源码(4 个) # 【待改】Step 3 新增 argparse +Go 服务源码(1 个) # 【待改】Step 3 扩展 flag +``` + +--- + +## 8. 验证清单 + +### 8.1 Step 1 验证 + +- [ ] `make` 编译成功,yaml-cpp 源文件正确编译链接 +- [ ] `services.yaml` 存在时,core 按 YAML 声明启动全部 11 个服务 +- [ ] `services.yaml` 不存在时,core 回退 `init.txt`,行为与改造前完全一致 +- [ ] `args` 字段的参数正确透传到 `_run.sh` +- [ ] `env` 字段的环境变量在子进程启动前生效 +- [ ] `sleep_before` 字段正确控制启动间隔 + +### 8.2 Step 2 验证 + +- [x] 全部 11 个 `_run.sh` 末尾 `exec` 行带 `"$@"` +- [x] waf 保留 `-c config.yaml` 作为脚本默认值,追加 `"$@"` 透传,services.yaml `args: []` +- [x] aibox 的 `$@` 改为 `"$@"`(加引号,防空格路径问题) +- [x] ca/gateway/captcha2/smtp 的 `sleep` 从 `_run.sh` 移除,由 `services.yaml` 的 `sleep_before` 管理 +- [ ] 手动执行 `_run.sh --help` 能透传到二进制(依赖 Step 3 CLI 适配) + +### 8.3 Step 3 验证 + +- [ ] 全部服务支持 `--help` 输出用法 +- [ ] 全部服务支持 `--version` 输出版本 +- [ ] `--port` 能覆盖默认端口并生效 +- [ ] `--log-level` 能控制日志输出级别 +- [ ] `_run.sh` 默认值注入 + `services.yaml` 覆盖,两者叠加不冲突 +- [ ] ca/gateway 的环境变量桥接模式正确工作 + +--- + +## 9. 风险与缓解 + +| 风险 | 影响 | 缓解措施 | +|------|------|----------| +| yaml-cpp 编译增加构建时间 | 低(~10s) | 可接受;如需优化可预编译为静态库 | +| pmc_mtd 改造影响核心启动路径 | 高 | 保留 `init.txt` 回退路径;先在测试环境验证 | +| _run.sh 移除 sleep 后启动时序变化 | 中 | `services.yaml` 的 `sleep_before` 提供等价等待 | +| 各服务 CLI 参数适配工作量大 | 中 | 分批适配;_run.sh 默认值注入可过渡 | +| Go flag 与 C++ program_options 语法差异 | 低 | 两者都支持 `-H value` 和 `--host value` 格式 | +| Python argparse 与 C++ program_options 行为差异 | 低 | 测试覆盖;argparse 默认不覆盖已设默认值 | + +--- + +## 10. 附录 + +### A. 各服务端口与配置对照 + +| 服务 | 端口 | 协议 | 配置来源 | CLI 框架现状 | +|------|------|------|----------|-------------| +| db2 | 8005 | pymsg | 硬编码 | 无 | +| ai_review | 8007 | http | 硬编码 | 无 | +| dnfs2 | 8006 | http | 硬编码 + confs | 无 | +| smtp | 8008 | pymsg | 硬编码 | 无 | +| fsys | 8090 | http | 硬编码 | 无 | +| waf | 443 | https | YAML 配置文件 | Go flag ✅ | +| ca | 8443 | https | confs + 环境变量 | program_options(仅 --help/--version) | +| gateway | 8445 | http | confs + 环境变量 | program_options(仅 --help/--version) | +| captcha2 | 8009 | pymsg | 硬编码 | 无 | +| aibox | 8765 | websocket | _setenv.sh + 硬编码 | argparse(已 import 未使用) | +| redirect80 | 80 | http | 硬编码 | 无 | + +### B. yaml-cpp 集成验证 + +已采用系统包方式(非 vendored),在 `_setup.deb.sh` / `_setup.rhel.sh` 中声明依赖: + +```bash +# Debian/Ubuntu +sudo apt install libyaml-cpp-dev + +# RHEL/CentOS +sudo dnf install yaml-cpp-devel +``` + +Makefile 中 `-lyaml-cpp` 链接,`InitParser.cpp` 中 `#include ` 引用。 + +### C. 环境变量约定(现有 + 新增) + +| 环境变量 | 使用方 | 当前/新增 | 说明 | +|----------|--------|-----------|------| +| `CONFS_HOST` | ca, gateway, dnfs2 | 现有 | confs 服务地址,默认 `127.0.0.1` | +| `CONFS_PORT` | ca, gateway, dnfs2 | 现有 | confs 服务端口,默认 `8010` | +| `CORE_HOST` | 未来 RegistrationClient | 新增 | core 注册中心地址,默认 `127.0.0.1` | +| `CORE_PORT` | 未来 RegistrationClient | 新增 | core 注册中心端口,默认 `5200` | +| `LOG_LEVEL` | 全部服务(可选) | 新增 | 日志级别,可被 `--log-level` 覆盖 | + +### D. 与注册中心计划的衔接点 + +| 本方案产出 | 注册中心计划消费点 | +|-----------|-------------------| +| `services.yaml` 格式 | P7 直接复用,追加 `health_endpoint`/`protocol`/`restart_max` 等字段 | +| `InitParser` 解析器 | P2 调用 `parseYaml()` 后自动填充 `ServiceRegistry` | +| `ServiceConfig.depends_on` | P7 DAG 拓扑排序的输入 | +| `ServiceConfig.args` | 各服务通过 CLI 参数接收注册中心分配的端口/实例名 | +| CLI `--instance` 参数 | P5 RegistrationClient SDK 用此值作为注册服务名 | +| CLI `--port` 参数 | P0 ServiceEntry 的 port 字段来源 | diff --git a/gateway/_run.sh b/gateway/_run.sh index 9c34359..b9b5ba8 100644 --- a/gateway/_run.sh +++ b/gateway/_run.sh @@ -4,7 +4,5 @@ # 启动时从 confs(CONFS_HOST:CONFS_PORT,默认 127.0.0.1:8010)拉取配置。 cd "$(dirname "$0")" || exit -# 等待依赖服务启动(confs/db) -sleep 2 - +# sleep 已移至 services.yaml 的 sleep_before 字段统一管理 exec ./build/gateway.out "$@" diff --git a/redirect80/_run.sh b/redirect80/_run.sh index d181884..28c65cf 100755 --- a/redirect80/_run.sh +++ b/redirect80/_run.sh @@ -13,4 +13,4 @@ if command -v setcap &>/dev/null; then fi fi -exec python3 redirect80.py +exec python3 redirect80.py "$@" diff --git a/smtp/_run.sh b/smtp/_run.sh index 0811c15..40ca352 100755 --- a/smtp/_run.sh +++ b/smtp/_run.sh @@ -2,5 +2,4 @@ cd "$(dirname "$0")" || exit source ./venv/bin/activate #exec ./smtp.bin -sleep 2 -exec python3 smtp_v2.py +exec python3 smtp_v2.py "$@" diff --git a/waf/_run.sh b/waf/_run.sh index 260fb9f..844c116 100644 --- a/waf/_run.sh +++ b/waf/_run.sh @@ -1,4 +1,4 @@ #!/bin/bash # 运行 WAF(需先 _set.sh 编译) cd "$(dirname "$0")" || exit -exec ./waf.bin -c config.yaml +exec ./waf.bin -c config.yaml "$@"