#include "stdafx.h" #include "FlowControlFSM.h" #define LOG_EVT_EXIT_ACM_FLOW 0x30500002 //退出坐席控制流程 //错误码 #define LOG_ERR_S0_ANSACMFLOW 0x30500080 #define LOG_ERR_S0_REQAGENTFLOW 0x30500081 #define LOG_ERR_S1_REQAGENTFLOW_FAILED 0x30500082 #define LOG_ERR_S2_ANSAGENTFLOW_FAILED 0x30500083 #define LOG_ERR_S2_NTFENTFLOW_FAILED 0x30500084 #define LOG_ERR_S3_ANSACMFLOW_FAILED 0x30500085 #define LOG_ERR_S5_DISCTRL_FAILED 0x30500086 #define LOG_ERR_S5_REQAGENTFLOW_FAILED 0x30500087 #define LOG_ERR_S7_ENTRY 0x30500088 #define LOG_ERR_S1_ASSIS_IDEL 0x30500089 #define LOG_ERR_S2_ASSIS_IDEL 0x3050008A #define LOG_ERR_S3_ASSIS_IDEL 0x3050008B #define LOG_ERR_S5_ASSIS_IDEL 0x3050008C #define LOG_EVT_CONNEC_ASSISTCHAN_FAILED 0x3050008D #define LOG_ERR_S2_CHAN_OFF 0x3050008E #define LOG_ERR_S3_CHAN_OFF 0x3050008F void ChannelClient::OnMessage( ErrorCodeEnum Error, ChannelService_State_Info &Msg, CSmartPointer pData ) { if (Error == Error_Succeed) { if (Msg.state == eChannelState_Connected) { m_pFSM->PostEventFIFO(new FSMEvent(USER_EVT_CHAN_ON)); } else if (Msg.state == eChannelState_Idle) { m_pFSM->PostEventFIFO(new FSMEvent(USER_EVT_CHAN_OFF)); } } } void ChannelClient::OnMessage( ErrorCodeEnum Error, ChannelService_Packet_Info &Msg, CSmartPointer pData ) { if (Error == Error_Succeed) { m_pFSM->ProcessPacket(Msg.sub_type, Msg.data); } } CFlowControlFSM::CFlowControlFSM(): m_pClient(NULL) { } CFlowControlFSM::~CFlowControlFSM() { } void CFlowControlFSM::OnStateTrans( int iSrcState, int iDstState ) { ChanState evt; evt.state = iDstState; evt.status = CSimpleStringA::Format("OnStateTrans from state %d to %d", iSrcState, iDstState); SpSendBroadcast(GetEntityBase()->GetFunction(), SP_MSG_OF(ChanState), SP_MSG_SIG_OF(ChanState), evt); switch (iDstState) { case s0: SetState("O", "Offline"); // offline break; case s1: SetState("F", "FrontFlow"); // frontflow break; case s2: SetState("B", "BackFlow"); // backflow break; case s3: SetState("C", "FrontCall"); // front call break; case s5: SetState("T", "Transferring"); // Transferring break; default: break; } } ErrorCodeEnum CFlowControlFSM::OnInit() { m_bConnectAssit = false; AddStateHooker(this); return Error_Succeed; } ErrorCodeEnum CFlowControlFSM::OnExit() { if (m_pClient != NULL) { m_pClient->GetFunction()->CloseSession(); m_pClient = NULL; } RemoveStateHooker(this); void FinishClose(CEntityBase *pEntity, ErrorCodeEnum Error = Error_Succeed); FinishClose(m_pEntity); return Error_Succeed; } bool CFlowControlFSM::IsAssistchanEntityAvailable() { if (Error_Succeed == ConnectToAssistchan(false)) { return true; } else { return false; } } ErrorCodeEnum CFlowControlFSM::ConnectToAssistchan(bool blogevt) { if (!IsAssistchanConnectSessionOK()) { FreeAssistchanClient(); m_pClient = new ChannelClient(m_pEntity, this); ErrorCodeEnum errorCode = m_pClient->Connect(); if (Error_Succeed != errorCode) { m_pClient->SafeDelete(); m_pClient = NULL; if (blogevt) { LogWarn(Severity_Middle, Error_InvalidState, LOG_EVT_CONNEC_ASSISTCHAN_FAILED, CSimpleStringA::Format("Connect to assistchan entity failed:0x%08x.", errorCode)); } return Error_InvalidState; } else { if (blogevt) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("Connect to assistchan Client Succeed!"); } ChannelService_BeginState_Sub ChannelSub; errorCode = m_pClient->BeginState(ChannelSub); if (Error_Succeed != errorCode) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("BeginState biz channel failed!"); m_pClient->GetFunction()->CloseSession(); m_pClient = NULL; return errorCode; } ChannelService_BeginRecv_Sub Sub; Sub.type = ACM_TYPE_FLW; errorCode = m_pClient->BeginRecv(Sub); if (Error_Succeed != errorCode) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("Register ACM_TYPE_FLW failed!"); m_pClient->GetFunction()->CloseSession(); m_pClient = NULL; return errorCode; } } } return Error_Succeed; } bool CFlowControlFSM::IsAssistchanConnectSessionOK() { return (m_pClient != NULL && !m_pClient->QuerySessionClosed()); } void CFlowControlFSM::FreeAssistchanClient() { if (m_pClient) { m_pClient->GetFunction()->CloseSession(); m_pClient = NULL; } } unsigned int CFlowControlFSM::s0_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_ANSACMFLOW) { AgentFlowResult evt; evt.error = Error_NetBroken; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(AgentFlowResult), SP_MSG_SIG_OF(AgentFlowResult), evt); LogWarn(Severity_Low, Error_Debug, LOG_ERR_S0_ANSACMFLOW, "s0 receive ANSACMFLOW"); } else if (event->iEvt == USER_EVT_REQAGENTFLOW) { AgentFlowResult evt; evt.error = Error_NetBroken; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(AgentFlowResult), SP_MSG_SIG_OF(AgentFlowResult), evt); LogWarn(Severity_Low, Error_Debug, LOG_ERR_S0_REQAGENTFLOW, "s0 receive REQAGENTFLOW"); } else if (event->iEvt == USER_EVT_ASSIS_IDEL) { if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } unsigned int CFlowControlFSM::s1_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_REQAGENTFLOW) { ReqAgentFlowEvent *rafe = static_cast(event); ErrorCodeEnum Error; if (m_pClient) { ChannelService_Send_Info Info; Info.compress = true; Info.encrypt = true; Info.sub_type = ACM_SUBTYPE_REQ_FLOW; Info.type = ACM_TYPE_FLW; SpBuffer buf; buf.OpenWrite(); #if defined(RVC_OS_WIN) buf& rafe->req_context; #else CSimpleString16Bit reqContext = CSimpleStringW216Bit(rafe->req_context); buf& reqContext; #endif //RVC_OS_WIN Info.data = buf.ToBlob(); Error = m_pClient->Send(Info); } else { Error = Error_NetBroken; LogWarn(Severity_Low, Error_Debug, LOG_ERR_S1_REQAGENTFLOW_FAILED, "s1 receive REQAGENTFLOW but chan is off."); } return Error == Error_Succeed ? 1 : 0; } else if (event->iEvt == USER_EVT_NTFENTFLOW) { NotifyEnterFlowEvent *nef = static_cast(event); NotifyEnterFlow evt; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(NotifyEnterFlow), SP_MSG_SIG_OF(NotifyEnterFlow), evt); } else if (event->iEvt == USER_EVT_ASSIS_IDEL) { LogWarn(Severity_Low, Error_Debug, LOG_ERR_S1_ASSIS_IDEL, "s1 ASSIS_IDEL."); if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } unsigned int CFlowControlFSM::s2_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_CHAN_OFF) { // notify UI to unlock the screen AgentFlowResult evt; evt.error = Error_NetBroken; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(AgentFlowResult), SP_MSG_SIG_OF(AgentFlowResult), evt); LogWarn(Severity_Low, Error_Debug, LOG_ERR_S2_CHAN_OFF, "s2 chan off."); } else if (event->iEvt == USER_EVT_ANSAGENTFLOW) { AnsAgentFlowEvent *afe = static_cast(event); AgentFlowResult evt; #if defined(RVC_OS_WIN) evt.ans_context = afe->ans_context; #else CSimpleStringW ans_context = CSimpleString16Bit2W(afe->ans_context); evt.ans_context = ans_context; #endif //RVC_OS_WIN evt.error = afe->err ? Error_Unexpect : Error_Succeed; if (evt.error != Error_Succeed){ LogWarn(Severity_Low, Error_Debug, LOG_ERR_S2_ANSAGENTFLOW_FAILED, "s2 receive ANSAGENTFLOW error."); } SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(AgentFlowResult), SP_MSG_SIG_OF(AgentFlowResult), evt); } else if (event->iEvt == USER_EVT_REQACMFLOW) { ReqACMFlowEvent *afe = static_cast(event); ACMFlowInvoke evt; #if defined(RVC_OS_WIN) evt.req_context = afe->req_context; #else CSimpleStringW req_context = CSimpleString16Bit2W(afe->req_context); evt.req_context = req_context; #endif //RVC_OS_WIN SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(ACMFlowInvoke), SP_MSG_SIG_OF(ACMFlowInvoke), evt); } else if (event->iEvt == USER_EVT_NTFENTFLOW) { ErrorCodeEnum result = DisallowControl(); if (result != Error_Succeed){ LogWarn(Severity_Low, Error_Debug, LOG_ERR_S2_NTFENTFLOW_FAILED, "s2 send NTFENTFLOW error."); } } else if (event->iEvt == USER_EVT_ASSIS_IDEL){ LogWarn(Severity_Low, Error_Debug, LOG_ERR_S2_ASSIS_IDEL, "s2 ASSIS_IDEL."); if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } void CFlowControlFSM::s2_on_exit() { } void CFlowControlFSM::s3_on_entry() { } void CFlowControlFSM::s3_on_exit() {} unsigned int CFlowControlFSM::s3_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_ANSACMFLOW) { AnsACMFlowEvent *afe = static_cast(event); ErrorCodeEnum Error; if (m_pClient) { ChannelService_Send_Info Info; Info.compress = true; Info.encrypt = true; Info.sub_type = ACM_SUBTYPE_ANS_FLOW; Info.type = ACM_TYPE_FLW; SpBuffer buf; buf.OpenWrite(); #if defined(RVC_OS_WIN) buf& afe->ans_context; #else CSimpleString16Bit ansContext = CSimpleStringW216Bit(afe->ans_context); buf& ansContext; #endif //RVC_OS_WIN Info.data = buf.ToBlob(); Error = m_pClient->Send(Info); } else { Error = Error_NetBroken; LogWarn(Severity_Low, Error_Debug, LOG_ERR_S3_ANSACMFLOW_FAILED, "s3 send ANSACMFLOW error."); } return Error == Error_Succeed ? 1 : 0; } else if (event->iEvt == USER_EVT_CHAN_OFF) { AgentFlowResult evt; evt.error = Error_NetBroken; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(AgentFlowResult), SP_MSG_SIG_OF(AgentFlowResult), evt); LogWarn(Severity_Low, Error_Debug, LOG_ERR_S3_CHAN_OFF, "s3 chan off."); } else if (event->iEvt == USER_EVT_ASSIS_IDEL) { LogWarn(Severity_Low, Error_Debug, LOG_ERR_S3_ASSIS_IDEL, "s3 ASSIS_IDEL."); if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } void CFlowControlFSM::s5_on_entry() { } void CFlowControlFSM::s5_on_exit() { } unsigned int CFlowControlFSM::s5_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_DISCTRL) { ErrorCodeEnum result = DisallowControl(); if (result != Error_Succeed) { LogWarn(Severity_Low, Error_Debug, LOG_ERR_S5_DISCTRL_FAILED, "s5 send DISCTRL error."); } } else if (event->iEvt == USER_EVT_REQAGENTFLOW) { ReqAgentFlowEvent* rafe = static_cast(event); ErrorCodeEnum Error; if (m_pClient) { ChannelService_Send_Info Info; Info.compress = true; Info.encrypt = true; Info.sub_type = ACM_SUBTYPE_REQ_FLOW; Info.type = ACM_TYPE_FLW; SpBuffer buf; buf.OpenWrite(); #if defined(RVC_OS_WIN) buf& rafe->req_context; #else CSimpleString16Bit reqContext = CSimpleStringW216Bit(rafe->req_context); buf& reqContext; #endif //RVC_OS_WIN Info.data = buf.ToBlob(); Error = m_pClient->Send(Info); } else { Error = Error_NetBroken; LogWarn(Severity_Low, Error_Debug, LOG_ERR_S5_REQAGENTFLOW_FAILED, "s5 send REQAGENTFLOW error."); } return Error == Error_Succeed ? 1 : 0; } else if (event->iEvt == USER_EVT_ASSIS_IDEL) { LogWarn(Severity_Low, Error_Debug, LOG_ERR_S5_ASSIS_IDEL, "s5 ASSIS_IDEL."); if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } void CFlowControlFSM::s7_on_entry() { LogWarn(Severity_Low, Error_Debug, LOG_ERR_S7_ENTRY, "s7 ENTRY."); } unsigned int CFlowControlFSM::s7_on_event(FSMEvent* event) { if (event->iEvt == USER_EVT_ASSIS_IDEL){ if (Error_Succeed == ConnectToAssistchan(false)) { m_bConnectAssit = true; } } return 0; } void CFlowControlFSM::ProcessPacket( int sub_type, CBlob &blob ) { if (sub_type == ACM_SUBTYPE_ANS_FLOW) { AnsAgentFlowEvent *e = new AnsAgentFlowEvent(); SpBuffer buf; buf.OpenRead((const char*)blob.m_pData, blob.m_iLength); buf.SetLength(blob.m_iLength); buf & e->err & e->ans_context; PostEventFIFO(e); } else if (sub_type == ACM_SUBTYPE_REQ_FLOW) { ReqACMFlowEvent *e = new ReqACMFlowEvent(); SpBuffer buf; buf.OpenRead((const char*)blob.m_pData, blob.m_iLength); buf.SetLength(blob.m_iLength); buf & e->req_context; PostEventFIFO(e); } else if (sub_type == ACM_SUBTYPE_NTF_ENTFLOW) { NotifyEnterFlowEvent *e = new NotifyEnterFlowEvent(); e->m_pFSM = this; SpBuffer buf; buf.OpenRead((const char*)blob.m_pData, blob.m_iLength); buf.SetLength(blob.m_iLength); buf & e->context; PostEventFIFO(e); } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("unknown sub_type from agent!"); } } ErrorCodeEnum CFlowControlFSM::SetState(const char *s, const char *sdesc) { return m_pEntity->GetFunction()->SetSysVar("BackInitiative", s); } ErrorCodeEnum CFlowControlFSM::DisallowControl() { if (m_pClient) { ChannelService_Send_Info Info; Info.compress = false; Info.encrypt = true; Info.id = 0; Info.sub_type = ACM_SUBTYPE_DIS_CONTROL; Info.type = ACM_TYPE_FLW; return m_pClient->Send(Info); } else { return Error_NetBroken; } } void NotifyEnterFlowEvent::OnUnhandled() { m_pFSM->DisallowControl(); }