271 lines
11 KiB
C++
271 lines
11 KiB
C++
#pragma once
|
||
|
||
/*
|
||
* pq_app.h
|
||
*
|
||
* 这是整个工具的公共边界文件:
|
||
* - interface.cpp 负责 Win32 GUI,通过这些结构体读取/显示配置和台账。
|
||
* - mq.cpp 负责 HTTP 台账/ICD 获取、RocketMQ 初始化和数据追踪落盘。
|
||
* - main.cpp 负责 JSON/XML 映射解析,生成 Excel 2003 XML 格式的 .xls。
|
||
* - icd_mapper.cpp 负责把外部 ICD 中的 DOI 描述补写到工作簿。
|
||
*
|
||
* 头文件中只放跨模块共享的数据结构和函数声明,不放 Win32/RocketMQ 的实现细节。
|
||
*/
|
||
|
||
#include <functional>
|
||
#include <string>
|
||
#include <utility>
|
||
#include <vector>
|
||
|
||
/*
|
||
* 工具运行配置。
|
||
*
|
||
* 输入来源:
|
||
* 1. pqDefaultConfig() 给出默认值;
|
||
* 2. GUI 中 readConfig() 会用用户界面上的编辑框覆盖默认值;
|
||
* 3. 命令行模式直接使用 main.cpp 中传入的 XML/JSON/origin 路径。
|
||
*
|
||
* 关键字段:
|
||
* frontInst/frontIp 前置节点标识和 IP,参与台账请求和追踪消息。
|
||
* terminalStatus 终端状态过滤条件,支持 JSON 数组字符串,如 "[0]"。
|
||
* monitorStatus 预留的测点状态过滤字段。
|
||
* icdFlag 为 "1" 时按 devType 请求 ICD 列表,为其他值时请求全量/默认列表。
|
||
* dataStatTopic 统计数据 Topic,对应 frontType=cfg_stat_data。
|
||
* dataRealtimeTopic 实时数据 Topic,对应 frontType=cfg_3s_data。
|
||
* topicAsk/tagAsk/keyAsk cfg_3s_data 发送 set_log 后的实时数据请求目标。
|
||
* dataTopic/dataTag/dataKey GUI 读取 frontType 后会设置成当前活跃数据 Topic/Tag/Key。
|
||
* traceRootDir 每次“数据追踪”按进程/装置/测点保存 JSON、origin 和报表的根目录。
|
||
*
|
||
* 输出影响:
|
||
* xmlSaveDir、jsonDataPath、originPaths、outputPath、traceRootDir 控制程序落盘位置。
|
||
*/
|
||
struct PqToolConfig {
|
||
std::string frontInst = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string frontIp = "192.168.1.68";
|
||
std::string terminalStatus = "[0]";
|
||
std::string monitorStatus = "[1,2]";
|
||
std::string icdFlag = "0";
|
||
|
||
std::string webDevice = "http://192.168.1.68:10202/nodeDevice/nodeDeviceList";
|
||
std::string webIcd = "http://192.168.1.68:10202/icd/icdPathList";
|
||
std::string webFiledownload = "http://192.168.1.68:10207/file/download";
|
||
std::string xmlSaveDir = "runtime\\downloaded_xml";
|
||
|
||
std::string producer = "TRACE_PRODUCER";
|
||
std::string ipport = "192.168.1.68:9876";
|
||
std::string producerAccessKey = "rmqroot";
|
||
std::string producerSecretKey = "001@#njcnmq";
|
||
std::string topicLOG = "ask_log_Topic";
|
||
std::string tagLOG = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string keyLOG = "Test_Keys";
|
||
std::string topicAsk = "ask_data_Topic";
|
||
std::string tagAsk = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string keyAsk = "Test_Keys";
|
||
|
||
std::string consumer = "TRACE_CONSUMER";
|
||
std::string consumerIpport = "192.168.1.68:9876";
|
||
std::string consumerAccessKey = "rmqroot";
|
||
std::string consumerSecretKey = "001@#njcnmq";
|
||
std::string dataStatTopic = "MQ_INST_1697676490574298_Bm3DLamM%LN_Topic";
|
||
std::string dataRealtimeTopic = "MQ_INST_1697676490574298_Bm3DLamM%Real_Time_Data_Topic";
|
||
std::string dataTopic = "MQ_INST_1697676490574298_Bm3DLamM%LN_Topic";
|
||
std::string dataStatTag = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string dataStatKey = "Test_Keys";
|
||
std::string dataRealtimeTag = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string dataRealtimeKey = "Test_Keys";
|
||
std::string dataTag = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string dataKey = "Test_Keys";
|
||
std::string traceTopic = "Trace_Topic";
|
||
std::string traceTag = "6c2adb324940e19e208d717f4970f2ee";
|
||
std::string traceKey = "Test_Key";
|
||
|
||
std::string xmlPath;
|
||
std::string jsonDataPath = "runtime\\json\\jsondata.txt";
|
||
std::vector<std::string> jsonDataPaths;
|
||
std::vector<std::string> originPaths;
|
||
std::string outputPath = "runtime\\final_sorted.xls";
|
||
std::string traceRootDir = "runtime\\trace_data";
|
||
};
|
||
|
||
/*
|
||
* 台账中的单个测点。
|
||
*
|
||
* 输入:pqFetchLedgerAndIcd() 从 WebDevice 接口的 monitorData 数组解析。
|
||
* 输出:GUI 左侧树显示;数据追踪时 monitor.id 会写入 MQ 追踪消息。
|
||
*/
|
||
struct PqLedgerMonitor {
|
||
std::string id;
|
||
std::string name;
|
||
std::string lineNo;
|
||
std::string voltageLevel;
|
||
std::string connectType;
|
||
std::string status;
|
||
std::vector<std::pair<std::string, std::string>> fields;
|
||
};
|
||
|
||
/*
|
||
* 台账中的单个装置。
|
||
*
|
||
* 输入:pqFetchLedgerAndIcd() 从 WebDevice 接口的 data 数组解析。
|
||
* 输出:
|
||
* - GUI 按 processNo -> device -> monitor 组织成树;
|
||
* - devType 用于匹配并下载对应 ICD/XML;
|
||
* - xmlPath 记录当前装置优先使用的 XML 模板。
|
||
*/
|
||
struct PqLedgerDevice {
|
||
std::string id;
|
||
std::string name;
|
||
std::string ip;
|
||
std::string status;
|
||
std::string devType;
|
||
std::string devKey;
|
||
std::string orgName;
|
||
std::string stationName;
|
||
std::string subName;
|
||
std::string manufacturer;
|
||
std::string port;
|
||
std::string series;
|
||
std::string updateTime;
|
||
std::string processNo;
|
||
std::string maxProcessNum;
|
||
std::string xmlPath;
|
||
std::vector<std::pair<std::string, std::string>> fields;
|
||
std::vector<PqLedgerMonitor> monitors;
|
||
};
|
||
|
||
// 日志回调:业务函数只发字符串,GUI/命令行决定显示到日志框还是控制台。
|
||
using PqLogFn = std::function<void(const std::string&)>;
|
||
|
||
/*
|
||
* MQ/追踪过程中抛给 GUI 的事件。
|
||
*
|
||
* kind:
|
||
* sent 已构造并发送/落盘的数据追踪请求;
|
||
* data DATATopic 收到的 jsondata 数据;
|
||
* trace TraceTopic 收到的 origin/原始 MMS 数据。
|
||
*
|
||
* path/traceDir 让 GUI 能把事件定位到具体追踪目录并自动刷新解析预览。
|
||
*/
|
||
struct PqMqEvent {
|
||
std::string kind;
|
||
std::string title;
|
||
std::string body;
|
||
std::string path;
|
||
std::string monitorId;
|
||
std::string traceDir;
|
||
};
|
||
|
||
using PqMqEventFn = std::function<void(const PqMqEvent&)>;
|
||
|
||
// 默认配置。mq.cpp 会把运行期路径修正到 exe 所在目录旁的 runtime 目录。
|
||
PqToolConfig pqDefaultConfig();
|
||
|
||
/*
|
||
* 获取台账并下载 ICD/XML。
|
||
*
|
||
* 输入:cfg 中的 WebDevice/WebIcd/WebFiledownload、状态过滤和保存目录。
|
||
* 输出:
|
||
* devices 装置和测点列表;
|
||
* firstXmlPath 第一个成功下载的 XML,用于自动填充 GUI 的 XML 路径;
|
||
* return true 表示接口请求和解析流程完成,异常会抛出到调用方。
|
||
*/
|
||
bool pqFetchLedgerAndIcd(const PqToolConfig& cfg,
|
||
std::vector<PqLedgerDevice>& devices,
|
||
std::string& firstXmlPath,
|
||
PqLogFn log);
|
||
|
||
/*
|
||
* 初始化 RocketMQ 运行时。
|
||
*
|
||
* 输入:生产者、消费者、Topic、Tag、Key、NameServer 和鉴权配置。
|
||
* 输出:运行配置会保存到 runtime\json\mq_runtime_config.json;
|
||
* 如果 DLL 不可用,函数仍返回 true,但后续发送会落到 mq_outbox_*.jsonl。
|
||
*/
|
||
bool pqInitializeMq(const PqToolConfig& cfg, PqLogFn log, PqMqEventFn event = {});
|
||
|
||
/*
|
||
* 构造数据追踪消息体。
|
||
*
|
||
* 输入:
|
||
* device.processNo 统计数据追踪时参与 processNo;实时数据固定 processNo=0。
|
||
* monitor.id 写入 messageBody.id,代表追踪的测点。
|
||
* frontType cfg_stat_data 或 cfg_3s_data。
|
||
* 输出:外层 RocketMQ JSON 字符串,key 为 guid,messageBody 是内部 JSON 字符串。
|
||
*/
|
||
std::string pqBuildTracePayload(const PqToolConfig& cfg,
|
||
const PqLedgerDevice& device,
|
||
const PqLedgerMonitor& monitor,
|
||
const std::string& frontType);
|
||
|
||
/*
|
||
* 发送一次数据追踪请求。
|
||
*
|
||
* 执行步骤:
|
||
* 1. 构造 payload 并在 trace_context.json 中记录本次追踪上下文;
|
||
* 2. 写 sent_trace_request.json 和 last_trace_request.json,便于复盘;
|
||
* 3. RocketMQ 可用时先同步发送到 topicLOG/tagLOG/keyLOG;
|
||
* 4. cfg_3s_data 再发送实时数据请求到 topicAsk/tagAsk/keyAsk;
|
||
* 5. RocketMQ 不可用时追加到对应 Topic 的 mq_outbox_*.jsonl 作为兜底。
|
||
*/
|
||
bool pqSendTraceRequest(const PqToolConfig& cfg,
|
||
const PqLedgerDevice& device,
|
||
const PqLedgerMonitor& monitor,
|
||
const std::string& frontType,
|
||
PqLogFn log,
|
||
PqMqEventFn event = {});
|
||
|
||
// 清空某个追踪目录下的 txt/json/jsonl/log 文本记录,保留目录本身。
|
||
void pqClearTraceRecords(const PqToolConfig& cfg,
|
||
const PqLedgerDevice& device,
|
||
const PqLedgerMonitor& monitor);
|
||
|
||
// 按 traceRootDir/process_x/device_x/monitor_x 生成稳定追踪目录。
|
||
std::string pqTraceDirectoryFor(const PqToolConfig& cfg,
|
||
const PqLedgerDevice& device,
|
||
const PqLedgerMonitor& monitor);
|
||
|
||
// 为装置寻找 XML:优先 device.xmlPath,其次 icd_response.json 下载缓存,最后 cfg.xmlPath。
|
||
std::string pqFindDeviceXmlPath(const PqToolConfig& cfg, const PqLedgerDevice& device);
|
||
|
||
/*
|
||
* 解析 XML + 单个 jsondata + 多个 origin,生成 Excel XML 工作簿。
|
||
* 这是旧调用形式,内部会转成 vector 版本。
|
||
*/
|
||
bool pqRunParser(const std::string& xmlPath,
|
||
const std::string& jsonPath,
|
||
const std::vector<std::string>& originPaths,
|
||
const std::string& outPath,
|
||
std::string* err,
|
||
const std::string& frontType = "");
|
||
|
||
/*
|
||
* 解析 XML + 多个 jsondata + 多个 origin,生成 Excel XML 工作簿。
|
||
*
|
||
* 输入:
|
||
* xmlPath ICD/XML 映射模板;
|
||
* jsonPaths DATATopic 统计/实时数据,可按 DATA_TYPE 分桶;
|
||
* originPaths TraceTopic 原始 MMS 数据,用于值对比和未匹配列表;
|
||
* frontType 为空表示生成所有工作表;cfg_stat_data/cfg_3s_data 表示只生成对应流程。
|
||
* 输出:
|
||
* outPath Excel 2003 XML 格式的 .xls;
|
||
* err 失败时写入异常信息;
|
||
* return true 成功,false 失败。
|
||
*/
|
||
bool pqRunParser(const std::string& xmlPath,
|
||
const std::vector<std::string>& jsonPaths,
|
||
const std::vector<std::string>& originPaths,
|
||
const std::string& outPath,
|
||
std::string* err,
|
||
const std::string& frontType = "");
|
||
|
||
/*
|
||
* 把外部 ICD 中 LN/DOI 的 desc 导入到工作簿“未匹配的原始数据”页。
|
||
* 通过原始路径前缀匹配 DO 路径,帮助解释没有在当前映射中匹配到的 origin 数据。
|
||
*/
|
||
bool pqApplyIcdDescriptionsToWorkbook(const std::string& icdPath,
|
||
const std::string& workbookPath,
|
||
std::string* message = nullptr);
|
||
|
||
// GUI 入口。main.cpp 无命令行参数时调用,内部创建 Win32 主窗口和消息循环。
|
||
int runPqGuiApp();
|