#include "StdAfx.h" #include "IvrFlow.h" #include "CellBase.h" #include "FlowTemplate.h" #include "MsgCenter.h" #include "NetworkIvr.h" #include "CellTimer.h" IMPLEMENT_DYNAMIC(CIvrFlow, CWnd) CIvrFlow::CIvrFlow(int Id) : m_Id(Id), m_State(IVR_FLOW_STATE_FREE), m_IsHangUp(false), m_IsNetLinkUp(false), m_AssoCallId(0), m_pFlowTemplate(NULL), m_pCurrentCell(NULL) { CreateEx(0, AfxRegisterWndClass(CS_GLOBALCLASS), "", 0, 0, 0, 0, 0, 0, 0); } CIvrFlow::~CIvrFlow(void) { __release(); DestroyWindow(); } BEGIN_MESSAGE_MAP(CIvrFlow, CWnd) ON_WM_TIMER() END_MESSAGE_MAP() /***************************************************************** **【函数名称】 __release **【函数功能】 释放资源 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::__release( void ) { if(m_pCurrentCell != NULL) __deleteCurrentCell(); m_VarTable.RemoveAll(); } /***************************************************************** **【函数名称】 __clearFlow **【函数功能】 流程结束时对流程进行清理 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::__clearFlow( void ) { m_AssoCallId = 0; m_IsHangUp = false; m_State = IVR_FLOW_STATE_FREE; __release(); CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast(m_Id)); CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast(m_Id)); if(m_IsNetLinkUp && m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO) start(); } /***************************************************************** **【函数名称】 __onTimerTimeOut **【函数功能】 流程节点最大执行时间超时处理函数 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::__onTimerTimeOut( void ) { ASSERT(m_pCurrentCell != NULL); ASSERT(m_pFlowTemplate != NULL); if(m_pFlowTemplate->type() != FLOW_SUB) // 执行子流程时不上报流程结束 { CPduEntity cmdFlowEnd(PDU_CMD_IVR_END); cmdFlowEnd.SetDataInt(1, m_Id); CNetworkIvr::GetInstance().send(cmdFlowEnd); } ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 节点[%s]超过最大执行时间, 流程[%d]将被释放"), m_pCurrentCell->name(), m_Id); __clearFlow(); } /***************************************************************** **【函数名称】 __onNextCellNull **【函数功能】 当下个节点为空的处理 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::__onNextCellNull( int NullCellPos ) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 查找节点[%d]失败, 流程[%d]将被释放"), NullCellPos, m_Id); CPduEntity CmdHangUp(PDU_CMD_IVR_HANGUP); CmdHangUp.SetDataInt(1, m_Id); CNetworkIvr::GetInstance().send(CmdHangUp); __clearFlow(); } /***************************************************************** **【函数名称】 __deleteCurrentCell **【函数功能】 删除当前节点 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::__deleteCurrentCell( void ) { ASSERT(m_pCurrentCell != NULL); if(m_pCurrentCell->maxWaitingTime() > 0) KillTimer((long)m_pCurrentCell); delete m_pCurrentCell; m_pCurrentCell = NULL; } /***************************************************************** **【函数名称】 start **【函数功能】 开始执行流程 **【参数】 pFlowTemp: 流程模板 **【返回值】 下一个节点编号 ****************************************************************/ int CIvrFlow::start( CFlowTemplate* pFlowTemp /*= NULL*/, int StartPos/* = 1*/ ) { if(pFlowTemp != NULL) m_pFlowTemplate = pFlowTemp; if(m_pFlowTemplate == NULL) { ASSERT(FALSE); return CELL_OP_ERROR; } CString CellName = ""; switch(m_pFlowTemplate->type()) { case FLOW_NORMAL: case FLOW_SUB: CellName = CELL_NAME_START; break; case FLOW_AUTO: CellName = CELL_NAME_TIMER; break; } int Pos = m_pFlowTemplate->getCellPos(CellName); if(Pos < 1) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]时未找到起始节点, Template = %s"), m_Id, m_pFlowTemplate->name()); return CELL_OP_ERROR; } Pos = (StartPos == 1) ? Pos : StartPos; m_State = IVR_FLOW_STATE_RUN; CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast(m_Id)); // 如果是自动流程,但是还未连接至CTI则等待,直到连至CTI后执行 if(m_pFlowTemplate->type() == FLOW_AUTO && !m_IsNetLinkUp) { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Flow}: 自动流程[%d]挂起, 等候与CTI连接, Template = %s"), m_Id, m_pFlowTemplate->name()); return CELL_OP_WAIT_FOR; } return next(Pos); } /***************************************************************** **【函数名称】 next **【函数功能】 执行流程下一结点 **【参数】 NextPos:下一结点编号 **【返回值】 后一个节点编号 ****************************************************************/ int CIvrFlow::next( int NextPos ) { ASSERT(m_pFlowTemplate != NULL); if(m_pFlowTemplate == NULL) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]后续节点时,流程模板为空"), m_Id); return CELL_OP_ERROR; } int NextCellPos = NextPos; m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos); if(m_pCurrentCell == NULL) { __onNextCellNull(NextCellPos); return NextCellPos; } while(m_pCurrentCell != NULL) { m_pCurrentCell->assoIvrFlow() = this; CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast(m_Id)); ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]开始执行节点[%s]"), m_Id, m_pCurrentCell->name()); NextCellPos = m_pCurrentCell->operate(); if(NextCellPos > 0) { __deleteCurrentCell(); m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos); if(m_pCurrentCell == NULL) { __onNextCellNull(NextCellPos); break; } } else if(NextCellPos == CELL_OP_END) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name()); __clearFlow(); break; } else if(NextCellPos == CELL_OP_WAIT_FOR) { if(m_pCurrentCell->maxWaitingTime() > 0) SetTimer(reinterpret_cast(m_pCurrentCell), m_pCurrentCell->maxWaitingTime() * 1000, NULL); break; } else if(NextCellPos == CELL_OP_ERROR) { CPduEntity cmdIVREnd(PDU_CMD_IVR_END); cmdIVREnd.SetDataInt(1, m_Id); if(!CNetworkIvr::GetInstance().send(cmdIVREnd)) ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 且通知Cti失败, 流程将被释放"), m_Id, m_pCurrentCell->name()); else ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 已成功通知Cti, 流程将被释放"), m_Id, m_pCurrentCell->name()); __clearFlow(); break; } else if(NextCellPos == CELL_OP_SEND_ERROR) { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时, 向Cti传送数据失败, 流程将被释放"), m_Id, m_pCurrentCell->name()); __clearFlow(); break; } } return NextCellPos; } /***************************************************************** **【函数名称】 procPdu **【函数功能】 处理PDU消息 **【参数】 pPduEntity:PDU消息 **【返回值】 下一个节点编号 ****************************************************************/ int CIvrFlow::procPdu( CPduEntity* pPduEntity ) { ASSERT(pPduEntity != NULL); bool HangupFlag = false; if(pPduEntity->GetCmdType() == PDU_CMD_CTI_IVR_HANGUP && !pPduEntity->GetIsExecReturn()) HangupFlag = true; if(m_pCurrentCell != NULL) { int NextCellPos = m_pCurrentCell->onOpResultReturn(pPduEntity); if(HangupFlag) ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到挂机消息, 流程当前节点为[%s], Note = %s, 下一节点[%d]"), m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos); else ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 流程当前节点为[%s], Note = %s, 下一节点[%d]"), m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos); if(NextCellPos > 0) // NextCellPos为可用的下一结点编号 { __deleteCurrentCell(); return next(NextCellPos); } else if(NextCellPos == CELL_OP_WAIT_FOR) { if(HangupFlag) m_IsHangUp = true; return CELL_OP_WAIT_FOR; } else if(NextCellPos == CELL_OP_END) { ASSERT(FALSE); ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name()); __clearFlow(); return CELL_OP_END; } else // CELL_OP_ERROR或者CELL_OP_SEND_ERROR的情况 { __clearFlow(); return CELL_OP_ERROR; } } else { if(HangupFlag) ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到挂机消息, 但是当前执行节点为空, 流程将被释放"), m_Id); else ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 但是执行节点却为空, 流程将被释放"), m_Id); __clearFlow(); return CELL_OP_ERROR; } } /***************************************************************** **【函数名称】 onNetLinkUpdated **【函数功能】 响应网络链接成功或断开事件 **【参数】 IsConnect:网络链接成功或断开 **【返回值】 ****************************************************************/ void CIvrFlow::onNetLinkUpdated( bool IsConnect ) { m_IsNetLinkUp = IsConnect; if(!IsConnect) { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络中断流程[%d]将被释放"), m_Id); __clearFlow(); } else { if(m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO) { ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络连接成功自动流程[%d]将启动"), m_Id); start(); } } } /***************************************************************** **【函数名称】 addVar **【函数功能】 添加系统变量 **【参数】 VarName: 变量名称 VarValue: 变量值 **【返回值】 ****************************************************************/ void CIvrFlow::addVar( const CString& VarName, const CString& VarValue ) { m_VarTable.SetAt(VarName, VarValue); } /***************************************************************** **【函数名称】 findVarValue **【函数功能】 查找系统变量 **【参数】 VarName:变量名称 VarValue:变量值 **【返回值】 true:查找到,false:未查找到 ****************************************************************/ bool CIvrFlow::findVarValue( const CString& VarName, CString& VarValue ) { if(m_VarTable.Lookup(VarName, VarValue)) return true; else return false; } /***************************************************************** **【函数名称】 replaceVar **【函数功能】 根据流程中的变量对指定字符串进行替换 **【参数】 Src: 要进行替换的字符串 Dst: 替换完成的字符串 **【返回值】 成功true,失败false ****************************************************************/ bool CIvrFlow::replaceVar( const CString& Src, CString& Dst ) { Dst = Src; int Begin = 0; while( (Begin = Dst.Find(VAR_REF_START_FLAG, Begin)) != -1) { int End = Dst.Find(VAR_REF_END_FLAG, Begin); if(End != -1 && (End - Begin) > 2) // 可以取其中的变量 { CString ValName = Dst.Mid(Begin + 2, End - Begin - 2); CString ValValue = _T(""); // 将变量替换为具体值 if( findVarValue(ValName, ValValue)) Dst.Replace((VAR_REF_START_FLAG + ValName + VAR_REF_END_FLAG), ValValue); else return false; } // end if else { return false; } } // end while return true; } /***************************************************************** **【函数名称】 copyVar **【函数功能】 复制目标流程的系统变量 **【参数】 DestFlow:目标流程 **【返回值】 ****************************************************************/ void CIvrFlow::copyVar( CIvrFlow& DestFlow ) { const VarTable::CPair* pPair = DestFlow.m_VarTable.PGetFirstAssoc(); while(pPair != NULL) { m_VarTable.SetAt(pPair->key, pPair->value); DestFlow.m_VarTable.PGetNextAssoc(pPair); } } /***************************************************************** **【函数名称】 setFlowInfo **【函数功能】 保存流程信息 **【参数】 CallId: 呼叫标识 TrunkId: 外线Id CallerNum:主叫号码 CalleeNum: 被叫号码 **【返回值】 ****************************************************************/ void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, const CString& CallerNum, const CString& CalleeNum ) { m_AssoCallId = CallId; // 给系统变量呼叫标识赋值 CString Data = ""; Data.Format(_T("%lu"), CallId); addVar(SYSTEM_VAR_CALLID, Data); // 给系统变量外线号赋值 Data.Format(_T("%u"), TrunkId); addVar(SYSTEM_VAR_OUTLINEID, Data); // 给系统变量主叫号码赋值 addVar(SYSTEM_VAR_CALLER, CallerNum); // 给系统变量被叫号码赋值 addVar(SYSTEM_VAR_CALLEE, CalleeNum); } /***************************************************************** **【函数名称】 setFlowInfo **【函数功能】 保存流程信息 **【参数】 CallId: 呼叫标识 TrunkId: 外线Id TaskId: 预测任务ID OpType: 操作类型 CallerNum:主叫号码 CalleeNum: 被叫号码 **【返回值】 ****************************************************************/ void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, int TaskId, UINT OpType, const CString& CallerNum, const CString& CalleeNum ) { setFlowInfo(CallId, TrunkId, CallerNum, CalleeNum); CString Data; Data.Format(_T("%d"), TaskId); addVar(SYSTEM_VAR_PRE_CALL_ID, Data); Data.Format(_T("%u"), OpType); addVar(SYSTEM_VAR_PRE_CALL_TYPE, Data); } /***************************************************************** **【函数名称】 setFlowAssoData **【函数功能】 设置流程随路数据 **【参数】 AssoData: 随路数据 **【返回值】 ****************************************************************/ void CIvrFlow::setFlowAssoData( CString AssoData ) { CString DataInfo = ""; CString DataName = ""; CString DataValue = ""; while(!AssoData.IsEmpty()) { int nIndex = AssoData.Find("|"); if(nIndex == -1) { DataInfo = AssoData; AssoData.Empty(); } else { DataInfo = AssoData.Left(nIndex); AssoData = AssoData.Right(AssoData.GetLength() - nIndex - 1); } // 解析单个随路数据 int Falg = DataInfo.Find(":"); if(Falg == -1) continue; // 获取变量名 DataName = DataInfo.Left(Falg); if(DataName.IsEmpty()) continue; // 获取变量值 DataValue = DataInfo.Right(DataInfo.GetLength() - Falg - 1); // 添加进随路数据 this->addVar(DataName, DataValue); } } /***************************************************************** **【函数名称】 OnTimer **【函数功能】 定时器响应函数 **【参数】 nIDEvent: 定时器ID **【返回值】 ****************************************************************/ void CIvrFlow::OnTimer( UINT_PTR nIDEvent ) { KillTimer(nIDEvent); if(m_pCurrentCell != NULL && nIDEvent == reinterpret_cast(m_pCurrentCell)) __onTimerTimeOut(); CWnd::OnTimer(nIDEvent); } /***************************************************************** **【函数名称】 onTimeUp **【函数功能】 定时器节点时间到 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlow::onTimerTimeUp( int NextPos ) { if(m_pCurrentCell->name() == CELL_NAME_TIMER) { __deleteCurrentCell(); next(NextPos); } }