SPAServer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. #include "SPAServer.h"
  2. #include "spdlog/spdlog.h"
  3. #include <filesystem>
  4. #include "ThreadPool/ThreadPool.h"
  5. #include "GlobalInfo/GlobalVariable.h"
  6. #include "GlobalInfo/GlobalConfig.h"
  7. #include "UniversalFunc.h"
  8. #include "FuncOrdinary.h"
  9. #include "FuncIllegalInvasion.h"
  10. #include "GlobalFuncThread.h"
  11. #include <QCoreApplication>
  12. SPAServer::SPAServer()
  13. {
  14. m_logger = spdlog::get("SPAServer");
  15. if(m_logger == nullptr)
  16. {
  17. SPDLOG_ERROR("APAServer logger is nullptr");
  18. return;
  19. }
  20. /* 读取全局的配置文件 */
  21. QString strConfigFile = QCoreApplication::applicationDirPath() + "/config.ini";
  22. if(!GConfig.readConfig(strConfigFile))
  23. {
  24. /* 读取配置文件失败,直接退出程序 */
  25. return;
  26. }
  27. GConfig.printValue();
  28. m_threadRunning = true;
  29. /* 初始化WebAPI */
  30. m_fromWebAPI.initWebApi("http://192.1.3.133:31000/v6/", "", "4c2f9fc91c22dd98331e47af2e2964f4");
  31. /* 模拟违禁品算法ID,后续需要动态调整 */
  32. g_actionList.ActContraband = "OD210_026_005246_001-IZRTKyEx";
  33. }
  34. SPAServer::~SPAServer()
  35. {
  36. }
  37. /* 启动服务 */
  38. void SPAServer::startServer()
  39. {
  40. /* 添加获取基础信息的线程 */
  41. // CPPTP.add_task(&SPAServer::threadFromSuperBrain, this);
  42. /* 测试Redis读取并解析数据线程 */
  43. CameraThreadInfo info;
  44. info.RedisIP = "172.16.36.80";
  45. info.RedisPort = 32222;
  46. info.RedisPWD = "Ff1z@TOFr^iwd%Ra";
  47. info.DeviceID = 117;
  48. info.vecAction.push_back("OD210_026_005246_001-IZRTKyEx");
  49. g_actionList.ActContraband = "OD210_026_005246_001-IZRTKyEx";
  50. // CPPTP.add_task(&SPAServer::threadFromRedis, this, info);
  51. // threadFromRedis(info);
  52. }
  53. /**
  54. * @brief 从基础平台获取算法信息和设备信息的线程函数
  55. * 从基础平台获取算法信息和设备信息,然后更新到EQM数据库所对应的表中
  56. *
  57. */
  58. void SPAServer::threadFromSuperBrain()
  59. {
  60. SPDLOG_LOGGER_INFO(m_logger, "开启 fromSuperBrainThread 线程, 获取算法和设备信息");
  61. /* 创建变量 */
  62. std::vector<AlgorithmInfo> vecAlgNewInfo;
  63. std::vector<DeviceInfo> vecDevNewInfo;
  64. /* 获取一次token,后续失效了再获取 */
  65. m_fromSuperBrain.getToken();
  66. while (m_threadRunning)
  67. {
  68. SPDLOG_LOGGER_INFO(m_logger, "刷新算法和设备信息");
  69. /* 先更新数据库的信息,防止从其他地方更改了数据库,这里没有刷新本地缓存 */
  70. m_fromWebAPI.getAlgorithmInfo(m_vecEqmAlgInfo);
  71. m_fromWebAPI.getDeviceInfo(m_vecEqmDevInfo);
  72. m_fromWebAPI.getDeviceAlgorithmInfo(m_vecEqmDevInfo, m_listDevIDDelete);
  73. /* 从超脑获取基础信息 */
  74. m_fromSuperBrain.getTaskTypeList(vecAlgNewInfo);
  75. m_fromSuperBrain.getDeviceList(vecDevNewInfo);
  76. /* 处理算法信息 */
  77. bool algIsUpdate = processAlgorithmInfo(vecAlgNewInfo);
  78. /* 处理设备信息 */
  79. bool devIsUpdate = processDeviceInfo(vecDevNewInfo);
  80. vecAlgNewInfo.clear();
  81. vecDevNewInfo.clear();
  82. /* 更新算法详细信息 */
  83. m_mutexActionInfo.lock();
  84. m_fromWebAPI.getActionInfo(m_listActionInfo);
  85. m_mutexActionInfo.unlock();
  86. /* 10秒更新一次 */
  87. std::this_thread::sleep_for(std::chrono::seconds(10));
  88. }
  89. SPDLOG_LOGGER_INFO(m_logger, "退出 fromSuperBrainThread 线程");
  90. }
  91. /* 处理算法信息,返回值为true,说明有改变,需要重新读取 */
  92. bool SPAServer::processAlgorithmInfo(std::vector<AlgorithmInfo> vecNewAlgInfo)
  93. {
  94. std::vector<AlgorithmInfo> vecAlgUpdate;
  95. std::vector<AlgorithmInfo> vecAlgDelete;
  96. /* 对比数据库表格信息,这里只有插入和删除,没有更新 */
  97. compareAlgorithmInfo(vecNewAlgInfo, vecAlgUpdate, vecAlgDelete);
  98. /* 更新数据库,先删除,再写入刷新 */
  99. bool isUpdate = false;
  100. if(vecAlgDelete.size() > 0)
  101. {
  102. SPDLOG_LOGGER_DEBUG(m_logger, "删除算法信息");
  103. m_fromWebAPI.deleteAlgorithmInfo(vecAlgDelete);
  104. isUpdate = true;
  105. }
  106. if(vecAlgUpdate.size() > 0)
  107. {
  108. SPDLOG_LOGGER_DEBUG(m_logger, "写入算法信息");
  109. m_fromWebAPI.writeAlgorithmInfo(vecAlgUpdate);
  110. isUpdate = true;
  111. }
  112. return isUpdate;
  113. }
  114. /**
  115. * @brief 处理设备信息
  116. *
  117. * @param vecNewDevInfo 传入新获取到的值
  118. * @return true 需要重新读取数据库,获取新的数据
  119. * @return false 无需读取数据库
  120. */
  121. bool SPAServer::processDeviceInfo(std::vector<DeviceInfo> vecNewDevInfo)
  122. {
  123. std::vector<DeviceInfo> vecDevInsert;
  124. std::vector<DeviceInfo> vecDevUpdate;
  125. std::vector<DeviceInfo> vecDevDelete;
  126. /*-------------------------------------------------------------------------
  127. ****** 这里只对比设备信息,不对比设备的算法信息,算法信息在下面单独对比 *******
  128. *------------------------------------------------------------------------*/
  129. /* 如果本地缓存没有数据,那么就全部插入 */
  130. if(m_vecEqmDevInfo.size() > 0)
  131. {
  132. for(auto& DevInfo : vecNewDevInfo)
  133. {
  134. bool isExist = false;
  135. for(auto& it0 : m_vecEqmDevInfo)
  136. {
  137. if(DevInfo.DeviceID == it0.DeviceID)
  138. {
  139. isExist = true;
  140. /* 对比其他项是否相等,不相等就更新 */
  141. if(DevInfo == it0)
  142. {
  143. continue;
  144. }else {
  145. vecDevUpdate.push_back(DevInfo);
  146. }
  147. break;
  148. }
  149. }
  150. if(!isExist)
  151. {
  152. vecDevInsert.push_back(DevInfo);
  153. }
  154. }
  155. }else {
  156. vecDevInsert = vecNewDevInfo;
  157. }
  158. /* 获取删除列表 */
  159. if(vecNewDevInfo.size() > 0)
  160. {
  161. bool isExist = false;
  162. for(const auto& it : m_vecEqmDevInfo)
  163. {
  164. isExist = false;
  165. for(const auto& it0 : vecNewDevInfo)
  166. {
  167. if(it.DeviceID == it0.DeviceID)
  168. {
  169. isExist = true;
  170. break;
  171. }
  172. }
  173. if(!isExist)
  174. {
  175. vecDevDelete.push_back(it);
  176. }
  177. }
  178. }else {
  179. vecDevDelete = m_vecEqmDevInfo;
  180. }
  181. bool isUpdate = false;
  182. /* 先删除多余的数据 */
  183. if(vecDevDelete.size() > 0)
  184. {
  185. SPDLOG_LOGGER_DEBUG(m_logger, "删除设备信息, 表: tActionCamer");
  186. m_fromWebAPI.deleteDeviceInfo(vecDevDelete);
  187. isUpdate = true;
  188. }
  189. /* 更新数据 */
  190. if(vecDevUpdate.size() > 0)
  191. {
  192. SPDLOG_LOGGER_DEBUG(m_logger, "更新设备信息, 表: tActionCamer");
  193. m_fromWebAPI.updateDeviceInfo(vecDevUpdate);
  194. isUpdate = true;
  195. }
  196. /* 插入数据 */
  197. if(vecDevInsert.size() > 0)
  198. {
  199. SPDLOG_LOGGER_DEBUG(m_logger, "插入设备信息, 表: tActionCamer");
  200. m_fromWebAPI.insertDeviceInfo(vecDevInsert);
  201. isUpdate = true;
  202. }
  203. /*-------------------------------------------------------------------------
  204. ************* 处理设备和算子关联的表格,单独对比设备的算法信息 *************
  205. *------------------------------------------------------------------------*/
  206. /* 插入新的设备信息 */
  207. if(vecDevInsert.size() > 0)
  208. {
  209. SPDLOG_LOGGER_DEBUG(m_logger, "插入设备和算法关联表(tActionCamer)");
  210. m_fromWebAPI.insertDeviceAlgorithmInfo(vecDevInsert);
  211. isUpdate = true;
  212. }
  213. vecDevUpdate.clear();
  214. /* 对比现有的设备是否需要更新算法 */
  215. compareDeviceAlgorithmInfo(vecNewDevInfo, vecDevUpdate);
  216. if(vecDevUpdate.size() > 0)
  217. {
  218. SPDLOG_LOGGER_DEBUG(m_logger, "更新设备和算法关联表(tActionCamer), 更新设备数目:{}", vecDevUpdate.size());
  219. m_fromWebAPI.updateDeviceAlgorithmInfo(vecDevUpdate);
  220. }
  221. /* 删除tActionCamer表中消失的设备信息 */
  222. if(m_listDevIDDelete.size() > 0)
  223. {
  224. SPDLOG_LOGGER_DEBUG(m_logger, "删除消失的设备关联的算法(tActionCamer)");
  225. m_fromWebAPI.deleteDeviceAlgorithmInfo(m_listDevIDDelete);
  226. isUpdate = true;
  227. }
  228. return isUpdate;
  229. }
  230. /* 对比现有的数据和新获取到的数据,取出要删除和添加的数据 */
  231. void SPAServer::compareAlgorithmInfo(const std::vector<AlgorithmInfo>& vecNewInfo, std::vector<AlgorithmInfo>& vecAlgUpdate, std::vector<AlgorithmInfo>& vecAlgDelete)
  232. {
  233. /* 取出要添加的,如果本地缓存是0,那么全部都要添加 */
  234. if(m_vecEqmAlgInfo.size() > 0)
  235. {
  236. for(const auto& it : vecNewInfo)
  237. {
  238. bool isExist = false;
  239. for(const auto& it0 : m_vecEqmAlgInfo)
  240. {
  241. /* 如果存在就退出循环 */
  242. if(it.ActionID == it0.ActionID)
  243. {
  244. isExist = true;
  245. break;
  246. }
  247. }
  248. if(!isExist)
  249. {
  250. vecAlgUpdate.push_back(it);
  251. }
  252. }
  253. }else {
  254. vecAlgUpdate = vecNewInfo;
  255. }
  256. /* 取出要删除的,如果新的数据是0,那么全部都要删除 */
  257. if(vecNewInfo.size() > 0)
  258. {
  259. bool isExist = false;
  260. for(const auto& it : m_vecEqmAlgInfo)
  261. {
  262. isExist = false;
  263. for(const auto& it0 : vecNewInfo)
  264. {
  265. if(it.ActionID == it0.ActionID)
  266. {
  267. isExist = true;
  268. break;
  269. }
  270. }
  271. if(!isExist)
  272. {
  273. vecAlgDelete.push_back(it);
  274. }
  275. }
  276. }else {
  277. vecAlgDelete = m_vecEqmAlgInfo;
  278. }
  279. }
  280. /**
  281. * @brief 对比设备和算法关联表是否需要更新
  282. * 对比规则:
  283. * 1、这里只对比已有的设备ID,需要删除的ID在获取到tActionCamer表是就已经取出来了
  284. * 2、如果设备ID相等,那么进一步对比算法信息是否相等
  285. * 3、如果设备ID相等,但是算法信息数目不相等,那么直接加入更新列表
  286. * 4、如果设备ID相等,算法信息数目相等,进一步对比算法信息
  287. *
  288. * @param vecNewInfo
  289. * @param vecDevUpdate
  290. */
  291. void SPAServer::compareDeviceAlgorithmInfo(const std::vector<DeviceInfo>& vecNewInfo, std::vector<DeviceInfo>& vecDevUpdate)
  292. {
  293. vecDevUpdate.clear();
  294. for(const auto& it0 : vecNewInfo)
  295. {
  296. for(const auto& it1 : m_vecEqmDevInfo)
  297. {
  298. if(it0.DeviceID == it1.DeviceID)
  299. {
  300. /* 设备的算法信息数目不相等,直接加入更新列表 */
  301. if(it0.vecAlgorithmInfo.size() != it1.vecAlgorithmInfo.size())
  302. {
  303. vecDevUpdate.push_back(it0);
  304. break;
  305. }
  306. /* 设备的算法信息数目相等,进一步对比算法信息 */
  307. bool isEquality = true;
  308. for(const auto& it2 : it0.vecAlgorithmInfo)
  309. {
  310. bool isEq2 = false;
  311. for(const auto& it3 : it1.vecAlgorithmInfo)
  312. {
  313. /* 这里只对比算法ID */
  314. if(it2.ActionID != it3.ActionID)
  315. {
  316. continue;
  317. }else {
  318. isEq2 = true;
  319. break;
  320. }
  321. }
  322. if(!isEq2)
  323. {
  324. isEquality = false;
  325. break;
  326. }
  327. }
  328. if(!isEquality)
  329. {
  330. vecDevUpdate.push_back(it0);
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. }
  337. /**
  338. * @brief 从Redis获取数据线程函数,这个是摄像机线程
  339. * 一个设备一个线程,这个线程的相关变量只在这个线程中使用
  340. * (注意,这个函数未被使用,不从这里获取Redis数据)
  341. * @param info
  342. */
  343. void SPAServer::threadFromRedis(const CameraThreadInfo& info)
  344. {
  345. SPDLOG_LOGGER_INFO(m_logger, "开启 fromRedisThread 线程,设备ID:{}", info.DeviceID);
  346. FromRedis fromRedis;
  347. fromRedis.setRedisIPAndPort(info.RedisIP, info.RedisPort);
  348. fromRedis.setRedisPassword(info.RedisPWD);
  349. if(fromRedis.connectRedis())
  350. {
  351. SPDLOG_LOGGER_INFO(m_logger, "连接Redis成功");
  352. }else {
  353. SPDLOG_LOGGER_ERROR(m_logger, "连接Redis失败");
  354. return;
  355. }
  356. CameraThreadInfo threadInfo = info;
  357. // std::string strKey = "117:OD210_026_005246_001-IZRTKyEx";
  358. /* 取出该设备的Key */
  359. std::vector<std::string> vecKey;
  360. for(const auto& it : info.vecAction)
  361. {
  362. std::string strKey = std::to_string(info.DeviceID) + ":" + it;
  363. vecKey.push_back(strKey);
  364. }
  365. std::string strRetValue;
  366. /* 进入线程循环 */
  367. while (m_threadRunning)
  368. {
  369. /* 循环读取这个设备关联的算法信息 */
  370. for(const auto& it : vecKey)
  371. {
  372. SPDLOG_LOGGER_INFO(m_logger, "读取Redis信息, Key: {}", it);
  373. if( !fromRedis.getRedisString(it, strRetValue) )
  374. {
  375. continue;
  376. }
  377. SPDLOG_LOGGER_TRACE(m_logger, "Redis Value:\n{}", strRetValue);
  378. /* 解析数据 */
  379. AlarmInfo alarmInfo;
  380. alarmInfo.ActionID = it.substr(it.find(":") + 1);
  381. /* 解析数据 */
  382. parseRedisBaseData(strRetValue, alarmInfo);
  383. parseRedisBBoxesData(strRetValue, alarmInfo);
  384. /* 信息时间有的效性判断,主要是记录Redis数据的有效性,是否长时间没有变化,排查错误时用的
  385. * 如果数据长时间数据不变,那么超脑那里就挂了,写入日志 */
  386. isEventTimeVaild(alarmInfo.EventTime);
  387. /* 是否需要写入EQM数据库判断
  388. * 人员计数和区域人员检测需要多次判断,其他的直接写入即可 */
  389. }
  390. std::this_thread::sleep_for(std::chrono::seconds(2));
  391. }
  392. return;
  393. }
  394. /**
  395. * @brief 分派任务的线程
  396. 1、 线程定时刷新房间和摄像机的关联关系,以及和算法Action的关联关系
  397. 2、 将算法信息加入到不同的列表中
  398. 需要多个摄像机配合的加入到 m_runListRoomActionInfo 列表
  399. 不需要多个摄像机配合的加入到 m_runListActionInfo 列表
  400. 3、 每次刷新都会清空ActionInfo或者RoomActionInfo的摄像机列表,但是不会动其他基本信息,如果是列表中没有对应的信息,
  401. 就会创建新的ActionInfo,那么RunState的状态是INIT,需要开启新的线程
  402. 如果刷新完成后,算法对应的摄像机列表为空,那么对应的线程就会停止运行,将RunState设置为STOP,本线程的下一轮
  403. 循环就会删除这个ActionInfo
  404. */
  405. void SPAServer::threadDistribution()
  406. {
  407. SPDLOG_LOGGER_INFO(m_logger, "开启分派任务线程");
  408. /* 房间相机关联信息 */
  409. std::list<RoomCameraInfo> listRC;
  410. /* 存储获取到的应用和启用时间的信息 */
  411. std::list<AppAndTimeInfo> listAppAndTime;
  412. /* 创建连接数据库实例 */
  413. std::shared_ptr<FromWebAPI> fromWebAPI = std::make_shared<FromWebAPI>();
  414. /* 初始化WebAPI */
  415. // fromWebAPI->initWebApi(const QString &url, const QString &serverIP, const QString &serID)
  416. while (m_threadRunning)
  417. {
  418. /* ======================================================= */
  419. /* 更新通道名称和摄像机名称信息 */
  420. std::map<int, std::string> mapChannelName;
  421. m_fromWebAPI.getChannelInfo(mapChannelName);
  422. GConfig.setChannelInfo(mapChannelName);
  423. std::map<int, std::string> mapCameraName;
  424. m_fromWebAPI.getCameraInfo(mapCameraName);
  425. GConfig.setCameraInfo(mapCameraName);
  426. /* ======================================================= */
  427. GThreadInfo.lockRunFAI();
  428. /* 先清理已经退出的线程所用到的Action或者RoomAction */
  429. GThreadInfo.clearNoneFuncThreadInfo();
  430. /* 清空已经停止运行的功能类实例 */
  431. clearNoneFuncThreadInfo();
  432. /* ======================================================= */
  433. /* 创建应用信息,根据从EQM数据库读取到的配置的应用信息创建 */
  434. fromWebAPI->getAlarmAppInfo(listAppAndTime);
  435. for(const auto& it : listAppAndTime)
  436. {
  437. /* 创建应用信息,如果已有该应用,就更新时间
  438. * 这里只创建应用信息块,没有对应的房间、算法信息 */
  439. GThreadInfo.addFuncThreadInfo(it);
  440. }
  441. /* 设置应用对应的频率信息 */
  442. for(auto& func : GThreadInfo.getList())
  443. {
  444. /* 设置频率名称 */
  445. func->strChannelName = GConfig.getChannelName(func->ChannelID);
  446. }
  447. /* 设置对应的摄像机名称列表 */
  448. GThreadInfo.setCameraInfo(GConfig.getCameraInfoMap());
  449. /* 先获取EQM数据库信息,取出房间和摄像机关联信息,包括所在的频率 */
  450. m_mutexActionInfo.lock();
  451. fromWebAPI->getActionInfo(m_listActionInfo);
  452. /* 将算法信息加入到不同的功能列表中,先清空功能对应的算法设备列表 */
  453. GThreadInfo.clearActionList();
  454. for(const auto& it : m_listActionInfo.getData())
  455. {
  456. GThreadInfo.addActionInfo(*it);
  457. }
  458. /* 检查算法信息的状态,频率里的应用没有配置摄像机就设置为线程运行状态为停止,退出该线程 */
  459. GThreadInfo.setNoneCameraFuncStop();
  460. m_mutexActionInfo.unlock();
  461. /* 开启线程 */
  462. for(const auto& it0 : GThreadInfo.getList())
  463. {
  464. if(it0->RunState == RunTimeState::RUN_STATE_INIT)
  465. {
  466. /* 创建实例 */
  467. FuncBase* pFunc = createFuncInstance(*it0);
  468. if(pFunc == nullptr)
  469. {
  470. SPDLOG_LOGGER_ERROR(m_logger, "创建功能实例失败:{}", it0->strFunctionName);
  471. continue;
  472. }
  473. CPPTP.add_task(&FuncBase::thread_task, pFunc);
  474. m_listFuncBase.push_back(pFunc);
  475. }
  476. }
  477. GThreadInfo.unlockRunFAI();
  478. /* 休眠n秒,默认应该是300秒 */
  479. std::this_thread::sleep_for(std::chrono::seconds(GConfig.CheckSet));
  480. }
  481. SPDLOG_LOGGER_INFO(m_logger, "分派任务线程退出");
  482. }
  483. /**
  484. * @brief 创建任务实例的函数,根据不同的功能创建出不同的实例
  485. *
  486. * @param info
  487. * @return FuncBase*
  488. */
  489. FuncBase* SPAServer::createFuncInstance(FuncThreadInfo& info)
  490. {
  491. if(info.appFunction == AppFunction::APP_NONE)
  492. {
  493. return nullptr;
  494. }
  495. FuncBase* pFunc = nullptr;
  496. /* 普通的功能,只用一个摄像机一个算法的功能 */
  497. if( info.appFunction == AppFunction::APP_AllDown || info.appFunction == AppFunction::APP_NoMask ||
  498. info.appFunction == AppFunction::APP_PlayPhone || info.appFunction == AppFunction::APP_Mouse ||
  499. info.appFunction == AppFunction::APP_Fatigue || info.appFunction == AppFunction::APP_Contraband )
  500. {
  501. auto tmpFunc = new FuncOrdinary();
  502. tmpFunc->setFuncThreadInfo(info);
  503. pFunc = tmpFunc;
  504. }
  505. else if(info.appFunction == AppFunction::APP_OnWork)
  506. {
  507. /* 人员在岗检测 */
  508. }
  509. else if(info.appFunction == AppFunction::APP_Illegal)
  510. {
  511. /* 非法入侵 */
  512. auto tmpFunc = new FuncIllegalInvasion();
  513. tmpFunc->setFuncThreadInfo(info);
  514. pFunc = tmpFunc;
  515. }
  516. else if(info.appFunction == AppFunction::APP_Regional)
  517. {
  518. /* 区域人员检测 */
  519. }
  520. return pFunc;
  521. }
  522. /* 清理没有在运行的线程实例 */
  523. void SPAServer::clearNoneFuncThreadInfo()
  524. {
  525. for(auto it = m_listFuncBase.begin(); it != m_listFuncBase.end(); )
  526. {
  527. if(!(*it)->getThreadRunning())
  528. {
  529. /* 需要转换成相应的子类实例才能删除 */
  530. if( (*it)->getApp() == AppFunction::APP_AllDown || (*it)->getApp() == AppFunction::APP_NoMask ||
  531. (*it)->getApp() == AppFunction::APP_PlayPhone || (*it)->getApp() == AppFunction::APP_Mouse ||
  532. (*it)->getApp() == AppFunction::APP_Fatigue || (*it)->getApp() == AppFunction::APP_Contraband )
  533. {
  534. FuncOrdinary* p = dynamic_cast<FuncOrdinary*>(*it);
  535. delete p;
  536. }
  537. else if((*it)->getApp() == AppFunction::APP_OnWork)
  538. {
  539. /* 人员在岗检测 */
  540. }
  541. else if((*it)->getApp() == AppFunction::APP_Illegal)
  542. {
  543. /* 非法入侵 */
  544. }
  545. else if((*it)->getApp() == AppFunction::APP_Regional)
  546. {
  547. /* 区域人员检测 */
  548. }
  549. it = m_listFuncBase.erase(it);
  550. }else {
  551. ++it;
  552. }
  553. }
  554. }