Ejemplo n.º 1
0
        /// <summary>
        /// Reads response and build UI for user
        /// consider user language, preferences and context
        /// </summary>
        public async Task HandleResponse(BotResponse response, long chatId)
        {
            // get user preferences first
            IUserPreferences userPreferences = response.User.UserPreferences;
            UserContextState userContext     = ContextController.GetUserState(response.User);

            // set dictionary of
            Dictionary <string, object> OpArgs = new Dictionary <string, object>();

            OpArgs.Add("ChatId", chatId);           // chat id is setted here and unchangeble!
            OpArgs.Add("Content", null);
            OpArgs.Add("ReplyMarkdown", null);

            bool IsAddHeader = Configs["ShowDialogPath"].GetValue <bool>();
            bool replaceMsg  = Configs["ReplaceDialogs"].GetValue <bool>();
            int  msgId       = -1;

            #region service method(s)
            async Task <bool> SendBack()
            {
                try
                {
                    Dialog dialog =     // owner dialog is like step aback
                                    response.Dialog.Owner == null ? Dialogs.RootDialog : response.Dialog.Owner;

                    OpArgs["Content"]       = ProcessContent(TranslateContent(dialog.Content, userPreferences), dialog, IsAddHeader);
                    OpArgs["ReplyMarkdown"] = GetMarkup(dialog, response.User);
                    OperationResult rMsg = await Operations["SendMessageOperation"].Execute(new OperationArgs(response.User, OpArgs));
                    msgId = (int)rMsg.Result;

                    // set user context and return to upper dialog
                    ContextController.SetState(new UserContextState(response.User, dialog, msgId));
                    return(true);
                }
                catch (Exception exp)
                {
                    BotManager.Core?.LogController?
                    .LogError(new DebugMessage("Can't show user error notification!", "Uidispatcher.SendBack()", exp));
                    return(false);
                }
            }

            async Task <bool> SendToDialog()
            {
                try
                {
                    // work with serial dialogs here (?)

                    Dialog dialog = response.Dialog;
                    OpArgs["Content"]       = ProcessContent(TranslateContent(dialog.Content, userPreferences), dialog, IsAddHeader);
                    OpArgs["ReplyMarkdown"] = GetMarkup(dialog, response.User);
                    OpArgs["MsgId"]         = msgId = userContext.LastMsgId;

                    if (replaceMsg && msgId > 0)
                    {
                        OperationResult rMsg   = await Operations["ReplaceMessageOperation"].Execute(new OperationArgs(response.User, OpArgs));
                        int?            msgVal = rMsg.Result as int?;
                        msgId = msgVal == null ? msgId : msgVal.Value;
                    }
                    else
                    {
                        OperationResult rMsg   = await Operations["SendMessageOperation"].Execute(new OperationArgs(response.User, OpArgs));
                        int?            msgVal = rMsg.Result as int?;
                        msgId = msgVal == null ? msgId : msgVal.Value;
                    }

                    // set user context and return to upper dialog
                    ContextController.SetState(new UserContextState(response.User, dialog, msgId));
                    return(true);
                }
                catch (Exception exp)
                {
                    BotManager.Core?.LogController?
                    .LogError(new DebugMessage("Can't show user error notification!", "Uidispatcher.SendToDialog()", exp));
                    return(false);
                }
            }

            #endregion

            // handle exception
            if (response is BotExceptionResponse)
            {
                var rsp = response as BotExceptionResponse;
                // print warning message to log
                BotManager.Core?.LogController?
                .LogWarning(new DebugMessage("Exception occured during dialog execution!", "Uidispatcher.HandleResponse()", rsp.Message));

                // print response to user if responce allow it
                if (rsp.ShowNotification)
                {
                    string content = TranslateContent((string)response.Data, userPreferences);
                    OpArgs["Content"] = content;
                    OperationArgs opArgs = new OperationArgs(response.User, OpArgs);

                    OperationResult result = await Operations["SendMessageOperation"].Execute(opArgs);
                    if (result.ResultType == OperationResult.OperationResultType.Failed || result.ResultType == OperationResult.OperationResultType.Unknown)
                    {
                        BotManager.Core?.LogController?
                        .LogError(new DebugMessage("Can't show user error notification!", "Uidispatcher.HandleResponse()", result.ExceptionMessage));

                        // nullify user context - we definitely have something uncommon
                        ContextController.ClearState(response.User);
                        return;                    // and do nothing. no menu and etc...
                    }
                }
                await Task.Delay(BotManager.Core.Configs.BasicDelay);

                // exception message sended succesfully, so display new one, above error
                await SendBack();

                // state changed, dialog showed, nothing more to do...
                return;
            }

            // dialog response recieved - redirect user to this dialog
            // and, of course change state
            if (response.Type == BotResponse.ResponseType.Dialog)
            {
                await SendToDialog();
            }
            // response is data so parse it and act accordingly
            else if (response.Type == BotResponse.ResponseType.Data)
            {
                // first transform raw data
                CallbackData callback = CallbackDataParser.ParseData((string)response.Data);

                // next - do something with this callback
                // supose make some separete method - too much logic here...
            }
            // response is plain text, so display it and keep state unchanged
            else if (response.Type == BotResponse.ResponseType.Text)
            {
                // check dialog - it should stay same cos it's just a text wich placed above
                Dialog dialog = userContext.CurrentDialog;
                OpArgs["Content"]       = ProcessContent(TranslateContent((string)response.Data, userPreferences), dialog, false);
                OpArgs["ReplyMarkdown"] = null;
                OperationResult rMsg = await Operations["SendMessageOperation"].Execute(new OperationArgs(response.User, OpArgs));
                msgId = (int)rMsg.Result;

                // set user context and return to upper dialog
                ContextController.SetState(new UserContextState(response.User, dialog, msgId));
            }
            else
            {
                // response is null or exception type, witch is wrong
                // make log entry, send user back and change user state
                BotManager.Core?.LogController?.LogWarning(new DebugMessage("Response can't be processed!", "UiDispatcher.HandleResponse()",
                                                                            $"UserId: {response.User.UserId}"));

                await SendBack();

                // state changed, dialog showed, nothing more to do...
                return;
            }
        }
Ejemplo n.º 2
0
        protected async void Api_OnCallbackQuery(object sender, Telegram.Bot.Args.CallbackQueryEventArgs e)
        {
            // first awaits some time to prevent flooding
            await Task.Delay(Configs.BasicDelay);

            CallbackData data = DataParser.ParseData(e.CallbackQuery.Data);
            IUser        user = await UsersController.GetOrCreateUser(e.CallbackQuery.From);

            BotResponse response = new BotResponse(user);

            // lock the context, so user cant spam thousand messages
            // while some operations execute!
            if (ContextController.GetUserState(user)?.OccupieContext() == false)
            {
                return;
            }
            var userState = ContextController.GetUserState(user);

            // juat show dialog, stored in button
            if (data.T == CallbackData.ContentTypeEnum.Dialog)
            {
                response = Dialogs.GetDialog(data.Id, user);
            }
            // service button pressed, there can be stored and operation
            // and data, retranslated to user input (used in serial dialogs)
            else if (data.T == CallbackData.ContentTypeEnum.Button)
            {
                Dialog     currentDia = ContextController.GetUserState(user).CurrentDialog;
                var        Operation  = BotManager.Core.Operations.GetOperation(data.D);
                BotRequest request    = new BotRequest();

                // data is operation - execute it
                if (Operation != null)
                {
                    var result = await BotManager.Core.Operations[data.D]
                                 .Execute(new Operations.OperationArgs(user, new Dictionary <string, object> {
                        { "CurrentDialog", currentDia }
                    }));
                    if (result.ResultType == Operations.OperationResult.OperationResultType.Failed)
                    {
                        // put error to console
                        BotManager.Core?.LogController?
                        .LogError(new DebugMessage("Operation '{}' fails!", "BotApi.Api_OnCallbackQuery()", result.ExceptionMessage));
                    }
                    response = result.Result as BotResponse;

                    // if data as string == null, so it be null
                    // request here used to support input awaiting
                    request = new BotRequest(response?.Data as string, BotRequest.RequestType.CallbackData, user);

                    // something wrong, go to root and notify user
                    if (response == null)
                    {
                        // notify someone (DoTo)
                        response = new BotResponse(null, BotResponse.ResponseType.Dialog, user, currentDia);
                    }
                }
                // data, just data
                // expected using in serial dialog!
                else
                {
                    request = new BotRequest(data.D, BotRequest.RequestType.CallbackData, user);
                }

                // if input awited - put response to user cache
                // and show next dialog (provided by AddRequest method)
                if (userState.CurrentState == UserContextState.ContextState.AwaitInput)
                {
                    response = ContextController.AddRequest(user, request);
                }
            }

            await UiController.HandleResponse(response, e.CallbackQuery.Message.Chat.Id);

            ContextController.GetUserState(user).RealiseContex();
        }