403 lines
13 KiB
C++
403 lines
13 KiB
C++
#include "app.hpp"
|
||
#include <algorithm>
|
||
#include <sstream>
|
||
#include <iomanip>
|
||
#include <ctime>
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// CmsEngine 构造与辅助
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 构造函数,初始化系统状态上下文与自增计数器
|
||
*/
|
||
CmsEngine::CmsEngine()
|
||
: nextId_(0)
|
||
{
|
||
systemContext_.currentMode = RunMode::Idle;
|
||
systemContext_.consistencyMark = 0;
|
||
systemContext_.switchTime = std::chrono::system_clock::now();
|
||
systemContext_.contextSnapshot = R"({"mode":"Idle","version":"1.0.0"})";
|
||
}
|
||
|
||
/**
|
||
* @brief 生成自增唯一标识
|
||
*
|
||
* @return std::string 格式如 "ID-00001"
|
||
*/
|
||
std::string CmsEngine::generateNextId()
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "ID-" << std::setw(5) << std::setfill('0') << (++nextId_);
|
||
return oss.str();
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 事件处理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 接入原始战场事件
|
||
*
|
||
* 执行基本合法性校验(ID 不能为空、优先级范围检查),通过后存入事件库。
|
||
*
|
||
* @param event 战场事件
|
||
* @return true 接入成功
|
||
* @return false 接入失败
|
||
*/
|
||
bool CmsEngine::ingestEvent(const EventRecord& event)
|
||
{
|
||
if (event.id.empty()) {
|
||
return false;
|
||
}
|
||
if (event.priority > 255) {
|
||
return false;
|
||
}
|
||
events_.push_back(event);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 处理待处理事件队列
|
||
*
|
||
* 遍历事件库中所有 Pending 状态的事件,自动将其状态标记为 Generated,
|
||
* 并据此生成一个对应的 TaskPlan 草案。
|
||
*
|
||
* @return size_t 处理的事件数量
|
||
*/
|
||
size_t CmsEngine::processPendingEvents()
|
||
{
|
||
size_t count = 0;
|
||
for (auto& evt : events_) {
|
||
if (evt.status == EventStatus::Pending) {
|
||
evt.status = EventStatus::Generated;
|
||
|
||
TaskPlan plan;
|
||
plan.id = generateNextId();
|
||
plan.name = "AutoPlan-" + evt.id;
|
||
plan.type = PlanType::Centralized;
|
||
plan.status = PlanStatus::Drafting;
|
||
plan.createTime = std::chrono::system_clock::now();
|
||
plan.relatedEventId = evt.id;
|
||
plan.resourceQuota = 0.5;
|
||
plan.constraints = "自动生成约束";
|
||
plans_.push_back(plan);
|
||
|
||
++count;
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
/**
|
||
* @brief 根据事件 ID 查找事件
|
||
*
|
||
* @param eventId 事件标识
|
||
* @return const EventRecord* 事件指针,未找到返回 nullptr
|
||
*/
|
||
const EventRecord* CmsEngine::findEventById(const std::string& eventId) const
|
||
{
|
||
for (const auto& evt : events_) {
|
||
if (evt.id == eventId) {
|
||
return &evt;
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 任务方案管理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 创建任务方案
|
||
*
|
||
* 校验方案名称非空后,为其分配系统 ID 并存入方案库。
|
||
*
|
||
* @param plan 待创建方案(id 由系统填充)
|
||
* @return true 创建成功
|
||
* @return false 名称不合法
|
||
*/
|
||
bool CmsEngine::createTaskPlan(TaskPlan& plan)
|
||
{
|
||
if (plan.name.empty()) {
|
||
return false;
|
||
}
|
||
plan.id = generateNextId();
|
||
plan.createTime = std::chrono::system_clock::now();
|
||
plans_.push_back(plan);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取所有任务方案列表
|
||
*
|
||
* @return const std::vector<TaskPlan>& 方案列表
|
||
*/
|
||
const std::vector<TaskPlan>& CmsEngine::getAllPlans() const
|
||
{
|
||
return plans_;
|
||
}
|
||
|
||
/**
|
||
* @brief 根据 ID 查找任务方案
|
||
*
|
||
* @param planId 任务标识
|
||
* @return const TaskPlan* 方案指针,未找到返回 nullptr
|
||
*/
|
||
const TaskPlan* CmsEngine::findPlanById(const std::string& planId) const
|
||
{
|
||
for (const auto& plan : plans_) {
|
||
if (plan.id == planId) {
|
||
return &plan;
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
/**
|
||
* @brief 更新任务方案状态
|
||
*
|
||
* @param planId 任务标识
|
||
* @param newStatus 新状态
|
||
* @return true 更新成功
|
||
* @return false 未找到方案
|
||
*/
|
||
bool CmsEngine::updatePlanStatus(const std::string& planId, PlanStatus newStatus)
|
||
{
|
||
for (auto& plan : plans_) {
|
||
if (plan.id == planId) {
|
||
plan.status = newStatus;
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 模板管理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 注册模板实例
|
||
*
|
||
* @param tmpl 模板实例
|
||
*/
|
||
void CmsEngine::registerTemplate(const TemplateInstance& tmpl)
|
||
{
|
||
templates_.push_back(tmpl);
|
||
}
|
||
|
||
/**
|
||
* @brief 根据场景匹配最佳模板
|
||
*
|
||
* 遍历模板库,返回置信度最高的模板(简单策略:置信度最大者)。
|
||
*
|
||
* @param scenario 场景描述(当前未用于精确匹配,仅做演示)
|
||
* @return const TemplateInstance* 最佳模板,无匹配返回 nullptr
|
||
*/
|
||
const TemplateInstance* CmsEngine::matchTemplate(const std::string& scenario) const
|
||
{
|
||
(void)scenario;
|
||
if (templates_.empty()) {
|
||
return nullptr;
|
||
}
|
||
const TemplateInstance* best = &templates_.front();
|
||
for (const auto& tmpl : templates_) {
|
||
if (tmpl.confidence > best->confidence) {
|
||
best = &tmpl;
|
||
}
|
||
}
|
||
return best;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 执行监控
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 上报节点执行状态
|
||
*
|
||
* 将节点遥测数据写入内部状态表,按 nodeId 覆盖更新。
|
||
*
|
||
* @param status 执行状态
|
||
*/
|
||
void CmsEngine::reportExecutionStatus(const ExecutionStatus& status)
|
||
{
|
||
nodeStatus_[status.nodeId] = status;
|
||
}
|
||
|
||
/**
|
||
* @brief 检查所有节点健康状态
|
||
*
|
||
* 异常判据:健康指数 < 0.5 或异常码 != 0 或心跳超时(距最后上报 > 30秒)。
|
||
*
|
||
* @return std::vector<ExecutionStatus> 异常节点列表
|
||
*/
|
||
std::vector<ExecutionStatus> CmsEngine::checkHealth() const
|
||
{
|
||
std::vector<ExecutionStatus> unhealthy;
|
||
const auto now = std::chrono::system_clock::now();
|
||
|
||
for (const auto& [nodeId, status] : nodeStatus_) {
|
||
(void)nodeId;
|
||
bool isUnhealthy = false;
|
||
|
||
if (status.healthIndex < 0.5) {
|
||
isUnhealthy = true;
|
||
}
|
||
if (status.errorCode != 0) {
|
||
isUnhealthy = true;
|
||
}
|
||
|
||
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
|
||
now - status.lastReport).count();
|
||
if (elapsed > 30) {
|
||
isUnhealthy = true;
|
||
}
|
||
|
||
if (isUnhealthy) {
|
||
unhealthy.push_back(status);
|
||
}
|
||
}
|
||
return unhealthy;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 用户会话管理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 创建用户会话
|
||
*
|
||
* 校验 userId 非空且不重复后存入会话表。
|
||
*
|
||
* @param session 用户会话
|
||
* @return true 创建成功
|
||
* @return false 用户已存在或 ID 为空
|
||
*/
|
||
bool CmsEngine::createSession(const UserSession& session)
|
||
{
|
||
if (session.userId.empty()) {
|
||
return false;
|
||
}
|
||
if (sessions_.find(session.userId) != sessions_.end()) {
|
||
return false;
|
||
}
|
||
sessions_[session.userId] = session;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 校验用户权限
|
||
*
|
||
* 检查用户会话的权限位图是否包含所需的权限掩码。
|
||
*
|
||
* @param userId 用户 ID
|
||
* @param permissionMask 所需权限位掩码
|
||
* @return true 有权限
|
||
* @return false 无权限或用户不存在
|
||
*/
|
||
bool CmsEngine::checkPermission(const std::string& userId,
|
||
uint64_t permissionMask) const
|
||
{
|
||
auto it = sessions_.find(userId);
|
||
if (it == sessions_.end()) {
|
||
return false;
|
||
}
|
||
return (it->second.permissionBitmap & permissionMask) == permissionMask;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 通知管理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 推送通知消息
|
||
*
|
||
* @param msg 通知消息
|
||
*/
|
||
void CmsEngine::pushNotification(const NotificationMessage& msg)
|
||
{
|
||
notifications_.push_back(msg);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取所有未读通知
|
||
*
|
||
* @return std::vector<NotificationMessage> 未读通知列表
|
||
*/
|
||
std::vector<NotificationMessage> CmsEngine::getUnreadNotifications() const
|
||
{
|
||
std::vector<NotificationMessage> unread;
|
||
for (const auto& msg : notifications_) {
|
||
if (!msg.isRead) {
|
||
unread.push_back(msg);
|
||
}
|
||
}
|
||
return unread;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
// 系统状态管理
|
||
// ══════════════════════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 切换系统运行模式
|
||
*
|
||
* 降级模式下不允许切换到其他模式(模拟故障隔离策略),其余模式可自由切换。
|
||
*
|
||
* @param newMode 目标模式
|
||
* @return true 切换成功
|
||
* @return false 切换被拒绝
|
||
*/
|
||
bool CmsEngine::switchMode(RunMode newMode)
|
||
{
|
||
if (systemContext_.currentMode == RunMode::Degraded && newMode != RunMode::Degraded) {
|
||
// 降级模式下不允许退出降级(模拟安全策略)
|
||
return false;
|
||
}
|
||
systemContext_.currentMode = newMode;
|
||
systemContext_.switchTime = std::chrono::system_clock::now();
|
||
systemContext_.consistencyMark = nextId_;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取当前系统状态上下文
|
||
*
|
||
* @return const SystemStateContext& 状态上下文
|
||
*/
|
||
const SystemStateContext& CmsEngine::getSystemContext() const
|
||
{
|
||
return systemContext_;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取引擎摘要信息
|
||
*
|
||
* @return std::string 包含事件数、方案数、节点数、未读通知数等
|
||
*/
|
||
std::string CmsEngine::getSummary() const
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "=== CMS Engine Summary ===\n"
|
||
<< " Events : " << events_.size() << "\n"
|
||
<< " Plans : " << plans_.size() << "\n"
|
||
<< " Templates : " << templates_.size() << "\n"
|
||
<< " Monitor Nodes : " << nodeStatus_.size() << "\n"
|
||
<< " Active Sessions : " << sessions_.size() << "\n"
|
||
<< " Notifications : " << notifications_.size() << "\n"
|
||
<< " Mode : ";
|
||
|
||
switch (systemContext_.currentMode) {
|
||
case RunMode::Idle: oss << "Idle"; break;
|
||
case RunMode::HumanLoop: oss << "HumanLoop"; break;
|
||
case RunMode::AutoExec: oss << "AutoExec"; break;
|
||
case RunMode::Degraded: oss << "Degraded"; break;
|
||
default: oss << "Unknown"; break;
|
||
}
|
||
oss << "\n============================";
|
||
return oss.str();
|
||
}
|