- 移除 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
进程机器(PMC · core)
进程托管服务 / 微服务编排中枢 · 可执行
nidus.out· systemd 服务Nidus版本:core v0.1.0(内嵌 confs 合并版)
pmc 是一个什么项目?
PMC(Process Machine,进程机器)是一个可以创建、管理子进程以及模块的进程托管程序。你可以在它的托管下运行独立的业务模块,由 PMC 负责拉起与守护。它是整个 UniServe Framework 的进程编排中枢——读取 services.yaml 声明式配置,顺序拉起并托管全部业务子进程(fsys / dnfs2 / db2 / ca / gateway / waf / captcha2 / smtp / ai_review / aibox / redirect80),并提供本地 HTTP 管理接口与内嵌配置服务。
崩溃守护由 systemd(Nidus.service)负责,PMC 自身不含自动重启子进程逻辑。
为什么要做这个项目?
2024 年,作者想做一个树莓派机器人,准备用 Python 写控制程序,但当时 Python 的多线程能力较弱,于是想到使用子进程(子系统)来分担工作,自己动手写了一个进程托管程序。后来演进为整套轻量级微服务架构的底座。
模块文件结构
core/
├── Makefile # 构建 / 安装(VERSION=0.1.0, APP_NAME=nidus)
├── services.yaml # 声明式服务启动配置(name/cmd/args/env/depends_on/sleep_before)
├── Nidus.service # systemd 单元(User=root, ExecStart=_run.sh)
├── _run.sh # 启动:nidus.out -i . --serve 5200 --confs 8010
├── _set.sh # 构建 + 创建 configs 符号链接 + make install
├── src/
│ ├── main.cpp # 入口:双模式 + 信号 + taskPool 生命周期
│ ├── main/
│ │ ├── PPool.cpp # 子进程池
│ │ ├── ProcessTask.cpp # boost.process 子进程封装
│ │ ├── pmc_mtd.cpp # list / kill / exec / parse_self_init_list
│ │ ├── subsys_call.cpp # 跨机子系统调用(MQ 发令 + Pipe 回传)
│ │ ├── Tttask.cpp # 消息队列通信任务
│ │ ├── HttpTask.cpp # 管理 HTTP 接口(:5200)
│ │ └── ConfsTask.cpp # 内嵌配置服务(:8010)
│ └── registry/
│ └── InitParser.cpp # services.yaml 解析器
└── include/
├── main/*.hh # PPool / ProcessTask / pmc_mtd / subsys_call / Tttask / HttpTask / ConfsTask
├── registry/InitParser.hh # services.yaml 解析器
├── tt/Pipe.h # IPC:命名管道(FIFO)
├── tt/Mq.h # IPC:消息队列
├── logs/Logger.hpp # 单例日志
└── cn/*.hpp # 中文化编程宏
注:早期 README 提到的
users/、extra/子模块目录已不再使用,模块托管统一改为通过services.yaml配置拉起各业务服务。
如何托管外部模块
编辑 services.yaml,在 services 列表中声明每个服务的 name、cmd、args、env、depends_on、sleep_before 等字段。PMC 启动时按声明顺序逐个拉起(先 clr() 清理已退出进程,再 crtp() 创建)。启动顺序很重要(redirect80 → waf → ca → gateway …)。
运行模式与命令行
PMC 支持两种工作模式:
- 命令行子系统调用(一次性,非服务模式):
--send <mq> --exec <cmd>:向目标 PMC 的消息队列发启动命令并取回结果--send <mq> --list:列出目标 PMC 运行的进程--send <mq> --kill <pid>:杀死目标 PMC 的某个进程
- HTTP 服务模式:
--serve <port>启动本地管理接口(默认127.0.0.1:5200,纯 HTTP,因 WAF 已终止 TLS)。
此外:
-i <dir/file>/--init:指定自启动配置(目录路径自动查找services.yaml,或直接指定.yaml文件)--confs <port>:启用内嵌 confs 配置服务(默认127.0.0.1:8010)-h/--help:打印帮助与 API MAP(/list/exec/kill路由)-v/--version:打印版本号
实际启动命令(_run.sh):
./nidus.out -i . --serve 5200 --confs 8010
生命周期:注册 SIGINT/SIGTERM → signalHandler 唤醒条件变量 cv → 主线程 cv.Wait() 返回后遍历 taskPool 调用 stop() 优雅退出。
架构:任务池模型
PMC 把所有常驻能力抽象为 ITask,用 libth 的 Thread(带 stop/wake/loop/clear 回调状态机)封装,统一加入 taskPool:
Tttask(tt/消息队列通信服务):以进程 pid 为名创建 boost.interprocess 消息队列,循环recv指令,回调parse_data_from_mq。HttpTask(HttpTask.cpp):在127.0.0.1:port起pmc::net::HttpServer(纯 HTTP,无 TLS),注册/list/exec/kill。ConfsTask(ConfsTask.cpp):起pmc::net::RpcServer(pymsg),提供配置分发。
三者并列由主线程启停。
架构:进程托管核心
PPool(PPool.hh/.cpp):std::list<std::shared_ptr<ProcessTask>>,接口crtp()(create process)/clr()(清理已退出)/kill(idx)/operator[]。注意 kill/list 用容器内下标而非 pid,代码内有 FIXME 标注不自然。ProcessTask(ProcessTask.hh/.cpp):boost::process::child封装,start()直接make_unique<child>(cmd),stop()调terminate()。当前编译走非__NEW_VER(boost.process v1)分支。pmc_mtd命名空间(pmc_mtd.cpp):list()→ 序列化所有子进程{index, pid, running, command}。kill(pid)→ 按 pid 遍历ppool匹配后kill(i)。exec(cmd)→ppool.crtp(cmd)。parse_self_init_list(path)→ 经InitParser解析services.yaml,按声明顺序clr()+crtp()拉起,支持sleep_before延时与env环境变量注入。
架构:进程间通信层(include/tt/)
跨进程 / 跨机的进程管理采用「消息队列发令 + 命名管道回传」:
Mq(tt/Mq.h):boost::interprocess::message_queue,名字/<name>,容量 2048×100。发送端send(json),接收端try_receive。Pipe(tt/Pipe.h):FIFO 命名管道,路径/tmp/pst-<pid>,CREATOR负责mkfifo/unlink。openForRead(nonblock)+select超时 +readPipe。
指令 JSON:{"pipe": "<回传管道名>", "type": "list"|"kill"|"exec", ...}。
- 服务端:
parse_data_from_mq()收到 JSON → 按type调pmc_mtd::list/kill/exec→ 经Pipe写回结果。 - 客户端:
subsys_call(subsys_call.cpp):send_*_and_recv_pipe(target, ...)先建Mq(target)发令,再开Pipe等回传(1 秒超时,失败返回"ERR")。 HttpTask的listProcesses/execCommand/killProcess在target非空时走subsys_call转发到目标机器 PMC,为空则本机pmc_mtd。
架构:HTTP 管理接口
- 仅监听
127.0.0.1:5200,纯 HTTP(WAF 已终止 TLS,无证书)。 - 三个 POST 路由:
/list/exec/kill,返回{"success", "message", "data"}。 - 管理员鉴权(
verify_admin_token):每个操作都先调gateway /admin/verify(gateway 是 Token 签发/验签唯一权威,RSA 验签 + is_admin + 过期检查),Authorization头优先、回退q4_tokenCookie;gateway 地址由GATEWAY_HOST/GATEWAY_PORT配置(默认127.0.0.1:8443)。gateway 不可用或异常一律fail-closed返回 401。 - 命令执行(
exec)与 pid 解析同时支持 query 参数与 JSON body。
内嵌 confs 配置服务(v0.1.0 起)
core 内置了统一配置服务(由 confs2 合并而来,pymsg RPC 协议,与 Python confs 完全兼容):
./nidus.out -i . --serve 5200 --confs 8010
--confs <port>:启用内嵌 confs 配置服务(get/list/reload/health 四个路由)- 不传
--confs时行为与原版完全一致 - 配置文件目录默认为
./configs(_set.sh会创建指向../confs/configs的符号链接) - 环境变量:
CONFS_ADDR/CONFS_PORT/CONFS_WORKERS/CONFS_DIR
ConfsTask(ConfsTask.cpp)由 confs2 移植,业务逻辑逐项对齐:
ConfigStore:线程安全(mutex),内存缓存 +mtime变化自动重载;get()在锁内 canonical 解析 + 前缀校验 + 存在性检查(无 TOCTOU);扩展名白名单(.ini/.conf/.cfg/.json/.yaml/.yml/.toml/.txt)+ 1 MiB 上限防路径遍历/DoS。- 路由:
get:取全文;带key时 INI 用Section.option取值(Section 大小写敏感、Option 不敏感)、JSON 用点路径取值。list:列目录全部配置元信息(name/size/mtime/cached)。reload:指定 name 重载,或省略 name 清空全部缓存。health:status/config_dir/cached/uptime。
ConfsLogC(ConfsLogC.hpp):基于libmsg::AsyncQueue,50 条/2 秒攒批异步写db:8005的Logs表,DB_HOST/DB_PORT可配(默认 127.0.0.1:8005),fail-safe 静默丢弃;含日志注入防护(sanitize_for_log过滤控制字符)。
支撑组件
Logger(logs/Logger.hpp):单例,控制台输出,支持 DEBUG/INFO/WARNING/ERROR/CRITICAL 级别(注释标注为 DeepSeek 创作,TODO 改为文件存储)。include/cn/:中文化编程宏(中文化.hpp等),提供 C++ 关键字中文别名。- 依赖库(Makefile):
libthlibhttp/libhttpclientlibmsgliblogclibcurl+ boost(program_options/json/thread/filesystem)+yaml-cpp+ssl/crypto/pthread。
PMC 的安装方式
# 1. 安装依赖
# 安装 UniServe 的 libth 包
git clone https://github.com/gopsc/UniServe_libth
cd UniServe_libth
sudo bash _set.sh
# 安装别的依赖
sudo apt update
sudo apt install git g++ make
sudo apt install libboost-all-dev
sudo apt install libyaml-cpp-dev
#sudo apt install libssl-dev
#sudo apt install libcurl4-openssl-dev
#sudo apt install libcurl4-gnutls-dev
# 2. 构建并安装 core
git clone https://github.com/gopsc/UniServe_core
cd UniServe_core
make # 等价于 make clear && make
sudo make install # 装入 /usr/local/bin/nidus + systemd
make install会把services.yaml拷到/etc/Nidus/、Nidus.service拷到/etc/systemd/system,并daemon-reload+enable+restart。
本仓库内的快捷方式:
bash core/_set.sh # make clear && make + 建 configs 符号链接 + make install
bash core/_run.sh # 直接 ./nidus.out -i . --serve 5200 --confs 8010
加密通信机制(废弃)
PMC 在启动时生成一个 AES 密钥,然后用一个 RSA 公钥将其加密发送给访问者,之后访问者与客户端之间的交流全部用此 AES 密钥加密。 该机制已废弃,当前管理接口与子系统调用改用 gateway 的 Token 验签(见「HTTP 管理接口」与「进程间通信层」章节)。
如何使用并发机器运行程序
首先应该在模块中创建一个启动脚本,脚本中应该完成工作目录的切换、虚拟环境的激活,以及程序的启动。在 services.yaml 中声明该脚本后,PMC 会按声明顺序执行这些启动脚本,从而把多个业务模块拉起并纳入托管。
已知待办与风险
- 无子进程自动重启:PMC 崩溃守护靠 systemd;单个业务进程退出后 PMC 不会拉起它(仅保留在
ppool中标记非运行)。 PPool用下标而非 pid 索引:kill(idx)语义不自然,FIXME 仍在。- 内存泄漏 TODO:
HttpTask/ConfsTask的start()获取资源后未确认释放(代码注释标注)。 /tmp/pst-*FIFO 残留:subsys_call异常路径可能留下管道文件。- 管理接口强依赖 gateway:
/admin/verify不可用时所有管理操作 fail-closed 拒绝(安全优先,但运维注意 gateway 必须在线)。 exec命令注入面:pmc_mtd::exec直接boost::process::child(cmd)以 shell 执行,仅在已通过管理员鉴权后可用——务必保证鉴权不被绕过。
上手要点
- 调整自启动服务/顺序:编辑
services.yaml(在services列表中增删条目,调整声明顺序)。 - 管理接口调用:必须携带 admin token(经 gateway 签发),例如带
Authorization: Bearer <token>或q4_tokenCookie 访问:5200。 - 构建:
core/_set.sh(会先创建configs → ../confs/configs符号链接,保证内嵌 confs 零迁移);make clear && make后make install装入 systemd。