Files
datatrace/source/pq_app.h

271 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 为 guidmessageBody 是内部 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();