/// <summary> /// Tries to reject all pending requests. /// </summary> /// <param name="messageRouterManager">The message router manager.</param> /// <param name="messageRouterResultHandler">The message router result handler.</param> /// <returns>True, if successful. False otherwise.</returns> public async Task <bool> RejectAllPendingRequestsAsync( MessageRouterManager messageRouterManager, MessageRouterResultHandler messageRouterResultHandler) { bool wasSuccessful = false; IList <Party> pendingRequests = messageRouterManager.RoutingDataManager.GetPendingRequests(); if (pendingRequests.Count > 0) { IList <MessageRouterResult> messageRouterResults = new List <MessageRouterResult>(); foreach (Party pendingRequest in pendingRequests) { messageRouterResults.Add(messageRouterManager.RejectPendingRequest(pendingRequest)); } foreach (MessageRouterResult messageRouterResult in messageRouterResults) { await messageRouterResultHandler.HandleResultAsync(messageRouterResult); } wasSuccessful = true; } return(wasSuccessful); }
/// <summary> /// From IMessageRouterResultHandler. /// </summary> /// <param name="messageRouterResult">The result to handle.</param> /// <returns></returns> public virtual async Task HandleResultAsync(MessageRouterResult messageRouterResult) { if (messageRouterResult == null) { throw new ArgumentNullException($"The given result ({nameof(messageRouterResult)}) is null"); } string messageRouterResultAsString = messageRouterResult.ToString(); if (messageRouterResult.Activity != null) { await MessagingUtils.ReplyToActivityAsync(messageRouterResult.Activity, messageRouterResultAsString); } else { MessageRouterManager messageRouterManager = MessageRouterManager.Instance; if (messageRouterResult.ConversationOwnerParty != null) { await messageRouterManager.SendMessageToPartyByBotAsync( messageRouterResult.ConversationOwnerParty, messageRouterResultAsString); } if (messageRouterResult.ConversationClientParty != null) { await messageRouterManager.SendMessageToPartyByBotAsync( messageRouterResult.ConversationClientParty, messageRouterResultAsString); } } }
public string RefreshAgent(int id) { string response = ResponseNone; MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IRoutingDataManager routingDataManager = messageRouterManager.RoutingDataManager; var Settings = new Settings.BotSettings(); Manager manager = new Manager(Settings[BotSettings.KeyRoutingDataStorageConnectionString]); try { Dictionary <Party, Party> connectedParties = routingDataManager.GetConnectedParties(); Dictionary <Party, Party> waitingConnectedParties = manager.GetWaitingConnectedParties(); foreach (var connectedPartie in connectedParties) { clientsParties.Add(connectedPartie.Value); } foreach (var waitingConnectedPartie in waitingConnectedParties) { clientsParties.Add(waitingConnectedPartie.Value); } response = JsonConvert.SerializeObject(clientsParties); } catch (InvalidOperationException e) { Debug.WriteLine($"{e.Message}"); } Debug.WriteLine("refresh"); return(response); }
public static void Register(HttpConfiguration config) { // Json settings config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented; JsonConvert.DefaultSettings = () => new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Newtonsoft.Json.Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, }; // Web API configuration and services config.EnableCors(); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // Message routing MessageRouterManager = new MessageRouterManager(new LocalRoutingDataManager()); MessageRouterResultHandler = new MessageRouterResultHandler(); CommandMessageHandler = new CommandMessageHandler(MessageRouterManager, MessageRouterResultHandler); BackChannelMessageHandler = new BackChannelMessageHandler(MessageRouterManager.RoutingDataManager); }
/// <summary> /// Notifies the conversation client (customer) or owner (agent) that an error has occured and /// sends the error message /// </summary> /// <param name="messageRouterResult">The result to handle.</param> private static async Task HandleErrorAsync(MessageRouterResult messageRouterResult) { if (string.IsNullOrEmpty(messageRouterResult.ErrorMessage)) { System.Diagnostics.Debug.WriteLine("An error occured"); } else { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IList <Party> aggregationParties = messageRouterManager.RoutingDataManager.GetAggregationParties(); if (aggregationParties == null || aggregationParties.Count == 0) { if (messageRouterResult.ConversationOwnerParty != null) { await messageRouterManager.SendMessageToPartyByBotAsync( messageRouterResult.ConversationOwnerParty, messageRouterResult.ErrorMessage); } } else { foreach (Party aggregationChannel in aggregationParties) { await messageRouterManager.SendMessageToPartyByBotAsync( aggregationChannel, messageRouterResult.ErrorMessage); } } System.Diagnostics.Debug.WriteLine(messageRouterResult.ErrorMessage); } }
/// <summary> /// Broadcasts the given message to all aggregation channels. /// </summary> /// <param name="messageRouterManager">The message router manager instance.</param> /// <param name="messageText">The message to broadcast.</param> public static async Task BroadcastMessageToAggregationChannelsAsync( MessageRouterManager messageRouterManager, string messageText) { foreach (Party aggregationChannel in messageRouterManager.RoutingDataManager.GetAggregationParties()) { await messageRouterManager.SendMessageToPartyByBotAsync(aggregationChannel, messageText); } }
private Activity HandleSystemMessage(Activity activity) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; if (activity.Type == ActivityTypes.DeleteUserData) { Party senderParty = MessagingUtils.CreateSenderParty(activity); IList <MessageRouterResult> messageRouterResults = messageRouterManager.RemoveParty(senderParty); foreach (MessageRouterResult messageRouterResult in messageRouterResults) { if (messageRouterResult.Type == MessageRouterResultType.OK) { System.Diagnostics.Debug.WriteLine(ConversationText.UserDataDeleted, senderParty.ChannelAccount?.Name); } } } else if (activity.Type == ActivityTypes.ConversationUpdate) { // Handle conversation state changes, like members being added and removed // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info // Not available in all channels if (activity.MembersRemoved != null && activity.MembersRemoved.Count > 0) { foreach (ChannelAccount channelAccount in activity.MembersRemoved) { Party partyToRemove = new Party(activity.ServiceUrl, activity.ChannelId, channelAccount, activity.Conversation); IList <MessageRouterResult> messageRouterResults = messageRouterManager.RemoveParty(partyToRemove); foreach (MessageRouterResult messageRouterResult in messageRouterResults) { if (messageRouterResult.Type == MessageRouterResultType.OK) { System.Diagnostics.Debug.WriteLine(ConversationText.PartyRemoved, partyToRemove.ChannelAccount?.Name); } } } } } else if (activity.Type == ActivityTypes.ContactRelationUpdate) { // Handle add/remove from contact lists // Activity.From + Activity.Action represent what happened } else if (activity.Type == ActivityTypes.Typing) { // Handle knowing that the user is typing } else if (activity.Type == ActivityTypes.Ping) { } return(null); }
public string GetAgentById(int Id) { MessageRouterManager messageRouterManager = MessageRouterManager.Instance; if (messageRouterManager.RoutingDataManager.GetPendingRequests().Count > 0) { Party conversationClientParty = messageRouterManager.RoutingDataManager.GetPendingRequests().Last(); messageRouterManager.RoutingDataManager.RemovePendingRequest(conversationClientParty); return(conversationClientParty.ToIdString()); } return(ResponseNone); }
#pragma warning disable 1998 private async Task <Activity> HandleSystemMessageAsync(Activity message) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; if (message.Type == ActivityTypes.DeleteUserData) { // Implement user deletion here // If we handle user deletion, return a real message Party senderParty = MessagingUtils.CreateSenderParty(message); if (messageRouterManager.RemoveParty(senderParty)?.Count > 0) { return(message.CreateReply($"Data of user {senderParty.ChannelAccount?.Name} removed")); } } else if (message.Type == ActivityTypes.ConversationUpdate) { // Handle conversation state changes, like members being added and removed // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info // Not available in all channels if (message.MembersRemoved != null && message.MembersRemoved.Count > 0) { foreach (ChannelAccount channelAccount in message.MembersRemoved) { Party party = new Party( message.ServiceUrl, message.ChannelId, channelAccount, message.Conversation); if (messageRouterManager.RemoveParty(party)?.Count > 0) { System.Diagnostics.Debug.WriteLine($"Party {party.ToString()} removed"); } } } } else if (message.Type == ActivityTypes.ContactRelationUpdate) { // Handle add/remove from contact lists // Activity.From + Activity.Action represent what happened } else if (message.Type == ActivityTypes.Typing) { // Handle knowing that the user is typing } else if (message.Type == ActivityTypes.Ping) { } return(null); }
/// <summary> /// Notifies the user that there are no aggregation channels setup /// </summary> /// <param name="messageRouterResult">The result to handle.</param> private static async Task <string> HandleNoAggregationChannelResultAsync(MessageRouterResult messageRouterResult) { string message = string.Empty; if (messageRouterResult.Activity != null) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; string botName = messageRouterManager.RoutingDataManager.ResolveBotNameInConversation( MessagingUtils.CreateSenderParty(messageRouterResult.Activity)); message = $"{(string.IsNullOrEmpty(messageRouterResult.ErrorMessage) ? "" : $"{messageRouterResult.ErrorMessage}: ")}The message router manager is not initialized; type \""; message += string.IsNullOrEmpty(botName) ? $"{Commands.CommandKeyword} " : $"@{botName} "; message += $"{Commands.CommandAddAggregationChannel}\" to setup the aggregation channel"; await MessagingUtils.ReplyToActivityAsync(messageRouterResult.Activity, message); }
/// <summary> /// Creates and sets up the instances required for message routing. /// </summary> public static void InitializeMessageRouting() { Settings = new BotSettings(); string connectionString = Settings[BotSettings.KeyRoutingDataStorageConnectionString]; IRoutingDataManager routingDataManager = null; if (string.IsNullOrEmpty(connectionString)) { System.Diagnostics.Debug.WriteLine($"WARNING!!! No connection string found - using {nameof(LocalRoutingDataManager)}"); routingDataManager = new LocalRoutingDataManager(); } else { System.Diagnostics.Debug.WriteLine($"Found a connection string - using {nameof(AzureTableStorageRoutingDataManager)}"); routingDataManager = new AzureTableStorageRoutingDataManager(connectionString); } MessageRouterManager = new MessageRouterManager(routingDataManager); MessageRouterResultHandler = new MessageRouterResultHandler(MessageRouterManager); CommandMessageHandler = new CommandMessageHandler(MessageRouterManager, MessageRouterResultHandler); BackChannelMessageHandler = new BackChannelMessageHandler(MessageRouterManager.RoutingDataManager); }
public string GetAgentById(int id) { string response = ResponseNone; MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IRoutingDataManager routingDataManager = messageRouterManager.RoutingDataManager; if (routingDataManager.GetAggregationParties().Count == 0 && routingDataManager.GetPendingRequests().Count > 0) { try { Party conversationClientParty = messageRouterManager.RoutingDataManager.GetPendingRequests().First(); messageRouterManager.RoutingDataManager.RemovePendingRequest(conversationClientParty); response = conversationClientParty.ToJsonString(); } catch (InvalidOperationException e) { System.Diagnostics.Debug.WriteLine($"Failed to handle a pending request: {e.Message}"); } } return(response); }
/// <summary> /// Handles sending of the given notification. /// </summary> /// <param name="notification">The notification to send.</param> /// <returns></returns> public async static Task SendNotificationAsync(Notification notification) { if (notification != null) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; if (notification.PartiesToNotify == null || notification.PartiesToNotify.Count() == 0) { // No receivers given - broadcast the notification to all users the bot is aware of notification.PartiesToNotify.AddRange(messageRouterManager.RoutingDataManager.GetUserParties()); } if (string.IsNullOrEmpty(notification.Message)) { // Notification message missing - let's insert something for the sake of example notification.Message = "Hello! This is a test notification message."; } foreach (Party partyToNotify in notification.PartiesToNotify) { await messageRouterManager.SendMessageToPartyByBotAsync(partyToNotify, notification.Message); } } }
public static void Register(HttpConfiguration config) { // Json settings config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented; JsonConvert.DefaultSettings = () => new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Newtonsoft.Json.Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, }; // Web API configuration and services config.EnableCors(); // Web API configuration and services // Configure Web API to use only bearer token authentication. //config.SuppressDefaultHostAuthentication(); // config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // Web API routes config.MapHttpAttributeRoutes(); config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream")); config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data")); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // Message routing MessageRouterManager = new MessageRouterManager(new LocalRoutingDataManager()); MessageRouterResultHandler = new MessageRouterResultHandler(); CommandMessageHandler = new CommandMessageHandler(MessageRouterManager, MessageRouterResultHandler); BackChannelMessageHandler = new BackChannelMessageHandler(MessageRouterManager.RoutingDataManager); }
#pragma warning restore 1998 private async Task OnMessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result) { IMessageActivity messageActivity = await result; if (messageActivity != null) { await context.PostAsync($"The text part of the received activity reads \"{messageActivity.Text}\""); if (messageActivity.ChannelData != null) { // For debugging let's broadcast the received channel data content MessageRouterManager messageRouterManager = MessageRouterManager.Instance; IList <Party> userParties = messageRouterManager.RoutingDataManager.GetUserParties(); if (userParties.Count == 0) { await context.PostAsync("I've got no user parties! This should not happen!"); } else { // Broadcast the channel data content foreach (Party party in userParties) { await messageRouterManager.SendMessageToPartyByBotAsync( party, $"Received the following channel data (as string): {messageActivity.ChannelData.ToString()}"); } } } } else { await context.PostAsync("The received activity was null or not of type IMessageActivity!"); } context.Done(new object()); }
/// <summary> /// Handles the received message. /// </summary> public async Task <HttpResponseMessage> Post([FromBody] Activity activity) { if (activity.Locale != null) { ConversationText.Culture = new CultureInfo(activity.Locale); } if (activity.Type == ActivityTypes.Message) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IMessageRouterResultHandler messageRouterResultHandler = WebApiConfig.MessageRouterResultHandler; messageRouterManager.MakeSurePartiesAreTracked(activity); // First check for commands (both from back channel and the ones directly typed) MessageRouterResult messageRouterResult = WebApiConfig.BackChannelMessageHandler.HandleBackChannelMessage(activity); if (messageRouterResult.Type != MessageRouterResultType.Connected && await WebApiConfig.CommandMessageHandler.HandleCommandAsync(activity) == false) { // No valid back channel (command) message or typed command detected // Let the message router manager instance handle the activity messageRouterResult = await messageRouterManager.HandleActivityAsync(activity, false); if (messageRouterResult.Type == MessageRouterResultType.NoActionTaken) { // No action was taken by the message router manager. This means that the // user is not connected (in a 1:1 conversation) with a human // (e.g. customer service agent) yet. // // You can, for example, check if the user (customer) needs human // assistance here or forward the activity to a dialog. You could also do // the check in the dialog too... // // Here's an example: if (!string.IsNullOrEmpty(activity.Text) && activity.Text.ToLower().Contains(CommandRequestConnection)) { messageRouterResult = messageRouterManager.RequestConnection(activity); } else { await Conversation.SendAsync(activity, () => new RootDialog()); } } } // Handle the result, if required await messageRouterResultHandler.HandleResultAsync(messageRouterResult); } else { await HandleSystemMessageAsync(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return(response); }
/// <summary> /// Handles the received message. /// </summary> public async Task <HttpResponseMessage> Post([FromBody] Activity activity) { //await Repository.UtilityRepo.LogMsgAsync("activity id" + activity.From.Id); //await Repository.UtilityRepo.LogMsgAsync("activity from" + activity.From.Name); //await Repository.UtilityRepo.LogMsgAsync("activity channel" + activity.ChannelId); // var t = System.Web.HttpContext.Current.Request.UserHostAddress; //var CallerIp = System.Web.HttpContext.Current.Request.UserHostAddress; var CallerAgent = System.Web.HttpContext.Current.Request.UserAgent; //var CalledUrl = System.Web.HttpContext.Current.Request.Url.OriginalString; var current = System.Web.HttpContext.Current; var ip = GetUserIP(current); await Repository.UtilityRepo.UpdatedUserAttendedByAsync(activity); if (activity.Locale != null) { ConversationText.Culture = new CultureInfo(activity.Locale); } if (activity.Type == ActivityTypes.Message) { MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IMessageRouterResultHandler messageRouterResultHandler = WebApiConfig.MessageRouterResultHandler; messageRouterManager.MakeSurePartiesAreTracked(activity); // First check for commands (both from back channel and the ones directly typed) MessageRouterResult messageRouterResult = WebApiConfig.BackChannelMessageHandler.HandleBackChannelMessage(activity); if (messageRouterResult.Type != MessageRouterResultType.Connected && await WebApiConfig.CommandMessageHandler.HandleCommandAsync(activity) == false) { // No valid back channel (command) message or typed command detected // Let the message router manager instance handle the activity messageRouterResult = await messageRouterManager.HandleActivityAsync(activity, false); if (messageRouterResult.Type == MessageRouterResultType.NoActionTaken) { // No action was taken by the message router manager. This means that the // user is not connected (in a 1:1 conversation) with a human // (e.g. customer service agent) yet. // // You can, for example, check if the user (customer) needs human // assistance here or forward the activity to a dialog. You could also do // the check in the dialog too... // // Here's an example: if (!string.IsNullOrEmpty(activity.Text) && activity.Text.ToLower().Contains(CommandRequestConnection)) //&& System.Web.HttpContext.Current.Session["UserID"] != null) { messageRouterResult = messageRouterManager.RequestConnection(activity); // log all the request and thier sources try { await Repository.UtilityRepo.LogPendingRequestAsync(activity, ip, CallerAgent); } catch (System.Data.Entity.Validation.DbEntityValidationException e) { foreach (var eve in e.EntityValidationErrors) { await Repository.UtilityRepo.LogMsgAsync(string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State)); foreach (var ve in eve.ValidationErrors) { await Repository.UtilityRepo.LogMsgAsync(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage)); } } //throw; } catch (Exception ex) { await Repository.UtilityRepo.LogMsgAsync("Eror on human request : " + ex.Message); } } else { try { await Repository.UtilityRepo.LogRequestMessageAsync(activity); // Call await Conversation.SendAsync(activity, () => new RootDialog()); } catch (FormCanceledException fcEx) when(fcEx.InnerException is TooManyAttemptsException) { ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl)); Activity reply = activity.CreateReply( $"Too Many Attempts at {fcEx.Last}. " + $"Completed Steps: {string.Join(", ", fcEx.Completed)}"); await Repository.UtilityRepo.LogMsgAsync("reply : " + reply.Text); await connector.Conversations.ReplyToActivityAsync(reply); } catch (FormCanceledException fcEx) { ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl)); Activity reply = activity.CreateReply( $"Form cancelled at {fcEx.Last}. " + $"Completed Steps: {string.Join(", ", fcEx.Completed)}"); await Repository.UtilityRepo.LogMsgAsync("reply : " + reply.Text); await connector.Conversations.ReplyToActivityAsync(reply); } catch (Exception ex) { await Repository.UtilityRepo.LogErrorAsync(ex); } } } } if (messageRouterResult != null && messageRouterResult.Type == MessageRouterResultType.OK && string.IsNullOrEmpty(messageRouterResult.ErrorMessage)) { await Repository.UtilityRepo.CustomerAgentChatHistoryLogAsync(messageRouterResult); } // Handle the result, if required await messageRouterResultHandler.HandleResultAsync(messageRouterResult); } else { await HandleSystemMessageAsync(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return(response); }
/// <summary> /// Constructor. /// </summary> /// <param name="messageRouterManager">The message router manager.</param> /// <param name="messageRouterResultHandler"/>A MessageRouterResultHandler instance for /// handling possible routing actions such as accepting a 1:1 conversation connection.</param> public CommandMessageHandler(MessageRouterManager messageRouterManager, MessageRouterResultHandler messageRouterResultHandler) { _messageRouterManager = messageRouterManager; _messageRouterResultHandler = messageRouterResultHandler; }
public MessageRouterResultHandler(MessageRouterManager messageRouterManager) { _messageRouterManager = messageRouterManager ?? throw new ArgumentNullException( $"The message router manager ({nameof(messageRouterManager)}) cannot be null"); }
/// <summary> /// Checks the given activity for back channel messages and handles them, if detected. /// Currently the only back channel message supported is for creating connections /// (establishing 1:1 conversations). /// </summary> /// <param name="activity">The activity to check for back channel messages.</param> /// <returns> /// The result: /// * MessageRouterResultType.Connected: A connection (1:1 conversation) was created /// * MessageRouterResultType.NoActionTaken: No back channel message detected /// * MessageRouterResultType.Error: See the error message for details /// </returns> public virtual MessageRouterResult HandleBackChannelMessage(Activity activity) { MessageRouterResult messageRouterResultNoAction = new MessageRouterResult { Type = MessageRouterResultType.NoActionTaken }; MessageRouterResult messageRouterResult = new MessageRouterResult(); var Settings = new BotSettings(); Manager manager = new Manager(Settings[BotSettings.KeyRoutingDataStorageConnectionString]); if (activity == null || string.IsNullOrEmpty(activity.Text)) { messageRouterResult.Type = MessageRouterResultType.Error; messageRouterResult.ErrorMessage = $"The given activity ({nameof(activity)}) is either null or the message is missing"; } else if (activity.Text.Equals(BackChannelId)) { if (activity.ChannelData == null) { messageRouterResult.Type = MessageRouterResultType.Error; messageRouterResult.ErrorMessage = "No channel data"; } else { // Handle accepted request and start 1:1 conversation Party conversationClientParty = null; try { conversationClientParty = ParsePartyFromChannelData(activity.ChannelData); Debug.WriteLine($"Client : {JsonConvert.SerializeObject(conversationClientParty)}"); } catch (Exception e) { messageRouterResult.Type = MessageRouterResultType.Error; messageRouterResult.ErrorMessage = $"Failed to parse the party information from the back channel message: {e.Message}"; } if (conversationClientParty != null) { Party conversationOwnerParty = MessagingUtils.CreateSenderParty(activity); Debug.WriteLine($"Owner : {JsonConvert.SerializeObject(conversationOwnerParty)}"); MessageRouterManager messageRouterManager = WebApiConfig.MessageRouterManager; IRoutingDataManager routingDataManager = messageRouterManager.RoutingDataManager; bool isConnected = false; Dictionary <Party, Party> connectedParties = routingDataManager.GetConnectedParties(); foreach (var connectedPartie in connectedParties) { if (connectedPartie.Value.ConversationAccount.Id == conversationClientParty.ConversationAccount.Id) { isConnected = true; break; } } if (isConnected) { bool deleteConnexion = manager.ExecuteRemoveConnexionByConversationClientId(conversationClientParty.ConversationAccount.Id); messageRouterResult = deleteConnexion ? manager.Connect(conversationOwnerParty, conversationClientParty) : messageRouterResultNoAction; } else { Dictionary <Party, Party> waitingConnectedParties = manager.GetWaitingConnectedParties(); bool isWaitingConnected = false; foreach (var waitingConnectedPartie in waitingConnectedParties) { if (waitingConnectedPartie.Value.ConversationAccount.Id == conversationClientParty.ConversationAccount.Id) { isWaitingConnected = true; break; } } if (isWaitingConnected) { bool deleteWaitingConnection = manager.ExecuteRemoveWaitingConnexionByConversationClientId(conversationClientParty.ConversationAccount.Id); messageRouterResult = deleteWaitingConnection ? manager.WaitingConnectAndClearPendingRequest(conversationOwnerParty, conversationClientParty) : messageRouterResultNoAction; messageRouterResult.Activity = activity; } else { messageRouterResult = manager.WaitingConnectAndClearPendingRequest(conversationOwnerParty, conversationClientParty); //messageRouterResult = _routingDataManager.ConnectAndClearPendingRequest( // conversationOwnerParty, conversationClientParty); messageRouterResult.Activity = activity; } } } } } else { // No back channel message detected //messageRouterResult.Type = MessageRouterResultType.NoActionTaken; ConnectionEntity waitingConnection = manager.RetrieveWaitingConnectionByConversationIdOwner(activity.Conversation.Id); if (waitingConnection != null) { Party conversationOwnerParty = JsonConvert.DeserializeObject <PartyEntity>(waitingConnection.Owner).ToParty(); Party conversationClientParty = JsonConvert.DeserializeObject <PartyEntity>(waitingConnection.Client).ToParty(); if (activity.Text == $"@{conversationOwnerParty.ChannelAccount.Name} accept {conversationClientParty.ChannelAccount.Id}" || activity.Text == $"@{conversationOwnerParty.ChannelAccount.Name} reject {conversationClientParty.ChannelAccount.Id}") { if (activity.Text.Contains("accept")) { messageRouterResult = manager.Connect(conversationOwnerParty, conversationClientParty); } else { messageRouterResult.Type = MessageRouterResultType.ConnectionRejected; messageRouterResult.ConversationClientParty = conversationClientParty; messageRouterResult.ConversationOwnerParty = conversationOwnerParty; } manager.RemoveWaitingConnection(conversationOwnerParty, conversationClientParty); } else { messageRouterResult.Type = MessageRouterResultType.ConnectionAlreadyRequested; if (activity.Conversation.Id == conversationOwnerParty.ConversationAccount.Id) { messageRouterResult.ConversationOwnerParty = conversationOwnerParty; messageRouterResult.ConversationClientParty = conversationClientParty; } else { messageRouterResult.ConversationClientParty = conversationClientParty; } } } else { // No back channel message detected messageRouterResult.Type = MessageRouterResultType.NoActionTaken; } } return(messageRouterResult); }
/// <summary> /// Tries to accept/reject a pending request. /// </summary> /// <param name="messageRouterManager">The message router manager.</param> /// <param name="messageRouterResultHandler">The message router result handler.</param> /// <param name="senderParty">The sender party (accepter/rejecter).</param> /// <param name="doAccept">If true, will try to accept the request. If false, will reject.</param> /// <param name="channelAccountIdOfPartyToAcceptOrReject">The channel account ID of the party whose request to accep/reject.</param> /// <returns>Null, if an accept/reject operation was executed successfully. /// A user friendly error message otherwise.</returns> public async Task <string> AcceptOrRejectRequestAsync( MessageRouterManager messageRouterManager, MessageRouterResultHandler messageRouterResultHandler, Party senderParty, bool doAccept, string channelAccountIdOfPartyToAcceptOrReject) { string errorMessage = null; IRoutingDataManager routingDataManager = messageRouterManager.RoutingDataManager; Party partyToAcceptOrReject = null; if (routingDataManager.GetPendingRequests().Count > 0) { try { partyToAcceptOrReject = routingDataManager.GetPendingRequests().Single( party => (party.ChannelAccount != null && !string.IsNullOrEmpty(party.ChannelAccount.Id) && party.ChannelAccount.Id.Equals(channelAccountIdOfPartyToAcceptOrReject))); } catch (InvalidOperationException e) { errorMessage = string.Format( ConversationText.FailedToFindPendingRequestForUserWithErrorMessage, channelAccountIdOfPartyToAcceptOrReject, e.Message); } } if (partyToAcceptOrReject != null) { Party connectedSenderParty = routingDataManager.FindConnectedPartyByChannel( senderParty.ChannelId, senderParty.ChannelAccount); bool senderIsConnected = (connectedSenderParty != null && routingDataManager.IsConnected(connectedSenderParty, ConnectionProfile.Owner)); MessageRouterResult messageRouterResult = null; if (doAccept) { if (senderIsConnected) { // The sender (accepter/rejecter) is ALREADY connected with another party Party otherParty = routingDataManager.GetConnectedCounterpart(connectedSenderParty); if (otherParty != null) { errorMessage = string.Format( ConversationText.AlreadyConnectedWithUser, otherParty.ChannelAccount?.Name); } else { errorMessage = ConversationText.ErrorOccured; } } else { bool createNewDirectConversation = !(NoDirectConversationsWithChannels.Contains(senderParty.ChannelId.ToLower())); // Try to accept messageRouterResult = await messageRouterManager.ConnectAsync( senderParty, partyToAcceptOrReject, createNewDirectConversation); } } else { // Note: Rejecting is OK even if the sender is alreay connected messageRouterResult = messageRouterManager.RejectPendingRequest(partyToAcceptOrReject, senderParty); } if (messageRouterResult != null) { await messageRouterResultHandler.HandleResultAsync(messageRouterResult); } } else { errorMessage = ConversationText.FailedToFindPendingRequest; } return(errorMessage); }