add qvvr interface
This commit is contained in:
@@ -2703,7 +2703,26 @@ bool extract_timestamp_from_cfg_file(const std::string& cfg_path, long long& sta
|
|||||||
return start_tm > 0 && trig_tm > 0;
|
return start_tm > 0 && trig_tm > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compare_qvvr_and_file(const std::string& cfg_path, const std::vector<qvvr_data>& data_list) {
|
||||||
|
long long start_tm = 0;
|
||||||
|
long long trig_tm = 0;
|
||||||
|
|
||||||
|
// 提取 .cfg 文件中的时间戳
|
||||||
|
if (!extract_timestamp_from_cfg_file(cfg_path, start_tm, trig_tm)) {
|
||||||
|
std::cerr << "Failed to extract timestamp from cfg file: " << cfg_path << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历所有暂态事件,查找与 trig_tm 匹配的
|
||||||
|
for (const auto& data : data_list) {
|
||||||
|
long long diff = static_cast<long long>(data.QVVR_time) - trig_tm;
|
||||||
|
if (std::abs(diff) <= 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////数据转换函数
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////数据转换函数
|
||||||
// DataArrayItem to_json
|
// DataArrayItem to_json
|
||||||
void to_json(nlohmann::json& j, const DataArrayItem& d) {
|
void to_json(nlohmann::json& j, const DataArrayItem& d) {
|
||||||
@@ -2844,7 +2863,7 @@ bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vect
|
|||||||
qfile.is_download = false;
|
qfile.is_download = false;
|
||||||
qfile.is_pair = false;
|
qfile.is_pair = false;
|
||||||
qfile.file_time_count = 0;
|
qfile.file_time_count = 0;
|
||||||
qfile.file_start =false;
|
qfile.used_status =true;
|
||||||
|
|
||||||
// 添加到唯一的 qvvrevent
|
// 添加到唯一的 qvvrevent
|
||||||
monitor.qvvrevent.qvvrfile.push_back(std::move(qfile)); //记录暂态文件组
|
monitor.qvvrevent.qvvrfile.push_back(std::move(qfile)); //记录暂态文件组
|
||||||
@@ -2861,72 +2880,158 @@ bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vect
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////下载成功通知
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////下载成功通知
|
||||||
|
//提取下载路径的文件名
|
||||||
|
std::string extract_filename(const std::string& path) {
|
||||||
|
size_t pos = path.find_last_of("/\\");
|
||||||
|
return (pos != std::string::npos) ? path.substr(pos + 1) : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送匹配的所有录波文件
|
||||||
|
bool SendAllQvvrFiles(qvvr_file& qfile, std::string& out_wavepath) {
|
||||||
|
std::vector<std::string> wavepaths;
|
||||||
|
std::string first_wavepath;
|
||||||
|
bool send_success = true;
|
||||||
|
|
||||||
|
for (const auto& file_localpath : qfile.file_download) {
|
||||||
|
std::string file_cloudpath = "comtrade/" + file_localpath;
|
||||||
|
std::string wavepath_result;
|
||||||
|
|
||||||
|
// 发送本地文件到远端,返回 wavepath
|
||||||
|
SOEFileWeb(const_cast<std::string&>(file_localpath), file_cloudpath, wavepath_result);
|
||||||
|
|
||||||
|
// 如果失败,重发一次
|
||||||
|
if (wavepath_result.empty()) {
|
||||||
|
std::cerr << "[SOEFileWeb] Warning: first send failed for file: " << file_localpath << ", retrying...\n";
|
||||||
|
SOEFileWeb(const_cast<std::string&>(file_localpath), file_cloudpath, wavepath_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wavepath_result.empty()) {
|
||||||
|
send_success = false;
|
||||||
|
std::cerr << "[SOEFileWeb] Failed: wavepath empty for file: " << file_localpath << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wavepaths.empty()) {
|
||||||
|
first_wavepath = wavepath_result;
|
||||||
|
} else if (wavepath_result != first_wavepath) {
|
||||||
|
send_success = false;
|
||||||
|
std::cerr << "[SOEFileWeb] Mismatch wavepath: " << wavepath_result
|
||||||
|
<< " vs " << first_wavepath << "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wavepaths.push_back(wavepath_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数量是否一致
|
||||||
|
if (!send_success || wavepaths.size() != qfile.file_download.size()) {
|
||||||
|
std::cerr << "[SOEFileWeb] Failed to send all qvvr files. "
|
||||||
|
<< "Sent: " << wavepaths.size()
|
||||||
|
<< ", Expected: " << qfile.file_download.size() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_wavepath = first_wavepath; // 返回统一的 wavepath
|
||||||
|
|
||||||
|
std::cout << "[SOEFileWeb] Success: all files sent for qfile. Wavepath = "
|
||||||
|
<< first_wavepath << "\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件下载结束接口
|
||||||
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id) {
|
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id) {
|
||||||
// 去除 mac 路径前缀
|
// 去除 mac 路径前缀,仅保留文件名
|
||||||
size_t pos = filename_with_mac.find_last_of("/\\");
|
std::string filename = extract_filename(filename_with_mac);
|
||||||
std::string filename = (pos != std::string::npos) ? filename_with_mac.substr(pos + 1) : filename_with_mac;
|
|
||||||
|
|
||||||
// 提取逻辑序号(如 PQM1 → 1)
|
// 提取逻辑序号(如 PQM1 → 1)
|
||||||
size_t under_pos = filename.find('_');
|
size_t under_pos = filename.find('_');
|
||||||
if (under_pos == std::string::npos) return false;
|
if (under_pos == std::string::npos) return false;
|
||||||
|
|
||||||
std::string type_part = filename.substr(0, under_pos); //PQMonitor_PQM1
|
std::string type_part = filename.substr(0, under_pos); // PQMonitor_PQM1
|
||||||
size_t num_start = type_part.find_last_not_of("0123456789");
|
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()) return false;
|
||||||
|
|
||||||
std::string seq_str = type_part.substr(num_start + 1);
|
std::string seq_str = type_part.substr(num_start + 1);
|
||||||
ushort logical_seq = static_cast<ushort>(std::stoi(seq_str));
|
ushort logical_seq = static_cast<ushort>(std::stoi(seq_str)); // 逻辑序号
|
||||||
|
|
||||||
for (auto& dev : terminal_devlist) {
|
for (auto& dev : terminal_devlist) {
|
||||||
if (dev.terminal_id != terminal_id) continue;
|
if (dev.terminal_id != terminal_id) continue;
|
||||||
|
|
||||||
for (auto& monitor : dev.line) {
|
for (auto& monitor : dev.line) {
|
||||||
try {
|
try {
|
||||||
|
// 将监测点台账中的 logical_device_seq 转换为数字进行匹配
|
||||||
ushort monitor_seq = static_cast<ushort>(std::stoi(monitor.logical_device_seq));
|
ushort monitor_seq = static_cast<ushort>(std::stoi(monitor.logical_device_seq));
|
||||||
if (monitor_seq != logical_seq) continue;
|
if (monitor_seq != logical_seq) continue;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
continue;
|
continue; // logical_device_seq 非法,跳过
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配监测点下 qvvrfile 中的 file_name
|
// 匹配监测点下 qvvrfile 中的 file_name
|
||||||
for (auto& qfile : monitor.qvvrevent.qvvrfile) {
|
for (auto& qfile : monitor.qvvrevent.qvvrfile) {
|
||||||
|
// file_name 中是文件名,需与提取的 filename 比较
|
||||||
auto it = std::find(qfile.file_name.begin(), qfile.file_name.end(), filename);
|
auto it = std::find(qfile.file_name.begin(), qfile.file_name.end(), filename);
|
||||||
if (it != qfile.file_name.end()) {
|
if (it != qfile.file_name.end()) {
|
||||||
// 添加到 file_download(去重)
|
// 添加到 file_download(记录完整路径,避免重复)
|
||||||
if (std::find(qfile.file_download.begin(), qfile.file_download.end(), filename) == qfile.file_download.end()) {
|
if (std::find(qfile.file_download.begin(), qfile.file_download.end(), filename_with_mac) == qfile.file_download.end()) {
|
||||||
qfile.file_download.push_back(filename);
|
qfile.file_download.push_back(filename_with_mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
qfile.file_time_count = 0;
|
qfile.file_time_count = 0; // 文件下载开始后,计时归零
|
||||||
qfile.file_start = true; //开始下载文件
|
|
||||||
|
|
||||||
// 检查 file_download 是否与 file_name 完全一致(集合相同)//每次下载都会对比
|
// file_download 中是完整路径,需提取文件名后与 file_name 做集合比较
|
||||||
std::set<std::string> s_name(qfile.file_name.begin(), qfile.file_name.end());
|
std::set<std::string> s_name(qfile.file_name.begin(), qfile.file_name.end());
|
||||||
std::set<std::string> s_down(qfile.file_download.begin(), qfile.file_download.end());
|
std::set<std::string> s_down;
|
||||||
|
for (const auto& path : qfile.file_download) {
|
||||||
|
s_down.insert(extract_filename(path)); // 提取每个路径中的文件名
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 file_download 是否与 file_name 完全一致(集合相同)
|
||||||
if (s_name == s_down) {
|
if (s_name == s_down) {
|
||||||
qfile.is_download = true; //全部下载完成
|
qfile.is_download = true; // 全部下载完成
|
||||||
|
|
||||||
// 找到其中的 .cfg 文件进行匹配
|
// 找到其中的 .cfg 文件进行匹配
|
||||||
for (const auto& f : qfile.file_download) {
|
for (const auto& fpath : qfile.file_download) {
|
||||||
if (f.size() >= 4 && f.substr(f.size() - 4) == ".cfg") {
|
std::string fname = extract_filename(fpath);
|
||||||
if (compare_qvvr_and_file(f)) {//提取文件时标和监测点事件的时标匹配
|
if (fname.size() >= 4 && fname.substr(fname.size() - 4) == ".cfg") {
|
||||||
qfile.is_pair = true;
|
// 提取文件时标和监测点事件的时标匹配
|
||||||
//发送所有文件
|
if (compare_qvvr_and_file(fpath, monitor.qvvrevent.qvvrdata)) {
|
||||||
|
qfile.is_pair = true; // 文件与事件匹配成功
|
||||||
|
|
||||||
//发送暂态事件
|
// 发送所有文件(已下载完成)
|
||||||
|
std::string wavepath;
|
||||||
|
if (SendAllQvvrFiles(qfile, wavepath)) {
|
||||||
|
//文件发送成功后更新事件
|
||||||
|
transfer_json_qvvr_data(terminal_id,
|
||||||
|
logical_seq,
|
||||||
|
monitor.qvvrevent.qvvrdata.QVVR_Amg,
|
||||||
|
monitor.qvvrevent.qvvrdata.QVVR_PerTime,
|
||||||
|
monitor.qvvrevent.qvvrdata.QVVR_time,
|
||||||
|
monitor.qvvrevent.qvvrdata.QVVR_type,
|
||||||
|
monitor.qvvrevent.qvvrdata.phase,
|
||||||
|
wavepath);
|
||||||
|
|
||||||
|
// 清除暂态数据
|
||||||
|
monitor.qvvrevent.qvvrfile.clear();
|
||||||
|
monitor.qvvrevent.qvvrdata.clear();
|
||||||
|
|
||||||
|
// 删除上传成功的文件
|
||||||
|
for (const auto& uploaded_file : qfile.file_download) {
|
||||||
|
if (std::remove(uploaded_file.c_str()) != 0) {
|
||||||
|
std::cerr << "[Cleanup] Failed to delete file: " << uploaded_file << "\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "[Cleanup] Deleted uploaded file: " << uploaded_file << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break; // 只处理第一个 cfg 文件
|
break; // 只处理第一个 cfg 文件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true; // 当前文件处理成功
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false; // 未匹配到终端ID或逻辑序号对应的监测点
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1149,32 +1149,24 @@ static void scanAndResendOfflineFiles(const std::string& dirPath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int transfer_json_qvvr_data(unsigned int func_type, int monitor_id,
|
int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
|
||||||
double mag, double dur, long long start_tm, long long end_tm, int dis_kind,
|
double mag, double dur, long long start_tm, int dis_kind,int phase,
|
||||||
const std::string& uuid_cfg, const std::string& uuid_dat,
|
const std::string& wavepath) {
|
||||||
const std::string& mp_id, const std::string& Qvvr_rptname, const std::string& devtype) {
|
|
||||||
|
|
||||||
// 监测点日志的 key, lnk20250526
|
// 监测点日志的 key, lnk20250526
|
||||||
std::string full_key_m_c = "monitor." + mp_id + ".COM";
|
std::string full_key_m_c = "monitor." + std::to_string(monitor_id) + ".COM";
|
||||||
std::string full_key_m_d = "monitor." + mp_id + ".DATA";
|
std::string full_key_m_d = "monitor." + std::to_string(monitor_id) + ".DATA";
|
||||||
// 监测点日志的 key, lnk20250526
|
// 监测点日志的 key, lnk20250526
|
||||||
|
|
||||||
// 获取装置类型的映射配置
|
if (dev_id.empty()) {
|
||||||
XmlConfig c_xmlcfg;
|
std::cout << "dev_id is null" << std::endl;
|
||||||
if (xmlinfo_list.count(devtype)) {
|
|
||||||
c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;
|
|
||||||
} else {
|
|
||||||
c_xmlcfg = xmlcfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mp_id.empty()) {
|
|
||||||
std::cout << "mp_id is null" << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造 JSON 对象
|
// 构造 JSON 对象
|
||||||
json root;
|
json root;
|
||||||
root["monitorId"] = mp_id;
|
root["devId"] = dev_id;
|
||||||
|
root["CpuNo"] = monitor_id;
|
||||||
root["amplitude"] = mag;
|
root["amplitude"] = mag;
|
||||||
root["duration"] = dur;
|
root["duration"] = dur;
|
||||||
root["eventType"] = dis_kind;
|
root["eventType"] = dis_kind;
|
||||||
@@ -1189,21 +1181,9 @@ int transfer_json_qvvr_data(unsigned int func_type, int monitor_id,
|
|||||||
std::string start_time_str = start_time_stream.str();
|
std::string start_time_str = start_time_stream.str();
|
||||||
|
|
||||||
root["startTime"] = start_time_str;
|
root["startTime"] = start_time_str;
|
||||||
root["wavePath"] = uuid_dat; //接口提供了两个文件名入参,实际上名字一样只用一个,可优化
|
root["wavePath"] = wavepath;
|
||||||
|
root["phase"] = phase;
|
||||||
|
|
||||||
if (c_xmlcfg.WavePhasicFlag == "1") { //映射配置分相
|
|
||||||
if (Qvvr_rptname.find(c_xmlcfg.WavePhasicA) != std::string::npos) {
|
|
||||||
root["phase"] = "A";
|
|
||||||
} else if (Qvvr_rptname.find(c_xmlcfg.WavePhasicB) != std::string::npos) {
|
|
||||||
root["phase"] = "B";
|
|
||||||
} else if (Qvvr_rptname.find(c_xmlcfg.WavePhasicC) != std::string::npos) {
|
|
||||||
root["phase"] = "C";
|
|
||||||
} else {
|
|
||||||
root["phase"] = "unknow";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
root["phase"] = "unknow"; //不分相
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string json_string = root.dump(4);
|
std::string json_string = root.dump(4);
|
||||||
std::cout << json_string << std::endl;
|
std::cout << json_string << std::endl;
|
||||||
@@ -1212,7 +1192,7 @@ int transfer_json_qvvr_data(unsigned int func_type, int monitor_id,
|
|||||||
std::string response;
|
std::string response;
|
||||||
SendJsonAPI_web(WEB_EVENT, "", json_string, response);
|
SendJsonAPI_web(WEB_EVENT, "", json_string, response);
|
||||||
|
|
||||||
// ================ 插入新功能 =========================
|
// ================ 暂态重发功能 =========================
|
||||||
if (!response.empty()) {
|
if (!response.empty()) {
|
||||||
try {
|
try {
|
||||||
json j_r = json::parse(response);
|
json j_r = json::parse(response);
|
||||||
@@ -1254,13 +1234,7 @@ int transfer_json_qvvr_data(unsigned int func_type, int monitor_id,
|
|||||||
|
|
||||||
void qvvr_test()
|
void qvvr_test()
|
||||||
{
|
{
|
||||||
char uuid_cfg[] = {"/comtrade/"};
|
|
||||||
char uuid_dat[] = {"/comtrade/"};
|
|
||||||
char mp_id[] = {"qvvrtest123"};
|
|
||||||
char Qvvr_rptname[] = {"unknow"};
|
|
||||||
char devtype[] = {"01"};
|
|
||||||
|
|
||||||
transfer_json_qvvr_data(1, 123456789, 220, 180, 1730894400.123, 1730894580, 1210001,uuid_cfg,uuid_dat,mp_id,Qvvr_rptname,devtype);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////通用接口响应
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////通用接口响应
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
//录波文件和暂态事件
|
//录波文件和暂态事件
|
||||||
class qvvr_data
|
class qvvr_data
|
||||||
{
|
{
|
||||||
int used_status; //是否占用
|
bool used_status; //是否占用
|
||||||
int QVVR_type; //暂态类型
|
int QVVR_type; //暂态类型
|
||||||
uint64_t QVVR_time; //暂态开始时间 unsigned longlong
|
uint64_t QVVR_time; //暂态开始时间 unsigned longlong
|
||||||
double QVVR_PerTime; //暂态持续时间
|
double QVVR_PerTime; //暂态持续时间
|
||||||
@@ -62,7 +62,7 @@ class qvvr_data
|
|||||||
|
|
||||||
class qvvr_file
|
class qvvr_file
|
||||||
{
|
{
|
||||||
bool file_start;
|
bool used_status;
|
||||||
int file_time_count; //组内文件下载时间计数(第一个文件下载后十分钟内如果其他文件没下载全或者下载全了没匹配事件则将已下载的文件都移到备份区comtrade_bak)
|
int file_time_count; //组内文件下载时间计数(第一个文件下载后十分钟内如果其他文件没下载全或者下载全了没匹配事件则将已下载的文件都移到备份区comtrade_bak)
|
||||||
bool is_download; //文件是否下载完全,最后一个文件下载成功后对比成功则更新这个标志
|
bool is_download; //文件是否下载完全,最后一个文件下载成功后对比成功则更新这个标志
|
||||||
bool is_pair; //文件是否和事件匹配,从comtrade/mac/路径下取file_download中的cfg文件提取时间和持续时间来匹配,匹配后接口发送这组file_download全部文件,发送成功后删除这组文件,然后更新事件中的文件列表
|
bool is_pair; //文件是否和事件匹配,从comtrade/mac/路径下取file_download中的cfg文件提取时间和持续时间来匹配,匹配后接口发送这组file_download全部文件,发送成功后删除这组文件,然后更新事件中的文件列表
|
||||||
@@ -454,14 +454,16 @@ std::string generate_json( //构造装置主动上送数据的报文
|
|||||||
const std::vector<DataArrayItem>& dataArray //数据数组。
|
const std::vector<DataArrayItem>& dataArray //数据数组。
|
||||||
);
|
);
|
||||||
|
|
||||||
int transfer_json_qvvr_data(unsigned int func_type, int monitor_id, //暂态事件的接口
|
//暂态事件接口
|
||||||
double mag, double dur, long long start_tm, long long end_tm, int dis_kind,
|
int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
|
||||||
const std::string& uuid_cfg, const std::string& uuid_dat,
|
double mag, double dur, long long start_tm, int dis_kind,int phase,
|
||||||
const std::string& mp_id, const std::string& Qvvr_rptname, const std::string& devtype);
|
const std::string& wavepath);
|
||||||
|
|
||||||
//录波文件目录接口
|
//录波文件目录接口
|
||||||
|
bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vector<std::string>& file_list_raw);
|
||||||
|
|
||||||
//录波文件下载完成通知接口
|
//录波文件下载完成通知接口
|
||||||
|
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user