refactor(ca): v1.1.0 配置体系重构为纯 CLI 传递
- 移除 confs 依赖:删 Conf.hpp 与 confs/configs/ca.ini,配置加载改为 CLI > 环境变量 > 默认值三层(与 dnfs2 同模式) - 新增 16 个配置选项,env 以 CA_* 为主并兼容旧名(LISTEN_ADDR/UPSTREAM_GATEWAY/DB_* 等),启动时配置完整性校验 - 原 ca.ini 配置值迁入 core/services.yaml ca 条目 args - 修复伪造 Token 触发 500:verify_token 统一捕获 RSA 验签异常,按验签失败返回 401(符合黑盒 B3/B4 契约) - 同步更新 ca/README.md 与根 README.md
This commit is contained in:
1 parent
8b6eb47c80
commit
9d548c064f
8 files changed
+244
-302
No files matched your search
+167
-149
@@ -10,6 +10,7 @@
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
@@ -23,7 +24,6 @@
|
||||
#include <openssl/kdf.h>
|
||||
#include "ExpBase.hpp"
|
||||
#include "LocalTime.hpp"
|
||||
#include "Conf.hpp"
|
||||
#include "DbC.hpp"
|
||||
#include <us/LogC.hpp>
|
||||
|
||||
@@ -32,7 +32,7 @@ using namespace qing;
|
||||
namespace json = boost::json;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
constexpr const char *_VER = "1.0.0";
|
||||
constexpr const char *_VER = "1.1.0";
|
||||
|
||||
//////////////////////////////////
|
||||
#include <sstream>
|
||||
@@ -376,28 +376,41 @@ std::string extract_token_from_request(const http::request<http::string_body>& r
|
||||
// 参数 raw_token:"base64data_signature" 格式(不含 "Bearer " 前缀)
|
||||
TokenInfo verify_token(const std::string& raw_token);
|
||||
|
||||
/* configure items */
|
||||
static std::string _ADDR;
|
||||
static int _PORT;
|
||||
static bool _TLS = false;
|
||||
/* 上游 gateway 地址(前置拓扑:ca 认证后转发至此),由 [Upstream] gateway 配置 */
|
||||
static std::string _UPSTREAM_GATEWAY = "http://127.0.0.1:8445";
|
||||
static int _TOKEN_KEEP_TIME = 3600; // Token 有效期(秒),可由 [Token] keep_time 配置
|
||||
static int _TOKEN_REFRESH_GRACE_MULTIPLIER = 2; // Token 刷新宽限期倍数,过期后 iat + keep_time*倍数 窗口内仍可刷新
|
||||
static int _TOKEN_MAX_REFRESH = 10; // Token 生命周期内最大刷新次数,可由 [Token] max_refresh 配置
|
||||
static std::vector<std::string> _CORS_ORIGINS; // CORS 允许的 Origin 白名单,可由 [CORS] allowed_origins 配置
|
||||
static std::vector<std::string> _ADMIN_USERS; // 管理员账号白名单,可由 [Admin] users 配置(分号分隔),登录时写入 Token payload 的 is_admin
|
||||
/* 环境变量读取辅助(v1.1.0 配置体系 CLI > env > 默认值) */
|
||||
static std::string env_or(const char* name, const std::string& def = "") {
|
||||
const char* v = std::getenv(name);
|
||||
return (v && *v) ? std::string(v) : def;
|
||||
}
|
||||
static int env_int_or(const char* name, int def) {
|
||||
const char* v = std::getenv(name);
|
||||
if (!v || !*v) return def;
|
||||
try { return std::stoi(v); }
|
||||
catch (...) { return def; }
|
||||
}
|
||||
static bool env_flag(const char* name) {
|
||||
std::string v = env_or(name);
|
||||
return v == "1" || v == "on" || v == "true" || v == "yes";
|
||||
}
|
||||
|
||||
/* 下游 pymsg 服务地址(从 confs [Downstream] 段加载,可被环境变量覆盖) */
|
||||
/* configure items(默认值即声明处初值,env 与 CLI 依次覆盖) */
|
||||
static std::string _ADDR = "127.0.0.1";
|
||||
static int _PORT = 8443;
|
||||
static bool _TLS = false;
|
||||
/* 上游 gateway 地址(前置拓扑:ca 认证后转发至此) */
|
||||
static std::string _UPSTREAM_GATEWAY = "http://127.0.0.1:8445";
|
||||
static int _TOKEN_KEEP_TIME = 3600; // Token 有效期(秒)
|
||||
static int _TOKEN_REFRESH_GRACE_MULTIPLIER = 2; // Token 刷新宽限期倍数,过期后 iat + keep_time*倍数 窗口内仍可刷新
|
||||
static int _TOKEN_MAX_REFRESH = 10; // Token 生命周期内最大刷新次数
|
||||
static std::vector<std::string> _CORS_ORIGINS; // CORS 允许的 Origin 白名单(分号分隔)
|
||||
static std::vector<std::string> _ADMIN_USERS; // 管理员账号白名单(分号分隔),登录时写入 Token payload 的 is_admin
|
||||
|
||||
/* 下游 pymsg 服务地址 */
|
||||
static std::string _DB_HOST = "127.0.0.1";
|
||||
static int _DB_PORT = 8005;
|
||||
static std::string _CAPTCHA_HOST = "127.0.0.1";
|
||||
static int _CAPTCHA_PORT = 8009;
|
||||
static std::string _SMTP_HOST = "127.0.0.1";
|
||||
static int _SMTP_PORT = 8008;
|
||||
/* confs 引导配置(不依赖 confs 本身,环境变量 CONFS_HOST/CONFS_PORT 覆盖,默认 127.0.0.1:8010) */
|
||||
static std::string _CONFS_HOST = "127.0.0.1";
|
||||
static int _CONFS_PORT = 8010;
|
||||
|
||||
/* WebSocket 代理路由:path -> ws://backend-host:port/target
|
||||
* 仅管理员用户可访问,握手阶段由 ws_proxy 回调验签 Token 中的 is_admin */
|
||||
@@ -620,9 +633,16 @@ TokenInfo verify_token(const std::string& raw_token) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// RSA 验签
|
||||
// RSA 验签(Verify 对非法签名格式(如奇数长度 hex)会抛异常,
|
||||
// 此处统一捕获按验签失败处理,避免伪造 Token 触发 500——审计 B3/B4 契约要求 401)
|
||||
auto publ = MyRSA::Public_Key::from_pem(_KEYGEN->get_public_key_pem());
|
||||
if (!publ.Verify(auth, sign)) {
|
||||
bool sig_ok = false;
|
||||
try {
|
||||
sig_ok = publ.Verify(auth, sign);
|
||||
} catch (const std::exception&) {
|
||||
sig_ok = false;
|
||||
}
|
||||
if (!sig_ok) {
|
||||
info.http_status = 401;
|
||||
return info;
|
||||
}
|
||||
@@ -767,14 +787,27 @@ void set_signal_action() {
|
||||
/* -------- 入口 --------*/
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
/* 首先处理命令行参数 */
|
||||
/* 首先处理命令行参数(v1.1.0 起配置全部经 CLI 传递) */
|
||||
po::options_description desc("cpp language web ca (central auth)");
|
||||
desc.add_options()
|
||||
("help,h", "output help message")
|
||||
("version,v", "output version message")
|
||||
("host", po::value<std::string>(), "绑定地址(默认 127.0.0.1),覆盖 [Server] address")
|
||||
("port", po::value<int>(), "监听端口(默认 8443),覆盖 [Server] port")
|
||||
("config", po::value<std::string>(), "confs 拉取的配置名(默认 ca.ini)")
|
||||
("host", po::value<std::string>(), "绑定地址(默认 127.0.0.1,env CA_HOST/LISTEN_ADDR)")
|
||||
("port", po::value<int>(), "监听端口(默认 8443,env CA_PORT/LISTEN_PORT)")
|
||||
("tls", "启用 HTTPS(证书 full_chain.crt/server.key;缺省纯 HTTP,env CA_TLS=on)")
|
||||
("upstream-gateway", po::value<std::string>(), "上游 gateway 地址(默认 http://127.0.0.1:8445,env CA_UPSTREAM_GATEWAY/UPSTREAM_GATEWAY)")
|
||||
("token-keep-time", po::value<int>(), "Token 有效期秒数(默认 3600,env CA_TOKEN_KEEP_TIME)")
|
||||
("token-refresh-grace-multiplier", po::value<int>(), "Token 刷新宽限期倍数(默认 2,env CA_TOKEN_REFRESH_GRACE_MULTIPLIER)")
|
||||
("token-max-refresh", po::value<int>(), "Token 最大刷新次数(默认 10,env CA_TOKEN_MAX_REFRESH)")
|
||||
("cors-origins", po::value<std::string>(), "CORS Origin 白名单,分号分隔(env CA_CORS_ORIGINS)")
|
||||
("admin-users", po::value<std::string>(), "管理员账号白名单,分号分隔(env CA_ADMIN_USERS)")
|
||||
("ws-proxy-routes", po::value<std::string>(), "WS 代理路由 /path=ws://host:port,分号分隔(env CA_WS_PROXY_ROUTES)")
|
||||
("db-host", po::value<std::string>(), "db 服务地址(默认 127.0.0.1,env CA_DB_HOST/DB_HOST)")
|
||||
("db-port", po::value<int>(), "db 服务端口(默认 8005,env CA_DB_PORT/DB_PORT)")
|
||||
("captcha-host", po::value<std::string>(), "captcha 服务地址(默认 127.0.0.1,env CA_CAPTCHA_HOST/CAPTCHA_HOST)")
|
||||
("captcha-port", po::value<int>(), "captcha 服务端口(默认 8009,env CA_CAPTCHA_PORT/CAPTCHA_PORT)")
|
||||
("smtp-host", po::value<std::string>(), "smtp 服务地址(默认 127.0.0.1,env CA_SMTP_HOST/SMTP_HOST)")
|
||||
("smtp-port", po::value<int>(), "smtp 服务端口(默认 8008,env CA_SMTP_PORT/SMTP_PORT)")
|
||||
("log-level", po::value<std::string>(), "日志级别 debug|info|warn|error(默认 info)")
|
||||
("instance", po::value<std::string>(), "实例名(注册中心用,默认 ca)")
|
||||
;
|
||||
@@ -808,133 +841,98 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ==================== 配置加载(两层:confs 强依赖 → 环境变量覆盖) ====================
|
||||
* 与 Python 服务(dnfs/db/static)保持一致的加载模式:
|
||||
* 1. 引导配置:confs 地址从 CONFS_HOST/CONFS_PORT 环境变量读取,缺省 127.0.0.1:8010
|
||||
* 2. 从 confs 拉取 ca.ini 全文(retry_on_refused=true 等待 confs 就绪)
|
||||
* 3. 用 boost::property_tree 解析 ini
|
||||
* 4. 环境变量覆盖(最高优先级,Docker 环境需要服务名而非 127.0.0.1)
|
||||
* 5. 配置完整性校验:必需字段缺失则启动失败
|
||||
* 不再支持本地 ini 文件回退(与 static 模块一致,配置统一由 confs 管理)。
|
||||
* ==================================================================================== */
|
||||
/* ==================== 配置加载(v1.1.0:CLI > 环境变量 > 默认值) ====================
|
||||
* 配置完全经命令行传递(与 dnfs2 同模式),不再依赖 confs 统一配置服务:
|
||||
* 1. 默认值:各配置项声明处初值(与原 ca.ini 默认值一致)
|
||||
* 2. 环境变量覆盖:CA_ 前缀为主,兼容旧名(LISTEN_ADDR / LISTEN_PORT / UPSTREAM_GATEWAY / DB_x / CAPTCHA_x / SMTP_x,Docker 环境需要服务名而非 127.0.0.1)
|
||||
* 3. CLI 参数覆盖:最高优先级
|
||||
* 4. 配置完整性校验:必需字段非法则启动失败
|
||||
* 部署侧由 core/services.yaml 的 args 声明完整传入配置。
|
||||
* ============================================================================== */
|
||||
|
||||
{
|
||||
/* 1. 引导配置:confs 连接地址(不依赖 confs 本身,避免循环依赖) */
|
||||
_CONFS_HOST = ConfIni::env("CONFS_HOST", "127.0.0.1");
|
||||
_CONFS_PORT = ConfIni::env_int("CONFS_PORT", 8010);
|
||||
|
||||
/* --config 覆盖 confs 拉取的配置名(在 confs 拉取前读取) */
|
||||
std::string confs_config_name = "ca.ini";
|
||||
if (vm.count("config")) {
|
||||
confs_config_name = vm["config"].as<std::string>();
|
||||
}
|
||||
|
||||
ConfIni cf;
|
||||
try {
|
||||
/* 从 confs 拉取配置 */
|
||||
std::cout << "[ca] 从 confs (" << _CONFS_HOST << ":" << _CONFS_PORT
|
||||
<< ") 拉取 " << confs_config_name << " ..." << std::endl;
|
||||
pmc::net::MsgClient confs_client(_CONFS_HOST, _CONFS_PORT, "ca");
|
||||
json::object req;
|
||||
req["_route"] = "get";
|
||||
req["name"] = confs_config_name;
|
||||
std::string resp_str = confs_client.call(
|
||||
json::serialize(req), /*timeout=*/5.0,
|
||||
/*retry_on_refused=*/true);
|
||||
auto resp = json::parse(resp_str).as_object();
|
||||
if (!resp.at("success").as_bool()) {
|
||||
std::string err = "unknown";
|
||||
if (auto* ev = resp.if_contains("error")) {
|
||||
if (ev->is_string()) err = ev->as_string().c_str();
|
||||
}
|
||||
std::cerr << "[ca] 致命错误: 从 confs 获取 ca.ini 失败: " << err << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string ini_content = resp.at("data").as_object().at("content").as_string().c_str();
|
||||
cf = ConfIni::fromString(ini_content);
|
||||
std::cout << "[ca] 配置来源: confs (ca.ini @ "
|
||||
<< _CONFS_HOST << ":" << _CONFS_PORT << ")" << std::endl;
|
||||
}
|
||||
catch (ConfIni::IniConfigureFileParseException &e) {
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
std::cerr << "ini parse error" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cerr << "[ca] 致命错误: 配置加载失败: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 2. 从 ini 读取配置 */
|
||||
_ADDR = cf.get<std::string>("Server.address", "");
|
||||
_PORT = cf.get<int>("Server.port", -1);
|
||||
_TLS = cf.get<bool>("Server.tls", false);
|
||||
_UPSTREAM_GATEWAY = cf.get<std::string>("Upstream.gateway", "http://127.0.0.1:8445");
|
||||
_TOKEN_KEEP_TIME = cf.get<int>("Token.keep_time", 3600);
|
||||
_TOKEN_REFRESH_GRACE_MULTIPLIER = cf.get<int>("Token.refresh_grace_multiplier", 2);
|
||||
_TOKEN_MAX_REFRESH = cf.get<int>("Token.max_refresh", 10);
|
||||
_CORS_ORIGINS = split(cf.get<std::string>("CORS.allowed_origins", ""), ';');
|
||||
_ADMIN_USERS = split(cf.get<std::string>("Admin.users", ""), ';');
|
||||
|
||||
/* 下游服务地址 */
|
||||
_DB_HOST = cf.get<std::string>("Downstream.db_host", "127.0.0.1");
|
||||
_DB_PORT = cf.get<int>("Downstream.db_port", 8005);
|
||||
_CAPTCHA_HOST = cf.get<std::string>("Downstream.captcha_host", "127.0.0.1");
|
||||
_CAPTCHA_PORT = cf.get<int>("Downstream.captcha_port", 8009);
|
||||
_SMTP_HOST = cf.get<std::string>("Downstream.smtp_host", "127.0.0.1");
|
||||
_SMTP_PORT = cf.get<int>("Downstream.smtp_port", 8008);
|
||||
|
||||
/* [WsProxy] WebSocket 代理路由:格式 /path=ws://host:port/target;... */
|
||||
/* 1. 环境变量覆盖(默认值之上) */
|
||||
{
|
||||
std::string ws_cfg = cf.get<std::string>("WsProxy.routes", "");
|
||||
if (!ws_cfg.empty()) {
|
||||
auto entries = split(ws_cfg, ';');
|
||||
for (auto& entry : entries) {
|
||||
auto eq = entry.find('=');
|
||||
if (eq != std::string::npos) {
|
||||
std::string path = entry.substr(0, eq);
|
||||
std::string url = entry.substr(eq + 1);
|
||||
auto trim = [](std::string& s) {
|
||||
while (!s.empty() && std::isspace((unsigned char)s.front())) s.erase(s.begin());
|
||||
while (!s.empty() && std::isspace((unsigned char)s.back())) s.pop_back();
|
||||
};
|
||||
trim(path); trim(url);
|
||||
if (!path.empty() && !url.empty()) {
|
||||
_WS_PROXY_ROUTES[path] = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string v = env_or("CA_HOST", env_or("LISTEN_ADDR"));
|
||||
if (!v.empty()) _ADDR = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_PORT", env_int_or("LISTEN_PORT", -1));
|
||||
if (v > 0) _PORT = v;
|
||||
}
|
||||
if (env_flag("CA_TLS")) _TLS = true;
|
||||
|
||||
{
|
||||
std::string v = env_or("CA_UPSTREAM_GATEWAY", env_or("UPSTREAM_GATEWAY"));
|
||||
if (!v.empty()) _UPSTREAM_GATEWAY = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_TOKEN_KEEP_TIME", -1);
|
||||
if (v > 0) _TOKEN_KEEP_TIME = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_TOKEN_REFRESH_GRACE_MULTIPLIER", -1);
|
||||
if (v > 0) _TOKEN_REFRESH_GRACE_MULTIPLIER = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_TOKEN_MAX_REFRESH", -1);
|
||||
if (v > 0) _TOKEN_MAX_REFRESH = v;
|
||||
}
|
||||
{
|
||||
std::string v = env_or("CA_CORS_ORIGINS");
|
||||
if (!v.empty()) _CORS_ORIGINS = split(v, ';');
|
||||
}
|
||||
{
|
||||
std::string v = env_or("CA_ADMIN_USERS");
|
||||
if (!v.empty()) _ADMIN_USERS = split(v, ';');
|
||||
}
|
||||
|
||||
/* 3. 环境变量覆盖(优先级最高,Docker 环境使用服务名而非 127.0.0.1) */
|
||||
std::string env_listen_addr = ConfIni::env("LISTEN_ADDR");
|
||||
if (!env_listen_addr.empty()) _ADDR = env_listen_addr;
|
||||
int env_listen_port = ConfIni::env_int("LISTEN_PORT", -1);
|
||||
if (env_listen_port > 0) _PORT = env_listen_port;
|
||||
{
|
||||
std::string v = env_or("CA_DB_HOST", env_or("DB_HOST"));
|
||||
if (!v.empty()) _DB_HOST = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_DB_PORT", env_int_or("DB_PORT", -1));
|
||||
if (v > 0) _DB_PORT = v;
|
||||
}
|
||||
{
|
||||
std::string v = env_or("CA_CAPTCHA_HOST", env_or("CAPTCHA_HOST"));
|
||||
if (!v.empty()) _CAPTCHA_HOST = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_CAPTCHA_PORT", env_int_or("CAPTCHA_PORT", -1));
|
||||
if (v > 0) _CAPTCHA_PORT = v;
|
||||
}
|
||||
{
|
||||
std::string v = env_or("CA_SMTP_HOST", env_or("SMTP_HOST"));
|
||||
if (!v.empty()) _SMTP_HOST = v;
|
||||
}
|
||||
{
|
||||
int v = env_int_or("CA_SMTP_PORT", env_int_or("SMTP_PORT", -1));
|
||||
if (v > 0) _SMTP_PORT = v;
|
||||
}
|
||||
|
||||
std::string env_upstream = ConfIni::env("UPSTREAM_GATEWAY");
|
||||
if (!env_upstream.empty()) _UPSTREAM_GATEWAY = env_upstream;
|
||||
/* WS 代理路由 env:/path=ws://host:port/target;...(解析逻辑与 CLI 共用) */
|
||||
std::string ws_cfg = env_or("CA_WS_PROXY_ROUTES");
|
||||
|
||||
std::string env_db_host = ConfIni::env("DB_HOST");
|
||||
if (!env_db_host.empty()) _DB_HOST = env_db_host;
|
||||
int env_db_port = ConfIni::env_int("DB_PORT", -1);
|
||||
if (env_db_port > 0) _DB_PORT = env_db_port;
|
||||
|
||||
std::string env_captcha_host = ConfIni::env("CAPTCHA_HOST");
|
||||
if (!env_captcha_host.empty()) _CAPTCHA_HOST = env_captcha_host;
|
||||
int env_captcha_port = ConfIni::env_int("CAPTCHA_PORT", -1);
|
||||
if (env_captcha_port > 0) _CAPTCHA_PORT = env_captcha_port;
|
||||
|
||||
std::string env_smtp_host = ConfIni::env("SMTP_HOST");
|
||||
if (!env_smtp_host.empty()) _SMTP_HOST = env_smtp_host;
|
||||
int env_smtp_port = ConfIni::env_int("SMTP_PORT", -1);
|
||||
if (env_smtp_port > 0) _SMTP_PORT = env_smtp_port;
|
||||
|
||||
/* 4. CLI 参数覆盖(最高优先级) */
|
||||
if (vm.count("host")) _ADDR = vm["host"].as<std::string>();
|
||||
if (vm.count("port")) _PORT = vm["port"].as<int>();
|
||||
if (vm.count("instance")) _INSTANCE = vm["instance"].as<std::string>();
|
||||
/* 2. CLI 参数覆盖(最高优先级) */
|
||||
if (vm.count("host")) _ADDR = vm["host"].as<std::string>();
|
||||
if (vm.count("port")) _PORT = vm["port"].as<int>();
|
||||
if (vm.count("tls")) _TLS = true;
|
||||
if (vm.count("upstream-gateway")) _UPSTREAM_GATEWAY = vm["upstream-gateway"].as<std::string>();
|
||||
if (vm.count("token-keep-time")) _TOKEN_KEEP_TIME = vm["token-keep-time"].as<int>();
|
||||
if (vm.count("token-refresh-grace-multiplier")) _TOKEN_REFRESH_GRACE_MULTIPLIER = vm["token-refresh-grace-multiplier"].as<int>();
|
||||
if (vm.count("token-max-refresh")) _TOKEN_MAX_REFRESH = vm["token-max-refresh"].as<int>();
|
||||
if (vm.count("cors-origins")) _CORS_ORIGINS = split(vm["cors-origins"].as<std::string>(), ';');
|
||||
if (vm.count("admin-users")) _ADMIN_USERS = split(vm["admin-users"].as<std::string>(), ';');
|
||||
if (vm.count("ws-proxy-routes")) ws_cfg = vm["ws-proxy-routes"].as<std::string>();
|
||||
if (vm.count("db-host")) _DB_HOST = vm["db-host"].as<std::string>();
|
||||
if (vm.count("db-port")) _DB_PORT = vm["db-port"].as<int>();
|
||||
if (vm.count("captcha-host")) _CAPTCHA_HOST = vm["captcha-host"].as<std::string>();
|
||||
if (vm.count("captcha-port")) _CAPTCHA_PORT = vm["captcha-port"].as<int>();
|
||||
if (vm.count("smtp-host")) _SMTP_HOST = vm["smtp-host"].as<std::string>();
|
||||
if (vm.count("smtp-port")) _SMTP_PORT = vm["smtp-port"].as<int>();
|
||||
if (vm.count("instance")) _INSTANCE = vm["instance"].as<std::string>();
|
||||
if (vm.count("log-level")) {
|
||||
_LOG_LEVEL = vm["log-level"].as<std::string>();
|
||||
// 归一化 warning → warn
|
||||
@@ -952,18 +950,38 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 5. 配置完整性校验 */
|
||||
if (_ADDR.empty() || _PORT == -1) {
|
||||
std::cerr << "[ca] 致命错误: 配置项 [Server] address/port 缺失"
|
||||
"(ini 中未配置且无 LISTEN_ADDR/LISTEN_PORT 环境变量覆盖)" << std::endl;
|
||||
/* WS 代理路由解析:/path=ws://host:port/target;... */
|
||||
if (!ws_cfg.empty()) {
|
||||
auto entries = split(ws_cfg, ';');
|
||||
for (auto& entry : entries) {
|
||||
auto eq = entry.find('=');
|
||||
if (eq != std::string::npos) {
|
||||
std::string path = entry.substr(0, eq);
|
||||
std::string url = entry.substr(eq + 1);
|
||||
auto trim = [](std::string& s) {
|
||||
while (!s.empty() && std::isspace((unsigned char)s.front())) s.erase(s.begin());
|
||||
while (!s.empty() && std::isspace((unsigned char)s.back())) s.pop_back();
|
||||
};
|
||||
trim(path); trim(url);
|
||||
if (!path.empty() && !url.empty()) {
|
||||
_WS_PROXY_ROUTES[path] = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. 配置完整性校验 */
|
||||
if (_ADDR.empty() || _PORT <= 0) {
|
||||
std::cerr << "[ca] 致命错误: 监听地址/端口非法"
|
||||
"(--host/--port 或 CA_HOST/CA_PORT 环境变量)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (_UPSTREAM_GATEWAY.empty()) {
|
||||
std::cerr << "[ca] 致命错误: 配置项 [Upstream] gateway 缺失" << std::endl;
|
||||
std::cerr << "[ca] 致命错误: 上游 gateway 地址缺失(--upstream-gateway)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (_DB_HOST.empty() || _DB_PORT <= 0) {
|
||||
std::cerr << "[ca] 致命错误: 配置项 [Downstream] db_host/db_port 缺失" << std::endl;
|
||||
std::cerr << "[ca] 致命错误: db 服务地址缺失(--db-host/--db-port)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user