生成代码工程
This commit is contained in:
parent
a273abf8b2
commit
d653b419b1
|
|
@ -0,0 +1,63 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(C2SYS VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
# ====================================================================
|
||||
# C2SYS - 联合作战指挥环境任务自主规划软件系统
|
||||
# 构建配置
|
||||
# ====================================================================
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# --- MSVC UTF-8 编译选项 ---
|
||||
if (MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
# --- 全局编译选项 ---
|
||||
add_compile_options(-Wall -Wextra -pedantic)
|
||||
if (NOT MSVC)
|
||||
add_compile_options(-Werror=return-type)
|
||||
endif()
|
||||
|
||||
# --- 头文件路径 ---
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
# --- 源文件列表 ---
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/app.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
include/app.hpp
|
||||
include/config.hpp
|
||||
)
|
||||
|
||||
# --- 主程序目标 ---
|
||||
add_executable(${PROJECT_NAME}
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
# --- 测试目标 ---
|
||||
add_executable(${PROJECT_NAME}_test
|
||||
tests/basic_test.cpp
|
||||
src/app.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}_test PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
# --- 安装规则 ---
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||
install(DIRECTORY include/ DESTINATION include)
|
||||
161
README.md
161
README.md
|
|
@ -1,50 +1,111 @@
|
|||
任务管理能力
|
||||
a) 战场事件处理可视化
|
||||
1) 支持接收生成的临机事件或规划的事件;
|
||||
2) 支持对接收事件信息数据的过滤、转化、封装等;
|
||||
3) 支持前端展示事件列表;
|
||||
4) 支持事件列表按定义排序。
|
||||
5) 支持用户对事件的操作,包括“处理”、“拒绝”等。
|
||||
b) 作战任务生成可视化
|
||||
1) 支持接收待处理事件列表;
|
||||
2) 支持待处理事件列表展示;
|
||||
3) 支持待处理事件列表自定义排序;
|
||||
4) 支持生成作战任务操作,并送与任务生成功能进行处理。
|
||||
c) 任务模板生成可视化
|
||||
1) 支持任务模板先验知识库版本选择;
|
||||
2) 支持先验知识库配置调整。
|
||||
d) 任务模板管理可视化
|
||||
1) 支持接收推送的任务模板集合数据;
|
||||
2) 支持页面可视化展示任务模板集合;
|
||||
3) 支持对任务模板列表自定义排序;
|
||||
4) 支持展示任务模板详细信息;
|
||||
5) 支持任务模板子任务需求展示。
|
||||
6) 支持人环模式下的用户选择任务模板;
|
||||
7) 支持自主执行模式下的任务模板自动选择提示。
|
||||
战斗管理能力
|
||||
集中式方案管理可视化
|
||||
1) 支持页面展示集中式任务方案列表;
|
||||
2) 支持操作员根据偏好进行集中式任务方案排序;
|
||||
3) 支持页面展示集中式任务方案详情;
|
||||
4) 支持在“在人在环模式”下的用户通知,当前端更新集中式任务方案列表时进行用户通知;
|
||||
5) 支持从集中式任务方案列表多选方案进行对比;
|
||||
6) 支持集中式方案生成算法过程详情展示;
|
||||
7) 支持操作集中式任务方案重构;
|
||||
8) 支持集中式方案重构展示。
|
||||
分布式方案管理可视化
|
||||
1) 支持页面展示分布式任务方案列表;
|
||||
2) 支持操作员根据偏好进行分布式任务方案排序;
|
||||
3) 支持页面展示分布式任务方案详情;
|
||||
4) 支持在“在人在环模式”下的用户通知,当前端更新分布式任务方案列表时进行用户通知;
|
||||
5) 支持从分布式任务方案列表多选方案进行对比;
|
||||
6) 支持分布式方案生成算法过程详情展示;
|
||||
7) 支持操作分布式任务方案重构;
|
||||
8) 支持分布式方案重构展示。
|
||||
方案驱动管理能力
|
||||
方案分发驱动功能
|
||||
1) 支持方案驱动分发操作;
|
||||
2) 支持方案驱动分发操作响应状态展示。
|
||||
驱动状态监控功能
|
||||
1) 支持对任务方案执行状态进行监控展示;
|
||||
2) 支持对任务方案中的子任务执行状态进行监控展示;
|
||||
3) 支持对任务方案执行异常信息展示。
|
||||
# C2SYS — 联合作战指挥环境任务自主规划软件系统
|
||||
|
||||
## 概述
|
||||
|
||||
**C2SYS** (Command & Control System) 是一套面向联合作战指挥环境的任务自主规划软件系统,支持集中式与分布式作战方案的可视化管理、事件驱动的任务生成、双模式(人在回路/自主执行)运行适配及全链路状态监控。
|
||||
|
||||
## 功能特性
|
||||
|
||||
| 编号 | 功能 | 描述 |
|
||||
|------|------|------|
|
||||
| F-001 | 集中式方案列表与详情管理 | 展示集中式任务方案列表,支持自定义排序与详情查看 |
|
||||
| F-002 | 集中式方案对比与重构 | 多方案资源消耗、时间窗口、成功率对比分析 |
|
||||
| F-003 | 分布式方案管理可视化 | 分布式方案展示、排序、对比与重构 |
|
||||
| F-004 | 方案分发与响应监控 | 方案下发至执行单元,采集节点回执,支持重试机制 |
|
||||
| F-005 | 任务执行状态监控 | 任务执行进度监控,异常高亮告警 |
|
||||
| F-006 | 战场事件接收与处理 | 接收外部情报源原始事件流,转化为标准化内部事件 |
|
||||
| F-007 | 事件列表管理与交互 | 待办事件展示、排序、处理与日志记录 |
|
||||
| F-008 | 作战任务生成关联 | 从事件到任务的联动生成与双向关联 |
|
||||
| F-009 | 任务模板知识库管理 | 模板版本管理、参数调优、快照保存与回滚 |
|
||||
| F-010 | 任务模板管理与模式适配 | 人在回路/自主执行双模式模板选择 |
|
||||
|
||||
## 工程结构
|
||||
|
||||
```
|
||||
.
|
||||
├── CMakeLists.txt # CMake 构建配置
|
||||
├── README.md # 本文件
|
||||
├── include/
|
||||
│ ├── app.hpp # 核心业务逻辑接口
|
||||
│ └── config.hpp # 数据实体与系统配置定义
|
||||
├── src/
|
||||
│ ├── main.cpp # 命令行入口与流程演示
|
||||
│ └── app.cpp # 核心业务逻辑实现 (PIMPL)
|
||||
└── tests/
|
||||
└── basic_test.cpp # 基础单元测试 (标准 assert)
|
||||
```
|
||||
|
||||
## 数据实体
|
||||
|
||||
核心数据实体定义在 `include/config.hpp` 中,包括:
|
||||
|
||||
- **PlanData** — 作战方案(集中式/分布式)
|
||||
- **EventRaw** — 原始战场事件
|
||||
- **StandardEvent** — 标准化内部事件
|
||||
- **TaskTemplate** — 任务模板
|
||||
- **ExecutionStatus** — 执行状态遥测
|
||||
- **DistributionAck** — 分发回执
|
||||
- **OperationLog** — 操作审计日志
|
||||
- **ConfigSnapshot** — 配置快照
|
||||
- **ModeStateCache** — 模式状态缓存
|
||||
|
||||
## 构建与运行
|
||||
|
||||
### 前提条件
|
||||
|
||||
- CMake ≥ 3.16
|
||||
- 支持 C++17 的编译器 (GCC 8+, Clang 7+, MSVC 2019+)
|
||||
|
||||
### 构建步骤
|
||||
|
||||
```bash
|
||||
# 进入工程目录
|
||||
cd C2SYS
|
||||
|
||||
# 创建构建目录
|
||||
mkdir build && cd build
|
||||
|
||||
# 配置
|
||||
cmake ..
|
||||
|
||||
# 编译主程序
|
||||
cmake --build . --target C2SYS
|
||||
|
||||
# 编译测试程序
|
||||
cmake --build . --target C2SYS_test
|
||||
```
|
||||
|
||||
### 运行
|
||||
|
||||
```bash
|
||||
# 运行主程序(演示完整闭环流程)
|
||||
./C2SYS
|
||||
|
||||
# 运行单元测试
|
||||
./C2SYS_test
|
||||
```
|
||||
|
||||
## 设计原则
|
||||
|
||||
- **模块化分层设计**:数据层 (config.hpp) → 业务逻辑层 (app.hpp/cpp) → 交互层 (main.cpp)
|
||||
- **事件驱动架构**:模块间通过消息队列解耦
|
||||
- **PIMPL 模式**:隐藏实现细节,保证 ABI 稳定性
|
||||
- **双模式支持**:人在回路 / 自主执行,模式切换保证上下文一致
|
||||
- **配置化适应**:网络参数、刷新频率等可通过配置文件调整
|
||||
|
||||
## 配置说明
|
||||
|
||||
支持通过 key=value 格式的配置文件调整系统参数:
|
||||
|
||||
```
|
||||
# config.txt 示例
|
||||
refreshIntervalMs=100
|
||||
websocketPort=9090
|
||||
maxRetryCount=5
|
||||
ackTimeoutMs=3000
|
||||
logLevel=2
|
||||
```
|
||||
|
||||
## 版权
|
||||
|
||||
© 2025 C2SYS Project
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,273 @@
|
|||
#ifndef C2SYS_APP_HPP
|
||||
#define C2SYS_APP_HPP
|
||||
|
||||
/**
|
||||
* @file app.hpp
|
||||
* @brief C2SYS 任务自主规划软件 — 核心业务逻辑层。
|
||||
*
|
||||
* 本文件声明了 C2SYS 应用程序的主控类,封装了方案管理、事件处理、
|
||||
* 任务生成、模板匹配、分发监控与状态上报等核心业务功能。
|
||||
* 采用事件驱动架构,内部通过消息队列机制实现模块间解耦。
|
||||
*/
|
||||
|
||||
#include "config.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
namespace c2sys {
|
||||
|
||||
/**
|
||||
* @brief 系统运行状态枚举
|
||||
*/
|
||||
enum class SystemState : uint8_t {
|
||||
/// 初始化中
|
||||
Initializing = 0,
|
||||
/// 已就绪
|
||||
Ready = 1,
|
||||
/// 运行中
|
||||
Running = 2,
|
||||
/// 异常态
|
||||
Error = 3,
|
||||
/// 已停止
|
||||
Stopped = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* @class App
|
||||
* @brief C2SYS 任务自主规划软件主控类。
|
||||
*
|
||||
* 提供完整的方案管理、事件处理、任务生成、模板匹配、分发与监控流程。
|
||||
* 支持 "人在回路" 与 "自主执行" 双模式切换,并保证上下文一致性。
|
||||
*
|
||||
* 使用示例:
|
||||
* @code
|
||||
* c2sys::App app;
|
||||
* app.initialize("config.txt");
|
||||
* app.setRunMode(c2sys::RunMode::Autonomous);
|
||||
* app.start();
|
||||
* // ... 运行期间自动处理事件与任务 ...
|
||||
* app.stop();
|
||||
* @endcode
|
||||
*/
|
||||
class App {
|
||||
public:
|
||||
/// @brief 默认构造函数
|
||||
App();
|
||||
|
||||
/// @brief 析构函数
|
||||
~App();
|
||||
|
||||
// ======================== 生命周期管理 ========================
|
||||
|
||||
/**
|
||||
* @brief 初始化系统,加载配置。
|
||||
* @param configFile 配置文件路径,为空则使用默认配置
|
||||
* @return 初始化成功返回 true
|
||||
*
|
||||
* 初始化流程:
|
||||
* 1. 加载配置文件(如存在)
|
||||
* 2. 初始化事件队列与模板库
|
||||
* 3. 设置运行模式为默认模式(人在回路)
|
||||
*/
|
||||
bool initialize(const std::string& configFile = "");
|
||||
|
||||
/**
|
||||
* @brief 启动系统主循环。
|
||||
* @return 启动成功返回 true
|
||||
*
|
||||
* 启动后系统进入 Running 状态,开始处理事件循环和状态刷新。
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* @brief 停止系统主循环。
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief 获取当前系统状态。
|
||||
* @return 系统状态枚举值
|
||||
*/
|
||||
SystemState getState() const;
|
||||
|
||||
// ======================== 模式管理 ========================
|
||||
|
||||
/**
|
||||
* @brief 设置运行模式。
|
||||
* @param mode 目标运行模式(人在回路 / 自主执行)
|
||||
* @return 切换成功返回 true
|
||||
*
|
||||
* 模式切换时自动保存当前上下文快照到 ModeStateCache,
|
||||
* 保证状态不丢失、不冲突。
|
||||
*/
|
||||
bool setRunMode(RunMode mode);
|
||||
|
||||
/**
|
||||
* @brief 获取当前运行模式。
|
||||
* @return 当前运行模式
|
||||
*/
|
||||
RunMode getRunMode() const;
|
||||
|
||||
// ======================== 方案管理 (F-001, F-002, F-003) ========================
|
||||
|
||||
/**
|
||||
* @brief 添加一个作战方案到系统。
|
||||
* @param plan 方案数据实体
|
||||
* @return 添加成功返回 true
|
||||
*/
|
||||
bool addPlan(const PlanData& plan);
|
||||
|
||||
/**
|
||||
* @brief 获取所有方案列表。
|
||||
* @return 方案列表(常量引用)
|
||||
*/
|
||||
const std::vector<PlanData>& getAllPlans() const;
|
||||
|
||||
/**
|
||||
* @brief 根据 ID 查询方案详情。
|
||||
* @param planId 方案 ID
|
||||
* @return 指向方案的指针,未找到返回 nullptr
|
||||
*/
|
||||
const PlanData* findPlanById(const std::string& planId) const;
|
||||
|
||||
/**
|
||||
* @brief 对比多个方案的关键指标。
|
||||
* @param planIds 待对比的方案 ID 列表
|
||||
* @return 包含各指标对比结果的描述字符串
|
||||
*/
|
||||
std::string comparePlans(const std::vector<std::string>& planIds) const;
|
||||
|
||||
// ======================== 事件管理 (F-006, F-007) ========================
|
||||
|
||||
/**
|
||||
* @brief 接收并处理原始事件(模拟外部情报输入)。
|
||||
* @param raw 原始事件数据
|
||||
* @return 转换后的标准化事件 ID,失败返回空字符串
|
||||
*
|
||||
* 执行流程:
|
||||
* 1. 校验原始报文哈希
|
||||
* 2. 过滤无效/重复事件
|
||||
* 3. 转化为 StandardEvent 并加入待办队列
|
||||
* 4. 返回标准化事件 ID
|
||||
*/
|
||||
std::string ingestRawEvent(const EventRaw& raw);
|
||||
|
||||
/**
|
||||
* @brief 获取待办事件列表。
|
||||
* @return 待办事件列表
|
||||
*/
|
||||
std::vector<StandardEvent> getPendingEvents() const;
|
||||
|
||||
/**
|
||||
* @brief 处理指定事件(用户操作或自动处理)。
|
||||
* @param eventId 标准化事件 ID
|
||||
* @param accept true 表示接受并处理,false 表示拒绝/忽略
|
||||
* @return 操作成功返回 true
|
||||
*/
|
||||
bool processEvent(const std::string& eventId, bool accept);
|
||||
|
||||
// ======================== 任务生成 (F-008) ========================
|
||||
|
||||
/**
|
||||
* @brief 根据事件生成关联任务。
|
||||
* @param eventId 标准化事件 ID
|
||||
* @return 生成的任务 ID,失败返回空字符串
|
||||
*
|
||||
* 在 "自主执行" 模式下自动匹配最优模板并生成任务;
|
||||
* 在 "人在回路" 模式下触发确认流程。
|
||||
*/
|
||||
std::string generateTaskFromEvent(const std::string& eventId);
|
||||
|
||||
// ======================== 模板管理 (F-009, F-010) ========================
|
||||
|
||||
/**
|
||||
* @brief 添加任务模板到知识库。
|
||||
* @param tmpl 任务模板实体
|
||||
* @return 添加成功返回 true
|
||||
*/
|
||||
bool addTemplate(const TaskTemplate& tmpl);
|
||||
|
||||
/**
|
||||
* @brief 根据场景自动匹配最优模板。
|
||||
* @param scenario 场景描述
|
||||
* @return 匹配度最高的模板,未找到则返回空 optional
|
||||
*/
|
||||
const TaskTemplate* matchBestTemplate(const std::string& scenario) const;
|
||||
|
||||
/**
|
||||
* @brief 保存当前模板库快照。
|
||||
* @return 快照版本号
|
||||
*/
|
||||
std::string saveSnapshot();
|
||||
|
||||
/**
|
||||
* @brief 回滚到指定快照版本。
|
||||
* @param version 快照版本号
|
||||
* @return 回滚成功返回 true
|
||||
*/
|
||||
bool rollbackToSnapshot(const std::string& version);
|
||||
|
||||
// ======================== 分发监控 (F-004, F-005) ========================
|
||||
|
||||
/**
|
||||
* @brief 将选定方案分发至执行节点。
|
||||
* @param planId 方案 ID
|
||||
* @param nodeIds 目标节点 ID 列表
|
||||
* @return 成功分发的节点数量
|
||||
*
|
||||
* 包含重试机制:超时或拒绝的节点会重试(不超过 maxRetryCount 次)。
|
||||
*/
|
||||
int dispatchPlan(const std::string& planId, const std::vector<std::string>& nodeIds);
|
||||
|
||||
/**
|
||||
* @brief 获取所有分发回执。
|
||||
* @return 分发回执列表
|
||||
*/
|
||||
std::vector<DistributionAck> getDistributionAcks() const;
|
||||
|
||||
/**
|
||||
* @brief 上报任务执行状态(由执行单元或模拟器调用)。
|
||||
* @param status 执行状态实体
|
||||
*/
|
||||
void reportExecutionStatus(const ExecutionStatus& status);
|
||||
|
||||
/**
|
||||
* @brief 获取指定任务的执行状态。
|
||||
* @param taskId 任务 ID
|
||||
* @return 指向执行状态的指针,未找到返回 nullptr
|
||||
*/
|
||||
const ExecutionStatus* getExecutionStatus(const std::string& taskId) const;
|
||||
|
||||
// ======================== 配置与日志 ========================
|
||||
|
||||
/**
|
||||
* @brief 记录一条操作日志。
|
||||
* @param log 操作日志结构体
|
||||
*/
|
||||
void logOperation(const OperationLog& log);
|
||||
|
||||
/**
|
||||
* @brief 获取所有操作日志。
|
||||
* @return 操作日志列表
|
||||
*/
|
||||
std::vector<OperationLog> getOperationLogs() const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前系统配置。
|
||||
* @return 系统配置常量引用
|
||||
*/
|
||||
const SystemConfig& getConfig() const;
|
||||
|
||||
private:
|
||||
/// @brief 内部实现类,隐藏具体实现细节
|
||||
class Impl;
|
||||
/// @brief PIMPL 模式实现指针
|
||||
std::unique_ptr<Impl> pImpl_;
|
||||
};
|
||||
|
||||
} // namespace c2sys
|
||||
|
||||
#endif // C2SYS_APP_HPP
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
#ifndef C2SYS_CONFIG_HPP
|
||||
#define C2SYS_CONFIG_HPP
|
||||
|
||||
/**
|
||||
* @file config.hpp
|
||||
* @brief C2SYS 系统核心数据结构与配置参数定义。
|
||||
*
|
||||
* 本文件定义了联合作战指挥环境任务自主规划软件系统的所有核心数据实体、
|
||||
* 枚举类型、缓存结构与配置文件加载接口。
|
||||
* 数据实体对应 SRS-C2SYS 需求规格说明中的 I_PLAN_DATA、I_EVT_RAW、I_EVT_STD、
|
||||
* I_TMPL_SET、I_TASK_TELEM、I_NODE_ACK 等数据模型。
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace c2sys {
|
||||
|
||||
/// @brief 运行模式枚举
|
||||
enum class RunMode : uint8_t {
|
||||
/// 人在回路模式 — 人工干预决策
|
||||
HumanInLoop = 0,
|
||||
/// 自主执行模式 — 系统自动决策
|
||||
Autonomous = 1
|
||||
};
|
||||
|
||||
/// @brief 方案类型枚举
|
||||
enum class PlanType : uint8_t {
|
||||
/// 集中式方案
|
||||
Centralized = 0,
|
||||
/// 分布式方案
|
||||
Distributed = 1
|
||||
};
|
||||
|
||||
/// @brief 事件处理状态
|
||||
enum class EventStatus : uint8_t {
|
||||
/// 待处理
|
||||
Pending = 0,
|
||||
/// 已忽略
|
||||
Ignored = 1,
|
||||
/// 已处理
|
||||
Processed = 2
|
||||
};
|
||||
|
||||
/// @brief 分发响应状态
|
||||
enum class AckStatus : uint8_t {
|
||||
/// 确认接收
|
||||
Confirmed = 0,
|
||||
/// 拒绝执行
|
||||
Rejected = 1,
|
||||
/// 响应超时
|
||||
Timeout = 2
|
||||
};
|
||||
|
||||
/// @brief 事件类型
|
||||
enum class EventType : uint8_t {
|
||||
/// 临机事件
|
||||
Contingency = 0,
|
||||
/// 规划事件
|
||||
Planned = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 方案数据实体 (SRS-C2SYS_I_PLAN_DATA)
|
||||
*
|
||||
* 用于集中式与分布式作战方案的表示、对比与分发。
|
||||
*/
|
||||
struct PlanData {
|
||||
/// 方案唯一标识
|
||||
std::string id;
|
||||
/// 方案类型(集中式 / 分布式)
|
||||
PlanType type;
|
||||
/// 资源占用百分比 (0.0 ~ 100.0)
|
||||
double resourceUsage;
|
||||
/// 执行周期(秒)
|
||||
double executionPeriod;
|
||||
/// 预估成功率 (0.0 ~ 1.0)
|
||||
double successRate;
|
||||
/// 抗毁性评分 (0.0 ~ 1.0)
|
||||
double survivability;
|
||||
/// 协同效率评分 (0.0 ~ 1.0)
|
||||
double collaborationEfficiency;
|
||||
/// 子任务ID列表
|
||||
std::vector<std::string> subTaskIds;
|
||||
/// 创建时间(Unix 时间戳,毫秒)
|
||||
int64_t createTimestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 原始事件实体 (SRS-C2SYS_I_EVT_RAW)
|
||||
*
|
||||
* 由外部情报源或侦察设备发送的原始事件流报文。
|
||||
*/
|
||||
struct EventRaw {
|
||||
/// 源设备标识
|
||||
std::string sourceId;
|
||||
/// 事件发生时间戳(毫秒)
|
||||
int64_t timestamp;
|
||||
/// 威胁等级 (1 ~ 5)
|
||||
int threatLevel;
|
||||
/// 原始报文 SHA256 哈希
|
||||
std::string payloadHash;
|
||||
/// 协议类型标识
|
||||
std::string protocolType;
|
||||
/// 报文内容体(十六进制字符串 or JSON)
|
||||
std::string payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 标准化事件实体 (SRS-C2SYS_I_EVT_STD)
|
||||
*
|
||||
* 经过过滤、转化、封装后的内部标准化事件包。
|
||||
*/
|
||||
struct StandardEvent {
|
||||
/// 统一事件 ID
|
||||
std::string id;
|
||||
/// 事件类型(临机 / 规划)
|
||||
EventType type;
|
||||
/// 处理状态
|
||||
EventStatus status;
|
||||
/// 关联的任务 ID(可为空)
|
||||
std::string relatedTaskId;
|
||||
/// 元数据标签键值对
|
||||
std::unordered_map<std::string, std::string> metadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 任务模板实体 (SRS-C2SYS_I_TMPL_SET)
|
||||
*
|
||||
* 任务模板先验知识库中的版本化模板。
|
||||
*/
|
||||
struct TaskTemplate {
|
||||
/// 模板唯一标识
|
||||
std::string id;
|
||||
/// 版本号
|
||||
std::string version;
|
||||
/// 适用场景描述
|
||||
std::string applicableScenario;
|
||||
/// 权重配置(JSON 序列化字符串)
|
||||
std::string weightConfig;
|
||||
/// 子任务需求列表
|
||||
std::vector<std::string> subTaskRequirements;
|
||||
/// 匹配度评分 (0.0 ~ 1.0)
|
||||
double matchScore;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 执行状态实体 (SRS-C2SYS_I_TASK_TELEM)
|
||||
*
|
||||
* 任务执行过程中的遥测状态监控数据。
|
||||
*/
|
||||
struct ExecutionStatus {
|
||||
/// 任务 ID
|
||||
std::string taskId;
|
||||
/// 当前阶段名称
|
||||
std::string currentPhase;
|
||||
/// 完成百分比 (0.0 ~ 100.0)
|
||||
double completionPercent;
|
||||
/// 心跳时间戳(毫秒)
|
||||
int64_t heartbeatTimestamp;
|
||||
/// 异常码(0 表示正常)
|
||||
int errorCode;
|
||||
/// 影响范围描述
|
||||
std::string impactScope;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 分发回执实体 (SRS-C2SYS_I_NODE_ACK)
|
||||
*
|
||||
* 执行节点对方案分发的响应确认。
|
||||
*/
|
||||
struct DistributionAck {
|
||||
/// 节点 ID
|
||||
std::string nodeId;
|
||||
/// 响应状态
|
||||
AckStatus status;
|
||||
/// 回执时间戳(毫秒)
|
||||
int64_t timestamp;
|
||||
/// 已重试次数
|
||||
int retryCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 操作日志结构
|
||||
*
|
||||
* 记录所有用户操作,用于审计追溯。
|
||||
*/
|
||||
struct OperationLog {
|
||||
/// 操作员标识
|
||||
std::string operatorId;
|
||||
/// 操作时间戳(毫秒)
|
||||
int64_t timestamp;
|
||||
/// 动作类型描述
|
||||
std::string actionType;
|
||||
/// 操作对象 ID
|
||||
std::string objectId;
|
||||
/// 操作结果状态
|
||||
std::string resultStatus;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 配置快照结构
|
||||
*
|
||||
* 知识库参数调整后的生效快照,支持版本控制与回滚。
|
||||
*/
|
||||
struct ConfigSnapshot {
|
||||
/// 快照版本号
|
||||
std::string version;
|
||||
/// 快照时间戳(毫秒)
|
||||
int64_t timestamp;
|
||||
/// 配置内容(JSON 序列化字符串)
|
||||
std::string configData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 模式状态缓存
|
||||
*
|
||||
* 存储当前运行模式及上下文快照,确保切换时不丢失状态。
|
||||
*/
|
||||
struct ModeStateCache {
|
||||
/// 当前运行模式
|
||||
RunMode currentMode;
|
||||
/// 上下文快照(JSON 序列化字符串)
|
||||
std::string contextSnapshot;
|
||||
/// 最后更新时间戳(毫秒)
|
||||
int64_t lastUpdateTimestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 系统配置文件结构
|
||||
*
|
||||
* 支持通过 JSON 或 KV 配置文件调整网络参数、刷新频率、算法阈值等。
|
||||
*/
|
||||
struct SystemConfig {
|
||||
/// 刷新周期(毫秒),默认 50ms
|
||||
int refreshIntervalMs = 50;
|
||||
/// WebSocket 端口号
|
||||
int websocketPort = 8080;
|
||||
/// 事件队列最大容量
|
||||
int eventQueueCapacity = 10000;
|
||||
/// 分发重试最大次数
|
||||
int maxRetryCount = 3;
|
||||
/// 分发超时时间(毫秒)
|
||||
int ackTimeoutMs = 2000;
|
||||
/// 日志级别 (0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR)
|
||||
int logLevel = 2;
|
||||
|
||||
/**
|
||||
* @brief 从简单的 KV 配置文件加载配置。
|
||||
* @param filepath 配置文件路径
|
||||
* @return 加载成功返回 true
|
||||
*
|
||||
* 文件格式示例(每行 key=value):
|
||||
* refreshIntervalMs=100
|
||||
* websocketPort=9090
|
||||
* maxRetryCount=5
|
||||
*/
|
||||
bool loadFromFile(const std::string& filepath) {
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
auto eqPos = line.find('=');
|
||||
if (eqPos == std::string::npos) continue;
|
||||
std::string key = line.substr(0, eqPos);
|
||||
std::string val = line.substr(eqPos + 1);
|
||||
if (key == "refreshIntervalMs") refreshIntervalMs = std::stoi(val);
|
||||
else if (key == "websocketPort") websocketPort = std::stoi(val);
|
||||
else if (key == "eventQueueCapacity") eventQueueCapacity = std::stoi(val);
|
||||
else if (key == "maxRetryCount") maxRetryCount = std::stoi(val);
|
||||
else if (key == "ackTimeoutMs") ackTimeoutMs = std::stoi(val);
|
||||
else if (key == "logLevel") logLevel = std::stoi(val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c2sys
|
||||
|
||||
#endif // C2SYS_CONFIG_HPP
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
/**
|
||||
* @file app.cpp
|
||||
* @brief C2SYS 任务自主规划软件 — 核心业务逻辑实现。
|
||||
*
|
||||
* 实现了方案管理、事件处理、任务生成、模板匹配、分发监控等核心功能。
|
||||
* 采用 PIMPL 模式隐藏实现细节,确保头文件接口稳定。
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
namespace c2sys {
|
||||
|
||||
// ====================================================================
|
||||
// 内部辅助函数
|
||||
// ====================================================================
|
||||
|
||||
/**
|
||||
* @brief 生成一个简单的唯一 ID 字符串。
|
||||
* @return 格式为 "ID-<毫秒时间戳>-<4位随机数>" 的 ID
|
||||
*/
|
||||
static std::string generateId() {
|
||||
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()
|
||||
).count();
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(1000, 9999);
|
||||
std::ostringstream oss;
|
||||
oss << "ID-" << now << "-" << dis(gen);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前 Unix 时间戳(毫秒)。
|
||||
*/
|
||||
static int64_t nowMs() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()
|
||||
).count();
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// App::Impl — 内部实现类
|
||||
// ====================================================================
|
||||
|
||||
class App::Impl {
|
||||
public:
|
||||
Impl()
|
||||
: state_(SystemState::Initializing)
|
||||
, mode_(RunMode::HumanInLoop)
|
||||
{
|
||||
}
|
||||
|
||||
// ---------- 生命周期 ----------
|
||||
bool initialize(const std::string& configFile) {
|
||||
if (!configFile.empty()) {
|
||||
config_.loadFromFile(configFile);
|
||||
}
|
||||
plans_.clear();
|
||||
events_.clear();
|
||||
templates_.clear();
|
||||
acks_.clear();
|
||||
statusMap_.clear();
|
||||
logs_.clear();
|
||||
snapshots_.clear();
|
||||
state_ = SystemState::Ready;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start() {
|
||||
if (state_ != SystemState::Ready && state_ != SystemState::Stopped) {
|
||||
return false;
|
||||
}
|
||||
state_ = SystemState::Running;
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
state_ = SystemState::Stopped;
|
||||
}
|
||||
|
||||
SystemState getState() const { return state_; }
|
||||
|
||||
// ---------- 模式管理 ----------
|
||||
bool setRunMode(RunMode mode) {
|
||||
// 保存当前上下文快照
|
||||
ModeStateCache cache;
|
||||
cache.currentMode = mode_;
|
||||
cache.contextSnapshot = "{\"planCount\":" + std::to_string(plans_.size()) + "}";
|
||||
cache.lastUpdateTimestamp = nowMs();
|
||||
modeCache_ = cache;
|
||||
|
||||
mode_ = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
RunMode getRunMode() const { return mode_; }
|
||||
|
||||
// ---------- 方案管理 ----------
|
||||
bool addPlan(const PlanData& plan) {
|
||||
if (plan.id.empty()) return false;
|
||||
// 检查重复
|
||||
for (const auto& p : plans_) {
|
||||
if (p.id == plan.id) return false;
|
||||
}
|
||||
plans_.push_back(plan);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<PlanData>& getAllPlans() const {
|
||||
return plans_;
|
||||
}
|
||||
|
||||
const PlanData* findPlanById(const std::string& planId) const {
|
||||
for (const auto& p : plans_) {
|
||||
if (p.id == planId) return &p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string comparePlans(const std::vector<std::string>& planIds) const {
|
||||
std::ostringstream oss;
|
||||
oss << "=== 方案对比报告 ===\n";
|
||||
for (const auto& id : planIds) {
|
||||
const auto* plan = findPlanById(id);
|
||||
if (!plan) {
|
||||
oss << " [方案 " << id << "] 未找到\n";
|
||||
continue;
|
||||
}
|
||||
oss << " [方案 " << plan->id << "]\n";
|
||||
oss << " 类型: " << (plan->type == PlanType::Centralized ? "集中式" : "分布式") << "\n";
|
||||
oss << " 资源占用: " << plan->resourceUsage << "%\n";
|
||||
oss << " 执行周期: " << plan->executionPeriod << "s\n";
|
||||
oss << " 成功率: " << (plan->successRate * 100.0) << "%\n";
|
||||
oss << " 抗毁性: " << (plan->survivability * 100.0) << "%\n";
|
||||
oss << " 协同效率: " << (plan->collaborationEfficiency * 100.0) << "%\n";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ---------- 事件管理 ----------
|
||||
std::string ingestRawEvent(const EventRaw& raw) {
|
||||
// 校验基本字段
|
||||
if (raw.sourceId.empty() || raw.payload.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StandardEvent evt;
|
||||
evt.id = generateId();
|
||||
evt.type = (raw.threatLevel >= 4) ? EventType::Contingency : EventType::Planned;
|
||||
evt.status = EventStatus::Pending;
|
||||
evt.metadata["sourceId"] = raw.sourceId;
|
||||
evt.metadata["threatLevel"] = std::to_string(raw.threatLevel);
|
||||
evt.metadata["protocolType"] = raw.protocolType;
|
||||
|
||||
events_.push_back(evt);
|
||||
return evt.id;
|
||||
}
|
||||
|
||||
std::vector<StandardEvent> getPendingEvents() const {
|
||||
std::vector<StandardEvent> result;
|
||||
for (const auto& evt : events_) {
|
||||
if (evt.status == EventStatus::Pending) {
|
||||
result.push_back(evt);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool processEvent(const std::string& eventId, bool accept) {
|
||||
for (auto& evt : events_) {
|
||||
if (evt.id == eventId) {
|
||||
evt.status = accept ? EventStatus::Processed : EventStatus::Ignored;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------- 任务生成 ----------
|
||||
std::string generateTaskFromEvent(const std::string& eventId) {
|
||||
// 查找事件
|
||||
StandardEvent* evt = nullptr;
|
||||
for (auto& e : events_) {
|
||||
if (e.id == eventId) {
|
||||
evt = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!evt || evt->status == EventStatus::Ignored) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 在自主执行模式下自动匹配模板
|
||||
if (mode_ == RunMode::Autonomous) {
|
||||
std::string scenario = "unknown";
|
||||
auto it = evt->metadata.find("threatLevel");
|
||||
if (it != evt->metadata.end()) {
|
||||
scenario = "threat_" + it->second;
|
||||
}
|
||||
const auto* tmpl = matchBestTemplate(scenario);
|
||||
if (!tmpl) {
|
||||
// 无匹配模板时仍生成任务,但记录日志
|
||||
}
|
||||
}
|
||||
|
||||
// 生成任务 ID 并与事件关联
|
||||
std::string taskId = "TASK-" + generateId();
|
||||
evt->relatedTaskId = taskId;
|
||||
|
||||
// 创建初始执行状态
|
||||
ExecutionStatus status;
|
||||
status.taskId = taskId;
|
||||
status.currentPhase = "INIT";
|
||||
status.completionPercent = 0.0;
|
||||
status.heartbeatTimestamp = nowMs();
|
||||
status.errorCode = 0;
|
||||
statusMap_[taskId] = status;
|
||||
|
||||
return taskId;
|
||||
}
|
||||
|
||||
// ---------- 模板管理 ----------
|
||||
bool addTemplate(const TaskTemplate& tmpl) {
|
||||
if (tmpl.id.empty()) return false;
|
||||
for (const auto& t : templates_) {
|
||||
if (t.id == tmpl.id) return false;
|
||||
}
|
||||
templates_.push_back(tmpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
const TaskTemplate* matchBestTemplate(const std::string& scenario) const {
|
||||
const TaskTemplate* best = nullptr;
|
||||
double bestScore = -1.0;
|
||||
for (const auto& t : templates_) {
|
||||
if (t.matchScore > bestScore) {
|
||||
bool match = (t.applicableScenario.find(scenario) != std::string::npos)
|
||||
|| scenario.find(t.applicableScenario) != std::string::npos;
|
||||
if (match || best == nullptr) {
|
||||
best = &t;
|
||||
bestScore = t.matchScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
std::string saveSnapshot() {
|
||||
ConfigSnapshot snap;
|
||||
snap.version = "SNAP-" + generateId();
|
||||
snap.timestamp = nowMs();
|
||||
snap.configData = "{\"templateCount\":" + std::to_string(templates_.size()) + "}";
|
||||
snapshots_[snap.version] = snap;
|
||||
return snap.version;
|
||||
}
|
||||
|
||||
bool rollbackToSnapshot(const std::string& version) {
|
||||
auto it = snapshots_.find(version);
|
||||
if (it == snapshots_.end()) return false;
|
||||
// 回滚快照:快照中保存了模板数量等信息,可据此恢复
|
||||
// 当前简化实现:仅验证快照存在
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------- 分发监控 ----------
|
||||
int dispatchPlan(const std::string& planId, const std::vector<std::string>& nodeIds) {
|
||||
const auto* plan = findPlanById(planId);
|
||||
if (!plan) return 0;
|
||||
|
||||
int successCount = 0;
|
||||
for (const auto& nodeId : nodeIds) {
|
||||
DistributionAck ack;
|
||||
ack.nodeId = nodeId;
|
||||
ack.timestamp = nowMs();
|
||||
ack.retryCount = 0;
|
||||
|
||||
// 模拟分发:80% 概率成功,20% 需要重试
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(0, 99);
|
||||
|
||||
int roll = dis(gen);
|
||||
if (roll < 80) {
|
||||
ack.status = AckStatus::Confirmed;
|
||||
successCount++;
|
||||
} else {
|
||||
// 重试机制
|
||||
for (int retry = 1; retry <= config_.maxRetryCount; ++retry) {
|
||||
ack.retryCount = retry;
|
||||
ack.timestamp = nowMs();
|
||||
int retryRoll = dis(gen);
|
||||
if (retryRoll < 80) {
|
||||
ack.status = AckStatus::Confirmed;
|
||||
successCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ack.status != AckStatus::Confirmed) {
|
||||
ack.status = AckStatus::Timeout;
|
||||
}
|
||||
}
|
||||
acks_.push_back(ack);
|
||||
}
|
||||
return successCount;
|
||||
}
|
||||
|
||||
std::vector<DistributionAck> getDistributionAcks() const {
|
||||
return acks_;
|
||||
}
|
||||
|
||||
void reportExecutionStatus(const ExecutionStatus& status) {
|
||||
statusMap_[status.taskId] = status;
|
||||
}
|
||||
|
||||
const ExecutionStatus* getExecutionStatus(const std::string& taskId) const {
|
||||
auto it = statusMap_.find(taskId);
|
||||
if (it != statusMap_.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ---------- 配置与日志 ----------
|
||||
void logOperation(const OperationLog& log) {
|
||||
logs_.push_back(log);
|
||||
}
|
||||
|
||||
std::vector<OperationLog> getOperationLogs() const {
|
||||
return logs_;
|
||||
}
|
||||
|
||||
const SystemConfig& getConfig() const {
|
||||
return config_;
|
||||
}
|
||||
|
||||
private:
|
||||
SystemState state_;
|
||||
RunMode mode_;
|
||||
SystemConfig config_;
|
||||
ModeStateCache modeCache_;
|
||||
|
||||
std::vector<PlanData> plans_;
|
||||
std::vector<StandardEvent> events_;
|
||||
std::vector<TaskTemplate> templates_;
|
||||
std::vector<DistributionAck> acks_;
|
||||
std::unordered_map<std::string, ExecutionStatus> statusMap_;
|
||||
std::vector<OperationLog> logs_;
|
||||
std::unordered_map<std::string, ConfigSnapshot> snapshots_;
|
||||
};
|
||||
|
||||
// ====================================================================
|
||||
// App 公开接口实现(委托至 pImpl_)
|
||||
// ====================================================================
|
||||
|
||||
App::App()
|
||||
: pImpl_(std::make_unique<Impl>())
|
||||
{
|
||||
}
|
||||
|
||||
App::~App() = default;
|
||||
|
||||
bool App::initialize(const std::string& configFile) {
|
||||
return pImpl_->initialize(configFile);
|
||||
}
|
||||
|
||||
bool App::start() {
|
||||
return pImpl_->start();
|
||||
}
|
||||
|
||||
void App::stop() {
|
||||
pImpl_->stop();
|
||||
}
|
||||
|
||||
SystemState App::getState() const {
|
||||
return pImpl_->getState();
|
||||
}
|
||||
|
||||
bool App::setRunMode(RunMode mode) {
|
||||
return pImpl_->setRunMode(mode);
|
||||
}
|
||||
|
||||
RunMode App::getRunMode() const {
|
||||
return pImpl_->getRunMode();
|
||||
}
|
||||
|
||||
bool App::addPlan(const PlanData& plan) {
|
||||
return pImpl_->addPlan(plan);
|
||||
}
|
||||
|
||||
const std::vector<PlanData>& App::getAllPlans() const {
|
||||
return pImpl_->getAllPlans();
|
||||
}
|
||||
|
||||
const PlanData* App::findPlanById(const std::string& planId) const {
|
||||
return pImpl_->findPlanById(planId);
|
||||
}
|
||||
|
||||
std::string App::comparePlans(const std::vector<std::string>& planIds) const {
|
||||
return pImpl_->comparePlans(planIds);
|
||||
}
|
||||
|
||||
std::string App::ingestRawEvent(const EventRaw& raw) {
|
||||
return pImpl_->ingestRawEvent(raw);
|
||||
}
|
||||
|
||||
std::vector<StandardEvent> App::getPendingEvents() const {
|
||||
return pImpl_->getPendingEvents();
|
||||
}
|
||||
|
||||
bool App::processEvent(const std::string& eventId, bool accept) {
|
||||
return pImpl_->processEvent(eventId, accept);
|
||||
}
|
||||
|
||||
std::string App::generateTaskFromEvent(const std::string& eventId) {
|
||||
return pImpl_->generateTaskFromEvent(eventId);
|
||||
}
|
||||
|
||||
bool App::addTemplate(const TaskTemplate& tmpl) {
|
||||
return pImpl_->addTemplate(tmpl);
|
||||
}
|
||||
|
||||
const TaskTemplate* App::matchBestTemplate(const std::string& scenario) const {
|
||||
return pImpl_->matchBestTemplate(scenario);
|
||||
}
|
||||
|
||||
std::string App::saveSnapshot() {
|
||||
return pImpl_->saveSnapshot();
|
||||
}
|
||||
|
||||
bool App::rollbackToSnapshot(const std::string& version) {
|
||||
return pImpl_->rollbackToSnapshot(version);
|
||||
}
|
||||
|
||||
int App::dispatchPlan(const std::string& planId, const std::vector<std::string>& nodeIds) {
|
||||
return pImpl_->dispatchPlan(planId, nodeIds);
|
||||
}
|
||||
|
||||
std::vector<DistributionAck> App::getDistributionAcks() const {
|
||||
return pImpl_->getDistributionAcks();
|
||||
}
|
||||
|
||||
void App::reportExecutionStatus(const ExecutionStatus& status) {
|
||||
pImpl_->reportExecutionStatus(status);
|
||||
}
|
||||
|
||||
const ExecutionStatus* App::getExecutionStatus(const std::string& taskId) const {
|
||||
return pImpl_->getExecutionStatus(taskId);
|
||||
}
|
||||
|
||||
void App::logOperation(const OperationLog& log) {
|
||||
pImpl_->logOperation(log);
|
||||
}
|
||||
|
||||
std::vector<OperationLog> App::getOperationLogs() const {
|
||||
return pImpl_->getOperationLogs();
|
||||
}
|
||||
|
||||
const SystemConfig& App::getConfig() const {
|
||||
return pImpl_->getConfig();
|
||||
}
|
||||
|
||||
} // namespace c2sys
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* @file main.cpp
|
||||
* @brief C2SYS 任务自主规划软件 — 命令行入口与流程演示。
|
||||
*
|
||||
* 本程序演示 C2SYS 系统的完整闭环流程:
|
||||
* 1. 初始化系统并加载配置
|
||||
* 2. 添加集中式与分布式方案
|
||||
* 3. 模式切换(人在回路 → 自主执行)
|
||||
* 4. 接收原始事件并转化为标准化事件
|
||||
* 5. 从事件生成任务
|
||||
* 6. 添加模板并进行模板匹配
|
||||
* 7. 方案分发与状态监控
|
||||
* 8. 输出对比报告与操作日志
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace c2sys;
|
||||
|
||||
/**
|
||||
* @brief 打印分隔线。
|
||||
*/
|
||||
static void printSeparator() {
|
||||
std::cout << "\n" << std::string(60, '=') << "\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 打印系统状态摘要。
|
||||
*/
|
||||
static void printSystemStatus(const App& app) {
|
||||
SystemState st = app.getState();
|
||||
RunMode mode = app.getRunMode();
|
||||
auto& config = app.getConfig();
|
||||
|
||||
std::cout << "【系统状态】\n";
|
||||
std::cout << " 运行状态: ";
|
||||
switch (st) {
|
||||
case SystemState::Initializing: std::cout << "初始化中"; break;
|
||||
case SystemState::Ready: std::cout << "已就绪"; break;
|
||||
case SystemState::Running: std::cout << "运行中"; break;
|
||||
case SystemState::Error: std::cout << "异常"; break;
|
||||
case SystemState::Stopped: std::cout << "已停止"; break;
|
||||
}
|
||||
std::cout << "\n 运行模式: " << (mode == RunMode::HumanInLoop ? "人在回路" : "自主执行") << "\n";
|
||||
std::cout << " 刷新周期: " << config.refreshIntervalMs << " ms\n";
|
||||
std::cout << " WebSocket端口: " << config.websocketPort << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主函数 — 系统流程演示入口。
|
||||
*/
|
||||
int main() {
|
||||
std::cout << "\n"
|
||||
<< "╔══════════════════════════════════════════════════════╗\n"
|
||||
<< "║ C2SYS 任务自主规划软件系统 v1.0.0 ║\n"
|
||||
<< "║ 联合作战指挥环境 · 任务自主规划演示 ║\n"
|
||||
<< "╚══════════════════════════════════════════════════════╝\n";
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 1:初始化系统
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 1】系统初始化\n";
|
||||
|
||||
App app;
|
||||
if (!app.initialize("")) {
|
||||
std::cerr << "错误:系统初始化失败!\n";
|
||||
return 1;
|
||||
}
|
||||
std::cout << " 系统初始化完成,使用默认配置。\n";
|
||||
printSystemStatus(app);
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 2:添加作战方案 (F-001, F-002, F-003)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 2】添加作战方案\n";
|
||||
|
||||
// 集中式方案 A
|
||||
PlanData planA;
|
||||
planA.id = "PLAN-CENTRAL-A";
|
||||
planA.type = PlanType::Centralized;
|
||||
planA.resourceUsage = 65.5;
|
||||
planA.executionPeriod = 120.0;
|
||||
planA.successRate = 0.92;
|
||||
planA.survivability = 0.75;
|
||||
planA.collaborationEfficiency = 0.80;
|
||||
planA.subTaskIds = {"ST-001", "ST-002"};
|
||||
planA.createTimestamp = 1715000000000LL;
|
||||
app.addPlan(planA);
|
||||
std::cout << " 添加集中式方案: " << planA.id << "\n";
|
||||
|
||||
// 集中式方案 B
|
||||
PlanData planB;
|
||||
planB.id = "PLAN-CENTRAL-B";
|
||||
planB.type = PlanType::Centralized;
|
||||
planB.resourceUsage = 78.2;
|
||||
planB.executionPeriod = 90.0;
|
||||
planB.successRate = 0.85;
|
||||
planB.survivability = 0.68;
|
||||
planB.collaborationEfficiency = 0.72;
|
||||
planB.subTaskIds = {"ST-003", "ST-004", "ST-005"};
|
||||
planB.createTimestamp = 1715000100000LL;
|
||||
app.addPlan(planB);
|
||||
std::cout << " 添加集中式方案: " << planB.id << "\n";
|
||||
|
||||
// 分布式方案 C
|
||||
PlanData planC;
|
||||
planC.id = "PLAN-DIST-C";
|
||||
planC.type = PlanType::Distributed;
|
||||
planC.resourceUsage = 52.0;
|
||||
planC.executionPeriod = 150.0;
|
||||
planC.successRate = 0.95;
|
||||
planC.survivability = 0.88;
|
||||
planC.collaborationEfficiency = 0.91;
|
||||
planC.subTaskIds = {"ST-006", "ST-007", "ST-008", "ST-009"};
|
||||
planC.createTimestamp = 1715000200000LL;
|
||||
app.addPlan(planC);
|
||||
std::cout << " 添加分布式方案: " << planC.id << "\n";
|
||||
|
||||
std::cout << " 当前方案总数: " << app.getAllPlans().size() << "\n";
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 3:方案对比 (F-002)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 3】方案对比分析\n";
|
||||
std::string compareReport = app.comparePlans({"PLAN-CENTRAL-A", "PLAN-CENTRAL-B", "PLAN-DIST-C"});
|
||||
std::cout << compareReport;
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 4:模式切换 (CON-001)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 4】模式切换:人在回路 → 自主执行\n";
|
||||
if (app.setRunMode(RunMode::Autonomous)) {
|
||||
std::cout << " 模式切换成功!当前模式:自主执行\n";
|
||||
} else {
|
||||
std::cout << " 模式切换失败!\n";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 5:接收原始事件 (F-006)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 5】接收原始事件流\n";
|
||||
|
||||
EventRaw raw1;
|
||||
raw1.sourceId = "RADAR-001";
|
||||
raw1.timestamp = 1715000300000LL;
|
||||
raw1.threatLevel = 4; // 高威胁 → 临机事件
|
||||
raw1.payloadHash = "a1b2c3d4e5f6...";
|
||||
raw1.protocolType = "LINK16";
|
||||
raw1.payload = R"({"target":"unknown","bearing":45,"speed":200})";
|
||||
std::string evtId1 = app.ingestRawEvent(raw1);
|
||||
std::cout << " 接收原始事件 [源: RADAR-001, 威胁等级: 4]\n";
|
||||
std::cout << " 生成标准化事件 ID: " << evtId1 << " (类型: 临机)\n";
|
||||
|
||||
EventRaw raw2;
|
||||
raw2.sourceId = "SAT-002";
|
||||
raw2.timestamp = 1715000350000LL;
|
||||
raw2.threatLevel = 2; // 低威胁 → 规划事件
|
||||
raw2.payloadHash = "b2c3d4e5f6a7...";
|
||||
raw2.protocolType = "SATCOM";
|
||||
raw2.payload = R"({"area":"A3","troop_movement":"scheduled"})";
|
||||
std::string evtId2 = app.ingestRawEvent(raw2);
|
||||
std::cout << " 接收原始事件 [源: SAT-002, 威胁等级: 2]\n";
|
||||
std::cout << " 生成标准化事件 ID: " << evtId2 << " (类型: 规划)\n";
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 6:处理事件 (F-007)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 6】事件列表与处理\n";
|
||||
|
||||
auto pendingEvents = app.getPendingEvents();
|
||||
std::cout << " 待办事件数: " << pendingEvents.size() << "\n";
|
||||
for (const auto& e : pendingEvents) {
|
||||
std::cout << " - " << e.id << " [" << (e.type == EventType::Contingency ? "临机" : "规划") << "]\n";
|
||||
}
|
||||
|
||||
// 处理第一个事件(接受)
|
||||
app.processEvent(evtId1, true);
|
||||
std::cout << " 已处理事件: " << evtId1 << " → 接受\n";
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 7:任务模板管理 (F-009, F-010)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 7】任务模板知识库管理\n";
|
||||
|
||||
TaskTemplate tmpl1;
|
||||
tmpl1.id = "TMPL-001";
|
||||
tmpl1.version = "1.0";
|
||||
tmpl1.applicableScenario = "threat_4";
|
||||
tmpl1.weightConfig = R"({"speed":0.3,"precision":0.5,"safety":0.2})";
|
||||
tmpl1.subTaskRequirements = {"侦察", "打击", "评估"};
|
||||
tmpl1.matchScore = 0.91;
|
||||
app.addTemplate(tmpl1);
|
||||
std::cout << " 添加模板: " << tmpl1.id << " (版本 " << tmpl1.version << ")\n";
|
||||
|
||||
TaskTemplate tmpl2;
|
||||
tmpl2.id = "TMPL-002";
|
||||
tmpl2.version = "2.0";
|
||||
tmpl2.applicableScenario = "threat_2";
|
||||
tmpl2.weightConfig = R"({"speed":0.2,"precision":0.3,"safety":0.5})";
|
||||
tmpl2.subTaskRequirements = {"巡逻", "监视", "报告"};
|
||||
tmpl2.matchScore = 0.85;
|
||||
app.addTemplate(tmpl2);
|
||||
std::cout << " 添加模板: " << tmpl2.id << " (版本 " << tmpl2.version << ")\n";
|
||||
|
||||
// 保存快照
|
||||
std::string snapVer = app.saveSnapshot();
|
||||
std::cout << " 保存配置快照: " << snapVer << "\n";
|
||||
|
||||
// 自动匹配模板(自主执行模式)
|
||||
const auto* matched = app.matchBestTemplate("threat_4");
|
||||
if (matched) {
|
||||
std::cout << " 场景 'threat_4' 匹配最优模板: " << matched->id
|
||||
<< " (评分: " << (matched->matchScore * 100.0) << "%)\n";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 8:从事件生成任务 (F-008)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 8】从事件生成关联任务\n";
|
||||
std::string taskId = app.generateTaskFromEvent(evtId1);
|
||||
if (!taskId.empty()) {
|
||||
std::cout << " 由事件 " << evtId1 << " 生成任务: " << taskId << "\n";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 9:方案分发与监控 (F-004, F-005)
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 9】方案分发与执行监控\n";
|
||||
|
||||
std::vector<std::string> nodes = {"NODE-A01", "NODE-B02", "NODE-C03", "NODE-D04"};
|
||||
int successCount = app.dispatchPlan("PLAN-DIST-C", nodes);
|
||||
std::cout << " 分发方案 'PLAN-DIST-C' 至 " << nodes.size() << " 个节点\n";
|
||||
std::cout << " 分发成功节点数: " << successCount << "/" << nodes.size() << "\n";
|
||||
|
||||
// 模拟执行状态上报
|
||||
ExecutionStatus execStatus;
|
||||
execStatus.taskId = taskId;
|
||||
execStatus.currentPhase = "EXECUTING";
|
||||
execStatus.completionPercent = 45.0;
|
||||
execStatus.heartbeatTimestamp = 1715000400000LL;
|
||||
execStatus.errorCode = 0;
|
||||
execStatus.impactScope = "区域A3";
|
||||
app.reportExecutionStatus(execStatus);
|
||||
std::cout << " 任务 " << taskId << " 执行状态更新: 阶段=" << execStatus.currentPhase
|
||||
<< ", 进度=" << execStatus.completionPercent << "%\n";
|
||||
|
||||
const auto* queriedStatus = app.getExecutionStatus(taskId);
|
||||
if (queriedStatus) {
|
||||
std::cout << " 查询任务状态: " << queriedStatus->currentPhase
|
||||
<< " (" << queriedStatus->completionPercent << "%) 正常\n";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 步骤 10:操作日志与汇总
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【步骤 10】操作日志记录\n";
|
||||
|
||||
OperationLog log1{"OPERATOR-01", nowMs(), "ADD_PLAN", "PLAN-CENTRAL-A", "SUCCESS"};
|
||||
OperationLog log2{"OPERATOR-01", nowMs(), "SWITCH_MODE", "Autonomous", "SUCCESS"};
|
||||
OperationLog log3{"OPERATOR-02", nowMs(), "PROCESS_EVENT", evtId1, "ACCEPTED"};
|
||||
OperationLog log4{"SYSTEM", nowMs(), "DISPATCH_PLAN", "PLAN-DIST-C", "PARTIAL"};
|
||||
|
||||
app.logOperation(log1);
|
||||
app.logOperation(log2);
|
||||
app.logOperation(log3);
|
||||
app.logOperation(log4);
|
||||
|
||||
std::cout << " 操作日志条目数: " << app.getOperationLogs().size() << "\n";
|
||||
for (const auto& log : app.getOperationLogs()) {
|
||||
std::cout << " [" << log.timestamp << "] " << log.operatorId
|
||||
<< " → " << log.actionType << " (" << log.resultStatus << ")\n";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 系统停止
|
||||
// ====================================================================
|
||||
printSeparator();
|
||||
std::cout << "【流程结束】系统停止\n";
|
||||
app.stop();
|
||||
printSystemStatus(app);
|
||||
|
||||
std::cout << "\n✅ C2SYS 演示流程执行完毕!所有功能已验证通过。\n";
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
/**
|
||||
* @file basic_test.cpp
|
||||
* @brief C2SYS 系统基础单元测试。
|
||||
*
|
||||
* 使用标准库 assert 对核心数据结构和业务功能进行验证。
|
||||
* 不依赖 GoogleTest 等外部测试框架。
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
#include "config.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace c2sys;
|
||||
|
||||
/**
|
||||
* @brief 测试数据实体构造与字段访问。
|
||||
*/
|
||||
static void testDataEntities() {
|
||||
std::cout << " [测试] 数据实体构造 ... ";
|
||||
|
||||
// PlanData
|
||||
PlanData plan;
|
||||
plan.id = "PLAN-TEST-001";
|
||||
plan.type = PlanType::Centralized;
|
||||
plan.resourceUsage = 50.0;
|
||||
plan.executionPeriod = 100.0;
|
||||
plan.successRate = 0.9;
|
||||
plan.survivability = 0.8;
|
||||
plan.collaborationEfficiency = 0.85;
|
||||
plan.subTaskIds = {"ST-A", "ST-B"};
|
||||
plan.createTimestamp = 1715000000000LL;
|
||||
|
||||
assert(plan.id == "PLAN-TEST-001");
|
||||
assert(plan.type == PlanType::Centralized);
|
||||
assert(plan.resourceUsage == 50.0);
|
||||
assert(plan.executionPeriod == 100.0);
|
||||
assert(plan.successRate == 0.9);
|
||||
assert(plan.survivability == 0.8);
|
||||
assert(plan.collaborationEfficiency == 0.85);
|
||||
assert(plan.subTaskIds.size() == 2);
|
||||
assert(plan.subTaskIds[0] == "ST-A");
|
||||
std::cout << "PlanData OK\n";
|
||||
|
||||
// EventRaw
|
||||
EventRaw raw;
|
||||
raw.sourceId = "RADAR-001";
|
||||
raw.timestamp = 1715000300000LL;
|
||||
raw.threatLevel = 4;
|
||||
raw.payloadHash = "abc123";
|
||||
raw.protocolType = "LINK16";
|
||||
raw.payload = "test_payload";
|
||||
|
||||
assert(raw.sourceId == "RADAR-001");
|
||||
assert(raw.threatLevel == 4);
|
||||
assert(raw.protocolType == "LINK16");
|
||||
std::cout << " [测试] 数据实体构造 ... EventRaw OK\n";
|
||||
|
||||
// StandardEvent
|
||||
StandardEvent evt;
|
||||
evt.id = "EVT-001";
|
||||
evt.type = EventType::Contingency;
|
||||
evt.status = EventStatus::Pending;
|
||||
evt.metadata["key1"] = "val1";
|
||||
|
||||
assert(evt.id == "EVT-001");
|
||||
assert(evt.type == EventType::Contingency);
|
||||
assert(evt.status == EventStatus::Pending);
|
||||
assert(evt.metadata.at("key1") == "val1");
|
||||
std::cout << " [测试] 数据实体构造 ... StandardEvent OK\n";
|
||||
|
||||
// TaskTemplate
|
||||
TaskTemplate tmpl;
|
||||
tmpl.id = "TMPL-001";
|
||||
tmpl.version = "1.0";
|
||||
tmpl.applicableScenario = "threat_4";
|
||||
tmpl.matchScore = 0.91;
|
||||
|
||||
assert(tmpl.id == "TMPL-001");
|
||||
assert(tmpl.matchScore == 0.91);
|
||||
std::cout << " [测试] 数据实体构造 ... TaskTemplate OK\n";
|
||||
|
||||
// ExecutionStatus
|
||||
ExecutionStatus st;
|
||||
st.taskId = "TASK-001";
|
||||
st.currentPhase = "EXECUTING";
|
||||
st.completionPercent = 50.0;
|
||||
st.errorCode = 0;
|
||||
|
||||
assert(st.taskId == "TASK-001");
|
||||
assert(st.completionPercent == 50.0);
|
||||
assert(st.errorCode == 0);
|
||||
std::cout << " [测试] 数据实体构造 ... ExecutionStatus OK\n";
|
||||
|
||||
// DistributionAck
|
||||
DistributionAck ack;
|
||||
ack.nodeId = "NODE-A";
|
||||
ack.status = AckStatus::Confirmed;
|
||||
ack.retryCount = 0;
|
||||
|
||||
assert(ack.nodeId == "NODE-A");
|
||||
assert(ack.status == AckStatus::Confirmed);
|
||||
std::cout << " [测试] 数据实体构造 ... DistributionAck OK\n";
|
||||
|
||||
std::cout << " [测试] 数据实体构造 ... 全部通过 ✓\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试 App 核心业务功能。
|
||||
*/
|
||||
static void testAppCoreFunctions() {
|
||||
std::cout << " [测试] App 核心功能 ... ";
|
||||
|
||||
App app;
|
||||
|
||||
// 初始化
|
||||
bool initOk = app.initialize("");
|
||||
assert(initOk);
|
||||
assert(app.getState() == SystemState::Ready);
|
||||
std::cout << "\n 初始化 OK\n";
|
||||
|
||||
// 模式切换
|
||||
bool modeOk = app.setRunMode(RunMode::Autonomous);
|
||||
assert(modeOk);
|
||||
assert(app.getRunMode() == RunMode::Autonomous);
|
||||
std::cout << " 模式切换 OK\n";
|
||||
|
||||
// 添加方案
|
||||
PlanData plan;
|
||||
plan.id = "PLAN-TEST";
|
||||
plan.type = PlanType::Centralized;
|
||||
plan.resourceUsage = 50.0;
|
||||
plan.executionPeriod = 100.0;
|
||||
plan.successRate = 0.9;
|
||||
bool addOk = app.addPlan(plan);
|
||||
assert(addOk);
|
||||
assert(app.getAllPlans().size() == 1);
|
||||
|
||||
// 重复添加应失败
|
||||
bool dupOk = app.addPlan(plan);
|
||||
assert(!dupOk);
|
||||
std::cout << " 方案管理 OK\n";
|
||||
|
||||
// 查找方案
|
||||
const auto* found = app.findPlanById("PLAN-TEST");
|
||||
assert(found != nullptr);
|
||||
assert(found->resourceUsage == 50.0);
|
||||
|
||||
const auto* notFound = app.findPlanById("NONEXIST");
|
||||
assert(notFound == nullptr);
|
||||
std::cout << " 方案查询 OK\n";
|
||||
|
||||
// 事件处理
|
||||
EventRaw raw;
|
||||
raw.sourceId = "RADAR-TEST";
|
||||
raw.timestamp = 1715000000000LL;
|
||||
raw.threatLevel = 4;
|
||||
raw.payloadHash = "hash123";
|
||||
raw.protocolType = "TEST";
|
||||
raw.payload = "test_data";
|
||||
|
||||
std::string evtId = app.ingestRawEvent(raw);
|
||||
assert(!evtId.empty());
|
||||
|
||||
auto pending = app.getPendingEvents();
|
||||
assert(pending.size() >= 1);
|
||||
|
||||
bool procOk = app.processEvent(evtId, true);
|
||||
assert(procOk);
|
||||
|
||||
auto pendingAfter = app.getPendingEvents();
|
||||
// 处理后待办应减少(或为空)
|
||||
std::cout << " 事件处理 OK\n";
|
||||
|
||||
// 任务生成
|
||||
std::string taskId = app.generateTaskFromEvent(evtId);
|
||||
assert(!taskId.empty());
|
||||
|
||||
const auto* taskStatus = app.getExecutionStatus(taskId);
|
||||
assert(taskStatus != nullptr);
|
||||
assert(taskStatus->currentPhase == "INIT");
|
||||
std::cout << " 任务生成 OK\n";
|
||||
|
||||
// 模板管理
|
||||
TaskTemplate tmpl;
|
||||
tmpl.id = "TMPL-TEST";
|
||||
tmpl.version = "1.0";
|
||||
tmpl.applicableScenario = "threat_4";
|
||||
tmpl.matchScore = 0.95;
|
||||
bool tmplOk = app.addTemplate(tmpl);
|
||||
assert(tmplOk);
|
||||
|
||||
const auto* matched = app.matchBestTemplate("threat_4");
|
||||
assert(matched != nullptr);
|
||||
assert(matched->id == "TMPL-TEST");
|
||||
std::cout << " 模板管理 OK\n";
|
||||
|
||||
// 快照管理
|
||||
std::string snapVer = app.saveSnapshot();
|
||||
assert(!snapVer.empty());
|
||||
bool rollbackOk = app.rollbackToSnapshot(snapVer);
|
||||
assert(rollbackOk);
|
||||
std::cout << " 快照管理 OK\n";
|
||||
|
||||
// 方案分发
|
||||
std::vector<std::string> nodes = {"NODE-X", "NODE-Y"};
|
||||
int success = app.dispatchPlan("PLAN-TEST", nodes);
|
||||
assert(success >= 0 && success <= 2);
|
||||
auto acks = app.getDistributionAcks();
|
||||
assert(acks.size() >= 1);
|
||||
std::cout << " 分发监控 OK\n";
|
||||
|
||||
// 执行状态上报
|
||||
ExecutionStatus status;
|
||||
status.taskId = taskId;
|
||||
status.currentPhase = "COMPLETED";
|
||||
status.completionPercent = 100.0;
|
||||
status.errorCode = 0;
|
||||
app.reportExecutionStatus(status);
|
||||
|
||||
const auto* updatedStatus = app.getExecutionStatus(taskId);
|
||||
assert(updatedStatus != nullptr);
|
||||
assert(updatedStatus->completionPercent == 100.0);
|
||||
std::cout << " 状态监控 OK\n";
|
||||
|
||||
// 操作日志
|
||||
OperationLog log{"TEST-OP", 1715000000000LL, "TEST", "OBJ-001", "OK"};
|
||||
app.logOperation(log);
|
||||
assert(app.getOperationLogs().size() >= 1);
|
||||
std::cout << " 操作日志 OK\n";
|
||||
|
||||
// 启动/停止
|
||||
bool startOk = app.start();
|
||||
assert(startOk);
|
||||
assert(app.getState() == SystemState::Running);
|
||||
|
||||
app.stop();
|
||||
assert(app.getState() == SystemState::Stopped);
|
||||
std::cout << " 生命周期管理 OK\n";
|
||||
|
||||
std::cout << " [测试] App 核心功能 ... 全部通过 ✓\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试 SystemConfig 配置加载。
|
||||
*/
|
||||
static void testConfigLoading() {
|
||||
std::cout << " [测试] 配置加载 ... ";
|
||||
|
||||
SystemConfig config;
|
||||
// 默认值检查
|
||||
assert(config.refreshIntervalMs == 50);
|
||||
assert(config.websocketPort == 8080);
|
||||
assert(config.maxRetryCount == 3);
|
||||
assert(config.logLevel == 2);
|
||||
|
||||
// 尝试加载不存在的配置文件应失败但不影响默认值
|
||||
bool loaded = config.loadFromFile("nonexistent_config.txt");
|
||||
assert(!loaded);
|
||||
assert(config.refreshIntervalMs == 50);
|
||||
|
||||
std::cout << "默认配置 OK, 文件不存在时回退 OK\n";
|
||||
std::cout << " [测试] 配置加载 ... 通过 ✓\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主测试函数入口。
|
||||
*/
|
||||
int main() {
|
||||
std::cout << "\n╔══════════════════════════════════════════════════════╗\n";
|
||||
std::cout << "║ C2SYS 系统单元测试 (基于 assert) ║\n";
|
||||
std::cout << "╚══════════════════════════════════════════════════════╝\n\n";
|
||||
|
||||
testDataEntities();
|
||||
std::cout << "\n";
|
||||
testConfigLoading();
|
||||
std::cout << "\n";
|
||||
testAppCoreFunctions();
|
||||
|
||||
std::cout << "\n✅ 所有单元测试通过!\n";
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue