internal HuntForAgentAsyncResult(AcdAgentHunter hunter, AcdCustomerSession session, List <AgentSkill> requestedSkills, AsyncCallback callback, object state) : base(callback, state) { _agentHunter = hunter; _session = session; _requestedSkills = requestedSkills; }
internal FindAgentAsyncResult(AsyncCallback asyncCallback, Object state, AcdCustomerSession requestor, AcdAgentMatchMaker matchMaker, List <Agent> exclusionList, List <AgentSkill> requestedSkills) : base(asyncCallback, state) { _matchMaker = matchMaker; _configuration = matchMaker._configuration; _exclusionList = exclusionList; _requestedSkills = requestedSkills; _requestor = requestor; }
internal AcdConferenceServicesAnchor(AcdCustomerSession session, ApplicationEndpoint endpoint, AcdLogger logger) { _endpoint = endpoint; _state = ConferenceServicesAnchorState.Idle; _logger = logger; _session = session; _conversation = new Conversation(endpoint); _conversation.Impersonate("sip:" + Guid.NewGuid() + "@" + endpoint.DefaultDomain, null, null); _conversation.ApplicationContext = this; }
/// <summary> /// Attempts to find an agent available to serve a customer. The operation may time out if no agent /// is available within a configurable max duration. /// </summary> internal IAsyncResult BeginFindAgent(AcdCustomerSession owner, List <Agent> exclusionList, List <AgentSkill> requestedSkills, AsyncCallback callback, object state) { var result = new FindAgentAsyncResult(callback, state, owner, this, exclusionList, requestedSkills); ThreadPool.QueueUserWorkItem((waitState) => { var tempAr = waitState as FindAgentAsyncResult; tempAr.Process(); }, result); return(result); }
internal IAsyncResult BeginHuntForAgent(AcdCustomerSession session, List <AgentSkill> requestedSkills, AsyncCallback callback, object state) { HuntForAgentAsyncResult ar = new HuntForAgentAsyncResult(this, session, requestedSkills, callback, state); ThreadPool.QueueUserWorkItem((waitState) => { var tempAr = waitState as HuntForAgentAsyncResult; tempAr.Process(true); }, ar); return(ar); }
/// <summary> /// Handles an incoming Application Sharing call. The incoming Application Sharing call can be one of two things: /// this can be a brand new customer session or a modality escalation. Else decline. /// </summary> private void HandleApplicationSharingCallReceived(object sender, CallReceivedEventArgs <ApplicationSharingCall> args) { //Declines if it is a brand new Conversation as we only expect, modality escalation in // an existing customer session for Application Sharing. if (args.IsNewConversation == true) { try { args.Call.Decline(new CallDeclineOptions(ResponseCode.TemporarilyUnavailable)); } catch (InvalidOperationException ivoex) { _logger.Log("AcdPortal cannot decline an imcoming Application Sharing Call properly", ivoex); } catch (RealTimeException ex) { _logger.Log("AcdPortal cannot decline an imcoming Application Sharing Call properly", ex); } } else if (args.IsNewConversation == false) { //this an Application Sharing escalation, hand off the call to the AcdCustomerSession for futher processing if (null != args.Call.Conversation.ApplicationContext) { AcdCustomerSession session = args.Call.Conversation.ApplicationContext as AcdCustomerSession; args.RingBackDisabled = true; ThreadPool.QueueUserWorkItem((waitState) => { session.HandleNewModality(args.Call); }); } else { // There was an issue retrieving the AcdCustomerSession, we are declining the call. try { args.Call.Decline(new CallDeclineOptions(ResponseCode.TemporarilyUnavailable)); } catch (InvalidOperationException ivoex) { _logger.Log("AcdPortal cannot decline an imcoming Application Sharing Call properly", ivoex); } catch (RealTimeException ex) { _logger.Log("AcdPortal cannot decline incoming Application Sharing call properly", ex); } } } }
private void OnMonitoringSessionTerminated(object sender, MonitoringSessionStateChangedEventArgs args) { AcdMonitoringSession monitoringSession = sender as AcdMonitoringSession; switch (args.NewState) { case MonitoringSessionState.Terminating: _agentSessionToMonitor = null; _agentToMonitor = null; this.UpdateState(SupervisorSessionState.GeneralAgentActivityTracking); break; case MonitoringSessionState.Terminated: monitoringSession.StateChanged -= this.OnMonitoringSessionTerminated; break; } }
/// <summary> /// Allocates the agent so that she cannot be allocated twice. /// </summary> internal void Allocate(AcdCustomerSession requestor) { lock (_syncRoot) { if (_allocated) { throw new InvalidOperationException("Agent is already allocated."); } if (requestor == null) { throw new InvalidOperationException("Agent Requestor cannot be null."); } Debug.Write("Agent " + this.SignInAddress.ToString() + "was allocated to" + requestor.ToString()); _owner = requestor; _allocated = true; _activeIdleSince = DateTime.UtcNow; _havePropertiesChanged = true; _allocationStatus = AgentAllocationStatus.AllocatedByMatchMaker; } }
/// <summary> /// Releases the agent so that she can be allocated subsequently. /// </summary> internal void Deallocate(object owner) { lock (_syncRoot) { if (!_allocated) { _logger.Log("Agent is not allocated."); } else if (_owner == owner) // we verify that only the one, that allocated the agent, deallocates her { _logger.Log("Agent " + this.SignInAddress.ToString() + "was deallocated by " + owner.ToString()); _allocated = false; _allocationStatus = AgentAllocationStatus.NotAllocated; _activeIdleSince = DateTime.UtcNow; _asyncResult = null; _owner = null; _havePropertiesChanged = true; } else { _logger.Log("Agent can only be deallocated by its owner"); } } }
/// <summary> /// Handles an incoming Instant Messaging call. The incoming Instant Messaging call can be one of two things: /// this can be a brand new customer session or a modality escalation. Else decline. /// </summary> private void HandleInstantMessagingCallReceived(object sender, CallReceivedEventArgs <InstantMessagingCall> args) { //Determines whether it is a new Call if (args.IsNewConversation == true) //New acd customer session { //Decline the call if the portal is draining its calls, else hand it off to a newly created Acd Customer session. if (_portalState < PortalState.Draining) //Only take new calls is we're not in the process of shutting down. { AcdCustomerSession session = new AcdCustomerSession(_logger, _matchMaker, this); //add the session to the list. lock (_syncRoot) { _sessions.Add(session); _numberOfSessionsEstablished++; } session.CustomerSessionStateChanged += CustomerSessionStateChanged; if (args.CustomMimeParts.Count > 0) { productType productInfo; List <AgentSkill> listOfRequestedSkills = new List <AgentSkill>(this.ProcessMimeParts(args.CustomMimeParts, out productInfo)); ThreadPool.QueueUserWorkItem((waitState) => { session.HandleInitialCall(args.Call, listOfRequestedSkills, productInfo); }); } else { ThreadPool.QueueUserWorkItem((waitState) => { session.HandleInitialCall(args.Call, null, null); }); } } else //If the call comes in while we're shutting down, terminate it { //UNDONE: Nice to have: - Play a message to the user that the portal is shutting down. try { args.Call.Decline(new CallDeclineOptions(ResponseCode.TemporarilyUnavailable)); } catch (RealTimeException ex) { _logger.Log("AcdPortal cannot decline incoming IM call properly while draining/terminating the portal", ex); } } } else { //this an audio escalation, hand off the call to the AcdCustomerSession for futher processing if (null != args.Call.Conversation.ApplicationContext) { AcdCustomerSession session = args.Call.Conversation.ApplicationContext as AcdCustomerSession; ThreadPool.QueueUserWorkItem((waitState) => { session.HandleNewModality(args.Call); }); } else { // There was an issue retrieving the AcdCustomerSession, we are declining the call. try { args.Call.Decline(); } catch (InvalidOperationException ex) { _logger.Log("AcdPortal cannot decline incoming IM call properly; the call must already be terminated", ex); } catch (RealTimeException ex) { _logger.Log("AcdPortal cannot decline incoming IM call properly", ex); } } } }
/// <summary> /// Handles incoming AudioVideoCall. The incoming call can be one of three things: a brand new conversation, /// a self transfer of an existing customer-facing call, an audio escalation. In Draining mode, only the incoming /// calls for existing Conversations will be processed. Initial Conversation calls coming in will be declined by the /// endpoint. /// </summary> private void HandleAudioVideoCallReceived(object sender, CallReceivedEventArgs <AudioVideoCall> args) { //Determines whether it is a new Call if (args.IsNewConversation && args.CallToBeReplaced == null) //New Acd customer session { AcdCustomerSession session = new AcdCustomerSession(_logger, _matchMaker, this); //add the session to the list. lock (_syncRoot) { _sessions.Add(session); _numberOfSessionsEstablished++; } //registering for an event to monitor the customer session state in order to determine when the draining is complete. session.CustomerSessionStateChanged += CustomerSessionStateChanged; if (args.CustomMimeParts.Count > 0) { productType productInformation; List <AgentSkill> listOfRequestedSkills = new List <AgentSkill>(this.ProcessMimeParts(args.CustomMimeParts, out productInformation)); ThreadPool.QueueUserWorkItem((waitState) => { session.HandleInitialCall(args.Call, listOfRequestedSkills, productInformation); }); } else { ThreadPool.QueueUserWorkItem((waitState) => { session.HandleInitialCall(args.Call, null, null); }); } } //it is not a new call but a modality addition else if (args.IsNewConversation == false && args.CallToBeReplaced == null) { if (null != args.Call.Conversation.ApplicationContext) { //this an audio escalation, hand-off the call to the AcdCustomerSession for futher processing AcdCustomerSession session = args.Call.Conversation.ApplicationContext as AcdCustomerSession; args.RingBackDisabled = true; session.HandleNewModality(args.Call); } else { // There was an issue retrieving the AcdCustomerSession, we are declining the call. try { args.Call.Decline(new CallDeclineOptions(ResponseCode.TemporarilyUnavailable)); } catch (RealTimeException ex) { _logger.Log("AcdPortal cannot decline incoming audio call properly", ex); } } } else if (args.CallToBeReplaced != null) { try { args.Call.Decline(); } catch (RealTimeException ex) { _logger.Log("AcdPortal failed declining an incoming call replacing an exisiting one", ex); } } else { //unexpected. Decline the incoming call try { args.Call.Decline(); } catch (RealTimeException ex) { _logger.Log("Acd customer session failed to decline an unexpected incoming Audio call", ex); } } }
internal PendingAgentMatchRequestQueueItem(AcdCustomerSession requestor, FindAgentAsyncResult findAgentAsyncResult, TimerItem tmrItem) { _Requestor = requestor; this.FindAgentAsyncResult = findAgentAsyncResult; _TmrItem = tmrItem; }