This commit is contained in:
lnk
2025-09-22 16:46:33 +08:00
parent 169aa9b34a
commit db8aa8c07d
8 changed files with 358 additions and 252 deletions

View File

@@ -2976,36 +2976,48 @@ std::vector<DeviceInfo> GenerateDeviceInfoFromLedger(const std::vector<terminal_
////////////////////////////////////////////////////////////////////////////////////////////////////录波文件通知
bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vector<std::string>& file_list_raw) {
bool assign_qvvr_file_list(const std::string& id,
ushort nCpuNo,
const std::vector<std::string>& file_list_raw) {
// ★新增:台账加锁(若上层已有锁,可移除本行)
std::lock_guard<std::mutex> lk(ledgermtx);
std::vector<std::string> file_names;
// 1. 提取文件名部分
for (const auto& full_path : file_list_raw) {
for (const auto& full_path_raw : file_list_raw) {
std::string full_path = sanitize(full_path_raw); // ★修改:清洗入参路径
size_t pos = full_path.find_last_of("/\\");
if (pos != std::string::npos && pos + 1 < full_path.size()) {
file_names.push_back(full_path.substr(pos + 1));
} else {
file_names.push_back(full_path);
}
std::string name = (pos != std::string::npos && pos + 1 < full_path.size())
? full_path.substr(pos + 1)
: full_path;
name = sanitize(name); // ★修改:清洗提取的文件名
file_names.push_back(name);
}
// ★可选:去重(如果 file_list_raw 里可能有重复)
std::sort(file_names.begin(), file_names.end());
file_names.erase(std::unique(file_names.begin(), file_names.end()), file_names.end());
// 2. 遍历终端
for (auto& dev : terminal_devlist) {
if (dev.terminal_id == id) { //根据终端id匹配终端
if (dev.terminal_id == id) { // 根据终端id匹配终端
for (auto& monitor : dev.line) {
try {
ushort monitor_seq = static_cast<ushort>(std::stoi(monitor.logical_device_seq));
if (monitor_seq == nCpuNo) { //根据监测点编号匹配监测点
// ★修改:清洗 logical_device_seq 再进行转换
std::string seq_str = sanitize(monitor.logical_device_seq);
ushort monitor_seq = static_cast<ushort>(std::stoi(seq_str));
if (monitor_seq == nCpuNo) { // 根据监测点编号匹配监测点
// 构造 qvvr_file
qvvr_file qfile;
qfile.file_name.assign(file_names.begin(), file_names.end()); //终端文件列表
qfile.is_download = false;
qfile.is_pair = false;
qfile.file_name.assign(file_names.begin(), file_names.end()); // 终端文件列表(已清洗)
qfile.is_download = false;
qfile.is_pair = false;
qfile.file_time_count = 0;
qfile.used_status =true;
qfile.used_status = true;
// 添加到唯一的 qvvrevent
monitor.qvvrevent.qvvrfile.push_back(std::move(qfile)); //记录暂态文件组
monitor.qvvrevent.qvvrfile.push_back(std::move(qfile)); // 记录暂态文件组
return true;
}
} catch (...) {
@@ -3017,7 +3029,6 @@ bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vect
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////下载成功通知
//提取下载路径的文件名
std::string extract_filename1(const std::string& path) {
@@ -3078,27 +3089,47 @@ bool SendAllQvvrFiles(qvvr_file& qfile, std::string& out_wavepath) {
}
//文件下载结束接口
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id) {
std::cout << "[update_qvvr_file_download] filename_with_mac=" << filename_with_mac
<< " terminal_id=" << terminal_id << std::endl;
bool update_qvvr_file_download(const std::string& filename_with_mac_in, const std::string& terminal_id) {
// ★ 先把原始入参清洗
std::string filename_with_mac = sanitize(filename_with_mac_in);
std::cout << "[update_qvvr_file_download] raw=" << filename_with_mac_in
<< " | sanitized=" << filename_with_mac
<< " | terminal_id=" << terminal_id << std::endl;
//台账加锁
std::lock_guard<std::mutex> lock(ledgermtx);
// 去除 mac 路径前缀,仅保留文件名
std::string filename = extract_filename1(filename_with_mac);
std::string filename = sanitize(extract_filename1(filename_with_mac));
// 提取逻辑序号(如 PQM1 → 1
size_t under_pos = filename.find('_');
if (under_pos == std::string::npos) return false;
// 提取逻辑序号(如 PQ_PQLD1 → 1
size_t under_pos1 = filename.find('_');
if (under_pos1 == std::string::npos) {
std::cout << "[DEBUG] 未找到 '_'filename=" << filename
<< "under_pos=npos返回 false\n";
return false;
}
size_t under_pos2 = filename.find('_', under_pos1 + 1);
std::string type_part = (under_pos2 == std::string::npos)
? filename.substr(0, under_pos1) // 兜底:只有一个下划线
: filename.substr(0, under_pos2); // 取到第二个下划线(得到 PQ_PQLD1
std::cout << "[DEBUG] type_part=" << type_part
<< " (under_pos1=" << under_pos1
<< ", under_pos2=" << under_pos2 << ")\n";
std::string type_part = filename.substr(0, under_pos); // PQMonitor_PQM1
size_t num_start = type_part.find_last_not_of("0123456789");
if (num_start == std::string::npos || num_start + 1 >= type_part.size()) return false;
if (num_start == std::string::npos || num_start + 1 >= type_part.size()) {
std::cout << "[DEBUG] 数字起始位置异常num_start=" << num_start
<< "type_part.size()=" << type_part.size()
<< "type_part=\"" << type_part << "\",返回 false\n";
return false;
}
std::string seq_str = type_part.substr(num_start + 1);
ushort logical_seq = static_cast<ushort>(std::stoi(seq_str)); // 逻辑序号
unsigned short logical_seq = static_cast<unsigned short>(std::stoul(seq_str));
std::cout << "[DEBUG] 解析到 logical_seq=" << logical_seq << "\n";
//找终端
for (auto& dev : terminal_devlist) {
@@ -3118,12 +3149,21 @@ bool update_qvvr_file_download(const std::string& filename_with_mac, const std::
// ★新增:不匹配时对比打印
std::cout << "[cmp-monitor-seq][NOT-MATCH]"
<< " monitor_id=" << monitor.monitor_id
<< " seq_in_ledger=\"" << seq_str << "\""
// ★ 这里之前打印的是 seq_str容易误导。改为 ledger 的原始串:
<< " seq_in_ledger_raw=\"" << monitor.logical_device_seq << "\""
<< " parsed=" << monitor_seq
<< " target_seq=" << logical_seq
<< std::endl;
continue;
}
else{
std::cout << "[cmp-monitor-seq][MATCH!!!]"
<< " monitor_id=" << monitor.monitor_id
<< " seq_in_ledger_raw=\"" << monitor.logical_device_seq << "\""
<< " parsed=" << monitor_seq
<< " target_seq=" << logical_seq
<< std::endl;
}
} catch (const std::exception& e) {
// ★新增:解析失败详细原因
std::cout << "[cmp-monitor-seq][PARSE-FAIL]"
@@ -3162,7 +3202,7 @@ bool update_qvvr_file_download(const std::string& filename_with_mac, const std::
std::set<std::string> s_name(qfile.file_name.begin(), qfile.file_name.end());
std::set<std::string> s_down;
for (const auto& path : qfile.file_download) {
s_down.insert(extract_filename1(path)); // 提取每个路径中的文件名
s_down.insert(sanitize(extract_filename1(path))); // 提取每个路径中的文件名
}
//打印s_name和s_down内容
@@ -4628,11 +4668,6 @@ void on_device_response_minimal(int response_code,
}
else {
// 准备日志用的 key
std::ostringstream mon_key_c, mon_key_d;
mon_key_c << "monitor." << matched_monitor->terminal_id << "." << matched_monitor->logical_device_seq << ".COM";
mon_key_d << "monitor." << matched_monitor->terminal_id << "." << matched_monitor->logical_device_seq << ".DATA";
// 2) 仅更新该监测点 recall_list 的首条,且要求处于 RUNNING
if (!matched_monitor->recall_list.empty()) {
RecallMonitor& front = matched_monitor->recall_list.front(); //取出首条
@@ -4651,7 +4686,7 @@ void on_device_response_minimal(int response_code,
<< " rc=" << response_code << std::endl; //错误响应码
//记录日志
DIY_ERRORLOG_CODE(mon_key_d.str().c_str(),static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%lld 至 %lld",mon_key_d.str().c_str(),front.StartTime,front.EndTime);
DIY_ERRORLOG_CODE(matched_monitor->monitor_id.c_str(),2,static_cast<int>(LogCode::LOG_CODE_RECALL),"【ERROR】监测点:%s 补招数据失败 - 失败时间点:%lld 至 %lld",matched_monitor->monitor_id.c_str(),front.StartTime,front.EndTime);
}
updated = true;
} else { //首条不是 RUNNING 状态,不应该收到这条响应
@@ -4902,6 +4937,157 @@ void on_device_response_minimal(int response_code,
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////记录暂态事件到本地
// 将一条暂态数据更新/写入到指定终端ID与逻辑序号的监测点
// 返回 true 表示已写入更新或追加false 表示未找到对应终端/监测点。
bool append_qvvr_event(const std::string& terminal_id,
int logical_seq, // 监测点序号(如 1
int nType, // 事件类型
double fPersisstime_sec, // 持续时间(秒)
double fMagnitude_pu, // 幅值pu
uint64_t triggerTimeMs, // 触发时间(毫秒)
int phase) // 相别
{
std::cout << "[append_qvvr_event] enter"
<< " tid=" << std::this_thread::get_id()
<< " terminal_id=" << terminal_id
<< " logical_seq=" << logical_seq
<< " type=" << nType
<< " per_s=" << fPersisstime_sec
<< " mag_pu=" << fMagnitude_pu
<< " time_ms=" << static_cast<unsigned long long>(triggerTimeMs)
<< " phase=" << phase
<< std::endl;
std::lock_guard<std::mutex> lk(ledgermtx);
std::cout << "[append_qvvr_event] lock acquired. terminal_devlist.size="
<< terminal_devlist.size() << std::endl;
// 1) 找终端
auto dev_it = std::find_if(terminal_devlist.begin(), terminal_devlist.end(),
[&](const terminal_dev& d){ return d.terminal_id == terminal_id; });
if (dev_it == terminal_devlist.end()) {
std::cout << "[append_qvvr_event][MISS] terminal not found: "
<< terminal_id << std::endl;
return false;
}
std::cout << "[append_qvvr_event][HIT] terminal_id=" << terminal_id
<< " monitors(line).size=" << dev_it->line.size()
<< std::endl;
// 2) 找监测点(按逻辑序号匹配:字符串等于 或 数值等于)
ledger_monitor* pMon = nullptr;
for (size_t i = 0; i < dev_it->line.size(); ++i) {
auto& m = dev_it->line[i];
bool eq_str = (m.logical_device_seq == std::to_string(logical_seq));
bool eq_num = false;
try {
if (!m.logical_device_seq.empty())
eq_num = (std::stoi(m.logical_device_seq) == logical_seq);
} catch (...) {
// 仅调试提示,不改变原逻辑
std::cout << "[append_qvvr_event][monitor #" << i
<< "] stoi fail, logical_device_seq=\""
<< m.logical_device_seq << "\"" << std::endl;
}
std::cout << "[append_qvvr_event][probe monitor #" << i
<< "] monitor_id=" << m.monitor_id
<< " logical_device_seq=\"" << m.logical_device_seq << "\""
<< " eq_str=" << eq_str << " eq_num=" << eq_num << std::endl;
if (eq_str || eq_num) { pMon = &m; break; }
}
if (!pMon) {
std::cout << "[append_qvvr_event][MISS] monitor not found by seq="
<< logical_seq << " in terminal_id=" << terminal_id << std::endl;
return false;
}
std::cout << "[append_qvvr_event][HIT] monitor_id=" << pMon->monitor_id
<< " logical_device_seq=" << pMon->logical_device_seq
<< " qvvrdata.size=" << pMon->qvvrevent.qvvrdata.size()
<< std::endl;
qvvr_event& qe = pMon->qvvrevent;
// 3) 先尝试“就地更新”(同类型 + 同时间戳 视为同一事件)
for (size_t i = 0; i < qe.qvvrdata.size(); ++i) {
auto& q = qe.qvvrdata[i];
if (q.QVVR_type == nType && q.QVVR_time == triggerTimeMs) {
std::cout << "[append_qvvr_event][UPDATE match idx=" << i << "]"
<< " old{used=" << q.used_status
<< ", per=" << q.QVVR_PerTime
<< ", mag=" << q.QVVR_Amg
<< ", phase=" << q.phase
<< "} -> new{used=true"
<< ", per=" << fPersisstime_sec
<< ", mag=" << fMagnitude_pu
<< ", phase=" << phase
<< "}" << std::endl;
q.used_status = true;
q.QVVR_PerTime = fPersisstime_sec;
q.QVVR_Amg = fMagnitude_pu;
q.phase = phase;
std::cout << "[append_qvvr_event] done(update)."
<< std::endl;
return true;
}
}
// 4) 复用空槽used_status=false
for (size_t i = 0; i < qe.qvvrdata.size(); ++i) {
auto& q = qe.qvvrdata[i];
if (!q.used_status) {
std::cout << "[append_qvvr_event][REUSE idx=" << i << "]"
<< " set{type=" << nType
<< ", time_ms=" << static_cast<unsigned long long>(triggerTimeMs)
<< ", per=" << fPersisstime_sec
<< ", mag=" << fMagnitude_pu
<< ", phase=" << phase
<< "}" << std::endl;
q.used_status = true;
q.QVVR_type = nType;
q.QVVR_time = triggerTimeMs;
q.QVVR_PerTime = fPersisstime_sec;
q.QVVR_Amg = fMagnitude_pu;
q.phase = phase;
std::cout << "[append_qvvr_event] done(reuse)."
<< std::endl;
return true;
}
}
// 5) 直接追加
qvvr_data q{};
q.used_status = true;
q.QVVR_type = nType;
q.QVVR_time = triggerTimeMs; // ms
q.QVVR_PerTime = fPersisstime_sec; // s
q.QVVR_Amg = fMagnitude_pu;
q.phase = phase;
qe.qvvrdata.push_back(q);
std::cout << "[append_qvvr_event][PUSH_BACK]"
<< " new_size=" << qe.qvvrdata.size()
<< " last_idx=" << (qe.qvvrdata.empty() ? -1 : (int)qe.qvvrdata.size()-1)
<< " {type=" << nType
<< ", time_ms=" << static_cast<unsigned long long>(triggerTimeMs)
<< ", per=" << fPersisstime_sec
<< ", mag=" << fMagnitude_pu
<< ", phase=" << phase
<< "}" << std::endl;
std::cout << "[append_qvvr_event] done(push_back)."
<< std::endl;
return true;
}