Example #1
0
        /// <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);
        }
Example #2
0
        /// <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);
                }
            }
        }
Example #3
0
        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);
        }
Example #4
0
        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);
            }
        }
Example #6
0
 /// <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);
     }
 }
Example #7
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
#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);
            }
Example #11
0
        /// <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);
        }
Example #12
0
        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);
                }
            }
        }
Example #14
0
        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());
        }
Example #16
0
        /// <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);
        }
Example #17
0
        /// <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;
 }
Example #19
0
 public MessageRouterResultHandler(MessageRouterManager messageRouterManager)
 {
     _messageRouterManager = messageRouterManager
                             ?? throw new ArgumentNullException(
                                       $"The message router manager ({nameof(messageRouterManager)}) cannot be null");
 }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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);
        }