import { EventEmitter } from 'events' ; import { Module } from '@ringcentral-integration/commons/lib/di' ; import { raceTimeout } from '@ringcentral-integration/commons/lib/raceTimeout' ; import { action , RcModuleV2 , state } from '@ringcentral-integration/core' ; import AgentLibrary from '@SDK' ; import { AGENT_TYPES , messageTypes } from '../../enums' ; import { _encodeSymbol } from '../constant' ; import { EvTypeError } from '../EvTypeError' ; import { evStatus } from './enums' ; import { EvCallbackTypes } from './enums/callbackTypes' ; import { Deps , EvACKResponse , EvAddSessionNotification , EvAgentConfig , EvAgentOptions , EvAgentScriptResult , EvAgentSettings , EvAuthenticateAgentWithEngageAccessTokenRes , EvAuthenticateAgentWithRcAccessTokenRes , EvBaseCall , EvClientCallMapping , EvColdTransferCallResponse , EvColdTransferIntlCallResponse , EvConfigureAgentOptions , EvDirectAgentListResponse , EvDispositionCallOptions , EvDispositionManualPassOptions , EvLogoutAgentResponse , EvMessageRes , EvOpenSocketResult , EvRequeueCallResponse , EvRequeueOption , EvScriptResponse , EvTokenType , EvWarmTransferCallResponse , EvWarmTransferIntlCallResponse , PauseRecord , PauseRecordResponse , RawEvAuthenticateAgentWithRcAccessTokenRes , RecordResponse , } from './interfaces' ; type ListenerType = typeof EvCallbackTypes [ 'OPEN_SOCKET' | 'CLOSE_SOCKET' ] ; type Listener < T extends keyof EvClientCallMapping , U extends EvClientCallMapping = EvClientCallMapping > = ( res : U [ T ] ) => void ; export type EvClientTransferParams = { dialDest : string ; callerId ? : string ; sipHeaders ? : string [ ] ; countryId ? : string ; } ; export type EvClientHandUpParams = { sessionId : string ; resetPendingDisp ? : boolean ; } ; export type EvClientHoldSessionParams = { state : boolean ; sessionId : string ; } ; export type EvClientManualOutdialParams = { destination : string ; callerId : string ; ringTime : number ; queueId : string ; countryId : string ; } ; @ Module ( { name : 'EvClient' , deps : [ 'EvClientOptions' ] } ) class EvClient extends RcModuleV2 < Deps > { /** SDK instance */ private _sdk : any ; private _onOpen : ( response : EvClientCallMapping [ 'openResponse' ] ) => void ; private _onClose : ( ) => void ; private _Sdk = AgentLibrary ; private _options : EvAgentOptions ; private _eventEmitter = new EventEmitter ( ) ; private _callbacks : Record < string , Function > = { } ; @ state appStatus : string = evStatus . START ; constructor ( deps ) { super ( { deps } ) ; this . _options = this . _deps . evClientOptions . options ; const { closeResponse , openResponse } = this . _deps . evClientOptions . callbacks ; this . _onOpen = ( res ) => { this . setAppStatus ( evStatus . CONNECTED ) ; openResponse ( res ) ; this . _eventEmitter . emit ( EvCallbackTypes . OPEN_SOCKET , res ) ; this . _sdk . terminateStats ( ) ; } ; this . _onClose = ( ) => { console . log ( 'EvCallbackTypes.CLOSE_SOCKET~' ) ; this . setAppStatus ( evStatus . CLOSED ) ; closeResponse ( ) ; this . _eventEmitter . emit ( EvCallbackTypes . CLOSE_SOCKET ) ; } ; if ( window . localStorage ) { const authHost = window . localStorage . getItem ( '__authHost__' ) ; if ( authHost ) { this . _options . authHost = authHost ; } } } addListener < T extends ListenerType > ( type , listener ) { this . _eventEmitter . addListener ( type , listener ) ; } addListenerByOnce < T extends ListenerType > ( type , listener ) { this . _eventEmitter . once ( type , listener ) ; } removeListener < T extends ListenerType > ( type , listener ) { this . _eventEmitter . removeListener ( type , listener ) ; } loadCurrentCall ( ) { return new Promise < EvBaseCall | void > ( ( resolve ) => { this . _sdk . loadCurrentCall ( resolve ) ; } ) ; } get currentCall ( ) : EvBaseCall { return this . _sdk . getCurrentCall ( ) ; } @ action setAppStatus ( status ) { this . appStatus = status ; } setEnv ( authHost ) { if ( window . localStorage ) { window . localStorage . setItem ( '__authHost__' , authHost ) ; window . location . reload ( ) ; } } setSIPNoLog ( authHost ) { if ( window . localStorage ) { window . localStorage . setItem ( '__SIP_NO_LOG__' , authHost ) ; window . location . reload ( ) ; } } onInitOnce ( ) { this . initSDK ( ) ; } initSDK ( ) { console . log ( 'initSDK' ) ; const { _Sdk : Sdk } = this ; this . _sdk = new Sdk ( { callbacks : { ... this . _callbacks , [ EvCallbackTypes . CLOSE_SOCKET ] : this . _onClose , [ EvCallbackTypes . OPEN_SOCKET ] : this . _onOpen , [ EvCallbackTypes . ACK ] : ( res ) => { this . _eventEmitter . emit ( EvCallbackTypes . ACK , res ) ; } } , ... this . _options } ) ; } on ( eventType , callback ) { const _callback = { [ eventType ] : ( ... args ) => callback ( ... args ) } ; this . _sdk . setCallbacks ( _callback ) ; this . _callbacks = { ... this . _callbacks , ... _callback } ; } getEventCallback ( eventType ) { return this . _sdk . getCallback ( eventType ) ; } getRefreshedToken ( ) { this . _sdk . getRefreshedToken ( ) ; } authenticateAgentWithEngageAccessToken ( engageAccessToken ) { return new Promise < EvAuthenticateAgentWithEngageAccessTokenRes > ( ( resolve ) => { this . setAppStatus ( evStatus . LOGIN ) ; this . _sdk . authenticateAgentWithEngageAccessToken ( engageAccessToken , ( response ) => { resolve ( response ) ; } ) ; } ) ; } configureAgent ( { dialDest , queueIds , chatIds , skillProfileId , dialGroupId , updateFromAdminUI = false , isForce = false , } ) { return new Promise < EvMessageRes > ( ( resolve ) => { this . _sdk . loginAgent ( dialDest , queueIds , chatIds , skillProfileId , dialGroupId , updateFromAdminUI , isForce , ( res ) => { resolve ( { type : messageTypes . CONFIGURE_AGENT , data : res } ) ; } ) ; } ) ; } dispositionManualPass ( { dispId , notes , callbackDTS , leadId , requestId , externId , } ) { return new Promise < EvDispositionManualPassOptions > ( ( resolve ) => { this . _sdk . dispositionManualPass ( dispId , notes , ( response ) => { resolve ( response ) ; } , callbackDTS , leadId , requestId , externId ) ; } ) ; } dispositionCall ( { uii , dispId = '' , notes = '' , callback , callbackDTS , contactForwardNumber , survey , externId , leadId , requestId = '' , } ) { return this . _sdk . dispositionCall ( this . decodeUii ( uii ) , dispId , notes , callback , callbackDTS , contactForwardNumber , survey , externId , leadId , requestId ) ; } authenticateAgent ( rcAccessToken , tokenType ) { return new Promise < EvAuthenticateAgentWithRcAccessTokenRes > ( ( resolve ) => { this . setAppStatus ( evStatus . LOGIN ) ; this . _sdk . authenticateAgentWithRcAccessToken ( rcAccessToken , tokenType , async ( res ) => { await this . authenticateAgentWithEngageAccessToken ( res . accessToken ) ; this . setAppStatus ( evStatus . LOGINED ) ; const _agents = ( res || { } ) . agents || [ ] ; const agents = _agents . map ( ( agent ) => ( { ... agent , agentId : agent && agent . agentId ? `${ agent . agentId }` : '' , agentType : AGENT_TYPES [ agent . agentType ] } ) ) ; resolve ( { ... res , agents } ) ; } ) ; } ) ; } openSocket ( agentId ) { const hasSupportWebSocket = 'WebSocket' in window ; if ( ! hasSupportWebSocket ) { throw new EvTypeError ( { type : messageTypes . INVALID_BROWSER } ) ; } return new Promise < EvOpenSocketResult > ( ( resolve ) => { this . addListenerByOnce ( EvCallbackTypes . OPEN_SOCKET , ( res ) => { resolve ( res ) ; } ) ; this . _sdk . openSocket ( agentId ) ; } ) ; } getAgentConfig ( ) { return new Promise < EvAgentConfig > ( ( resolve ) => { this . _sdk . getAgentConfig ( ( res ) => { resolve ( res ) ; } ) ; } ) ; } async getAndHandleAuthenticateResponse ( rcAccessToken , tokenType ) { const authenticateResponse = await raceTimeout ( this . authenticateAgent ( rcAccessToken , tokenType ) , { timeout : 120 * 1000 , onTimeout : ( resolve ) => resolve ( null ) } ) ; if ( ! authenticateResponse ) { throw new EvTypeError ( { type : messageTypes . CONNECT_TIMEOUT } ) ; } if ( authenticateResponse . type === 'Authenticate Error' || authenticateResponse . message ) { throw new EvTypeError ( { type : messageTypes . CONNECT_ERROR , data : authenticateResponse . message } ) ; } if ( ! authenticateResponse || ! authenticateResponse . agents || ! authenticateResponse . agents . length ) { throw new EvTypeError ( { type : messageTypes . NO_AGENT } ) ; } if ( ! authenticateResponse . agents [ 0 ] || ! authenticateResponse . agents [ 0 ] . agentId ) { throw new EvTypeError ( { type : messageTypes . UNEXPECTED_AGENT } ) ; } return authenticateResponse ; } /**
     * when manual close socket, that closeSocket will auto reconnected by agent SDK
     */ closeSocket ( ) { this . _sdk . closeSocket ( ) ; } get ifSocketExist ( ) { return ! ! this . _sdk . socket ; } hangup ( { sessionId , resetPendingDisp = false } ) { return this . _sdk . hangup ( sessionId , resetPendingDisp ) ; } logoutAgent ( agentId ) { return new Promise < EvLogoutAgentResponse > ( ( resolve ) => { this . _sdk . logoutAgent ( agentId , ( result ) => { resolve ( result ) ; } ) ; } ) ; } manualOutdial ( { destination , callerId , ringTime , countryId , queueId , } ) { return this . _sdk . manualOutdial ( destination , callerId , ringTime , countryId , queueId ) ; } manualOutdialCancel ( uii ) { this . _sdk . manualOutdialCancel ( uii ) ; } offhookInit ( ) { this . _sdk . offhookInit ( ) ; } offhookTerm ( ) { this . _sdk . offhookTerm ( ) ; } hold ( holdState ) { this . _sdk . hold ( holdState ) ; } pauseRecord ( isRecord ) { return new Promise < PauseRecord > ( ( resolve , reject ) => { return this . _sdk . pauseRecord ( isRecord , ( response ) => { const formattedResponse = { ... response , pause : response . pause ? Number ( response . pause ) : null } ; if ( response . status === 'OK' ) { resolve ( formattedResponse ) ; } else { reject ( formattedResponse ) ; } } ) ; } ) ; } record ( state ) { return new Promise < RecordResponse > ( ( resolve , reject ) => { return this . _sdk . record ( state , ( response ) => { if ( response . status === 'OK' ) { resolve ( response ) ; } else { reject ( response ) ; } } ) ; } ) ; } holdSession ( { state , sessionId } ) { this . _sdk . holdSession ( state , sessionId ) ; } coldTransferCall ( { dialDest , callerId = '' , sipHeaders = [ ] , } ) { return new Promise < EvColdTransferCallResponse > ( ( resolve , reject ) => { this . _sdk . coldXfer ( dialDest , callerId , sipHeaders , ( data ) => { if ( data . status === 'OK' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; } ) ; } warmTransferCall ( { dialDest , callerId = '' , sipHeaders = [ ] , } ) { return new Promise < EvWarmTransferCallResponse > ( ( resolve , reject ) => { this . _sdk . warmXfer ( dialDest , callerId , sipHeaders , ( data ) => { if ( data . status === 'OK' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; } ) ; } coldTransferIntlCall ( { dialDest , callerId = '' , sipHeaders = [ ] , countryId = '' , } ) { return new Promise < EvColdTransferIntlCallResponse > ( ( resolve , reject ) => { this . _sdk . internationalColdXfer ( dialDest , callerId , sipHeaders , countryId , ( data ) => { if ( data . status === 'OK' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; } ) ; } warmTransferIntlCall ( { dialDest , callerId = '' , sipHeaders = [ ] , countryId = '' , } ) { return new Promise < EvWarmTransferIntlCallResponse > ( ( resolve , reject ) => { this . _sdk . internationalWarmXfer ( dialDest , callerId , sipHeaders , countryId , ( data ) => { if ( data . status === 'OK' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; } ) ; } cancelWarmTransferCall ( dialDest ) { this . _sdk . warmXferCancel ( dialDest ) ; } requeueCall ( { queueId , skillId = '' , maintain = false } ) { return new Promise < EvRequeueCallResponse > ( ( resolve , reject ) => { this . _sdk . requeueCall ( queueId , skillId , maintain , ( data ) => { if ( data . status === 'OK' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; } ) ; } fetchDirectAgentList ( ) { return new Promise < EvDirectAgentListResponse > ( ( resolve ) => { this . _sdk . directAgentXferList ( ( data ) => { resolve ( data ) ; } ) ; } ) ; } encodeUii ( { uii , sessionId } ) { return `${ uii }${ _encodeSymbol }${ sessionId }` ; } param _encodeSymbol encodeRingingUii ( { uii } ) { return this . encodeUii ( { uii : this . decodeUii ( uii ) , sessionId : _encodeSymbol } ) ; } decodeUii ( uii ) { return uii . split ( _encodeSymbol ) [ 0 ] ; } param uii getMainId ( uii ) { return this . encodeUii ( { sessionId : '1' , uii } ) ; } rejectDirectAgentTransferCall ( uii ) { this . _sdk . rejectDirectAgentXfer ( this . decodeUii ( uii ) ) ; } coldDirectAgentTransfer ( targetAgentId ) { this . _sdk . coldDirectAgentXfer ( targetAgentId ) ; } warmDirectAgentTransfer ( targetAgentId ) { this . _sdk . warmDirectAgentXfer ( targetAgentId ) ; } sendVoicemailDirectAgentTransfer ( targetAgentId ) { this . _sdk . voicemailDirectAgentXfer ( targetAgentId ) ; } cancelDirectAgentTransfer ( targetAgentId ) { this . _sdk . cancelDirectAgentXfer ( targetAgentId ) ; } setAgentState ( agentState , agentAuxState ) { return this . _sdk . setAgentState ( agentState , agentAuxState ) ; } private _multiLoginRequest ( ) { return new Promise < any > ( ( resolve , reject ) => { this . _sdk . multiLoginRequest ( ) ; this . on ( EvCallbackTypes . LOGIN , ( data ) => { if ( data . status === 'SUCCESS' ) { resolve ( data ) ; } else { reject ( data ) ; } } ) ; this . on ( EvCallbackTypes . GENERIC_NOTIFICATION , ( data ) => { if ( data . messageCode === '-99' ) { reject ( data ) ; } } ) ; } ) ; } async multiLoginRequest ( ) { try { await raceTimeout ( this . _multiLoginRequest ( ) , { onTimeout : ( res , rej ) => rej ( ) } ) ; } catch ( error ) { throw new Error ( '_multiLoginRequest fail or 30s timeout' ) ; } } /**
     * WebRTC related method
     */ sipInit ( ) { this . _sdk . sipInit ( ) ; } sipAnswer ( ) { this . _sdk . sipAnswer ( ) ; } sipRegister ( ) { this . _sdk . sipRegister ( ) ; } sipTerminate ( ) { this . _sdk . sipTerminate ( ) ; } sipHangUp ( ) { this . _sdk . sipHangUp ( ) ; } sipReject ( ) { this . _sdk . sipReject ( ) ; } sipSendDTMF ( dtmf ) { this . _sdk . sipSendDTMF ( dtmf ) ; } sipToggleMute ( state ) { this . _sdk . sipToggleMute ( state ) ; } /**
     * AgentScript related method
     */ getScript ( scriptId , version ) { return new Promise < EvScriptResponse > ( ( resolve , reject ) => { this . _sdk . getScript ( scriptId , version , ( res ) => { if ( res . status ) { resolve ( res ) ; } } ) ; } ) ; } async saveScriptResult ( uii , scriptId , jsonResult ) { this . _sdk . saveScriptResult ( uii , scriptId , jsonResult ) ; return jsonResult ; } /**
     * GET - /voice/api/v1/agent/:accountId/knowledgeBaseGroups
        params:
        accountId: AgentSvc.agentSettings.accountId,
        guid: AgentSvc.agentSettings.guid,
        knowledgeBaseGroupIds: knowledgeBaseGroupIds
  
        knowledgeBaseGroupIds = comma list of all groups you care about
     */ async getKnowledgeBaseGroups ( knowledgeBaseGroupIds ) { this . getRefreshedToken ( ) ; const uiModel = this . _sdk . _getUIModel ( ) . getInstance ( ) ; const HttpService = this . _sdk . _HttpService ; const agentSettings = this . _sdk . getAgentSettings ( ) ; const engageAccessToken = `Bearer ${ uiModel . authenticateRequest . engageAccessToken }` ; try { const { status , response } = await new HttpService ( `${ uiModel . authHost }/voice/api/v1/` ) . httpGet ( `agent/${ agentSettings . accountId }/knowledgeBaseGroups` , { headers : { 'Content-Type' : 'application/json' , Authorization : engageAccessToken } , queryParams : { guid : agentSettings . guid , knowledgeBaseGroupIds } } ) ; if ( status === 200 ) { return JSON . parse ( response ) ; } } catch ( error ) { console . log ( 'getKnowledgeBaseGroups fail' ) ; } return null ; } } export { EvClient } ;