中间件底层,websocket

Queue.cpp 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "StdAfx.h"
  2. #include "Queue.h"
  3. #include "IncomingCall.h"
  4. #include "AcdCore.h"
  5. #include "StrategyLoop.h"
  6. #include "StrategyMaxFree.h"
  7. #include "StrategyMinAnswer.h"
  8. #include "StrategySpecifiedAgent.h"
  9. #include "StrategyLoopByAgentId.h"
  10. CQueue::CQueue(UINT QueueNo) : m_QueueNo(QueueNo)
  11. {
  12. __initStrategy();
  13. }
  14. CQueue::~CQueue(void)
  15. {
  16. __freeStrategy();
  17. }
  18. /*****************************************************************
  19. **【函数名称】 __initStrategy
  20. **【函数功能】 初始化座席分配策略
  21. **【参数】
  22. **【返回值】
  23. ****************************************************************/
  24. void CQueue::__initStrategy(void)
  25. {
  26. CStrategyAD* pStrategy = NULL;
  27. // 循环接听
  28. pStrategy = new CStrategyLoop();
  29. m_StrategyMap.SetAt(AGENT_STRATEGY_LOOP, pStrategy);
  30. // 2020-01-13 循环接听,按照座席id大小顺序
  31. pStrategy = new CStrategyLoopByAgentId();
  32. m_StrategyMap.SetAt(AGENT_STRATEGY_LOOPBYAGENTID, pStrategy);
  33. // 目前空闲时间最长的座席
  34. pStrategy = new CStrategyMaxFree();
  35. m_StrategyMap.SetAt(AGENT_STRATEGY_MAX_CUR_FREE_TIME, pStrategy);
  36. // 目前接听次数最少的坐席
  37. pStrategy = new CStrategyMinAnswer();
  38. m_StrategyMap.SetAt(AGENT_STRATEGY_MINI_CALLS, pStrategy);
  39. // 指定座席
  40. pStrategy = new CStrategySpecifiedAgent();
  41. m_StrategyMap.SetAt(AGENT_STRATEGY_KNOWN, pStrategy);
  42. }
  43. /*****************************************************************
  44. **【函数名称】 __freeStrategy
  45. **【函数功能】 释放座席分配策略
  46. **【参数】
  47. **【返回值】
  48. ****************************************************************/
  49. void CQueue::__freeStrategy(void)
  50. {
  51. AGENT_STRATEGY Key;
  52. CStrategyAD* pStrategy = NULL;
  53. POSITION Pos = m_StrategyMap.GetStartPosition();
  54. while (Pos != NULL)
  55. {
  56. m_StrategyMap.GetNextAssoc(Pos, Key, pStrategy);
  57. ASSERT(pStrategy != NULL);
  58. delete pStrategy;
  59. pStrategy = NULL;
  60. }
  61. m_StrategyMap.RemoveAll();
  62. }
  63. /*****************************************************************
  64. **【函数名称】 __getStrategy
  65. **【函数功能】 获取指定的座席分配策略
  66. **【参数】
  67. **【返回值】
  68. ****************************************************************/
  69. CStrategyAD* CQueue::__getStrategy(AGENT_STRATEGY StrategyId)
  70. {
  71. // 找到对应的座席分配策略
  72. CStrategyAD* pStrategy = NULL;
  73. if (!m_StrategyMap.Lookup(StrategyId, pStrategy))
  74. pStrategy = m_StrategyMap[AGENT_STRATEGY_LOOP]; // 如果指定的策略不存在,则选取循环接听策略
  75. return pStrategy;
  76. }
  77. /*****************************************************************
  78. **【函数名称】 __onAgentDispatched
  79. **【函数功能】 处理请求座席结果
  80. **【参数】 Result: 请求座席结果
  81. Agent: 请求到的座席ID
  82. Exten: 请求到的座席分机号
  83. CallIndex: 请求座席的来电索引
  84. **【返回值】
  85. ****************************************************************/
  86. void CQueue::__onAgentDispatched(QUEUE_AGENT_RESULT Result, UINT Agent, UINT Exten, CIncomingCall* pCall)
  87. {
  88. switch (Result)
  89. {
  90. case QUEUE_AGENT_OK: // 请求座席成功
  91. {
  92. pCall->onQueueOK(Agent, Exten);
  93. m_CallGroup.delCall(pCall->index());
  94. }
  95. break;
  96. case QUEUE_AGENT_FAILED_NO_AGENT: // 无签入座席
  97. case QUEUE_AGENT_FAILED_NO_FREE: // 座席全忙
  98. case QUEUE_AGETN_FAILED_NO_SPEC: // 在指定策略下无匹配座席
  99. {
  100. pCall->onQueueFailed(Result, Agent);
  101. }
  102. break;
  103. } // end switch
  104. }
  105. /*****************************************************************
  106. **【函数名称】 clear
  107. **【函数功能】 清除所有资源
  108. **【参数】
  109. **【返回值】
  110. ****************************************************************/
  111. void CQueue::clear(void)
  112. {
  113. m_CallGroup.clear();
  114. m_AgentGroup.clear();
  115. }
  116. CString CQueue::callIndex()
  117. {
  118. int index = 0;
  119. CIncomingCall* pIncomingCall = NULL;
  120. CString str;
  121. /*
  122. POSITION pos = m_CallGroup.GetHeadPosition();
  123. while (pos != NULL)
  124. {
  125. index++;
  126. pIncomingCall = m_CallGroup.GetNext(pos);
  127. if (pIncomingCall)
  128. {
  129. str.Format("%d|%d#%s", pIncomingCall->index(), index,str);
  130. }
  131. }
  132. */
  133. std::stringstream ss;
  134. POSITION pos = m_CallGroup.GetHeadPosition();
  135. while (pos != NULL)
  136. {
  137. index++;
  138. pIncomingCall = m_CallGroup.GetNext(pos);
  139. if (pIncomingCall)
  140. {
  141. ss << pIncomingCall->index() << "|" << index << "#";
  142. }
  143. }
  144. str.Format("%s", ss.str().c_str());
  145. ss.str("");
  146. return str;
  147. }
  148. /*****************************************************************
  149. **【函数名称】 onQueueRequest
  150. **【函数功能】 呼叫请求排队响应
  151. **【参数】 pCmd: PDU命令内容
  152. **【返回值】 被操作呼叫
  153. ****************************************************************/
  154. void CQueue::onQueueRequest(CPduEntity* pCmd)
  155. {
  156. int CallPos = 0;
  157. // 是否为重复请求座席
  158. CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(1));
  159. if (pCall != NULL)
  160. {
  161. pCall->updateQueueInfo(pCmd); // 重置座席分配策略及信息
  162. }
  163. else
  164. {
  165. pCall = m_CallGroup.addCall(pCmd, CallPos);
  166. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, "{CQueue}: 呼叫请求排队, m_QueueNo=%d,Index = %d,Caller=%s,CallPos = %d", m_QueueNo, pCmd->GetDataInt(1), pCmd->GetDataString(6), CallPos);
  167. } // end if
  168. // 当前来电是否可以请求座席(如果不能,直接返回请求座席失败)
  169. if (pCall != m_CallGroup.getTopWaitedCall())
  170. {
  171. QUEUE_AGENT_RESULT Result = QUEUE_AGENT_FAILED_NO_FREE;
  172. if (m_AgentGroup.GetCount() == 0)
  173. Result = QUEUE_AGENT_FAILED_NO_AGENT;
  174. __onAgentDispatched(Result, CallPos, 0, pCall);
  175. } // end if
  176. else
  177. {
  178. // 处理排队请求
  179. distributeAgent();
  180. }
  181. }
  182. /*****************************************************************
  183. **【函数名称】 onQueueCancel
  184. **【函数功能】 呼叫取消排队
  185. **【参数】 pCmd: PDU命令内容
  186. **【返回值】
  187. ****************************************************************/
  188. bool CQueue::onQueueCancel(CPduEntity* pCmd)
  189. {
  190. // 删除呼叫
  191. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, "{CQueue}: 呼叫取消排队, m_QueueNo=%d,Index = %d,Caller=%s", m_QueueNo, pCmd->GetDataInt(1), pCmd->GetDataString(6));
  192. return m_CallGroup.delCall(pCmd->GetDataInt(1));
  193. }
  194. /*****************************************************************
  195. **【函数名称】 onQueuePause
  196. **【函数功能】 呼叫暂停排队
  197. **【参数】 pCmd: PDU命令内容
  198. **【返回值】
  199. ****************************************************************/
  200. bool CQueue::onQueuePause(CPduEntity* pCmd)
  201. {
  202. CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(0));
  203. if (pCall == NULL)
  204. return false;
  205. pCall->setCallState(OUTER_CALL_PAUSE);
  206. return true;
  207. }
  208. /*****************************************************************
  209. **【函数名称】 onQueueContinue
  210. **【函数功能】 呼叫继续排队
  211. **【参数】 pCmd: PDU命令内容
  212. **【返回值】
  213. ****************************************************************/
  214. bool CQueue::onQueueContinue(CPduEntity* pCmd)
  215. {
  216. CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(1));
  217. if (pCall == NULL)
  218. return false;
  219. if (pCall->callId() != pCmd->GetDataULong(2)) { // 2023-05-25 判断获取到的来电callid是否和请求的相同,不相同删除
  220. m_CallGroup.delCall(pCmd->GetDataInt(1));
  221. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_ERROR, _T("{继续排队故障,根据ivr索引获取到来电callid[%ld]与真实callid不同[%ld]"), pCall->callId(), pCmd->GetDataULong(2));
  222. return false;
  223. }
  224. pCall->updateQueueInfo(pCmd);
  225. // 主动请求坐席
  226. distributeAgent();
  227. return true;
  228. }
  229. /*****************************************************************
  230. **【函数名称】 addAgent
  231. **【函数功能】 添加座席
  232. **【参数】
  233. **【返回值】
  234. ****************************************************************/
  235. void CQueue::addAgent(CAgent* pAgent)
  236. {
  237. m_AgentGroup.add(pAgent);
  238. // 2022-09-07 保存签入后坐席所在组的位置
  239. saveCurAllAgent();
  240. }
  241. /*****************************************************************
  242. **【函数名称】 delAgent
  243. **【函数功能】 删除座席
  244. **【参数】
  245. **【返回值】
  246. ****************************************************************/
  247. void CQueue::delAgent(CAgent* pAgent, bool isSave)
  248. {
  249. m_AgentGroup.remove(pAgent);
  250. // 2022-09-07 保存签入后坐席所在组的位置
  251. if(isSave)
  252. saveCurAllAgent();
  253. }
  254. /*****************************************************************
  255. **【函数名称】 distributeAgent
  256. **【函数功能】
  257. **【参数】
  258. **【返回值】
  259. ****************************************************************/
  260. void CQueue::distributeAgent(void)
  261. {
  262. // 查找当前要排队的呼叫
  263. CIncomingCall* pCall = m_CallGroup.getTopWaitedCall();
  264. if (pCall == NULL)
  265. return;
  266. pCall->setCallState(OUTER_CALL_QUEUE);
  267. CStrategyAD* pStrategy = __getStrategy(pCall->agentStrategy()); // 请求座席的排队策略
  268. ASSERT(pStrategy != NULL);
  269. // 显示日志
  270. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{坐席排队策略号: %lu, m_QueueNo=%d[%d],Index = %d,CallID=%ld,Caller=%s"), pCall->agentStrategy(), m_QueueNo, pCall->groupAsked(), pCall->index(), pCall->callId(), pCall->callerNum());
  271. // 开始请求座席
  272. UINT Agent = 0; // 要返回的座席工号
  273. UINT Exten = 0; // 要返回的座席分机号
  274. QUEUE_AGENT_RESULT Result = m_AgentGroup.distributeAgent(pStrategy, pCall->infoEx(), Agent, Exten);
  275. //2022-01-01
  276. if (QUEUE_AGENT_OK != Result)
  277. {
  278. int index = 0;
  279. POSITION pos, nextPos;
  280. pos = m_CallGroup.GetHeadPosition();
  281. while (pos)
  282. {
  283. index++;
  284. auto a = m_CallGroup.GetAt(pos);
  285. nextPos = pos;
  286. m_CallGroup.GetNext(nextPos);
  287. if (a->index() == pCall->index())
  288. {
  289. break;
  290. }
  291. pos = nextPos;
  292. }
  293. Agent = index;
  294. }
  295. else {
  296. saveCurAllAgent();
  297. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{坐席排队成功,策略号: %lu, m_QueueNo=%d[%d],Index=%d,CallID=%ld,Caller=%s,Agent[%u|%u]"), pCall->agentStrategy(), m_QueueNo, pCall->groupAsked(), pCall->index(), pCall->callId(), pCall->callerNum(), Agent, Exten);
  298. }
  299. // 处理请求结果
  300. __onAgentDispatched(Result, Agent, Exten, pCall);
  301. }
  302. std::string CQueue::saveCurAllAgent()
  303. {
  304. // 2022-09-07 保存签入后坐席所在组的位置
  305. std::string allAgent = m_AgentGroup.GetCurAllAgent();
  306. std::string no = std::to_string(m_QueueNo);
  307. pushOnlineAgentGroupDetail(no, allAgent);
  308. return "";
  309. }