ThreadWriteDBManager.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. #include "ThreadWriteDBManager.h"
  2. #include "GlobalInfo.h"
  3. #include "GlobalVariable.h"
  4. #include "spdlog.h"
  5. #include "GlobalInfo.h"
  6. #include "SystemConfig.h"
  7. #include <mutex>
  8. #include <qdatetime.h>
  9. #include <thread>
  10. #include <QFile>
  11. ThreadWriteDBManager::~ThreadWriteDBManager()
  12. {
  13. }
  14. /* 线程工作函数 */
  15. void ThreadWriteDBManager::thread_task()
  16. {
  17. /* 初始化信息 */
  18. if(!initData())
  19. {
  20. SPDLOG_LOGGER_ERROR(m_logger, "写数据库线程初始化数据失败");
  21. return;
  22. }
  23. /* 设置标志位 */
  24. m_isRunning = true;
  25. m_isStop = false;
  26. m_threadState = EThreadState::State_Running;
  27. SPDLOG_LOGGER_INFO(m_logger, "✉ 写数据库线程开始运行");
  28. /* 运行线程功能 */
  29. task();
  30. /* 清理数据 */
  31. clearData();
  32. m_threadState = EThreadState::State_Stopped;
  33. m_isStop = true;
  34. SPDLOG_LOGGER_WARN(m_logger, "✉ 写数据库线程结束运行");
  35. }
  36. /* 停止线程 */
  37. void ThreadWriteDBManager::thread_stop()
  38. {
  39. m_isRunning = false; // 设置线程停止标志位
  40. }
  41. void ThreadWriteDBManager::thread_stop_block()
  42. {
  43. thread_stop();
  44. while(m_threadState != EThreadState::State_Stopped) // 等待线程停止
  45. {
  46. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  47. }
  48. }
  49. /* 添加报警内容 */
  50. void ThreadWriteDBManager::addAlarmInfo(const AlarmInfo_t& alarmInfo)
  51. {
  52. std::lock_guard<std::mutex> lock(m_mutexListAlarm);
  53. m_listAlarm.push_back(alarmInfo);
  54. }
  55. void ThreadWriteDBManager::addAlarmInfo(const std::list<AlarmInfo_t>& listAlarm)
  56. {
  57. std::lock_guard<std::mutex> lock(m_mutexListAlarm);
  58. m_listAlarm.insert(m_listAlarm.end(), listAlarm.begin(), listAlarm.end());
  59. }
  60. /* 添加一致性报警信息,键为主通道信息,值为次通道信息 */
  61. void ThreadWriteDBManager::addAlarmInfo(const AlarmInfo_t& mainAlarm, const AlarmInfo_t& subAlarm)
  62. {
  63. std::lock_guard<std::mutex> lock(m_mutexListAlarmConsistency);
  64. m_listAlarmConsistency.push_back(std::make_pair(mainAlarm, subAlarm));
  65. }
  66. /* 录音文件写入数据库,isNewFile = true 是插入数据库,= false是更新数据库 */
  67. void ThreadWriteDBManager::addRecordFileInfo(std::list<RecordFileInfo_t>& listRecordFile, bool isNewFile)
  68. {
  69. std::lock_guard<std::mutex> lock(m_mutexListRecordFile);
  70. m_listRecordFile.insert(m_listRecordFile.end(), listRecordFile.begin(), listRecordFile.end());
  71. m_isRecordFileInsert.store(isNewFile);
  72. }
  73. /* 线程工作函数 */
  74. void ThreadWriteDBManager::task()
  75. {
  76. while(m_isRunning.load())
  77. {
  78. std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 每100毫秒执行一次
  79. m_currentTime = QDateTime::currentDateTime();
  80. /* 写入普通报警文件 */
  81. alarmInfoToDB();
  82. /* 写入一致性报警文件 */
  83. consistencyAlarmInfoToDB();
  84. /* 写录音文件信息到数据库 */
  85. recordFileInfoToDB();
  86. /* 定时删除报警文件和录音文件,文件路径从数据库中获取 */
  87. deleteTimeoutFile();
  88. /* 定时删除数据库信息 */
  89. deleteTimeoutRecordInfo();
  90. }
  91. }
  92. /* 初始化数据 */
  93. bool ThreadWriteDBManager::initData()
  94. {
  95. if(m_logger == nullptr)
  96. {
  97. m_logger = spdlog::get("WriteDB");
  98. if(m_logger == nullptr)
  99. {
  100. fmt::print("Alarm is nullptr");
  101. return false; // 日志记录器获取失败
  102. }
  103. }
  104. /* 登陆WebAPI */
  105. if(!m_fromWebAPI.initWebApi(GInfo.webAPIUrl(), GInfo.webAPIID(), GInfo.webApiAppType()))
  106. {
  107. SPDLOG_LOGGER_ERROR(m_logger, "报警信息处理线程登录WebAPI失败");
  108. return false;
  109. }
  110. SPDLOG_LOGGER_INFO(m_logger, "报警信息处理线程登录WebAPI成功");
  111. /* 获取文件存储的根目录 */
  112. m_strRootPath = GInfo.rootPath();
  113. if(m_strRootPath.endsWith('/'))
  114. {
  115. m_strRootPath.chop(1);
  116. }
  117. /* 获取数据库的配置信息 */
  118. m_dbConfig = SysConfig.getDatabaseConfig();
  119. m_lastProcessLogTime = QDateTime::currentDateTime();
  120. m_lastDeleteFileTime = QDateTime::currentDateTime();
  121. return true;
  122. }
  123. /* 清理数据 */
  124. void ThreadWriteDBManager::clearData()
  125. {
  126. }
  127. /* 普通报警写入数据库 */
  128. void ThreadWriteDBManager::alarmInfoToDB()
  129. {
  130. /* 普通的报警数据写入数据库 */
  131. std::list<AlarmInfo_t> listAlarm;
  132. {
  133. std::lock_guard<std::mutex> lock(m_mutexListAlarm);
  134. if(m_listAlarm.empty())
  135. {
  136. return; // 没有报警信息
  137. }
  138. listAlarm = std::move(m_listAlarm); // 移动报警信息列表
  139. m_listAlarm.clear(); // 清空报警列表
  140. }
  141. for(auto& alarm : listAlarm)
  142. {
  143. /* 处理报警路径 */
  144. processFilePath(alarm.strAlarmFilePath);
  145. }
  146. if(!m_fromWebAPI.insertAlarmInfo(listAlarm))
  147. {
  148. SPDLOG_LOGGER_ERROR(m_logger, "写入报警信息失败");
  149. }
  150. /* 清空报警列表 */
  151. listAlarm.clear();
  152. }
  153. /* 一致性报警写入数据库 */
  154. void ThreadWriteDBManager::consistencyAlarmInfoToDB()
  155. {
  156. /* 写入一致性报警信息 */
  157. std::list<std::pair<AlarmInfo_t, AlarmInfo_t>> listAlarmConsistency;
  158. {
  159. std::lock_guard<std::mutex> lock(m_mutexListAlarmConsistency);
  160. if(m_listAlarmConsistency.empty())
  161. {
  162. return; // 没有一致性报警信息
  163. }
  164. listAlarmConsistency = std::move(m_listAlarmConsistency); // 移动一致性报警信息列表
  165. m_listAlarmConsistency.clear(); // 清空一致性报警列表
  166. }
  167. /* 处理报警路径 */
  168. for(auto it = listAlarmConsistency.begin(); it != listAlarmConsistency.end(); ++it)
  169. {
  170. processFilePath(it->first.strAlarmFilePath);
  171. processFilePath(it->second.strAlarmFilePath);
  172. }
  173. for(const auto& alarmPair : listAlarmConsistency)
  174. {
  175. if(!m_fromWebAPI.insertConsistencyAlarmInfo(alarmPair.first, alarmPair.second))
  176. {
  177. SPDLOG_LOGGER_ERROR(m_logger, "写入一致性报警信息失败");
  178. }
  179. }
  180. /* 清空报警信息 */
  181. listAlarmConsistency.clear();
  182. }
  183. /* 录音文件写数据库 */
  184. void ThreadWriteDBManager::recordFileInfoToDB()
  185. {
  186. std::list<RecordFileInfo_t> listRecordFile;
  187. {
  188. std::lock_guard<std::mutex> lock(m_mutexListRecordFile);
  189. if(m_listRecordFile.empty())
  190. {
  191. return; // 没有录音文件信息
  192. }
  193. listRecordFile = std::move(m_listRecordFile); // 移动录音文件信息列表
  194. m_listRecordFile.clear();
  195. }
  196. /* 处理录音文件路径 */
  197. for(auto& recordFile : listRecordFile)
  198. {
  199. processFilePath(recordFile.FilePath);
  200. }
  201. if(m_isRecordFileInsert.load())
  202. {
  203. if(!m_fromWebAPI.insertRecordFileInfo(listRecordFile))
  204. {
  205. SPDLOG_LOGGER_ERROR(m_logger, "写入录音文件信息失败");
  206. }
  207. } else
  208. {
  209. if(!m_fromWebAPI.updateRecordFileInfo(listRecordFile))
  210. {
  211. SPDLOG_LOGGER_ERROR(m_logger, "更新录音文件信息失败");
  212. }
  213. }
  214. }
  215. /* 处理报警路径,去掉前面的本地路径,只保留服务自己创建的文件夹及之后的路径 */
  216. bool ThreadWriteDBManager::processFilePath(QString& strFilePath)
  217. {
  218. if(strFilePath.isEmpty())
  219. {
  220. return false;
  221. }
  222. /* 去掉前面的目录,只留下报警文件夹及之后的路径 */
  223. if(strFilePath.startsWith(m_strRootPath))
  224. {
  225. strFilePath = strFilePath.mid(m_strRootPath.length());
  226. if(!strFilePath.startsWith('/'))
  227. {
  228. strFilePath = '/' + strFilePath;
  229. }
  230. }
  231. return true;
  232. }
  233. /* 定时删除报警文件和录音文件,文件路径从数据库中获取,十分钟检查一次
  234. 注意: 这个函数需要在删除数据库记录之前执行,删除文件路径是从数据库中读取的 */
  235. void ThreadWriteDBManager::deleteTimeoutFile()
  236. {
  237. if(m_lastDeleteFileTime.secsTo(m_currentTime) < 600)
  238. {
  239. return; // 十分钟检查一次
  240. }
  241. m_lastDeleteFileTime = m_currentTime;
  242. /* 删除录音文件 */
  243. deleteTimeoutRecordFile();
  244. /* 删除报警文件 */
  245. deleteTimeoutAlarmFile();
  246. }
  247. /* 删除录音文件 */
  248. void ThreadWriteDBManager::deleteTimeoutRecordFile()
  249. {
  250. /* 计算录音文件删除时间 */
  251. int retainHour = SysConfig.getDatabaseConfig().nRecordFileRetain;
  252. QDateTime recordDeleteTime = m_currentTime.addSecs(-retainHour * 3600);
  253. /* 从数据库中获取早于这个时间的录音文件记录 */
  254. std::list<RecordFileInfo_t> listRecordFile;
  255. if(!m_fromWebAPI.getRecordFileInfoBeforeTime(recordDeleteTime, listRecordFile))
  256. {
  257. SPDLOG_LOGGER_ERROR(m_logger, "获取早于 {} 的录音文件信息失败", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  258. return;
  259. }
  260. if(listRecordFile.empty())
  261. {
  262. SPDLOG_LOGGER_INFO(m_logger, "没有早于 {} 的录音文件信息", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  263. return;
  264. }
  265. for(auto& recordFile : listRecordFile)
  266. {
  267. QString strFilePath = recordFile.FilePath;
  268. if(strFilePath.isEmpty())
  269. {
  270. continue; // 跳过空路径
  271. }
  272. /* 删除文件 */
  273. QString fullPath = m_strRootPath + strFilePath;
  274. if(QFile::exists(fullPath))
  275. {
  276. if(!QFile::remove(fullPath))
  277. {
  278. SPDLOG_LOGGER_ERROR(m_logger, "删除录音文件 {} 失败", fullPath.toStdString());
  279. } else
  280. {
  281. SPDLOG_LOGGER_TRACE(m_logger, "删除录音文件 {}", fullPath.toStdString());
  282. }
  283. } else
  284. {
  285. SPDLOG_LOGGER_WARN(m_logger, "录音文件 {} 不存在", fullPath.toStdString());
  286. }
  287. recordFile.fileState = eRecordState::eRS_Deleted;
  288. }
  289. /* 更新数据库录音文件信息 */
  290. if(!m_fromWebAPI.updateRecordFileInfo(listRecordFile))
  291. {
  292. SPDLOG_LOGGER_ERROR(m_logger, "更新数据库录音文件信息失败");
  293. return;
  294. }
  295. }
  296. /* 删除报警文件 */
  297. void ThreadWriteDBManager::deleteTimeoutAlarmFile()
  298. {
  299. /* 计算报警文件删除时间 */
  300. int retainDay = SysConfig.getDatabaseConfig().nAlarmFileRetain;
  301. QDateTime alarmDeleteTime = m_currentTime.addDays(-retainDay);
  302. /* 从数据库中获取早于这个时间的报警文件记录 */
  303. std::list<AlarmInfo_t> listAlarm;
  304. if(!m_fromWebAPI.getAlarmInfoBeforeTime(alarmDeleteTime, listAlarm))
  305. {
  306. SPDLOG_LOGGER_ERROR(m_logger, "获取早于 {} 的报警信息失败", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  307. return;
  308. }
  309. if(listAlarm.empty())
  310. {
  311. SPDLOG_LOGGER_INFO(m_logger, "没有早于 {} 的报警信息", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  312. return;
  313. }
  314. for(auto& alarm : listAlarm)
  315. {
  316. QString strFilePath = alarm.strAlarmFilePath;
  317. if(strFilePath.isEmpty())
  318. {
  319. continue; // 跳过空路径
  320. }
  321. /* 删除文件 */
  322. QString fullPath = m_strRootPath + strFilePath;
  323. if(QFile::exists(fullPath))
  324. {
  325. if(!QFile::remove(fullPath))
  326. {
  327. SPDLOG_LOGGER_ERROR(m_logger, "删除报警文件 {} 失败", fullPath.toStdString());
  328. } else
  329. {
  330. SPDLOG_LOGGER_TRACE(m_logger, "删除报警文件 {}", fullPath.toStdString());
  331. }
  332. } else
  333. {
  334. SPDLOG_LOGGER_WARN(m_logger, "删除报警音频文件失败,报警文件 {} 不存在", fullPath.toStdString());
  335. }
  336. alarm.fileState = eRecordState::eRS_Deleted;
  337. }
  338. /* 更新数据库中的报警信息 */
  339. if(!m_fromWebAPI.updateAlarmFileState(listAlarm))
  340. {
  341. SPDLOG_LOGGER_ERROR(m_logger, "更新数据库报警文件信息失败");
  342. return;
  343. }
  344. }
  345. /* 删除超过时长的数据库记录信息 */
  346. void ThreadWriteDBManager::deleteTimeoutRecordInfo()
  347. {
  348. if(m_lastProcessLogTime.secsTo(m_currentTime) < 600)
  349. {
  350. return;
  351. }
  352. m_lastProcessLogTime = m_currentTime;
  353. /* 计算录音文件删除时间 */
  354. int retainDay = SysConfig.getDatabaseConfig().nRecordLogRetain;
  355. QDateTime recordDeleteTime = m_currentTime.addDays(-retainDay);
  356. if(!m_fromWebAPI.deleteRecordFileInfoBeforeTime(recordDeleteTime))
  357. {
  358. SPDLOG_LOGGER_ERROR(m_logger, "删除早于 {} 的录音文件信息失败", recordDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  359. }
  360. /* 计算报警日志删除时间 */
  361. retainDay = SysConfig.getDatabaseConfig().nAlarmLogRetain;
  362. QDateTime alarmDeleteTime = m_currentTime.addDays(-retainDay);
  363. if(!m_fromWebAPI.deleteAlarmInfoBeforeTime(alarmDeleteTime))
  364. {
  365. SPDLOG_LOGGER_ERROR(m_logger, "删除早于 {} 的报警信息失败", alarmDeleteTime.toString("yyyy-MM-dd HH:mm:ss").toStdString());
  366. }
  367. }