| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- #include "EslGateway.h"
- #include <thread>
- #include <regex>
- #include "Config.h"
- #include "Log.h"
- #include "JdbcHelper.h"
- #include "SqlWrite.h"
- #include "Util.h"
- #define ESL_CMD_SCAN_INTERNAL "api sofia status profile internal reg\n\n"
- #define ESL_HEADER_CALLID "Channel-Call-UUID"
- #define ESL_HEADER_CCID "variable_cc_member_session_uuid" // freeswitchs自带的callcenter模块转接坐席后,callid产生变化,可通过该通道变量进行关联
- #define ESL_HEADER_CHANID "Unique-ID"
- #define ESL_HEADER_CALLER "Caller-Caller-ID-Number"
- #define ESL_HEADER_CALLEE "Caller-Callee-ID-Number"
- #define ESL_HEADER_DEST_NUM "Caller-Destination-Number"
- #define ESL_HEADER_DIRECTION "Call-Direction"
- #define ESL_HEADER_SUBCLASS "Event-Subclass"
- #define ESL_HEADER_EXTEN_NO "username"
- // ESL事件头域常量值
- #define ESL_HDR_DIRECTION_INBOUND "inbound"
- #define ESL_HDR_DIRECTION_OUTBOUND "outbound"
- #define ESL_HDR_SUBCLASS_SIP_REG "sofia::register"
- #define ESL_HDR_SUBCLASS_SIP_UNREG "sofia::unregister"
- #define ESL_HDR_SUBCLASS_ASR "asr"
- EslGateway::EslGateway() :m_Stop(true), m_pEventThread(nullptr), m_wsServer(nullptr)
- {
- }
- EslGateway::~EslGateway()
- {
- }
- bool EslGateway::initWs()
- {
- auto cfg = CConfig::GetInstance();
- if (m_wsServer == nullptr) {
- m_wsServer = std::make_unique<CWebSocketServer>();
- m_wsServer->setCallbackRecvMsg(std::bind(&this_type::__onWsMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- m_wsServer->setCallbackClose(std::bind(&this_type::__onWsClose, this, std::placeholders::_1));
- return m_wsServer->init(cfg->wsPort(), cfg->wssPort(), cfg->sslFile(), cfg->sslPwd());
- }
- return true;
- }
- bool EslGateway::runWs()
- {
- if (m_wsServer != nullptr) {
- m_wsServer->run();
- }
- return true;
- }
- bool EslGateway::initDB()
- {
- auto cfg = CConfig::GetInstance();
- if (!JdbcHelper::GetInstance()->init(cfg->dbHost(), cfg->dbUser(), cfg->dbPwd(), cfg->dbName()))
- {
- LOG_ERROR("程序运行失败,数据库驱动加载失败");
- return false;
- }
- if (JdbcHelper::GetInstance()->jdbc_connect(false))
- {
- LOG_ERROR("程序运行失败,数据库连接失败");
- return false;
- }
- LOG_INFO("数据库连接成功");
- std::string strSQL;
- strSQL = "CREATE TABLE If Not Exists `asrinfo` (" \
- "`id` bigint NOT NULL AUTO_INCREMENT," \
- "`callid` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL," \
- "`agent` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, " \
- "`exten` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, " \
- "`occur_time` datetime NULL DEFAULT CURRENT_TIMESTAMP, " \
- "`msg` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
- "`src` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
- "`dst` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, " \
- "PRIMARY KEY(`id`) USING BTREE " \
- ")ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;";
- JdbcHelper::GetInstance()->jdbc_executeUpdate(strSQL, nullptr, [=](sql::SQLException &e) {
- LOG_ERROR_S(boost::str(Format("数据库表初始化失败,错误信息:%s\n%s") % e.what() % strSQL));
- });
- return true;
- }
- bool EslGateway::start()
- {
- memset(&m_EslHdl4Listen, '\0', sizeof(esl_handle_t));
- memset(&m_EslHdl4Send, '\0', sizeof(esl_handle_t));
- auto cfg = CConfig::GetInstance();
- LOG_INFO("{EslGateway}: 处理客户端连接, ip = %s,port=%d,pwd=%s", cfg->fsIp().c_str(), cfg->fsPort(), cfg->fsPwd().c_str());
- esl_connect(&m_EslHdl4Listen, cfg->fsIp().c_str(), cfg->fsPort(), NULL, cfg->fsPwd().c_str());
- if (!m_EslHdl4Listen.connected)
- return false;
- LOG_INFO("{EslGateway}: 处理客户端连接m_EslHdl4Listen OK");
- esl_events(&m_EslHdl4Listen, ESL_EVENT_TYPE_PLAIN,
- ("CHANNEL_CREATE CHANNEL_ANSWER CHANNEL_HANGUP_COMPLETE DETECTED_SPEECH CUSTOM sofia::register sofia::unregister callcenter::info"));
- esl_connect(&m_EslHdl4Send, cfg->fsIp().c_str(), cfg->fsPort(), NULL, cfg->fsPwd().c_str());
- if (!m_EslHdl4Send.connected) {
- esl_disconnect(&m_EslHdl4Listen);
- return false;
- }
- scanExten();
- m_Stop = false;
- if (m_pEventThread == nullptr) {
- m_pEventThread = std::make_unique<boost::thread>(std::bind(&this_type::__eventThread, this));
- }
- return true;
- }
- void EslGateway::stop()
- {
- m_Stop.store(true);
- if (m_pEventThread) {
- m_pEventThread->interrupt();
- m_pEventThread->join();
- m_pEventThread.reset();
- }
- memset(&m_EslHdl4Listen, '\0', sizeof(esl_handle_t));
- memset(&m_EslHdl4Send, '\0', sizeof(esl_handle_t));
- }
- void EslGateway::scanExten()
- {
- if (esl_send_recv(&m_EslHdl4Send, ESL_CMD_SCAN_INTERNAL) != ESL_SUCCESS)
- return;
- if (m_EslHdl4Send.last_sr_event == nullptr || m_EslHdl4Send.last_sr_event->body == nullptr)
- return;
- std::string body = m_EslHdl4Send.last_sr_event->body;
- std::list<std::string> rows;
- boost::split(rows, body, boost::is_any_of("\n"));
- while (!rows.empty()) {
- std::string var = rows.front();
- rows.pop_front();
- std::regex space("\t| ");
- var = std::regex_replace(var, space, "");
- std::regex reg("IP:(.*)");
- if (std::regex_match(var, reg)) {
- std::string extenNo, extenIP;
- extenIP = std::regex_replace(var, reg, "$1");
- while (!rows.empty()) {
- var = rows.front();
- rows.pop_front();
- std::regex space("\t| ");
- var = std::regex_replace(var, space, "");
- reg = std::regex("Auth-User:(.*)");
- if (std::regex_match(var, reg)) {
- extenNo = std::regex_replace(var, reg, "$1");
- if (!extenNo.empty() && !extenIP.empty()) {
- LOG_DEBUG("分机注册:%s %s", extenNo.c_str(), extenIP.c_str());
- __addExtenChan(extenNo);
- }
- break;
- }
- }
- }
- }
- }
- bool EslGateway::excDetectSpeech(const std::string & strChanId)
- {
- return true;
- execte("set", "fire_asr_events=true", strChanId);
- return execte("detect_speech", "unimrcp:mrcpv2 hello hello", strChanId);
- }
- bool EslGateway::excDetectSpeechResume(const std::string & strChanId)
- {
- return true;
- return execte("detect_speech", "resume", strChanId);
- }
- bool EslGateway::execte(const std::string & strApp, const std::string & strParam, const std::string & strChanId)
- {
- esl_status_t Status = esl_execute(&m_EslHdl4Send, strApp.c_str(), strParam.c_str(), strChanId.c_str());
- return Status == ESL_SUCCESS;
- }
- void EslGateway::__eventThread(void)
- {
- esl_event_t* pEvent = nullptr;
- esl_handle_t* pListenHandle = &m_EslHdl4Listen;
- // 下面的设置保证执行同时多个APP时,后面的不会抢占前面的
- pListenHandle->event_lock = 1;
- while (!m_Stop)
- {
- // esl_recv_event会阻塞线程,其第二个参数为1,表示优先检查内部缓存列表,防止遗漏事件。
- auto status = esl_recv_event(pListenHandle, 1, nullptr);
- if ((status == ESL_SUCCESS || status == ESL_BREAK) && !m_Stop)
- {
- pEvent = pListenHandle->last_ievent;
- if (pEvent != nullptr)
- {
- __onEslEvent(pEvent);
- }
- }
- else // 连接中断
- {
- // 连接中断
- LOG_WARN_S("FS链接断开...");
- do
- {
- LOG_WARN_S("FS 3秒后自动重连...");
- std::this_thread::sleep_for(std::chrono::seconds(3));
- LOG_WARN_S("FS开始重连...");
- } while (!start() && !m_Stop);
- }
- }
- }
- void EslGateway::__onEslEvent(esl_event_t * pEvent)
- {
- switch (pEvent->event_id)
- {
- case ESL_EVENT_CHANNEL_CREATE:
- case ESL_EVENT_CHANNEL_ANSWER:
- case ESL_EVENT_CHANNEL_HANGUP_COMPLETE:
- __onEslEvtChanEvent(pEvent);
- break;
- case ESL_EVENT_DETECTED_SPEECH:
- __detectSpeech(pEvent);
- break;
- case ESL_EVENT_CUSTOM:
- __onEslEvtCustom(pEvent);
- break;
- default:
- break;
- }
- }
- void EslGateway::__onEslEvtChanEvent(esl_event_t * pEvent)
- {
- // 获取会话ID
- std::string strCallID = "";
- if ((strCallID = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CCID))) == "") {
- strCallID = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLID));
- }
- // 获取通道ID
- const auto pChanID = esl_event_get_header(pEvent, ESL_HEADER_CHANID);
- const std::string strChanID = std::to_string(pChanID);
- // 获取主被叫
- std::string strCaller = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLER));
- std::string strCallee = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_CALLEE));
- if (strCallee == "") {
- strCallee = std::to_string(esl_event_get_header(pEvent, ESL_HEADER_DEST_NUM));
- }
- // 获取通道方向
- CALL_DIRECTION emDirection;
- if (strcmp(esl_event_get_header(pEvent, ESL_HEADER_DIRECTION), ESL_HDR_DIRECTION_INBOUND) == 0)
- emDirection = CALL_DIRECTION_INBOUND;
- else
- emDirection = CALL_DIRECTION_OUTBOUND;
- switch (pEvent->event_id)
- {
- case ESL_EVENT_CHANNEL_CREATE:
- {
- LOG_INFO_S(boost::str(Format("ESL通道创建事件[%s][%s]") % strCallID %strChanID));
- std::shared_ptr<Chan> pChan = nullptr;
- if (emDirection == CALL_DIRECTION_INBOUND) { // 呼入
- pChan = __getExtenChan(strCaller);
- if (pChan == nullptr) { // 中继呼入
- pChan = __addTrunkChan(strCaller);
- LOG_INFO_S(boost::str(Format("中继[%s]呼入[%s]-[%s]") % strCaller %strCaller %strCallee));
- }
- else {
- LOG_INFO_S(boost::str(Format("分机[%s]外呼[%s]-[%s]") % strCaller % strCaller %strCallee));
- }
- }
- else {
- pChan = __getExtenChan(strCallee);
- if (pChan == nullptr) { // 中继呼出
- pChan = __addTrunkChan(strCallee);
- LOG_INFO_S(boost::str(Format("中继[%s]呼出[%s]-[%s]") % strCallee % strCaller %strCallee));
- }
- else {
- LOG_INFO_S(boost::str(Format("分机[%s]呼入[%s]-[%s]") % strCallee % strCaller %strCallee));
- }
- }
- pChan->Create(strCallID, strChanID, strCaller, strCallee, emDirection);
- LOG_DEBUG_S(boost::str(Format("通道信息[%s]") % pChan->to_string()));
- const auto spSession = __findSession(strCallID, strChanID);
- spSession->addChan(pChan);
- }
- break;
- case ESL_EVENT_CHANNEL_ANSWER:
- {
- LOG_INFO_S(boost::str(Format("ESL通道接听事件[%s][%s]") % strCallID %strChanID));
- const auto spSession = __findSession(strCallID, strChanID);
- if (spSession->size() == 2) {
- const auto pChan = spSession->getChan(strChanID);
- const auto pAssoChan = spSession->getAssoChan(strChanID);
-
- if (pChan == nullptr) {
- LOG_WARN_S(boost::str(Format("SessionID[%s]Caller[%s]Callee[%s]ChanID_old[%s]ChanID_new[%s]") % spSession->Id() % strCaller %strCallee % pChanID %strChanID));
- //return;
- }
- //if (pChan->Type() == pAssoChan->Type()) { // 分机打分机,两个都是中继 不进行语音识别
- // LOG_WARN_S(boost::str(Format("会话[%s]中两条通道类型[%s]相同,不进行语音识别")% spSession->Id() % (pChan->Type()== DEV_RES_TYPE_EXT?"分机":"中继")));
- // return;
- //}
- if (pChan->Type() == DEV_RES_TYPE_EXT && pAssoChan->Type()== DEV_RES_TYPE_EXT) { // 分机打分机,两个都是中继 不进行语音识别
- LOG_WARN_S(boost::str(Format("会话[%s]中两条分机通道[%s][%s],不进行语音识别")% spSession->Id() % pChanID %strChanID));
- return;
- }
- if (pChan->Type() == DEV_RES_TYPE_EXT && pChan->Direct() == CALL_DIRECTION_OUTBOUND) { // 呼入
- pChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallIn", "Agent");
- pAssoChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallIn", "User");
- }
- else if (pChan->Type() != DEV_RES_TYPE_EXT && pChan->Direct() != CALL_DIRECTION_OUTBOUND) { // 呼入
- pChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallIn", "User");
- pAssoChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallIn", "Agent");
- }
- else if (pChan->Type() == DEV_RES_TYPE_EXT && pChan->Direct() != CALL_DIRECTION_OUTBOUND) { // 呼出
- pChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallOut", "Agent");
- pAssoChan->setCallInfo(strCallID, pChan->No(), pAssoChan->No(), "CallOut", "User");
- }
- else if (pChan->Type() != DEV_RES_TYPE_EXT && pChan->Direct() == CALL_DIRECTION_OUTBOUND) { // 呼出
- pChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallOut", "User");
- pAssoChan->setCallInfo(strCallID, pAssoChan->No(), pChan->No(), "CallOut", "Agent");
- }
- else { // 未知逻辑
- LOG_ERROR_S(boost::str(Format("未知逻辑,CallId[%s]ChanID[%s]Caller[%s]Callee[%s]Direct[%d]") % strCallID %strChanID %strCaller %strCallee %emDirection));
- return;
- }
- std::string strExtNo = "";
- if (pChan->Type() == DEV_RES_TYPE_EXT) {
- strExtNo = pChan->No();
- }
- else {
- strExtNo = pAssoChan->No();
- }
- auto it = m_mapExtAgent.find(strExtNo);
- if (it != m_mapExtAgent.end()) {
- pChan->bindAgent(it->second);
- pAssoChan->bindAgent(it->second);
- }
- excDetectSpeech(strChanID);
- excDetectSpeech(pAssoChan->ChanID());
- LOG_INFO_S(boost::str(Format("开始识别会话[%s]\n[%s]") % pChan->No() % pChan->to_string()));
- LOG_INFO_S(boost::str(Format("开始识别会话[%s]\n[%s]") % pAssoChan->No() % pAssoChan->to_string()));
- }
- }
- break;
- case ESL_EVENT_CHANNEL_HANGUP_COMPLETE:
- {
- LOG_INFO_S(boost::str(Format("ESL通道挂机事件[%s][%s]") % strCallID %strChanID));
- __delSession(strCallID, strChanID);
- }
- break;
- default:
- break;
- }
- }
- void EslGateway::__hangupEvent(esl_event_t * pEvent)
- {
- }
- void EslGateway::__detectSpeech(esl_event_t * pEvent)
- {
- /*LOG_DEBUG_S("语音识别消息");
- char *pContent = new char[2048];
- esl_event_serialize(pEvent, &pContent, ESL_TRUE);
- LOG_DEBUG_S(pContent);
- if (pContent) {
- delete pContent;
- pContent = nullptr;
- }*/
- std::string strCallID = "";
- auto pCallID = esl_event_get_header(pEvent, ESL_HEADER_CALLID);
- strCallID = pCallID == nullptr ? "" : pCallID;
- auto pCallCCID = esl_event_get_header(pEvent, ESL_HEADER_CCID);
- if (pCallCCID != nullptr) {
- strCallID = pCallCCID;
- }
- // 获取通道ID
- std::string strChanID = "";
- auto pChanID = esl_event_get_header(pEvent, ESL_HEADER_CHANID);
- strChanID = pChanID == nullptr ? "" : pChanID;
- char* speechType = nullptr;
- speechType = esl_event_get_header(pEvent, "Speech-Type");
- if (speechType == nullptr) {
- LOG_WARN_S(boost::str(Format("ESL语音识别事件[%s][%s],Speech-Type 空") % strCallID %strChanID));
- return;
- }
- LOG_INFO_S(boost::str(Format("ESL语音识别事件[%s][%s][%s]") % speechType % strCallID %strChanID));
- const auto pSession = __findSession(strCallID, strChanID);
- if (pSession == nullptr) {
- LOG_WARN_S(boost::str(Format("ESL语音识别事件处理失败,找不到会话[%s][%s]") % strCallID %strChanID));
- return;
- }
- const auto pChan = pSession->getChan(strChanID);
- if (pChan == nullptr)return;
- if (strcmp(speechType, "begin-speaking") == 0) {
- pChan->setSentenceBeginTime();
- }
- else if (strcmp(speechType, "detected-speech") == 0)
- {
- excDetectSpeechResume(strChanID); // 识别结束,继续识别
- char* result = esl_event_get_body(pEvent);
- if (result) {
- std::string strRes, err;
- parseASRXml(result, strRes, err);
- pChan->setTransSentenceText(strRes, pSession->transSentenceIndex());
- auto strAsrRes = pChan->asrInfo();
- LOG_INFO_S(boost::str(Format("识别结果:\n[%s]")%strAsrRes));
- std::string strExtNo = "";
- if (pChan->Type() == DEV_RES_TYPE_EXT) {
- strExtNo = pChan->No();
- }
- else {
- const auto pAssoChan = pSession->getAssoChan(strChanID);
- if (pAssoChan) {
- strExtNo = pAssoChan->No();
- }
- }
- // 推送
- if (strExtNo != "") {
- if (m_wsServer) {
- auto pair = m_mapConId.equal_range(strExtNo);
- for (auto it = pair.first; it != pair.second; ++it) {
- m_wsServer->sendMsg(it->second, strAsrRes);
- LOG_INFO_S(boost::str(Format("识别结果发送到[%s]") % strExtNo));
- }
- }
- std::string strSQL;
- Format fmt("insert into asrinfo(callid,agent,exten,msg,src,dst) VALUES('%s','%s','%s','%s','%s','%s')");
- fmt %pSession->Id() % "" %strExtNo %strRes %result %strAsrRes;
- strSQL = fmt.str();
- SqlWrite::GetInstance()->addSql(strSQL);
- }
- }
- }
- }
- void EslGateway::__onEslEvtCustom(esl_event_t * pEvent)
- {
- const char* pSubClass = esl_event_get_header(pEvent, ESL_HEADER_SUBCLASS);
- if (pSubClass == nullptr)return;
- auto HeaderValue = esl_event_get_header(pEvent, ESL_HEADER_EXTEN_NO);
- if (strcmp(pSubClass, ESL_HDR_SUBCLASS_SIP_REG) == 0) { // 分机注册
- if (HeaderValue == nullptr) return;
- __addExtenChan(std::to_string(HeaderValue));
- }
- else if (strcmp(pSubClass, ESL_HDR_SUBCLASS_SIP_UNREG) == 0) { // 分机取消注册
- if (HeaderValue == nullptr) return;
- __delExtenChan(std::to_string(HeaderValue));
- }
- }
- void EslGateway::__addExtenChan(const std::string & strNo)
- {
- auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
- if (it == m_lstExtenChan.end()) {
- auto pChan = std::make_shared<Chan>(DEV_RES_TYPE_EXT, strNo);
- m_lstExtenChan.emplace_back(pChan);
- }
- LOG_INFO_S(boost::str(Format("分机[%s]注册") % strNo));
- }
- void EslGateway::__delExtenChan(const std::string & strNo)
- {
- auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
- if (it != m_lstExtenChan.end()) {
- m_lstExtenChan.erase(it);
- LOG_INFO_S(boost::str(Format("分机[%s]注册取消成功") % strNo));
- }
- else {
- LOG_INFO_S(boost::str(Format("分机[%s]注册取消失败,分机不存在") % strNo));
- }
- }
- std::shared_ptr<Chan> EslGateway::__getExtenChan(const std::string & strNo)
- {
- auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->No().compare(strNo) == 0; });
- if (it != m_lstExtenChan.end()) {
- return *it;
- }
- return nullptr;
- }
- std::shared_ptr<Chan> EslGateway::__addTrunkChan(const std::string & strNo)
- {
- auto pChan = std::make_shared<Chan>(DEV_RES_TYPE_TRUNK, strNo);
- m_lstTrunkChan.emplace_back(pChan);
- LOG_INFO_S(boost::str(Format("添加中继资源[%s]") % strNo));
- return pChan;
- }
- bool EslGateway::__delTrunkChan(const std::string & strChanID)
- {
- auto it = std::find_if(m_lstTrunkChan.begin(), m_lstTrunkChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->ChanID().compare(strChanID) == 0; });
- if (it != m_lstTrunkChan.end()) {
-
- LOG_DEBUG_S(boost::str(Format("删除中继%s")% (*it)->to_string()));
- m_lstTrunkChan.erase(it);
- return true;
- }
- return false;
- }
- std::shared_ptr<Session> EslGateway::__findSession(const std::string & strCallID, const std::string&strChanID)
- {
- auto it = std::find_if(m_lstSession.begin(), m_lstSession.end(), [=](const std::pair<std::string, std::shared_ptr<Session>>& p) {
- return (p.first.compare(strCallID)==0 && strCallID != "") || p.second->getChan(strChanID) != nullptr;
- });
- if (it != m_lstSession.end()) {
- LOG_DEBUG_S(boost::str(Format("找到会话[%s],通道[%s][%s]") % it->first%strCallID%strChanID));
- return it->second;
- }
- auto spSession = std::make_shared<Session>(strCallID);
- m_lstSession.insert(std::make_pair(strCallID, spSession));
- LOG_DEBUG_S(boost::str(Format("创建新会话[%s]") % strCallID));
- return spSession;
- }
- void EslGateway::__delSession(const std::string & strCallID, const std::string & strChanID)
- {
- auto it = std::find_if(m_lstSession.begin(), m_lstSession.end(), [=](const std::pair<std::string, std::shared_ptr<Session>>& p) {
- return p.first.compare(strCallID) == 0 || p.second->getChan(strChanID) != nullptr;
- });
- if (it != m_lstSession.end()) {
- auto pSession = it->second;
- auto pChan = pSession->getChan(strChanID);
- if (pChan) {
- pSession->delChan(pChan);
- if (pChan->Type() == DEV_RES_TYPE_EXT) {
- pChan->Hangup();
- }
- else {
- __delTrunkChan(strChanID);
- }
- }
- if (pSession->size() == 0) {
- m_lstSession.erase(it);
- LOG_INFO_S(boost::str(Format("会话销毁CallID[%s]ChanID[%s]") % strCallID %strChanID));
- }
- }
- else {
- LOG_WARN_S(boost::str(Format("会话中未找到通道资源[%s][%s]") % strCallID %strChanID));
- if (!__delTrunkChan(strChanID)) {
- auto it = std::find_if(m_lstExtenChan.begin(), m_lstExtenChan.end(), [=](const std::shared_ptr<Chan>&pChan) {return pChan->ChanID().compare(strChanID)==0; });
- if (it != m_lstExtenChan.end()) {
- (*it)->Hangup();
- }
- }
- }
- }
- void EslGateway::__onWsMessage(const long & lConId, const std::string & strMsg, const std::string & strIP)
- {
- Json::Value root;
- Json::String errs;
- Json::CharReaderBuilder builder;
- builder["collectComments"] = true;
- std::unique_ptr<Json::CharReader>pReader(builder.newCharReader());
- if (!pReader->parse(strMsg.c_str(), strMsg.c_str() + strMsg.length(), &root, &errs) || errs != "" || !root.isObject()) {
- Format fmt("json字符串格式异常,异常信息[%s]\n[%s]");
- fmt %errs %strMsg;
- LOG_ERROR_S(fmt.str());
- return;
- }
- const auto type = root["Type"].asString();
- const auto AgentID = root["AgentID"].asString();
- const auto AgentExten = root["AgentExten"].asString();
- bool bOk = false;
- std::string strDesc = "失败";
- if (type == "Login") {
- auto it = std::find_if(m_mapConId.begin(), m_mapConId.end(), [=](std::pair<std::string, long>pair) {
- return pair.first == AgentExten && pair.second == lConId;
- });
- if (it == m_mapConId.end()) {
- m_mapConId.insert(std::make_pair(AgentExten, lConId));
- }
- bOk = true;
- }
- else if (type == "Logout") {
- auto it = std::find_if(m_mapConId.begin(), m_mapConId.end(), [=](std::pair<std::string, long>pair) {
- return pair.first == AgentExten && pair.second == lConId;
- });
- if (it != m_mapConId.end()) {
- m_mapConId.erase(it);
- }
- bOk = true;
- }
- else if (type == "BindExtAgent") {
- strDesc = "失败,分机已与其它坐席进行关联";
- auto it = m_mapExtAgent.find(AgentExten);
- if (it == m_mapExtAgent.end()) {
- strDesc = "成功";
- bOk = true;
- m_mapExtAgent[AgentExten] = AgentID;
- }
- LOG_INFO_S(boost::str(Format("绑定分机[%s]坐席[%s]关系[%s]") % AgentExten%AgentID%strDesc));
- }
- else if (type == "UnBindExtAgent") {
- strDesc = "失败,未进行关联";
- auto it = m_mapExtAgent.find(AgentExten);
- if (it != m_mapExtAgent.end()) {
- strDesc = "成功";
- bOk = true;
- m_mapExtAgent.erase(it);
- }
- LOG_INFO_S(boost::str(Format("解除绑定分机[%s]坐席[%s]关系[%s]") % AgentExten%AgentID%strDesc));
- }
- auto strJson = __createJson(type, bOk, strDesc);
- m_wsServer->sendMsg(lConId, strJson);
- }
- void EslGateway::__onWsClose(const long & lConId)
- {
- for (auto it = m_mapConId.begin(); it != m_mapConId.end();) {
- if (it->second == lConId) {
- it = m_mapConId.erase(it);
- }
- else {
- ++it;
- }
- }
- }
- std::string EslGateway::__createJson(const std::string & strType, const bool & bOk, const std::string&strDesc)
- {
- Json::Value root;
- root["Type"] = strType;
- root["Result"] = bOk;
- root["Desc"] = strDesc;
- Json::StreamWriterBuilder builder;
- return Json::writeString(builder, root);
- }
|