linux版本中间件

EslGateway.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. #include "EslGateway.h"
  2. #include <thread>
  3. #include <regex>
  4. #include "Config.h"
  5. #include "Log.h"
  6. #include "JdbcHelper.h"
  7. #include "SqlWrite.h"
  8. #include "Util.h"
  9. #define ESL_CMD_SCAN_INTERNAL "api sofia status profile internal reg\n\n"
  10. #define ESL_HEADER_CALLID "Channel-Call-UUID"
  11. #define ESL_HEADER_CCID "variable_cc_member_session_uuid" // freeswitchs自带的callcenter模块转接坐席后,callid产生变化,可通过该通道变量进行关联
  12. #define ESL_HEADER_CHANID "Unique-ID"
  13. #define ESL_HEADER_CALLER "Caller-Caller-ID-Number"
  14. #define ESL_HEADER_CALLEE "Caller-Callee-ID-Number"
  15. #define ESL_HEADER_DEST_NUM "Caller-Destination-Number"
  16. #define ESL_HEADER_DIRECTION "Call-Direction"
  17. #define ESL_HEADER_SUBCLASS "Event-Subclass"
  18. #define ESL_HEADER_EXTEN_NO "username"
  19. // ESL事件头域常量值
  20. #define ESL_HDR_DIRECTION_INBOUND "inbound"
  21. #define ESL_HDR_DIRECTION_OUTBOUND "outbound"
  22. #define ESL_HDR_SUBCLASS_SIP_REG "sofia::register"
  23. #define ESL_HDR_SUBCLASS_SIP_UNREG "sofia::unregister"
  24. #define ESL_HDR_SUBCLASS_ASR "asr"
  25. EslGateway::EslGateway() :m_Stop(true), m_pEventThread(nullptr), m_wsServer(nullptr)
  26. {
  27. }
  28. EslGateway::~EslGateway()
  29. {
  30. }
  31. bool EslGateway::initWs()
  32. {
  33. auto cfg = CConfig::GetInstance();
  34. if (m_wsServer == nullptr) {
  35. m_wsServer = std::make_unique<CWebSocketServer>();
  36. m_wsServer->setCallbackRecvMsg(std::bind(&this_type::__onWsMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
  37. m_wsServer->setCallbackClose(std::bind(&this_type::__onWsClose, this, std::placeholders::_1));
  38. return m_wsServer->init(cfg->wsPort(), cfg->wssPort(), cfg->sslFile(), cfg->sslPwd());
  39. }
  40. return true;
  41. }
  42. bool EslGateway::runWs()
  43. {
  44. if (m_wsServer != nullptr) {
  45. m_wsServer->run();
  46. }
  47. return true;
  48. }
  49. bool EslGateway::initDB()
  50. {
  51. auto cfg = CConfig::GetInstance();
  52. if (!JdbcHelper::GetInstance()->init(cfg->dbHost(), cfg->dbUser(), cfg->dbPwd(), cfg->dbName()))
  53. {
  54. LOG_ERROR("程序运行失败,数据库驱动加载失败");
  55. return false;
  56. }
  57. if (JdbcHelper::GetInstance()->jdbc_connect(false))
  58. {
  59. LOG_ERROR("程序运行失败,数据库连接失败");
  60. return false;
  61. }
  62. LOG_INFO("数据库连接成功");
  63. std::string strSQL;
  64. strSQL = "CREATE TABLE If Not Exists `asrinfo` (" \
  65. "`id` bigint NOT NULL AUTO_INCREMENT," \
  66. "`callid` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL," \
  67. "`agent` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, " \
  68. "`exten` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, " \
  69. "`occur_time` datetime NULL DEFAULT CURRENT_TIMESTAMP, " \
  70. "`msg` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
  71. "`src` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
  72. "`dst` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
  73. "PRIMARY KEY(`id`) USING BTREE " \
  74. ")ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;";
  75. JdbcHelper::GetInstance()->jdbc_executeUpdate(strSQL, nullptr, [=](sql::SQLException &e) {
  76. LOG_ERROR_S(boost::str(Format("数据库表初始化失败,错误信息:%s\n%s") % e.what() % strSQL));
  77. });
  78. return true;
  79. }
  80. bool EslGateway::start()
  81. {
  82. memset(&m_EslHdl4Listen, '\0', sizeof(esl_handle_t));
  83. memset(&m_EslHdl4Send, '\0', sizeof(esl_handle_t));
  84. auto cfg = CConfig::GetInstance();
  85. LOG_INFO("{EslGateway}: 处理客户端连接, ip = %s,port=%d,pwd=%s", cfg->fsIp().c_str(), cfg->fsPort(), cfg->fsPwd().c_str());
  86. esl_connect(&m_EslHdl4Listen, cfg->fsIp().c_str(), cfg->fsPort(), NULL, cfg->fsPwd().c_str());
  87. if (!m_EslHdl4Listen.connected)
  88. return false;
  89. LOG_INFO("{EslGateway}: 处理客户端连接m_EslHdl4Listen OK");
  90. esl_events(&m_EslHdl4Listen, ESL_EVENT_TYPE_PLAIN,
  91. ("CHANNEL_CREATE CHANNEL_ANSWER CHANNEL_HANGUP_COMPLETE DETECTED_SPEECH CUSTOM sofia::register sofia::unregister callcenter::info"));
  92. esl_connect(&m_EslHdl4Send, cfg->fsIp().c_str(), cfg->fsPort(), NULL, cfg->fsPwd().c_str());
  93. if (!m_EslHdl4Send.connected) {
  94. esl_disconnect(&m_EslHdl4Listen);
  95. return false;
  96. }
  97. scanExten();
  98. m_Stop = false;
  99. if (m_pEventThread == nullptr) {
  100. m_pEventThread = std::make_unique<boost::thread>(std::bind(&this_type::__eventThread, this));
  101. }
  102. return true;
  103. }
  104. void EslGateway::stop()
  105. {
  106. m_Stop.store(true);
  107. if (m_pEventThread) {
  108. m_pEventThread->interrupt();
  109. m_pEventThread->join();
  110. m_pEventThread.reset();
  111. }
  112. memset(&m_EslHdl4Listen, '\0', sizeof(esl_handle_t));
  113. memset(&m_EslHdl4Send, '\0', sizeof(esl_handle_t));
  114. }
  115. void EslGateway::scanExten()
  116. {
  117. if (esl_send_recv(&m_EslHdl4Send, ESL_CMD_SCAN_INTERNAL) != ESL_SUCCESS)
  118. return;
  119. if (m_EslHdl4Send.last_sr_event == nullptr || m_EslHdl4Send.last_sr_event->body == nullptr)
  120. return;
  121. std::string body = m_EslHdl4Send.last_sr_event->body;
  122. std::list<std::string> rows;
  123. boost::split(rows, body, boost::is_any_of("\n"));
  124. while (!rows.empty()) {
  125. std::string var = rows.front();
  126. rows.pop_front();
  127. std::regex space("\t| ");
  128. var = std::regex_replace(var, space, "");
  129. std::regex reg("IP:(.*)");
  130. if (std::regex_match(var, reg)) {
  131. std::string extenNo, extenIP;
  132. extenIP = std::regex_replace(var, reg, "$1");
  133. while (!rows.empty()) {
  134. var = rows.front();
  135. rows.pop_front();
  136. std::regex space("\t| ");
  137. var = std::regex_replace(var, space, "");
  138. reg = std::regex("Auth-User:(.*)");
  139. if (std::regex_match(var, reg)) {
  140. extenNo = std::regex_replace(var, reg, "$1");
  141. if (!extenNo.empty() && !extenIP.empty()) {
  142. LOG_DEBUG("分机注册:%s %s", extenNo.c_str(), extenIP.c_str());
  143. __addExtenChan(extenNo);
  144. }
  145. break;
  146. }
  147. }
  148. }
  149. }
  150. }
  151. bool EslGateway::excDetectSpeech(const std::string & strChanId)
  152. {
  153. return true;
  154. execte("set", "fire_asr_events=true", strChanId);
  155. return execte("detect_speech", "unimrcp:mrcpv2 hello hello", strChanId);
  156. }
  157. bool EslGateway::excDetectSpeechResume(const std::string & strChanId)
  158. {
  159. return true;
  160. return execte("detect_speech", "resume", strChanId);
  161. }
  162. bool EslGateway::execte(const std::string & strApp, const std::string & strParam, const std::string & strChanId)
  163. {
  164. esl_status_t Status = esl_execute(&m_EslHdl4Send, strApp.c_str(), strParam.c_str(), strChanId.c_str());
  165. return Status == ESL_SUCCESS;
  166. }
  167. void EslGateway::__eventThread(void)
  168. {
  169. esl_event_t* pEvent = nullptr;
  170. esl_handle_t* pListenHandle = &m_EslHdl4Listen;
  171. // 下面的设置保证执行同时多个APP时,后面的不会抢占前面的
  172. pListenHandle->event_lock = 1;
  173. while (!m_Stop)
  174. {
  175. // esl_recv_event会阻塞线程,其第二个参数为1,表示优先检查内部缓存列表,防止遗漏事件。
  176. auto status = esl_recv_event(pListenHandle, 1, nullptr);
  177. if ((status == ESL_SUCCESS || status == ESL_BREAK) && !m_Stop)
  178. {
  179. pEvent = pListenHandle->last_ievent;
  180. if (pEvent != nullptr)
  181. {
  182. __onEslEvent(pEvent);
  183. }
  184. }
  185. else // 连接中断
  186. {
  187. // 连接中断
  188. LOG_WARN_S("FS链接断开...");
  189. do
  190. {
  191. LOG_WARN_S("FS 3秒后自动重连...");
  192. std::this_thread::sleep_for(std::chrono::seconds(3));
  193. LOG_WARN_S("FS开始重连...");
  194. } while (!start() && !m_Stop);
  195. }
  196. }
  197. }
  198. void EslGateway::__onEslEvent(esl_event_t * pEvent)
  199. {
  200. switch (pEvent->event_id)
  201. {
  202. case ESL_EVENT_CHANNEL_CREATE:
  203. case ESL_EVENT_CHANNEL_ANSWER:
  204. case ESL_EVENT_CHANNEL_HANGUP_COMPLETE:
  205. __onEslEvtChanEvent(pEvent);
  206. break;
  207. case ESL_EVENT_DETECTED_SPEECH:
  208. __detectSpeech(pEvent);
  209. break;
  210. case ESL_EVENT_CUSTOM:
  211. __onEslEvtCustom(pEvent);
  212. break;
  213. default:
  214. break;
  215. }
  216. }
  217. void EslGateway::__onEslEvtChanEvent(esl_event_t * pEvent)
  218. {
  219. // 获取会话ID
  220. std::string strCallID = "";
  221. if ((strCallID = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CCID))) == "") {
  222. strCallID = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLID));
  223. }
  224. // 获取通道ID
  225. const auto pChanID = esl_event_get_header(pEvent, ESL_HEADER_CHANID);
  226. const std::string strChanID = std::to_string(pChanID);
  227. // 获取主被叫
  228. std::string strCaller = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLER));
  229. std::string strCallee = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLEE));
  230. if (strCallee == "") {
  231. strCallee = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_DEST_NUM));
  232. }
  233. // 获取通道方向
  234. CALL_DIRECTION emDirection;
  235. if (strcmp(esl_event_get_header(pEvent, ESL_HEADER_DIRECTION), ESL_HDR_DIRECTION_INBOUND) == 0)
  236. emDirection = CALL_DIRECTION_INBOUND;
  237. else
  238. emDirection = CALL_DIRECTION_OUTBOUND;
  239. switch (pEvent->event_id)
  240. {
  241. case ESL_EVENT_CHANNEL_CREATE:
  242. {
  243. LOG_INFO_S(boost::str(Format("ESL通道创建事件[%s][%s]") % strCallID %strChanID));
  244. std::shared_ptr<Chan> pChan = nullptr;
  245. if (emDirection == CALL_DIRECTION_INBOUND) { // 呼入
  246. pChan = __getExtenChan(strCaller);
  247. if (pChan == nullptr) { // 中继呼入
  248. pChan = __addTrunkChan(strCaller);
  249. LOG_INFO_S(boost::str(Format("中继[%s]呼入[%s]-[%s]") % strCaller %strCaller %strCallee));
  250. }
  251. else {
  252. LOG_INFO_S(boost::str(Format("分机[%s]外呼[%s]-[%s]") % strCaller % strCaller %strCallee));
  253. }
  254. }
  255. else {
  256. pChan = __getExtenChan(strCallee);
  257. if (pChan == nullptr) { // 中继呼出
  258. pChan = __addTrunkChan(strCallee);
  259. LOG_INFO_S(boost::str(Format("中继[%s]呼出[%s]-[%s]") % strCallee % strCaller %strCallee));
  260. }
  261. else {
  262. LOG_INFO_S(boost::str(Format("分机[%s]呼入[%s]-[%s]") % strCallee % strCaller %strCallee));
  263. }
  264. }
  265. pChan->Create(strCallID, strChanID, strCaller, strCallee, emDirection);
  266. LOG_DEBUG_S(boost::str(Format("通道信息[%s]") % pChan->to_string()));
  267. const auto spSession = __findSession(strCallID, strChanID);
  268. spSession->addChan(pChan);
  269. }
  270. break;
  271. case ESL_EVENT_CHANNEL_ANSWER:
  272. {
  273. LOG_INFO_S(boost::str(Format("ESL通道接听事件[%s][%s]") % strCallID %strChanID));
  274. const auto spSession = __findSession(strCallID, strChanID);
  275. if (spSession->size() == 2) {
  276. const auto pChan = spSession->getChan(strChanID);
  277. const auto pAssoChan = spSession->getAssoChan(strChanID);
  278. if (pChan == nullptr) {
  279. LOG_WARN_S(boost::str(Format("SessionID[%s]Caller[%s]Callee[%s]ChanID_old[%s]ChanID_new[%s]") % spSession->Id() % strCaller %strCallee % pChanID %strChanID));
  280. //return;
  281. }
  282. //if (pChan->Type() == pAssoChan->Type()) { // 分机打分机,两个都是中继 不进行语音识别
  283. // LOG_WARN_S(boost::str(Format("会话[%s]中两条通道类型[%s]相同,不进行语音识别")% spSession->Id() % (pChan->Type()== DEV_RES_TYPE_EXT?"分机":"中继")));
  284. // return;
  285. //}
  286. if (pChan->Type() == DEV_RES_TYPE_EXT && pAssoChan->Type()== DEV_RES_TYPE_EXT) { // 分机打分机,两个都是中继 不进行语音识别
  287. LOG_WARN_S(boost::str(Format("会话[%s]中两条分机通道[%s][%s],不进行语音识别")% spSession->Id() % pChanID %strChanID));
  288. return;
  289. }
  290. if (pChan->Type() == DEV_RES_TYPE_EXT && pChan->Direct() == CALL_DIRECTION_OUTBOUND) { // 呼入
  291. pChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallIn", "Agent");
  292. pAssoChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallIn", "User");
  293. }
  294. else if (pChan->Type() != DEV_RES_TYPE_EXT && pChan->Direct() != CALL_DIRECTION_OUTBOUND) { // 呼入
  295. pChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallIn", "User");
  296. pAssoChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallIn", "Agent");
  297. }
  298. else if (pChan->Type() == DEV_RES_TYPE_EXT && pChan->Direct() != CALL_DIRECTION_OUTBOUND) { // 呼出
  299. pChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallOut", "Agent");
  300. pAssoChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallOut", "User");
  301. }
  302. else if (pChan->Type() != DEV_RES_TYPE_EXT && pChan->Direct() == CALL_DIRECTION_OUTBOUND) { // 呼出
  303. pChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallOut", "User");
  304. pAssoChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallOut", "Agent");
  305. }
  306. else { // 未知逻辑
  307. LOG_ERROR_S(boost::str(Format("未知逻辑,CallId[%s]ChanID[%s]Caller[%s]Callee[%s]Direct[%d]") % strCallID %strChanID %strCaller %strCallee %emDirection));
  308. return;
  309. }
  310. std::string strExtNo = "";
  311. if (pChan->Type() == DEV_RES_TYPE_EXT) {
  312. strExtNo = pChan->No();
  313. }
  314. else {
  315. strExtNo = pAssoChan->No();
  316. }
  317. auto it = m_mapExtAgent.find(strExtNo);
  318. if (it != m_mapExtAgent.end()) {
  319. pChan->bindAgent(it->second);
  320. pAssoChan->bindAgent(it->second);
  321. }
  322. excDetectSpeech(strChanID);
  323. excDetectSpeech(pAssoChan->ChanID());
  324. LOG_INFO_S(boost::str(Format("开始识别会话[%s]\n[%s]") % pChan->No() % pChan->to_string()));
  325. LOG_INFO_S(boost::str(Format("开始识别会话[%s]\n[%s]") % pAssoChan->No() % pAssoChan->to_string()));
  326. }
  327. }
  328. break;
  329. case ESL_EVENT_CHANNEL_HANGUP_COMPLETE:
  330. {
  331. LOG_INFO_S(boost::str(Format("ESL通道挂机事件[%s][%s]") % strCallID %strChanID));
  332. __delSession(strCallID, strChanID);
  333. }
  334. break;
  335. default:
  336. break;
  337. }
  338. }
  339. void EslGateway::__hangupEvent(esl_event_t * pEvent)
  340. {
  341. }
  342. void EslGateway::__detectSpeech(esl_event_t * pEvent)
  343. {
  344. /*LOG_DEBUG_S("语音识别消息");
  345. char *pContent = new char[2048];
  346. esl_event_serialize(pEvent, &pContent, ESL_TRUE);
  347. LOG_DEBUG_S(pContent);
  348. if (pContent) {
  349. delete pContent;
  350. pContent = nullptr;
  351. }*/
  352. std::string strCallID = "";
  353. auto pCallID = esl_event_get_header(pEvent, ESL_HEADER_CALLID);
  354. strCallID = pCallID == nullptr ? "" : pCallID;
  355. auto pCallCCID = esl_event_get_header(pEvent, ESL_HEADER_CCID);
  356. if (pCallCCID != nullptr) {
  357. strCallID = pCallCCID;
  358. }
  359. // 获取通道ID
  360. std::string strChanID = "";
  361. auto pChanID = esl_event_get_header(pEvent, ESL_HEADER_CHANID);
  362. strChanID = pChanID == nullptr ? "" : pChanID;
  363. char* speechType = nullptr;
  364. speechType = esl_event_get_header(pEvent, "Speech-Type");
  365. if (speechType == nullptr) {
  366. LOG_WARN_S(boost::str(Format("ESL语音识别事件[%s][%s],Speech-Type 空") % strCallID %strChanID));
  367. return;
  368. }
  369. LOG_INFO_S(boost::str(Format("ESL语音识别事件[%s][%s][%s]") % speechType % strCallID %strChanID));
  370. const auto pSession = __findSession(strCallID, strChanID);
  371. if (pSession == nullptr) {
  372. LOG_WARN_S(boost::str(Format("ESL语音识别事件处理失败,找不到会话[%s][%s]") % strCallID %strChanID));
  373. return;
  374. }
  375. const auto pChan = pSession->getChan(strChanID);
  376. if (pChan == nullptr)return;
  377. if (strcmp(speechType, "begin-speaking") == 0) {
  378. pChan->setSentenceBeginTime();
  379. }
  380. else if (strcmp(speechType, "detected-speech") == 0)
  381. {
  382. excDetectSpeechResume(strChanID); // 识别结束,继续识别
  383. char* result = esl_event_get_body(pEvent);
  384. if (result) {
  385. std::string strRes, err;
  386. parseASRXml(result, strRes, err);
  387. pChan->setTransSentenceText(strRes, pSession->transSentenceIndex());
  388. auto strAsrRes = pChan->asrInfo();
  389. LOG_INFO_S(boost::str(Format("识别结果:\n[%s]")%strAsrRes));
  390. std::string strExtNo = "";
  391. if (pChan->Type() == DEV_RES_TYPE_EXT) {
  392. strExtNo = pChan->No();
  393. }
  394. else {
  395. const auto pAssoChan = pSession->getAssoChan(strChanID);
  396. if (pAssoChan) {
  397. strExtNo = pAssoChan->No();
  398. }
  399. }
  400. // 推送
  401. if (strExtNo != "") {
  402. if (m_wsServer) {
  403. auto pair = m_mapConId.equal_range(strExtNo);
  404. for (auto it = pair.first; it != pair.second; ++it) {
  405. m_wsServer->sendMsg(it->second, strAsrRes);
  406. LOG_INFO_S(boost::str(Format("识别结果发送到[%s]") % strExtNo));
  407. }
  408. }
  409. std::string strSQL;
  410. Format fmt("insert into asrinfo(callid,agent,exten,msg,src,dst) VALUES('%s','%s','%s','%s','%s','%s')");
  411. fmt %pSession->Id() % "" %strExtNo %strRes %result %strAsrRes;
  412. strSQL = fmt.str();
  413. SqlWrite::GetInstance()->addSql(strSQL);
  414. }
  415. }
  416. }
  417. }
  418. void EslGateway::__onEslEvtCustom(esl_event_t * pEvent)
  419. {
  420. const char* pSubClass = esl_event_get_header(pEvent, ESL_HEADER_SUBCLASS);
  421. if (pSubClass == nullptr)return;
  422. auto HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_EXTEN_NO);
  423. if (strcmp(pSubClass, ESL_HDR_SUBCLASS_SIP_REG) == 0) { // 分机注册
  424. if (HeaderValue == nullptr) return;
  425. __addExtenChan(std::to_string(HeaderValue));
  426. }
  427. else if (strcmp(pSubClass, ESL_HDR_SUBCLASS_SIP_UNREG) == 0) { // 分机取消注册
  428. if (HeaderValue == nullptr) return;
  429. __delExtenChan(std::to_string(HeaderValue));
  430. }
  431. }
  432. void EslGateway::__addExtenChan(const std::string & strNo)
  433. {
  434. auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
  435. if (it == m_lstExtenChan.end()) {
  436. auto pChan = std::make_shared<Chan>(DEV_RES_TYPE_EXT, strNo);
  437. m_lstExtenChan.emplace_back(pChan);
  438. }
  439. LOG_INFO_S(boost::str(Format("分机[%s]注册") % strNo));
  440. }
  441. void EslGateway::__delExtenChan(const std::string & strNo)
  442. {
  443. auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
  444. if (it != m_lstExtenChan.end()) {
  445. m_lstExtenChan.erase(it);
  446. LOG_INFO_S(boost::str(Format("分机[%s]注册取消成功") % strNo));
  447. }
  448. else {
  449. LOG_INFO_S(boost::str(Format("分机[%s]注册取消失败,分机不存在") % strNo));
  450. }
  451. }
  452. std::shared_ptr<Chan> EslGateway::__getExtenChan(const std::string & strNo)
  453. {
  454. auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
  455. if (it != m_lstExtenChan.end()) {
  456. return *it;
  457. }
  458. return nullptr;
  459. }
  460. std::shared_ptr<Chan> EslGateway::__addTrunkChan(const std::string & strNo)
  461. {
  462. auto pChan = std::make_shared<Chan>(DEV_RES_TYPE_TRUNK, strNo);
  463. m_lstTrunkChan.emplace_back(pChan);
  464. LOG_INFO_S(boost::str(Format("添加中继资源[%s]") % strNo));
  465. return pChan;
  466. }
  467. bool EslGateway::__delTrunkChan(const std::string & strChanID)
  468. {
  469. auto it = std::find_if(m_lstTrunkChan.begin(), m_lstTrunkChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->ChanID().compare(strChanID) == 0; });
  470. if (it != m_lstTrunkChan.end()) {
  471. LOG_DEBUG_S(boost::str(Format("删除中继%s")% (*it)->to_string()));
  472. m_lstTrunkChan.erase(it);
  473. return true;
  474. }
  475. return false;
  476. }
  477. std::shared_ptr<Session> EslGateway::__findSession(const std::string & strCallID, const std::string&strChanID)
  478. {
  479. auto it = std::find_if(m_lstSession.begin(), m_lstSession.end(), [=](const std::pair<std::string, std::shared_ptr<Session>>& p) {
  480. return (p.first.compare(strCallID)==0 && strCallID != "") || p.second->getChan(strChanID) != nullptr;
  481. });
  482. if (it != m_lstSession.end()) {
  483. LOG_DEBUG_S(boost::str(Format("找到会话[%s],通道[%s][%s]") % it->first%strCallID%strChanID));
  484. return it->second;
  485. }
  486. auto spSession = std::make_shared<Session>(strCallID);
  487. m_lstSession.insert(std::make_pair(strCallID, spSession));
  488. LOG_DEBUG_S(boost::str(Format("创建新会话[%s]") % strCallID));
  489. return spSession;
  490. }
  491. void EslGateway::__delSession(const std::string & strCallID, const std::string & strChanID)
  492. {
  493. auto it = std::find_if(m_lstSession.begin(), m_lstSession.end(), [=](const std::pair<std::string, std::shared_ptr<Session>>& p) {
  494. return p.first.compare(strCallID) == 0 || p.second->getChan(strChanID) != nullptr;
  495. });
  496. if (it != m_lstSession.end()) {
  497. auto pSession = it->second;
  498. auto pChan = pSession->getChan(strChanID);
  499. if (pChan) {
  500. pSession->delChan(pChan);
  501. if (pChan->Type() == DEV_RES_TYPE_EXT) {
  502. pChan->Hangup();
  503. }
  504. else {
  505. __delTrunkChan(strChanID);
  506. }
  507. }
  508. if (pSession->size() == 0) {
  509. m_lstSession.erase(it);
  510. LOG_INFO_S(boost::str(Format("会话销毁CallID[%s]ChanID[%s]") % strCallID %strChanID));
  511. }
  512. }
  513. else {
  514. LOG_WARN_S(boost::str(Format("会话中未找到通道资源[%s][%s]") % strCallID %strChanID));
  515. if (!__delTrunkChan(strChanID)) {
  516. auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->ChanID().compare(strChanID)==0; });
  517. if (it != m_lstExtenChan.end()) {
  518. (*it)->Hangup();
  519. }
  520. }
  521. }
  522. }
  523. void EslGateway::__onWsMessage(const long & lConId, const std::string & strMsg, const std::string & strIP)
  524. {
  525. Json::Value root;
  526. Json::String errs;
  527. Json::CharReaderBuilder builder;
  528. builder["collectComments"] = true;
  529. std::unique_ptr<Json::CharReader>pReader(builder.newCharReader());
  530. if (!pReader->parse(strMsg.c_str(), strMsg.c_str() + strMsg.length(), &root, &errs) || errs != "" || !root.isObject()) {
  531. Format fmt("json字符串格式异常,异常信息[%s]\n[%s]");
  532. fmt %errs %strMsg;
  533. LOG_ERROR_S(fmt.str());
  534. return;
  535. }
  536. const auto type = root["Type"].asString();
  537. const auto AgentID = root["AgentID"].asString();
  538. const auto AgentExten = root["AgentExten"].asString();
  539. bool bOk = false;
  540. std::string strDesc = "失败";
  541. if (type == "Login") {
  542. auto it = std::find_if(m_mapConId.begin(), m_mapConId.end(), [=](std::pair<std::string, long>pair) {
  543. return pair.first == AgentExten && pair.second == lConId;
  544. });
  545. if (it == m_mapConId.end()) {
  546. m_mapConId.insert(std::make_pair(AgentExten, lConId));
  547. }
  548. bOk = true;
  549. }
  550. else if (type == "Logout") {
  551. auto it = std::find_if(m_mapConId.begin(), m_mapConId.end(), [=](std::pair<std::string, long>pair) {
  552. return pair.first == AgentExten && pair.second == lConId;
  553. });
  554. if (it != m_mapConId.end()) {
  555. m_mapConId.erase(it);
  556. }
  557. bOk = true;
  558. }
  559. else if (type == "BindExtAgent") {
  560. strDesc = "失败,分机已与其它坐席进行关联";
  561. auto it = m_mapExtAgent.find(AgentExten);
  562. if (it == m_mapExtAgent.end()) {
  563. strDesc = "成功";
  564. bOk = true;
  565. m_mapExtAgent[AgentExten] = AgentID;
  566. }
  567. LOG_INFO_S(boost::str(Format("绑定分机[%s]坐席[%s]关系[%s]") % AgentExten%AgentID%strDesc));
  568. }
  569. else if (type == "UnBindExtAgent") {
  570. strDesc = "失败,未进行关联";
  571. auto it = m_mapExtAgent.find(AgentExten);
  572. if (it != m_mapExtAgent.end()) {
  573. strDesc = "成功";
  574. bOk = true;
  575. m_mapExtAgent.erase(it);
  576. }
  577. LOG_INFO_S(boost::str(Format("解除绑定分机[%s]坐席[%s]关系[%s]") % AgentExten%AgentID%strDesc));
  578. }
  579. auto strJson = __createJson(type, bOk, strDesc);
  580. m_wsServer->sendMsg(lConId, strJson);
  581. }
  582. void EslGateway::__onWsClose(const long & lConId)
  583. {
  584. for (auto it = m_mapConId.begin(); it != m_mapConId.end();) {
  585. if (it->second == lConId) {
  586. it = m_mapConId.erase(it);
  587. }
  588. else {
  589. ++it;
  590. }
  591. }
  592. }
  593. std::string EslGateway::__createJson(const std::string & strType, const bool & bOk, const std::string&strDesc)
  594. {
  595. Json::Value root;
  596. root["Type"] = strType;
  597. root["Result"] = bOk;
  598. root["Desc"] = strDesc;
  599. Json::StreamWriterBuilder builder;
  600. return Json::writeString(builder, root);
  601. }