From 2ab30dfbc614183af3a80e04640d7348393955cd Mon Sep 17 00:00:00 2001 From: lnk Date: Wed, 2 Apr 2025 11:48:18 +0800 Subject: [PATCH] add funtion in qvvr offline --- json/create_json.cpp | 286 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 285 insertions(+), 1 deletion(-) diff --git a/json/create_json.cpp b/json/create_json.cpp index 6131555..17bd5f8 100644 --- a/json/create_json.cpp +++ b/json/create_json.cpp @@ -4252,6 +4252,290 @@ QString errorlog_datamatch_pgsql(QString id, QString time, int BASE_MAT_NUM,int } #endif //lnk202411-5 暂态数据不再使用kafka发送,改成http接口 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件 +// 下面这部分是你要在原函数中“插入的新增功能”所需的辅助函数 +// ***************************************************************************************** +// 获取指定目录下所有文件的信息(文件名、修改时间、大小),以便后续做删除或判断文件总大小 +struct FileInfo { + std::string fileName; + time_t modTime; // 上次修改时间 + long long fileSize; // 文件大小 +}; + +// 扫描目录,获取该目录下所有普通文件的信息 +static void getDirectoryFilesInfo(const std::string &dirPath, std::vector &fileList) +{ + DIR* dp = opendir(dirPath.c_str()); + if (!dp) { + std::cerr << "Failed to get info from : " << dirPath << std::endl; + return; // 打开失败则直接返回 + } + + struct dirent* entry = NULL; + while ((entry = readdir(dp)) != NULL) { + // 跳过 . 和 .. + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + // 拼出完整路径 + std::string fullPath = dirPath + entry->d_name; + + // 获取文件信息 + struct stat st; + if (stat(fullPath.c_str(), &st) == 0) { + if (S_ISREG(st.st_mode)) { + FileInfo fi; + fi.fileName = fullPath; // 包含路径 + fi.modTime = st.st_mtime; // 修改时间 + fi.fileSize = (long long)st.st_size; // 文件大小 + + fileList.push_back(fi); + } + } + } + closedir(dp); +} + +// 将 JSON 字符串写入指定文件 +// 注意此处仅做简单演示,实际项目中可加更多错误处理、日志输出等 +static void writeJsonToFile(const char* filePath, const char* jsonString) +{ + FILE* fp = fopen(filePath, "w"); + if (!fp) { + std::cerr << "Failed to write in file : " << filePath << std::endl; + return; + } + fprintf(fp, "%s", jsonString); + fclose(fp); +} + +// 检查 qvvr 目录下文件总大小,若超过 10M 则删除最老的一个文件 +// 注意:该逻辑严格按照你需求“只删一个最老的文件”来实现,而不是循环删到小于10M +static void checkAndRemoveOldestIfNeeded(const std::string &dirPath, long long maxBytes) +{ + // 1) 判断目录是否存在,不存在则尝试创建 + { + struct stat st; + // 调用 stat() 判断是否存在 + if (stat(dirPath.c_str(), &st) == -1) { + if (errno == ENOENT) { + // 目录不存在,尝试创建 + // 注意:mkdir 只会创建最后一级目录,若需要递归创建父目录,请自行扩展 + if (mkdir(dirPath.c_str(), 0777) != 0) { + // 若 mkdir 失败,可根据实际需求进行日志输出或错误处理 + std::cerr << "Failed to create directory: " << dirPath << std::endl; + return; // 创建失败则直接返回,避免后续操作报错 + } + } else { + // stat() 调用出错,但并非 ENOENT,可根据需求处理 + std::cerr << "stat error: " << strerror(errno) << std::endl; + return; + } + } + else { + // 如果能 stat 到 dirPath,需要再判断是否真的是个“目录”而非普通文件 + if (!S_ISDIR(st.st_mode)) { + // 存在同名的非目录文件,无法作为目录使用 + std::cerr << dirPath << " exists but is not a directory." << std::endl; + return; + } + } + } + + // ============== 以下是原有的逻辑 ============== + // 获取目录下所有文件信息 + std::vector fileList; + getDirectoryFilesInfo(dirPath, fileList); + + // 计算总大小 + long long totalSize = 0; + for (size_t i = 0; i < fileList.size(); ++i) { + totalSize += fileList[i].fileSize; + } + + // 如果超过阈值,则删除最老的那个 + if (totalSize > maxBytes && !fileList.empty()) { + // 按修改时间升序排序,最老(修改时间最早)的排在最前面 + std::sort(fileList.begin(), fileList.end(), + // C++98 的比较写法 + static_cast( + // 不能使用lambda,用函数指针 + // 比较函数 + (bool (*)(const FileInfo&, const FileInfo&))[] (const FileInfo &a, const FileInfo &b) { + return a.modTime < b.modTime; + } + ) + ); + + // 删掉第一个(最老的文件) + remove(fileList[0].fileName.c_str()); + } +} + +// 扫描目录下的离线文件,依次读取并发送;若发送成功则删除该文件,发送不成功则保留 +static void scanAndResendOfflineFiles(const std::string &dirPath) +{ + // 获取目录下所有文件信息 + std::vector fileList; + getDirectoryFilesInfo(dirPath, fileList); + + // 逐个文件尝试重发 + for (size_t i = 0; i < fileList.size(); ++i) { + // 读取文件内容(即之前存的 JSON) + FILE* fp = fopen(fileList[i].fileName.c_str(), "r"); + if (!fp) { + std::cerr << " fail to open exsist file " << fileList[i].fileName << std::endl; + continue; + } + + // 读取到内存 + std::string jsonContent; + char buf[1024]; + while (!feof(fp)) { + if (fgets(buf, sizeof(buf), fp)) { + jsonContent += buf; + } + } + fclose(fp); + + // 尝试发送 + char* ptr = NULL; // 接收返回 + SendJsonAPI_web(0, "", jsonContent.c_str(), &ptr); + if (ptr != NULL) { + // 表示有响应,则可视为成功;根据项目需要可加更精细的判断 + handleCommentResponse(std::string(ptr)); + free(ptr); + // 删除文件 + remove(fileList[i].fileName.c_str()); + } + else { + // 发送失败,保留文件,以便下次重试 + } + } +} +// ***************************************************************************************** + + +// ======================== 原先的函数 ======================== +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, +char* uuid_cfg,char* uuid_dat, +char* mp_id,char* Qvvr_rptname,char* devtype) +{ + // 原本的逻辑,不做任何改动 + // --------------------------------------------------------------- + XmlConfig c_xmlcfg; + if (xmlinfo_list.contains(devtype)) { + c_xmlcfg = xmlinfo_list[devtype]->xmlcfg;//查找映射 + } + else { + c_xmlcfg = xmlcfg; + } + + if (strlen(mp_id) == 0) { + std::cout << "mp_id is null" << std::endl; + return 0; + } + + cJSON* root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "monitorId", mp_id); + cJSON_AddNumberToObject(root, "amplitude", mag); + cJSON_AddNumberToObject(root, "duration", dur); + cJSON_AddNumberToObject(root, "eventType", dis_kind); + + char start_time_str[25]; + time_t start_sec = start_tm / 1000; + struct tm* time_info = localtime(&start_sec); + strftime(start_time_str, sizeof(start_time_str), "%Y-%m-%d %H:%M:%S", time_info); + snprintf(start_time_str + strlen(start_time_str), sizeof(start_time_str) - strlen(start_time_str), ".%03lld", start_tm % 1000); + cJSON_AddStringToObject(root, "startTime", start_time_str); + + // cJSON_AddStringToObject(root, "wavePathcfg", uuid_cfg); + // cJSON_AddStringToObject(root, "wavePathdat", uuid_dat); + cJSON_AddStringToObject(root, "wavePath", uuid_dat); + + if (c_xmlcfg.WavePhasicFlag == "1") { + QString Qvvr_Rptname; + Qvvr_Rptname.append(Qvvr_rptname); + if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicA) != -1) { + cJSON_AddStringToObject(root, "phase", "A"); + } + else if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicB) != -1) { + cJSON_AddStringToObject(root, "phase", "B"); + } + else if (Qvvr_Rptname.indexOf(c_xmlcfg.WavePhasicC) != -1) { + cJSON_AddStringToObject(root, "phase", "C"); + } + else { + cJSON_AddStringToObject(root, "phase", "unknow"); + } + } + else { + cJSON_AddStringToObject(root, "phase", "unknow"); + } + + char* json_string = cJSON_Print(root); + printf("%s\n", json_string); // 输出 JSON 字符串 + + // 发送到暂态接口 + char* ptr = NULL; + SendJsonAPI_web(WEB_EVENT, "", json_string, &ptr); + + // ================ 插入新功能 ========================= + // ********** 新增功能开始 ********** + { + // 如果发送失败(ptr == NULL),则把当前 json 存入指定目录(/FeProject/dat/qvvr/) + if (ptr == NULL) { + // 1) 先检查/FeProject/dat/qvvr/目录文件大小是否超过 10M,若超过则删除最老的一个文件 + std::string qvvrDir = "/FeProject/dat/qvvr/"; + checkAndRemoveOldestIfNeeded(qvvrDir, 10LL * 1024 * 1024); + + // 2) 将此条 json 存为文件,文件名: mp_id-start_time_str-dis_kind.txt + // 例如: 502-2025-04-02 15:25:30.123-3.txt (仅示例) + std::string fileName = qvvrDir; + fileName += mp_id; + fileName += "-"; + fileName += start_time_str; + fileName += "-"; + + char buf[64]; + sprintf(buf, "%d", dis_kind); + fileName += buf; + fileName += ".txt"; + + // 把 json_string 写入文件 + writeJsonToFile(fileName.c_str(), json_string); + } + + // 无论此次发送成功或失败,都要扫描/FeProject/dat/qvvr/目录下的文件并尝试依次重发 + { + std::string qvvrDir = "/FeProject/dat/qvvr/"; + scanAndResendOfflineFiles(qvvrDir); + } + } + // ********** 新增功能结束 ********** + + // 下面继续原逻辑,不动 + if (ptr != NULL) { + handleCommentResponse(std::string(ptr)); + free(ptr); + } else { + // 处理 ptr 为 NULL 的情况,例如日志记录或错误处理 + std::cout << "Error: Received NULL response" << std::endl; + // 释放内存 + cJSON_Delete(root); + free(json_string); + return 0; + } + + // 释放内存 + cJSON_Delete(root); + free(json_string); + return 1; +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////暂态事件放入文件 +#if 0 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, //伏值,持续时间,开始时间,结束时间,暂态类型 char* uuid_cfg,char* uuid_dat, //两个录波文件 @@ -4398,7 +4682,7 @@ char* mp_id,char* Qvvr_rptname,char* devtype) // return 1; } - +#endif void qvvr_test() { char uuid_cfg[] = {"/comtrade/"};