中间件底层,websocket

AcdCore.cpp 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. #include "StdAfx.h"
  2. #include "AcdCore.h"
  3. #include "Config.h"
  4. #include "Agent.h"
  5. #include "Exten.h"
  6. #include "NetworkAcd.h"
  7. #include "MsgCenter.h"
  8. #include "../Public/Auth/AuthMgr.h"
  9. #include "../Public/DaemonClient/DaemonClient.h"
  10. #include "SoftAuther.h"
  11. #include "YamlConfig.h"
  12. #include "SqlWriter.h"
  13. SINGLETON_IMPLEMENT(CAcdCore)
  14. CAcdCore::CAcdCore(void) : m_SubjectRepository(&m_AgentOffice, &m_ExtenCtrl, &m_QueueMgr)
  15. {
  16. //AllocConsole();//为当前的窗口程序申请一个Console窗口
  17. //freopen("CONOUT$", "w+", stdout);
  18. }
  19. CAcdCore::~CAcdCore(void)
  20. {
  21. }
  22. /*****************************************************************
  23. **【函数名称】 __onAgentStateUpdated
  24. **【函数功能】 座席状态变化事件响应
  25. **【参数】 AgentId: 座席工号
  26. ExtId: 分机号
  27. Status: 座席当前状态
  28. **【返回值】
  29. ****************************************************************/
  30. void CAcdCore::__onAgentStateUpdated( UINT AgentId )
  31. {
  32. CAgent* pAgent = m_AgentOffice.getAgentById(AgentId);
  33. if(pAgent == NULL)
  34. return;
  35. AGENT_STATE State = pAgent->state();
  36. // 通知事件订阅
  37. m_SubjectRepository.onAgentStateUpdated(pAgent->id(), pAgent->assoExten(), State, pAgent->group());
  38. // 如果有座席变为空闲,通知来电队列刷新排队
  39. if(State == AGENT_STATE_FREE)
  40. m_QueueMgr.onAgentFree(pAgent);
  41. }
  42. /*****************************************************************
  43. **【函数名称】 __onPhoneStateUpdated
  44. **【函数功能】 分机状态变化事件响应
  45. **【参数】 AgentId: 座席工号
  46. ExtId: 分机号
  47. Status: 座席当前状态
  48. **【返回值】
  49. ****************************************************************/
  50. void CAcdCore::__onPhoneStateUpdated( UINT ExtenId )
  51. {
  52. CExten* pExten = m_ExtenCtrl.getExten(ExtenId);
  53. if(pExten == NULL)
  54. return;
  55. // 通知事件订阅
  56. m_SubjectRepository.onPhoneStateUpdated(pExten->assoAgent(), pExten->id(), pExten->state());
  57. }
  58. /*****************************************************************
  59. **【函数名称】 __onQueueStateUpdated
  60. **【函数功能】 排队状态变化事件响应
  61. **【参数】 Count: 等待排队的呼叫数量
  62. **【返回值】
  63. ****************************************************************/
  64. void CAcdCore::__onQueueStateUpdated( UINT QueueNo )
  65. {
  66. UINT Count = m_QueueMgr.callCount(QueueNo);
  67. // 通知事件订阅
  68. m_SubjectRepository.onQueueStateUpdated(QueueNo, Count);
  69. }
  70. /*****************************************************************
  71. **【函数名称】 __removeAgent
  72. **【函数功能】 关闭指定座席
  73. **【参数】 AgentId: 要关闭座席的工号
  74. ExtId: 要关闭座席的分机号
  75. HostAgent: 主控制坐席工号
  76. **【返回值】
  77. ****************************************************************/
  78. void CAcdCore::__removeAgent( UINT AgentId, UINT ExtId, UINT HostAgent )
  79. {
  80. if(!m_AgentOffice.isAgentExisted(AgentId))
  81. return;
  82. // ych 2018.5.4 安图拷贝
  83. CAgent* pAgent = m_AgentOffice.getAgentById(AgentId);
  84. CAgentProperty AgentProperty;
  85. AgentProperty.pAgent = pAgent;
  86. pAgent->GetAgentProperty(AgentProperty);
  87. AgentProperty.m_FirstLogTimeToday = CTime::GetCurrentTime();
  88. m_AgentOffice.GetAgentPropertyMap().insert(pair<UINT, CAgentProperty>(AgentId, AgentProperty));
  89. // 清空对应的座席信息
  90. m_ExtenCtrl.setAssoAgent(ExtId, 0); // 清除关联分机
  91. m_SubjectRepository.clearObserver(AgentId); // 清除订阅信息
  92. m_AgentOffice.removeAgent(AgentId, HostAgent); // 清除对应座席
  93. }
  94. /*****************************************************************
  95. **【函数名称】 __onCmdAgentReg
  96. **【函数功能】 PDU注册命令
  97. **【参数】 a_pCmd: PDU命令内容
  98. **【返回值】
  99. ****************************************************************/
  100. void CAcdCore::__onCmdAgentReg( CPduEntity* a_pCmd )
  101. {
  102. if(a_pCmd->GetLocalDevType() == PDU_DEV_TYPE_AGENT) // 仅处理座席注册
  103. {
  104. // 获取发送方的IP
  105. CString PeerIp = _T("");
  106. // CNetworkAcd::GetInstance().getPduSource(a_pCmd, PeerIp);
  107. // 是否为相同主机的座席重复签入
  108. UINT AgentId = a_pCmd->GetLocalDevId();
  109. if(m_AgentOffice.isAgentExisted(AgentId, PeerIp))
  110. {
  111. //关闭原座席
  112. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%ld]重复登录, IP Address = %s"), AgentId, PeerIp);
  113. __removeAgent(AgentId, m_AgentOffice.getAgentAssoExten(AgentId), 0);
  114. } // end if
  115. // 查找当前座席是否已注册
  116. if(m_AgentOffice.isAgentExisted(AgentId))
  117. a_pCmd->SetDataBool(0, false);
  118. else
  119. a_pCmd->SetDataBool(0, true);
  120. // 返回执行结果
  121. a_pCmd->SetToExecReturn();
  122. CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  123. } // end if
  124. else if (a_pCmd->GetLocalDevType()==PDU_DEV_TYPE_SERVER)
  125. {
  126. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("-------------------Server已连接---------------------------"));
  127. a_pCmd->SetToExecReturn();
  128. a_pCmd->SetDataBool(0, true);
  129. CNetInterface::getNetInstance()->Send(a_pCmd, PDU_DEV_TYPE_SERVER, 0);
  130. }
  131. }
  132. /*****************************************************************
  133. **【函数名称】 __onCmdAgentDial
  134. **【函数功能】 处理呼叫相关的命令
  135. **【参数】 a_pCmd: PDU命令内容
  136. **【返回值】
  137. ****************************************************************/
  138. void CAcdCore::__onCmdAgentDial( CPduEntity* a_pCmd )
  139. {
  140. if(a_pCmd->GetIsExecReturn()) // CTI -> Agent 的返回命令
  141. {
  142. UINT DestDevId = a_pCmd->GetDataUInt(2);
  143. //CNetworkAcd::GetInstance().send2Agent(DestDevId, a_pCmd);
  144. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  145. }
  146. else // Agent -> CTI 的请求命令
  147. {
  148. CString DestNum = _T("");
  149. CString CmdHint = _T("");
  150. UINT AgentId = a_pCmd->GetDataUInt(2);
  151. switch(a_pCmd->GetCmdType())
  152. {
  153. case PDU_CMD_AGENT_TRANSTALK: // 座席转移
  154. {
  155. CString transferType = a_pCmd->GetDataString(5);
  156. if (transferType == "1") //如果指定技能组转移,直接用以下函数处理
  157. {
  158. __onCmdAgentTransferSkillGroup(a_pCmd);
  159. return;
  160. }
  161. CmdHint = _T("座席转移");
  162. DestNum = a_pCmd->GetDataString(3);
  163. }
  164. break;
  165. case PDU_CMD_AGENT_THREETALK: // 三方会议
  166. {
  167. CmdHint = _T("座席三方");
  168. DestNum = a_pCmd->GetDataString(3);
  169. }
  170. break;
  171. case PDU_CMD_AGENT_CONSULTATION_CALL: // 协商呼叫
  172. {
  173. CmdHint = _T("座席协商");
  174. DestNum = a_pCmd->GetDataString(4);
  175. }
  176. break;
  177. case PDU_CMD_AGENT_MAKECALL: // 坐席外呼
  178. {
  179. CmdHint = _T("座席呼叫");
  180. DestNum = a_pCmd->GetDataString(4);
  181. // 如果主叫座席分机非空闲或摘机拨号,禁止呼出
  182. INNER_STATE ExtStatus = m_ExtenCtrl.getExtenState(a_pCmd->GetDataUInt(1));
  183. if (ExtStatus != INNER_STATE_FREE || ExtStatus == INNER_STATE_INIT)
  184. {
  185. a_pCmd->SetToExecReturn();
  186. a_pCmd->SetDataBool(0, false);
  187. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  188. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  189. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%ld]请求呼叫失败, 关联分机非空闲"), AgentId);
  190. return; // 不再向CTI转发
  191. } // end if
  192. if(!m_AgentOffice.setAgentState4Calling(AgentId))
  193. {
  194. a_pCmd->SetToExecReturn();
  195. a_pCmd->SetDataBool(0, false);
  196. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  197. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  198. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%u]请求呼叫失败, 座席状态异常或已被锁定"), AgentId);
  199. return; // 不再向CTI转发
  200. }
  201. }
  202. break;
  203. } // end switch
  204. if(!CConfig::isMatchCallPrefix(DestNum)) // 呼叫分机
  205. {
  206. if (false == m_ExtenCtrl.isExtenExisted(atoi(DestNum))) // 分机号不存在
  207. {
  208. a_pCmd->SetToExecReturn();
  209. a_pCmd->SetDataBool(0, false);
  210. // CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  211. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  212. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 请求呼叫分机 %s 失败,分机号不存在"), DestNum);
  213. return; // 不再向CTI转发
  214. }
  215. // 查找要呼叫的分机座席工号
  216. UINT DestAgentId = m_ExtenCtrl.getAssoAgent(atoi(DestNum));
  217. if(m_AgentOffice.isAgentExisted(DestAgentId) && !m_AgentOffice.lockAgent(DestAgentId)) // 被叫叫座席非空闲
  218. {
  219. a_pCmd->SetToExecReturn();
  220. a_pCmd->SetDataBool(0, false);
  221. // CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  222. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  223. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%u]请求呼叫失败, 目标座席[%u]非空闲,[%d]"), AgentId, DestAgentId, m_AgentOffice.getAgentState(DestAgentId));
  224. return; // 不再向CTI转发
  225. }
  226. } // end if
  227. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%s], Agent = %lu, Exten = %lu, Dest Number = %s"),
  228. CmdHint, AgentId, a_pCmd->GetDataUInt(1), DestNum);
  229. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  230. } // end if
  231. }
  232. /*****************************************************************
  233. **【函数名称】 __onCmdAgentLogin
  234. **【函数功能】 座席签入命令
  235. **【参数】 a_pCmd: PDU命令内容
  236. **【返回值】
  237. ****************************************************************/
  238. void CAcdCore::__onCmdAgentLogin( CPduEntity* a_pCmd )
  239. {
  240. // 得到座席签入信息
  241. UINT ExtId = a_pCmd->GetDataUInt(1);
  242. UINT AgentId = a_pCmd->GetDataUInt(2);
  243. CString Group = a_pCmd->GetDataString(3);
  244. UINT AgentType = a_pCmd->GetDataUInt(4);
  245. UINT TimePostProcessing = a_pCmd->GetDataUInt(5);
  246. // 显示日志
  247. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL,
  248. _T("{Core}: AGENT -> ACD, CMD = [座席签入], Agent = %lu, Exten = %lu, Group = %s, Type = %lu"), AgentId, ExtId, Group, AgentType);
  249. // 校验
  250. bool IsSucceed = false;
  251. if(!CNetworkAcd::GetInstance().isCtiConnected()) // CTI是否已连接
  252. {
  253. a_pCmd->SetDataBool(0, false);
  254. a_pCmd->SetDataUInt(6, LOGIN_ERR_NO_CTI);
  255. }
  256. //#ifndef _DEBUG
  257. else if(m_AgentOffice.getAgentCount() >= (UINT)m_Auther.GetAgentCount()) //ACD 授权数量验证
  258. {
  259. a_pCmd->SetDataBool(0, false);
  260. a_pCmd->SetDataUInt(6, LOGIN_ERR_AUTH_FAILED);
  261. }
  262. //#endif
  263. else if(!m_ExtenCtrl.isExtenExisted(ExtId)) // 查找要签入的分机是否存在
  264. {
  265. a_pCmd->SetDataBool(0, false);
  266. a_pCmd->SetDataUInt(6, LOGIN_ERR_NO_EXT);
  267. }
  268. else if(m_ExtenCtrl.isExtenUsed(ExtId)) // 分机是否已被占用
  269. {
  270. a_pCmd->SetDataBool(0, false);
  271. a_pCmd->SetDataUInt(6, LOGIN_ERR_BIND_EXT);
  272. /*
  273. UINT AgentID = m_ExtenCtrl.getAssoAgent(ExtId);
  274. __removeAgent(AgentID, ExtId, AgentID);
  275. CPduEntity cmd(PDU_CMD_AGENT_LOGOUT); // 2022-01-06 分机被挤掉,告诉被挤坐席迁出
  276. cmd.SetDataUInt(1, ExtId);
  277. cmd.SetDataUInt(2, AgentID);
  278. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  279. a_pCmd->SetDataBool(0, true);
  280. IsSucceed = true;
  281. */
  282. }
  283. else // 可以签入
  284. {
  285. a_pCmd->SetDataBool(0, true);
  286. IsSucceed = true;
  287. } // end if
  288. // 如果签入执行成功
  289. if(IsSucceed)
  290. {
  291. // 生成座席实例
  292. INNER_STATE ExtStatus = m_ExtenCtrl.getExtenState(ExtId);
  293. if(!m_AgentOffice.insertAgent(AgentId, ExtId, Group, AgentType, TimePostProcessing, ExtStatus))
  294. {
  295. a_pCmd->SetDataBool(0, false);
  296. a_pCmd->SetDataUInt(6, LOGIN_ERR_BIND_AGENT);
  297. }
  298. else
  299. {
  300. // 通知CTI座席已签入
  301. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  302. CPduEntity pdu(PDU_CMD_AGENT_RESET);
  303. pdu.SetDataUInt(1,a_pCmd->GetDataUInt(1));
  304. pdu.SetDataUInt(2,a_pCmd->GetDataUInt(2));
  305. CNetworkAcd::GetInstance().send2Cti(&pdu);
  306. // 建立分机与座席的关联
  307. m_ExtenCtrl.setAssoAgent(ExtId, AgentId);
  308. }
  309. } // end if
  310. // 返回签入执行结果
  311. a_pCmd->SetToExecReturn();
  312. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  313. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  314. }
  315. /*****************************************************************
  316. **【函数名称】 __onCmdAgentLogout
  317. **【函数功能】 座席签出命令
  318. **【参数】 a_pCmd: PDU命令内容
  319. **【返回值】
  320. ****************************************************************/
  321. void CAcdCore::__onCmdAgentLogout( CPduEntity* a_pCmd )
  322. {
  323. // 得到座席信息
  324. UINT ExtId = a_pCmd->GetDataUInt(1);
  325. UINT AgentId = a_pCmd->GetDataUInt(2);
  326. UINT Reason = a_pCmd->GetDataUInt(3); // HP-Server自己主动签出坐席 2019-12-3
  327. // 显示日志
  328. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席签出], Agent = %lu, Exten = %lu"), AgentId, ExtId);
  329. // ych 2018.5.16
  330. // m_AgentOffice.setAgentState(AgentId, AGENT_STATE_LOGOUT);
  331. if (m_AgentOffice.setAgentState(AgentId, AGENT_STATE_LOGOUT, Reason == 3 ? true : false))
  332. {
  333. a_pCmd->SetDataBool(0, true);
  334. }
  335. else
  336. {
  337. a_pCmd->SetDataBool(0, false);
  338. //tj 通知Server
  339. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  340. return;
  341. }
  342. // 通知CTI座席签出
  343. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  344. //tj 通知Server
  345. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  346. // 清空对应的座席信息
  347. Sleep(100);
  348. /*__removeAgent(AgentId, ExtId, AgentId);*/
  349. __removeAgent(AgentId, ExtId, Reason == 3 ? 3 : AgentId);
  350. }
  351. /*****************************************************************
  352. **【函数名称】 __onCmdAgentSetState
  353. **【函数功能】 主动设置座席状态
  354. **【参数】 a_pCmd: PDU命令内容
  355. **【返回值】
  356. ****************************************************************/
  357. void CAcdCore::__onCmdAgentSetState( CPduEntity* a_pCmd )
  358. {
  359. // 得到座席信息
  360. UINT AgentId = a_pCmd->GetDataUInt(2);
  361. AGENT_STATE State = static_cast<AGENT_STATE>(a_pCmd->GetDataUInt(3));
  362. // 显示日志
  363. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席状态设置], Agent = %lu, State = %d"), AgentId, State);
  364. // 设置座席逻辑状态
  365. if(m_AgentOffice.setAgentState(AgentId, State))
  366. a_pCmd->SetDataBool(0, true);
  367. else
  368. a_pCmd->SetDataBool(0, false);
  369. // 返回执行结果
  370. a_pCmd->SetToExecReturn();
  371. //CNetworkAcd::GetInstance().send2Agent(a_pCmd->GetLocalDevId(), a_pCmd);
  372. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  373. }
  374. /*****************************************************************
  375. **【函数名称】 __onCmdAgentSubscribe
  376. **【函数功能】 订阅管理
  377. **【参数】 a_pCmd: PDU命令内容
  378. **【返回值】
  379. ****************************************************************/
  380. void CAcdCore::__onCmdAgentSubscribe( CPduEntity* a_pCmd )
  381. {
  382. UINT AgentId = a_pCmd->GetDataUInt(2);
  383. SUBJECT_TYPE Type = static_cast<SUBJECT_TYPE>(a_pCmd->GetDataUInt(4));
  384. int PduType;
  385. // 订阅管理
  386. switch(a_pCmd->GetCmdType())
  387. {
  388. case PDU_CMD_AGENT_SUBSCRIBE: // 事件订阅
  389. PduType = 1;
  390. m_SubjectRepository.registObserver(AgentId, Type, a_pCmd->GetDataInt(3));
  391. break;
  392. case PDU_CMD_AGENT_CANCEL_SUBSCRIBE:// 取消订阅
  393. PduType = 2;
  394. m_SubjectRepository.removeObserver(AgentId, Type, a_pCmd->GetDataInt(3));
  395. break;
  396. } // end switch
  397. // 显示日志
  398. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席订阅], Agent = %lu, mode(1-订阅 2-取消) = %d, Type = %d"),
  399. AgentId, PduType, Type);
  400. }
  401. /*****************************************************************
  402. **【函数名称】 __onCmdAgentForceLogout
  403. **【函数功能】 强制签出指定座席
  404. **【参数】 a_pCmd: PDU命令内容
  405. **【返回值】
  406. ****************************************************************/
  407. void CAcdCore::__onCmdAgentForceLogout( CPduEntity* a_pCmd )
  408. {
  409. // 得到主控座席和受控座席信息
  410. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  411. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  412. // 显示日志
  413. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席强制签出], Agent = %lu, TargetAgent = %lu"), HostAgentId, TargetAgentId);
  414. // 座席是否已签入
  415. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  416. {
  417. a_pCmd->SetDataBool(0, false);
  418. // 坐席不存在的情况下对坐席操作的错误日志
  419. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 强制坐席[%d]签出失败, 坐席[%d]未签入"), TargetAgentId, TargetAgentId);
  420. }
  421. else
  422. {
  423. if (m_AgentOffice.setAgentState(TargetAgentId, AGENT_STATE_LOGOUT))
  424. {
  425. a_pCmd->SetDataBool(0, true);
  426. }
  427. else
  428. {
  429. a_pCmd->SetDataBool(0, false);
  430. }
  431. UINT TargetExtId = m_AgentOffice.getAgentAssoExten(TargetAgentId);
  432. // 通知CTI座席签出
  433. CPduEntity cmd(PDU_CMD_AGENT_LOGOUT);
  434. cmd.SetDataUInt(1, TargetExtId);
  435. cmd.SetDataUInt(2, TargetAgentId);
  436. CNetworkAcd::GetInstance().send2Cti(&cmd);
  437. // 关闭座席
  438. __removeAgent(TargetAgentId, TargetExtId, HostAgentId);
  439. } // end if
  440. // 返回执行结果
  441. a_pCmd->SetToExecReturn();
  442. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  443. }
  444. /*****************************************************************
  445. **【函数名称】 __onCmdAgentMonControl
  446. **【函数功能】 班长电话控制
  447. **【参数】 a_pCmd: PDU命令内容
  448. **【返回值】
  449. ****************************************************************/
  450. void CAcdCore::__onCmdAgentMonControl( CPduEntity* a_pCmd )
  451. {
  452. if(!a_pCmd->GetIsExecReturn()) // OCX发出的命令
  453. {
  454. // 得到主控座席和受控座席信息
  455. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  456. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  457. // 显示日志
  458. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%d](班长控制), Agent = %lu, TargetAgent = %lu"),
  459. a_pCmd->GetCmdType(), HostAgentId, TargetAgentId);
  460. // 确定目标座席已签入
  461. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  462. {
  463. // 添加坐席不存在的情况下对坐席操作的错误日志
  464. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 班长[%d]对坐席[%d]执行[%d]控制失败, 目标坐席未签入"),
  465. HostAgentId, TargetAgentId, a_pCmd->GetCmdType());
  466. // 返回执行结果
  467. a_pCmd->SetDataBool(0, false);
  468. a_pCmd->SetToExecReturn();
  469. //CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  470. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  471. return;
  472. }
  473. // 确保班长座席状态空闲
  474. if (!m_AgentOffice.setAgentState(HostAgentId, AGENT_STATE_FREE))
  475. {
  476. // 添加坐席不存在的情况下对坐席操作的错误日志
  477. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 班长[%d]对坐席[%d]执行[%d]控制失败, 班长状态非空闲"),
  478. HostAgentId, TargetAgentId, a_pCmd->GetCmdType());
  479. a_pCmd->SetDataBool(0, false);
  480. a_pCmd->SetToExecReturn();
  481. // CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  482. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  483. return;
  484. }
  485. // 转发命令到CTI
  486. a_pCmd->SetDataUInt(3, m_AgentOffice.getAgentAssoExten(TargetAgentId));
  487. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  488. }
  489. else // CTI的执行结果返回
  490. {
  491. //CNetworkAcd::GetInstance().send2Agent(a_pCmd->GetDataUInt(2), a_pCmd);
  492. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  493. } // end if
  494. }
  495. /*****************************************************************
  496. **【函数名称】 __onCmdAgentForceState
  497. **【函数功能】 强制座席状态控制
  498. **【参数】 a_pCmd PDU命令内容
  499. **【返回值】
  500. ****************************************************************/
  501. void CAcdCore::__onCmdAgentForceState( CPduEntity* a_pCmd )
  502. {
  503. // 得到主控座席和受控座席信息
  504. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  505. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  506. AGENT_STATE State = static_cast<AGENT_STATE>(a_pCmd->GetDataUInt(5));
  507. // 显示日志
  508. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席强制状态转换], Agent = %lu, TargetAgent = %lu, State = %d"),
  509. HostAgentId, TargetAgentId, State);
  510. // 座席是否已签入
  511. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  512. {
  513. a_pCmd->SetDataBool(0, false);
  514. // 添加坐席不存在的情况下对坐席操作的错误日志
  515. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 对坐席[%d]执行强制状态转换失败, 目标坐席没有签入"), TargetAgentId);
  516. }
  517. else
  518. {
  519. // 改变受控座席状态
  520. if(m_AgentOffice.setAgentState(TargetAgentId, State))
  521. a_pCmd->SetDataBool(0, true);
  522. else
  523. a_pCmd->SetDataBool(0, false);
  524. } // end if
  525. // 返回执行结果
  526. a_pCmd->SetToExecReturn();
  527. //CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  528. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  529. }
  530. /*****************************************************************
  531. **【函数名称】 __onCmdCtiExtenInfo
  532. **【函数功能】 内线分机状态变化命令
  533. **【参数】 a_pCmd: PDU命令内容
  534. **【返回值】
  535. ****************************************************************/
  536. void CAcdCore::__onCmdCtiExtenInfo( CPduEntity* a_pCmd )
  537. {
  538. UINT ExtID = a_pCmd->GetDataUInt(0);
  539. UINT State = a_pCmd->GetDataUInt(1);
  540. UINT Agentid = m_ExtenCtrl.getAssoAgent(ExtID); // 坐席工号
  541. if(State == INNER_STATE_REMOVE)
  542. {
  543. if (ExtID != 0)
  544. {
  545. if (Agentid != 0)
  546. __removeAgent(Agentid, ExtID, 0); // 迁出坐席
  547. //删除分机
  548. m_ExtenCtrl.removeExten(ExtID);
  549. }
  550. }
  551. else
  552. {
  553. // 显示日志
  554. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [线路状态信息], Exten = %lu, State = %lu,ActionID = %d,TrunkNum = %s"), ExtID, State,a_pCmd->GetDataInt(11),a_pCmd->GetDataString(13));
  555. // 通知分机管理类
  556. m_ExtenCtrl.onExtenStateUpdated(a_pCmd);
  557. if (Agentid != 0)
  558. {
  559. m_AgentOffice.onExtenStateUpdated(Agentid, a_pCmd); // 通知座席管理类。报坐席和分机状态
  560. }
  561. }
  562. }
  563. /*****************************************************************
  564. **【函数名称】 __onCmdCtiRecord
  565. **【函数功能】 CTI通知座席录音信息
  566. **【参数】 a_pCmd: PDU命令内容
  567. **【返回值】
  568. ****************************************************************/
  569. void CAcdCore::__onCmdCtiRecord( CPduEntity* a_pCmd )
  570. {
  571. UINT Exten = a_pCmd->GetDataUInt(0);
  572. // 显示日志
  573. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [录音信息], Exten = %lu, CallId = %lu, FileName = %s"),
  574. Exten, a_pCmd->GetDataULong(1), a_pCmd->GetDataString(2));
  575. // 通过分机号查找对应的座席工号
  576. UINT AgentId = m_ExtenCtrl.getAssoAgent(Exten);
  577. if(AgentId != 0) // 有关联座席
  578. {
  579. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  580. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  581. }
  582. else // 录音未通知日志
  583. {
  584. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 录音信息[%s]未通知到坐席, 座席未签入"), a_pCmd->GetDataString(2));
  585. } // end if
  586. }
  587. /*****************************************************************
  588. **【函数名称】 __onCmdCtiDevCall
  589. **【函数功能】 CTI通知座席物理外呼信息
  590. **【参数】 a_pCmd: PDU命令内容
  591. **【返回值】
  592. ****************************************************************/
  593. void CAcdCore::__onCmdCtiDevCall( CPduEntity* a_pCmd )
  594. {
  595. UINT AgentId = a_pCmd->GetDataUInt(2);
  596. // 显示日志
  597. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [外呼信息], Exten = %lu, Agent = %lu, CallId = %lu, Number = %s"),
  598. a_pCmd->GetDataUInt(1), AgentId, a_pCmd->GetDataULong(3), a_pCmd->GetDataString(4));
  599. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  600. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  601. }
  602. /*****************************************************************
  603. **【函数名称】 __onCmdCtiTrunkUsage
  604. **【函数功能】 CTI通知呼叫任务中继利用率
  605. **【参数】 a_pCmd: PDU命令内容
  606. **【返回值】
  607. ****************************************************************/
  608. void CAcdCore::__onCmdCtiTrunkUsage( CPduEntity* a_pCmd )
  609. {
  610. UINT TaskId = a_pCmd->GetDataUInt(0);
  611. UINT Usage = a_pCmd->GetDataUInt(1);
  612. m_SubjectRepository.onTrunkUsageUpdated(TaskId, Usage);
  613. }
  614. /*****************************************************************
  615. **【函数名称】 __onCmdIvrQueue
  616. **【函数功能】 排队管理操作
  617. **【参数】 a_pCmd: PDU命令内容
  618. **【返回值】
  619. ****************************************************************/
  620. void CAcdCore::__onCmdIvrQueue( CPduEntity* a_pCmd )
  621. {
  622. PDU_CMD_TYPE CmdType = a_pCmd->GetCmdType();
  623. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [%d](来电排队)"), CmdType);
  624. switch(CmdType)
  625. {
  626. case PDU_CMD_IVR_WANT_AGENT: // IVR请求座席
  627. {
  628. m_QueueMgr.onQueueAsking(a_pCmd);
  629. }
  630. break;
  631. case PDU_CMD_IVR_QUEUE_CONTINUE: // IVR通知CTI继续排队
  632. {
  633. m_QueueMgr.onQueueContinue(a_pCmd);
  634. }
  635. break;
  636. case PDU_CMD_IVR_QUEUE_CANCEL: // IVR通知CTI取消排队
  637. {
  638. m_QueueMgr.onQueueCancel(a_pCmd);
  639. }
  640. break;
  641. case PDU_CMD_CTI_ACD_QUEUE_PAUSE: // CTI通知ACD暂停排队
  642. {
  643. m_QueueMgr.onQueuePause(a_pCmd);
  644. }
  645. break;
  646. } // end switch
  647. // 2022-04-02 呼入电话在对应坐席组的排队位置
  648. m_QueueMgr.onUpdateCallIndex();
  649. // 发送技能组排队情况
  650. __onCmdAgentSkillGroupWaitCount();
  651. }
  652. /*****************************************************************
  653. **【函数名称】 __onCmdNeed2Forward
  654. **【函数功能】 处理Agent与CTI相与转发的命令
  655. **【参数】 a_pCmd: PDU命令内容
  656. **【返回值】
  657. ****************************************************************/
  658. void CAcdCore::__onCmdNeed2Forward( CPduEntity* a_pCmd )
  659. {
  660. if(a_pCmd->GetIsExecReturn()) // CTI -> Agent 的返回命令
  661. {
  662. UINT AgentId = a_pCmd->GetDataUInt(2);
  663. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  664. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  665. }
  666. else // Agent -> CTI 的请求命令
  667. {
  668. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  669. } // end if
  670. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%d], Agent = %lu, Exten = %lu"),
  671. a_pCmd->GetCmdType(), a_pCmd->GetDataUInt(2), a_pCmd->GetDataUInt(1));
  672. }
  673. void CAcdCore::__onCmdDataSendToAgent(CPduEntity * a_pCmd)
  674. {
  675. int count = a_pCmd->GetDataUInt(0);
  676. if (a_pCmd->GetCmdType() == PDU_CMD_CTI_TRUNKUSE_COUNT)
  677. {
  678. m_TrunkCount = count;
  679. m_TrunkCount = a_pCmd->GetDataUInt(1); // 当前中继呼入数量
  680. m_ExtCallOutCount = a_pCmd->GetDataUInt(2); // 当前外呼数量
  681. AgentRingCount = a_pCmd->GetDataUInt(3); // 当前坐席振铃数量
  682. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}:收到中继利用数量: %d"),count);
  683. }
  684. else if (a_pCmd->GetCmdType() == PDU_CMD_IVR_WAITER_COUNT)
  685. {
  686. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}:收到等待数量: %d"),count);
  687. m_WaitCount = count;
  688. CString curDay;
  689. CTime tm;
  690. tm = CTime::GetCurrentTime();
  691. int curHour = tm.GetHour();
  692. std::cout << curHour << std::endl;
  693. if ((9 <= curHour && curHour < 11) ||(14 == curHour ))
  694. {
  695. auto curTime = tm.Format("%Y-%m-%d %H:%M:%S");
  696. CString sql;
  697. sql.Format("insert into rep_wait_count(Count,UpdateTime) values(%d,'%s')", count, curTime);
  698. CSqlWriter::GetInstance().addSql(sql);
  699. std::cout << sql.GetBuffer(0) << std::endl;
  700. }
  701. }
  702. bool isSuccess = CNetworkAcd::GetInstance().send2Server(a_pCmd);
  703. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}: 通知[%d][%s],当前数量:%d"), a_pCmd->GetCmdType(), isSuccess ? "成功" : "失败", count);
  704. }
  705. void CAcdCore::__onCmdGetAgentList(CPduEntity * a_pCmd)
  706. {
  707. CString szAgentList;
  708. m_AgentOffice.getAllAgentStateList(szAgentList);
  709. int t_agent_id = a_pCmd->GetDataUInt(1);
  710. if (!pushAgentList(t_agent_id, szAgentList.GetBuffer(0))) // 如果rcf失败在使用原来参数传递
  711. {
  712. if (szAgentList.GetLength() >= 512)
  713. {
  714. szAgentList = szAgentList.Left(511);
  715. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("ACD -> HP-SERVER,坐席[%lu]获取坐席列表字符超出被截取 "), a_pCmd->GetDataUInt(1));
  716. }
  717. a_pCmd->SetDataString(2, szAgentList);
  718. }
  719. szAgentList.ReleaseBuffer();
  720. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  721. }
  722. void CAcdCore::__onCmdMonitor(CPduEntity * a_pCmd)
  723. {
  724. // 返回监控执行结果
  725. a_pCmd->SetToExecReturn();
  726. int WaiteCallCount = m_QueueMgr.callCount();
  727. int AgentLoginCount = m_AgentOffice.getAgentCount();
  728. int AgentSpeakCount = 0;
  729. int AgentOnlineCount = 0;
  730. int AgentReposeCount = 0;
  731. m_AgentOffice.GetCurAgentCount(AgentSpeakCount, AgentOnlineCount, AgentReposeCount);
  732. char strValue[PDU_MAX_DATA_BUF_LEN] = { 0 };
  733. sprintf_s(strValue, "%d|%d|%d|%d", AgentSpeakCount, AgentOnlineCount, AgentReposeCount, WaiteCallCount);
  734. a_pCmd->SetDataString(2, strValue);
  735. a_pCmd->SetDataBool(0, true);
  736. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  737. }
  738. void CAcdCore::__onCmdAgentDetail(CPduEntity * a_pCmd)
  739. {
  740. // 返回坐席详情执行结果
  741. a_pCmd->SetToExecReturn();
  742. int ringCount = 0;
  743. m_AgentOffice.GetCurAgentCount(AgentSpeakCount, AgentOnlineCount, AgentReposeCount, AgentFreeCount, AgentProcessingCount, ringCount);
  744. //AgentRingCount = ringCount;
  745. char strValue[PDU_MAX_DATA_BUF_LEN] = { 0 };
  746. sprintf_s(strValue, "%d|%d|%d|%d|%d|%d|%d|%d|%d", AgentSpeakCount, AgentOnlineCount, AgentReposeCount, m_WaitCount, AgentFreeCount, AgentProcessingCount, AgentRingCount, m_ExtCallOutCount, m_TrunkCount);
  747. a_pCmd->SetDataString(2, strValue);
  748. a_pCmd->SetDataBool(0, true);
  749. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  750. m_LoginCount = AgentOnlineCount;
  751. m_TalkingCount = AgentSpeakCount;
  752. }
  753. void CAcdCore::__onCmdUpdateAgentCount()
  754. {
  755. static time_t lastTime = time(NULL);
  756. static bool isFirst = true;
  757. int64_t timesamp = time(NULL) - lastTime;
  758. std::cout << timesamp << std::endl;
  759. if (timesamp >= (5 * 60) || isFirst)
  760. {
  761. CString sql;
  762. sql.Format("update rep_service set Checkin=%d,Conversation=%d", m_LoginCount, m_TalkingCount);
  763. CSqlWriter::GetInstance().addSql(sql);
  764. lastTime = time(NULL);
  765. isFirst = false;
  766. }
  767. }
  768. void CAcdCore::__onCmdAgentTransferSkillGroup(CPduEntity * a_pCmd)
  769. {
  770. UINT ExtenId = 0;
  771. UINT AgentId = 0;
  772. CString QueueNo = a_pCmd->GetDataString(3);
  773. if (!m_QueueMgr.GetFreeAgent(atoi(QueueNo), AgentId, ExtenId)) // 没有获取到指定技能组的空闲坐席
  774. {
  775. a_pCmd->SetDataBool(0, false);
  776. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  777. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL,"[%s][%d]获取坐席失败",__FUNCTION__,__LINE__ );
  778. }
  779. else
  780. {
  781. if (!m_AgentOffice.lockAgent(AgentId)) // 被叫叫座席非空闲
  782. {
  783. a_pCmd->SetToExecReturn();
  784. a_pCmd->SetDataBool(0, false);
  785. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  786. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, "[%s][%d]锁定坐席失败", __FUNCTION__, __LINE__);
  787. return; // 不再向CTI转发
  788. }
  789. CString DestNum;
  790. DestNum.Format("%lu", ExtenId);
  791. a_pCmd->SetDataString(3, DestNum);
  792. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%s], Agent = %lu, Exten = %lu, Dest Number = [%s][%lu][%lu]"),
  793. "指定技能组转移", a_pCmd->GetDataUInt(2), a_pCmd->GetDataUInt(1), QueueNo, AgentId, ExtenId);
  794. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  795. }
  796. }
  797. void CAcdCore::__onCmdAgentSkillGroupWaitCount()
  798. {
  799. CPduEntity cmd(PDU_CMD_AGENT_SKILL_GROUP_WAIT_COUNT);
  800. cmd.SetDataString(0, m_QueueMgr.waitCount());
  801. CNetworkAcd::GetInstance().send2Server(&cmd);
  802. }
  803. void CAcdCore::__onCallInAgent(CPduEntity * a_pCmd)
  804. {
  805. if (a_pCmd->GetCmdType() != PDU_CMD_CTI_LINE_STATE) // 只处理分机状态信息
  806. return;
  807. UINT ExtID = a_pCmd->GetDataUInt(0);
  808. UINT State = a_pCmd->GetDataUInt(1);
  809. CString Callee = a_pCmd->GetDataString(5);
  810. CString ExtIDStr;
  811. ExtIDStr.Format("%d",ExtID);
  812. static std::map<CString, GroupTalking> groupCount;
  813. CExten* pExten = m_ExtenCtrl.getExten(ExtID);
  814. if (pExten != NULL && ExtIDStr == Callee) // 被叫号码=当前分机号时,说明当前分机是被叫
  815. {
  816. if (pExten->GetPeerLineType() != DEV_RES_TYPE_EXT && State == INNER_STATE_TALKING)
  817. {
  818. UINT Agentid = pExten->assoAgent();// 坐席工号
  819. auto pAgent = m_AgentOffice.getAgentById(Agentid);
  820. if (pAgent != NULL)
  821. {
  822. CString groupId = pAgent->group();
  823. auto it = groupCount.find(groupId);
  824. if (it != groupCount.end())
  825. {
  826. it->second.add(ExtID);
  827. CString str;
  828. str.Format("%s|%d", groupId,it->second.count());
  829. std::string ss;
  830. ss = str.GetBuffer(0);
  831. pushRedis(ss);
  832. }
  833. else
  834. {
  835. GroupTalking gTalking;
  836. gTalking.add(ExtID);
  837. groupCount[groupId] = gTalking;
  838. CString str;
  839. str.Format("%s|%d", groupId, it->second.count());
  840. std::string ss;
  841. ss = str.GetBuffer(0);
  842. pushRedis(ss);
  843. }
  844. }
  845. }
  846. }
  847. if (State == INNER_STATE_REMOVE || State == INNER_STATE_FREE) // 话机移除或空闲
  848. {
  849. std::vector<std::string> vecs;
  850. auto it = groupCount.begin();
  851. while (it != groupCount.end())
  852. {
  853. it->second.del(ExtID);
  854. CString str;
  855. str.Format("%s|%d", it->first, it->second.count());
  856. std::string ss;
  857. ss = str.GetBuffer(0);
  858. vecs.emplace_back(ss);
  859. ++it;
  860. }
  861. if(!vecs.empty())
  862. pushRedis(vecs);
  863. }
  864. }
  865. /*****************************************************************
  866. **【函数名称】 stage1Start
  867. **【函数功能】 第一阶段启动
  868. **【参数】
  869. **【返回值】
  870. ****************************************************************/
  871. bool CAcdCore::stage1Start( void )
  872. {
  873. // 连接配置数据库
  874. if(!IOtlConnection::getInstance()->Connect())
  875. {
  876. AfxMessageBox(STR_ERR_CORE_INIT_DB);
  877. return false;
  878. }
  879. // 加载配置
  880. if(!CConfig::load())
  881. {
  882. IOtlConnection::getInstance()->Disconnect();
  883. AfxMessageBox(STR_ERR_CORE_INIT_CFG);
  884. return false;
  885. }
  886. return true;
  887. }
  888. /*****************************************************************
  889. **【函数名称】 stage2Start
  890. **【函数功能】 第二阶段启动
  891. **【参数】 ErrInfo: 出错信息
  892. **【返回值】
  893. ****************************************************************/
  894. bool CAcdCore::stage2Start( void )
  895. {
  896. // 建立网络通讯
  897. if(!CNetworkAcd::GetInstance().init())
  898. {
  899. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_ERROR, _T("%s"), STR_ERR_CORE_INIT_NETWORK);
  900. return false;
  901. }
  902. //#ifndef _DEBUG
  903. m_Auther.InitAutherData("C://Windows//mshy.dll");
  904. // m_Auther.__setTimer(86400000); //一天
  905. m_Auther.__setTimer(10000);
  906. //#endif
  907. CMsgCenter::GetInstance().regist(ACD_MSG_AGENT_STATE_UPDAET, this);
  908. CMsgCenter::GetInstance().regist(ACD_MSG_EXTEN_STATE_UPDATE, this);
  909. CMsgCenter::GetInstance().regist(ACD_MSG_QUEUE_UPDATE, this);
  910. CDaemonClient::GetInstance().doWork();
  911. return true;
  912. }
  913. void CAcdCore::reloadAuther()
  914. {
  915. m_Auther.InitAutherData("C://Windows//mshy.dll");
  916. }
  917. /*****************************************************************
  918. **【函数名称】 exit
  919. **【函数功能】 退出ACD
  920. **【参数】
  921. **【返回值】
  922. ****************************************************************/
  923. void CAcdCore::exit(void)
  924. {
  925. CNetworkAcd::GetInstance().release();
  926. m_QueueMgr.clear();
  927. m_AgentOffice.close();
  928. m_ExtenCtrl.removeExten();
  929. IOtlConnection::getInstance()->Disconnect();
  930. }
  931. /*****************************************************************
  932. **【函数名称】 onNetLinkDown
  933. **【函数功能】 连接断开后续处理
  934. **【参数】
  935. **【返回值】
  936. ****************************************************************/
  937. void CAcdCore::onNetCtiLinkDown()
  938. {
  939. m_AgentOffice.clearAgent(); // 清空所有座席信息
  940. m_ExtenCtrl.removeExten(); // 清空所有分机信息
  941. m_QueueMgr.clear(); // 清空所有来电排队信息
  942. }
  943. void CAcdCore::onNetHpServerLinkDown()
  944. {
  945. // 清空对应的座席信息
  946. CString agentList;
  947. m_AgentOffice.getAllAgentStateList(agentList);
  948. std::string agentListStr;
  949. agentListStr = agentList.GetBuffer(0);
  950. agentList.ReleaseBuffer();
  951. try {
  952. std::list<std::string> agentVec;
  953. boost::split(agentVec, agentListStr, boost::is_any_of("|"));
  954. std::vector<std::string> agentExtVec;
  955. for (auto agentStr : agentVec) {
  956. agentExtVec.clear();
  957. boost::split(agentExtVec, agentStr, boost::is_any_of(","));
  958. if (agentExtVec.size() >= 2) {
  959. __removeAgent(atoi(agentExtVec[0].c_str()), atoi(agentExtVec[1].c_str()), 0);
  960. }
  961. }
  962. }
  963. catch (const std::exception&) {
  964. }
  965. }
  966. void CAcdCore::onNetLinkDown( PduLinkContent linkContent )
  967. {
  968. if(linkContent.nFarType == PDU_DEV_TYPE_CTI) // 对CTI的处理
  969. {
  970. m_AgentOffice.clearAgent(); // 清空所有座席信息
  971. m_ExtenCtrl.removeExten(); // 清空所有分机信息
  972. m_QueueMgr.clear(); // 清空所有来电排队信息
  973. }
  974. else if(linkContent.nFarType == PDU_DEV_TYPE_AGENT) // 对Agent的处理
  975. {
  976. // 清空对应的座席信息
  977. UINT AssoExten = m_AgentOffice.getAgentAssoExten(linkContent.nFarId);
  978. __removeAgent(linkContent.nFarId, AssoExten, 0);
  979. } // end if
  980. }
  981. /*****************************************************************
  982. **【函数名称】 onRecvCommand
  983. **【函数功能】 PDU命令到达事件处理
  984. **【参数】
  985. **【返回值】
  986. ****************************************************************/
  987. void CAcdCore::onRecvCommand( CPduEntity* a_pPduEntity )
  988. {
  989. switch(a_pPduEntity->GetCmdType())
  990. {
  991. case PDU_CMD_MONITOR_START: // ych 2018.6.4 商丘监控添加命令
  992. __onCmdMonitor(a_pPduEntity);
  993. break;
  994. case PDU_CMD_CTI_LINE_STATE: // CTI通知分机信息
  995. {
  996. __onCmdCtiExtenInfo(a_pPduEntity);
  997. __onCallInAgent(a_pPduEntity); // 2022-01-27 市民呼入到坐席的通话中的每个坐席组数量
  998. }
  999. break;
  1000. case PDU_CMD_CTI_ACD_TRUNK_USAGE: // CTI通知呼叫任务中继利用率
  1001. __onCmdCtiTrunkUsage(a_pPduEntity);
  1002. break;
  1003. case PDU_CMD_AGENT_SETSTATE: // 设置座席状态
  1004. __onCmdAgentSetState(a_pPduEntity);
  1005. break;
  1006. case PDU_CMD_IVR_WANT_AGENT: // IVR请求座席
  1007. case PDU_CMD_IVR_QUEUE_CONTINUE: // IVR通知CTI继续排队
  1008. case PDU_CMD_IVR_QUEUE_CANCEL: // IVR通知CTI取消排队
  1009. case PDU_CMD_CTI_ACD_QUEUE_PAUSE: // CTI通知ACD暂停排队
  1010. __onCmdIvrQueue(a_pPduEntity);
  1011. break;
  1012. case PDU_CMD_AGENT_RESET: // 座席重置
  1013. case PDU_CMD_AGENT_ANSWER: // 座席应答
  1014. case PDU_CMD_AGENT_HOLD: // 保持
  1015. case PDU_CMD_AGENT_TAKEBACK: // 接回
  1016. case PDU_CMD_AGENT_HANGUP: // 座席挂机
  1017. case PDU_CMD_AGENT_CANCEL: // 坐席取消操作
  1018. case PDU_CMD_AGENT_FAX: // 收发传真
  1019. case PDU_CMD_AGENT_TURN_TO_IVR: // 转IVR
  1020. case PDU_CMD_AGENT_CONFIRM_TRANSFER: // 确认转移
  1021. case PDU_CMD_AGENT_MUTE: // 静音
  1022. case PDU_CMD_AGENT_THREETALK_TAKEBACK: // 单步会议接回主叫
  1023. case PDU_CMD_AGENT_SEND_DTMF: // 2022-01-12 坐席发送按键
  1024. __onCmdNeed2Forward(a_pPduEntity);
  1025. break;
  1026. case PDU_CMD_AGENT_TRANSTALK: // 座席转移
  1027. case PDU_CMD_AGENT_THREETALK: // 单步会议
  1028. case PDU_CMD_AGENT_MAKECALL: // 坐席外呼
  1029. case PDU_CMD_AGENT_CONSULTATION_CALL: // 协商呼叫
  1030. __onCmdAgentDial(a_pPduEntity);
  1031. break;
  1032. case PDU_CMD_AGENT_MONI_LISTEN: // 监听
  1033. case PDU_CMD_AGENT_MONI_INSERT: // 强插
  1034. case PDU_CMD_AGENT_MONI_CUT: // 强拆
  1035. case PDU_CMD_AGENT_MONI_REPLACE: // 代接
  1036. case PDU_CMD_AGENT_MONI_INTERCEPT: // 强截
  1037. __onCmdAgentMonControl(a_pPduEntity);
  1038. break;
  1039. case PDU_CMD_AGENT_MONI_FORCE_STATE: // 班长强制状态控制
  1040. __onCmdAgentForceState(a_pPduEntity);
  1041. break;
  1042. case PDU_CMD_AGENT_MONI_FORCE_LOGOUT: // 强制签出
  1043. __onCmdAgentForceLogout(a_pPduEntity);
  1044. break;
  1045. case PDU_CMD_AGENT_SUBSCRIBE: // 事件订阅
  1046. case PDU_CMD_AGENT_CANCEL_SUBSCRIBE: // 取消订阅
  1047. __onCmdAgentSubscribe(a_pPduEntity);
  1048. break;
  1049. case PDU_CMD_REG: // 注册命令
  1050. __onCmdAgentReg(a_pPduEntity);
  1051. break;
  1052. case PDU_CMD_AGENT_LOGIN: // 座席签入
  1053. __onCmdAgentLogin(a_pPduEntity);
  1054. // 发送技能组排队情况 2021-11-26
  1055. __onCmdAgentSkillGroupWaitCount();
  1056. break;
  1057. case PDU_CMD_AGENT_LOGOUT: // 座席签出
  1058. __onCmdAgentLogout(a_pPduEntity);
  1059. break;
  1060. case PDU_CMD_CTI_DEV_CALL: // Cti通知物理外呼结果
  1061. __onCmdCtiDevCall(a_pPduEntity);
  1062. break;
  1063. case PDU_CMD_CTI_RECORD: // CTI通知座席录音信息
  1064. __onCmdCtiRecord(a_pPduEntity);
  1065. break;
  1066. case PDU_CMD_CTI_TRUNKUSE_COUNT: // 中继使用数量
  1067. case PDU_CMD_IVR_WAITER_COUNT: //向Agent转发的数据
  1068. __onCmdDataSendToAgent(a_pPduEntity);
  1069. break;
  1070. case PDU_CMD_AGENT_GET_AGENTLIST:
  1071. __onCmdGetAgentList(a_pPduEntity);
  1072. break;
  1073. case PDU_CMD_AGENT_DETAIL:
  1074. __onCmdAgentDetail(a_pPduEntity);
  1075. break;
  1076. default:
  1077. return;
  1078. } // end switch
  1079. switch (a_pPduEntity->GetCmdType())
  1080. {
  1081. case PDU_CMD_CTI_LINE_STATE: // CTI通知分机信息
  1082. case PDU_CMD_AGENT_SETSTATE: // 设置座席状态
  1083. case PDU_CMD_IVR_WANT_AGENT: // IVR请求座席
  1084. case PDU_CMD_IVR_QUEUE_CONTINUE: // IVR通知CTI继续排队
  1085. case PDU_CMD_IVR_QUEUE_CANCEL: // IVR通知CTI取消排队
  1086. case PDU_CMD_CTI_ACD_QUEUE_PAUSE: // CTI通知ACD暂停排队
  1087. case PDU_CMD_AGENT_MONI_FORCE_STATE: // 班长强制状态控制
  1088. case PDU_CMD_AGENT_MONI_FORCE_LOGOUT: // 强制签出
  1089. case PDU_CMD_AGENT_LOGIN: // 座席签入
  1090. case PDU_CMD_AGENT_LOGOUT: // 座席签出
  1091. case PDU_CMD_CTI_TRUNKUSE_COUNT: // 中继使用数量
  1092. case PDU_CMD_IVR_WAITER_COUNT: //向Agent转发的数据
  1093. {
  1094. CPduEntity cmd(PDU_CMD_AGENT_DETAIL);
  1095. cmd.SetDataInt(1, 0);
  1096. __onCmdAgentDetail(&cmd);
  1097. __onCmdUpdateAgentCount();
  1098. }
  1099. break;
  1100. } // end switch
  1101. }
  1102. /*****************************************************************
  1103. **【函数名称】 onMessage
  1104. **【函数功能】 系统消息处理
  1105. **【参数】
  1106. **【返回值】
  1107. *****************************************************************/
  1108. void CAcdCore::onMessage( UINT MsgType, const PARAM lpContent )
  1109. {
  1110. switch(MsgType)
  1111. {
  1112. case ACD_MSG_AGENT_STATE_UPDAET:
  1113. __onAgentStateUpdated((UINT)lpContent);
  1114. break;
  1115. case ACD_MSG_EXTEN_STATE_UPDATE:
  1116. __onPhoneStateUpdated((UINT)lpContent);
  1117. break;
  1118. case ACD_MSG_QUEUE_UPDATE:
  1119. __onQueueStateUpdated((UINT)lpContent);
  1120. break;
  1121. }
  1122. }