#include "ThreadWriteDBManager.h" #include "GlobalInfo.h" #include "GlobalVariable.h" #include "spdlog.h" #include "GlobalInfo.h" #include "SystemConfig.h" #include #include #include #include ThreadWriteDBManager::~ThreadWriteDBManager() { } /* 线程工作函数 */ void ThreadWriteDBManager::thread_task() { /* 初始化信息 */ if(!initData()) { SPDLOG_LOGGER_ERROR(m_logger, "写数据库线程初始化数据失败"); return; } /* 设置标志位 */ m_isRunning = true; m_isStop = false; m_threadState = EThreadState::State_Running; SPDLOG_LOGGER_INFO(m_logger, "✉ 写数据库线程开始运行"); /* 运行线程功能 */ task(); /* 清理数据 */ clearData(); m_threadState = EThreadState::State_Stopped; m_isStop = true; SPDLOG_LOGGER_WARN(m_logger, "✉ 写数据库线程结束运行"); } /* 停止线程 */ void ThreadWriteDBManager::thread_stop() { m_isRunning = false; // 设置线程停止标志位 } void ThreadWriteDBManager::thread_stop_block() { thread_stop(); while(m_threadState != EThreadState::State_Stopped) // 等待线程停止 { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } /* 添加报警内容 */ void ThreadWriteDBManager::addAlarmInfo(const AlarmInfo_t& alarmInfo) { std::lock_guard lock(m_mutexListAlarm); m_listAlarm.push_back(alarmInfo); } void ThreadWriteDBManager::addAlarmInfo(const std::list& listAlarm) { std::lock_guard lock(m_mutexListAlarm); m_listAlarm.insert(m_listAlarm.end(), listAlarm.begin(), listAlarm.end()); } /* 添加一致性报警信息,键为主通道信息,值为次通道信息 */ void ThreadWriteDBManager::addAlarmInfo(const AlarmInfo_t& mainAlarm, const AlarmInfo_t& subAlarm) { std::lock_guard lock(m_mutexListAlarmConsistency); m_listAlarmConsistency.push_back(std::make_pair(mainAlarm, subAlarm)); } /* 录音文件写入数据库,isNewFile = true 是插入数据库,= false是更新数据库 */ void ThreadWriteDBManager::addRecordFileInfo(std::list& listRecordFile, bool isNewFile) { std::lock_guard lock(m_mutexListRecordFile); m_listRecordFile.insert(m_listRecordFile.end(), listRecordFile.begin(), listRecordFile.end()); m_isRecordFileInsert.store(isNewFile); } /* 线程工作函数 */ void ThreadWriteDBManager::task() { while(m_isRunning.load()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 每100毫秒执行一次 m_currentTime = QDateTime::currentDateTime(); /* 写入普通报警文件 */ alarmInfoToDB(); /* 写入一致性报警文件 */ consistencyAlarmInfoToDB(); /* 写录音文件信息到数据库 */ recordFileInfoToDB(); /* 定时删除报警文件和录音文件,文件路径从数据库中获取 */ deleteTimeoutFile(); /* 定时删除数据库信息 */ deleteTimeoutRecordInfo(); } } /* 初始化数据 */ bool ThreadWriteDBManager::initData() { if(m_logger == nullptr) { m_logger = spdlog::get("WriteDB"); if(m_logger == nullptr) { fmt::print("Alarm is nullptr"); return false; // 日志记录器获取失败 } } /* 登陆WebAPI */ if(!m_fromWebAPI.initWebApi(GInfo.webAPIUrl(), GInfo.webAPIID(), GInfo.webApiAppType())) { SPDLOG_LOGGER_ERROR(m_logger, "报警信息处理线程登录WebAPI失败"); return false; } SPDLOG_LOGGER_INFO(m_logger, "报警信息处理线程登录WebAPI成功"); /* 获取文件存储的根目录 */ m_strRootPath = GInfo.rootPath(); if(m_strRootPath.endsWith('/')) { m_strRootPath.chop(1); } /* 获取数据库的配置信息 */ m_dbConfig = SysConfig.getDatabaseConfig(); m_lastProcessLogTime = QDateTime::currentDateTime(); m_lastDeleteFileTime = QDateTime::currentDateTime(); return true; } /* 清理数据 */ void ThreadWriteDBManager::clearData() { } /* 普通报警写入数据库 */ void ThreadWriteDBManager::alarmInfoToDB() { /* 普通的报警数据写入数据库 */ std::list listAlarm; { std::lock_guard lock(m_mutexListAlarm); if(m_listAlarm.empty()) { return; // 没有报警信息 } listAlarm = std::move(m_listAlarm); // 移动报警信息列表 m_listAlarm.clear(); // 清空报警列表 } for(auto& alarm : listAlarm) { /* 处理报警路径 */ processFilePath(alarm.strAlarmFilePath); } if(!m_fromWebAPI.insertAlarmInfo(listAlarm)) { SPDLOG_LOGGER_ERROR(m_logger, "写入报警信息失败"); } /* 清空报警列表 */ listAlarm.clear(); } /* 一致性报警写入数据库 */ void ThreadWriteDBManager::consistencyAlarmInfoToDB() { /* 写入一致性报警信息 */ std::list> listAlarmConsistency; { std::lock_guard lock(m_mutexListAlarmConsistency); if(m_listAlarmConsistency.empty()) { return; // 没有一致性报警信息 } listAlarmConsistency = std::move(m_listAlarmConsistency); // 移动一致性报警信息列表 m_listAlarmConsistency.clear(); // 清空一致性报警列表 } /* 处理报警路径 */ for(auto it = listAlarmConsistency.begin(); it != listAlarmConsistency.end(); ++it) { processFilePath(it->first.strAlarmFilePath); processFilePath(it->second.strAlarmFilePath); } for(const auto& alarmPair : listAlarmConsistency) { if(!m_fromWebAPI.insertConsistencyAlarmInfo(alarmPair.first, alarmPair.second)) { SPDLOG_LOGGER_ERROR(m_logger, "写入一致性报警信息失败"); } } /* 清空报警信息 */ listAlarmConsistency.clear(); } /* 录音文件写数据库 */ void ThreadWriteDBManager::recordFileInfoToDB() { std::list listRecordFile; { std::lock_guard lock(m_mutexListRecordFile); if(m_listRecordFile.empty()) { return; // 没有录音文件信息 } listRecordFile = std::move(m_listRecordFile); // 移动录音文件信息列表 m_listRecordFile.clear(); } /* 处理录音文件路径 */ for(auto& recordFile : listRecordFile) { processFilePath(recordFile.FilePath); } if(m_isRecordFileInsert.load()) { if(!m_fromWebAPI.insertRecordFileInfo(listRecordFile)) { SPDLOG_LOGGER_ERROR(m_logger, "写入录音文件信息失败"); } } else { if(!m_fromWebAPI.updateRecordFileInfo(listRecordFile)) { SPDLOG_LOGGER_ERROR(m_logger, "更新录音文件信息失败"); } } } /* 处理报警路径,去掉前面的本地路径,只保留服务自己创建的文件夹及之后的路径 */ bool ThreadWriteDBManager::processFilePath(QString& strFilePath) { if(strFilePath.isEmpty()) { return false; } /* 去掉前面的目录,只留下报警文件夹及之后的路径 */ if(strFilePath.startsWith(m_strRootPath)) { strFilePath = strFilePath.mid(m_strRootPath.length()); if(!strFilePath.startsWith('/')) { strFilePath = '/' + strFilePath; } } return true; } /* 定时删除报警文件和录音文件,文件路径从数据库中获取,十分钟检查一次 注意: 这个函数需要在删除数据库记录之前执行,删除文件路径是从数据库中读取的 */ void ThreadWriteDBManager::deleteTimeoutFile() { if(m_lastDeleteFileTime.secsTo(m_currentTime) < 6) { return; // 十分钟检查一次 } m_lastDeleteFileTime = m_currentTime; /* 删除录音文件 */ deleteTimeoutRecordFile(); /* 删除报警文件 */ deleteTimeoutAlarmFile(); } /* 删除录音文件 */ void ThreadWriteDBManager::deleteTimeoutRecordFile() { /* 计算录音文件删除时间 */ int retainHour = SysConfig.getDatabaseConfig().nRecordFileRetain; QDateTime recordDeleteTime = m_currentTime.addSecs(-retainHour * 3600); /* 从数据库中获取早于这个时间的录音文件记录 */ std::list listRecordFile; if(!m_fromWebAPI.getRecordFileInfoBeforeTime(recordDeleteTime, listRecordFile)) { SPDLOG_LOGGER_ERROR(m_logger, "获取早于 {} 的录音文件信息失败", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); return; } if(listRecordFile.empty()) { SPDLOG_LOGGER_INFO(m_logger, "没有早于 {} 的录音文件信息", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); return; } for(auto& recordFile : listRecordFile) { QString strFilePath = recordFile.FilePath; if(strFilePath.isEmpty()) { continue; // 跳过空路径 } /* 删除文件 */ QString fullPath = m_strRootPath + strFilePath; if(QFile::exists(fullPath)) { if(!QFile::remove(fullPath)) { SPDLOG_LOGGER_ERROR(m_logger, "删除录音文件 {} 失败", fullPath.toStdString()); } else { SPDLOG_LOGGER_TRACE(m_logger, "删除录音文件 {}", fullPath.toStdString()); } } else { SPDLOG_LOGGER_WARN(m_logger, "录音文件 {} 不存在", fullPath.toStdString()); } recordFile.fileState = eRecordState::eRS_Deleted; } /* 更新数据库录音文件信息 */ if(!m_fromWebAPI.updateRecordFileInfo(listRecordFile)) { SPDLOG_LOGGER_ERROR(m_logger, "更新数据库录音文件信息失败"); return; } } /* 删除报警文件 */ void ThreadWriteDBManager::deleteTimeoutAlarmFile() { /* 计算报警文件删除时间 */ int retainDay = SysConfig.getDatabaseConfig().nAlarmFileRetain; QDateTime alarmDeleteTime = m_currentTime.addDays(-retainDay); /* 从数据库中获取早于这个时间的报警文件记录 */ std::list listAlarm; if(!m_fromWebAPI.getAlarmInfoBeforeTime(alarmDeleteTime, listAlarm)) { SPDLOG_LOGGER_ERROR(m_logger, "获取早于 {} 的报警信息失败", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); return; } if(listAlarm.empty()) { SPDLOG_LOGGER_INFO(m_logger, "没有早于 {} 的报警信息", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); return; } for(auto& alarm : listAlarm) { QString strFilePath = alarm.strAlarmFilePath; if(strFilePath.isEmpty()) { continue; // 跳过空路径 } /* 删除文件 */ QString fullPath = m_strRootPath + strFilePath; if(QFile::exists(fullPath)) { if(!QFile::remove(fullPath)) { SPDLOG_LOGGER_ERROR(m_logger, "删除报警文件 {} 失败", fullPath.toStdString()); } else { SPDLOG_LOGGER_TRACE(m_logger, "删除报警文件 {}", fullPath.toStdString()); } } else { SPDLOG_LOGGER_WARN(m_logger, "删除报警音频文件失败,报警文件 {} 不存在", fullPath.toStdString()); } alarm.fileState = eRecordState::eRS_Deleted; } /* 更新数据库中的报警信息 */ if(!m_fromWebAPI.updateAlarmFileState(listAlarm)) { SPDLOG_LOGGER_ERROR(m_logger, "更新数据库报警文件信息失败"); return; } } /* 删除超过时长的数据库记录信息 */ void ThreadWriteDBManager::deleteTimeoutRecordInfo() { if(m_lastProcessLogTime.secsTo(m_currentTime) < 600) { return; } m_lastProcessLogTime = m_currentTime; /* 计算录音文件删除时间 */ int retainDay = SysConfig.getDatabaseConfig().nRecordLogRetain; QDateTime recordDeleteTime = m_currentTime.addDays(-retainDay); if(!m_fromWebAPI.deleteRecordFileInfoBeforeTime(recordDeleteTime)) { SPDLOG_LOGGER_ERROR(m_logger, "删除早于 {} 的录音文件信息失败", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); } /* 计算报警日志删除时间 */ retainDay = SysConfig.getDatabaseConfig().nAlarmLogRetain; QDateTime alarmDeleteTime = m_currentTime.addDays(-retainDay); if(!m_fromWebAPI.deleteAlarmInfoBeforeTime(alarmDeleteTime)) { SPDLOG_LOGGER_ERROR(m_logger, "删除早于 {} 的报警信息失败", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString()); } }