1

My telegram bot is necessary so that the user can answer questions in order and save these answers in the same order for a specific user in parallel.

static readonly ConcurrentDictionary<int, string[]> Answers = new ConcurrentDictionary<int, string[]>();

static void Main(string[] args)
        {
            try
            {
                Task t1 = CreateHostBuilder(args).Build().RunAsync();
                Task t2 = BotOnMessage();
                await Task.WhenAll(t1, t2);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }

here is my BotOnMessage() method to receive and process messages from users

async static Task BotOnMessage()
        {
            int offset = 0;
            int timeout = 0;

            try
            {
                await bot.SetWebhookAsync("");
                while (true)
                {
                    var updates = await bot.GetUpdatesAsync(offset, timeout);

                    foreach (var update in updates)
                    {
                        var message = update.Message;

                        if (message.Text == "/start")
                        {
                            Registration(message.Chat.Id.ToString(), message.Chat.FirstName.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
                            var replyKeyboard = new ReplyKeyboardMarkup
                            {
                                Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("eng"),
                                        new KeyboardButton("ger")
                                    },
                                }
                            };

                            replyKeyboard.OneTimeKeyboard = true;

                            await bot.SendTextMessageAsync(message.Chat.Id, "choose language", replyMarkup: replyKeyboard);
                        }

                        switch (message.Text)
                        {
                            case "eng":
                                var replyKeyboardEN = new ReplyKeyboardMarkup
                                {
                                    Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("choice1"),
                                        new KeyboardButton("choice2")
                                    },
                                }
                                };
                                replyKeyboardEN.OneTimeKeyboard = true;
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardEN);
                                await AnonymEN();
                                break;

                            case "ger":
                                var replyKeyboardGR = new ReplyKeyboardMarkup
                                {
                                    Keyboard = new[]
                                {
                                    new[]
                                    {
                                        new KeyboardButton("choice1.1"),
                                        new KeyboardButton("choice2.2")
                                    },
                                }
                                };
                                replyKeyboardGR.OneTimeKeyboard = true;
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter choice", replyMarkup: replyKeyboardGR);
                                await AnonymGR();
                                break;
                        }

                       
                        offset = update.Id + 1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }

and AnonymEN() method for eng case in switch. The problem appears here when I call this method from switch case in BotOnMessage(). Until switch (message.Text) multiple users can asynchronously send messages and get response. When first user enters AnonymEN() second user can't get response from this method until first user will finish it till the end. Also I call BotOnMessage() in the end of AnonymEN() to get back for initial point with possibility to start bot again. For the ordered structure of questions and answers I used ConcurrentDictionary way from here Save user messages sent to bot and send finished form to other user. Any suggestion and solution how to edit code to make this bot available for multiple users at one time?

async static Task AnonymEN()
        {
            int offset = 0;
            int timeout = 0;

            try
            {
                await bot.SetWebhookAsync("");
                while (true)
                {
                    var updates = await bot.GetUpdatesAsync(offset, timeout);

                    foreach (var update in updates)
                    {
                        var message = update.Message;

                        int userId = (int)message.From.Id;

                        if (message.Type == MessageType.Text)
                        {
                            if (Answers.TryGetValue(userId, out string[] answers))
                            {
                                var title = message.Text;

                                if (answers[0] == null)
                                {
                                    answers[0] = message.Text;
                                    await bot.SendTextMessageAsync(message.Chat, "Enter age");

                                }
                                else
                                {
                                    SaveMessage(message.Chat.Id.ToString(), "anonym", "anonym", "anonym", answers[0].ToString(), title.ToString(), createdDateNoTime.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
                                    Answers.TryRemove(userId, out string[] _);
                                    await bot.SendTextMessageAsync(message.Chat.Id, "ty for request click /start");
                                    await BotOnMessage();
                                }
                            }
                            else if (message.Text == "choice1")
                            {
                                Answers.TryAdd(userId, new string[1]);
                                await bot.SendTextMessageAsync(message.Chat.Id, "Enter name");
                            }
                        }
                        offset = update.Id + 1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error" + ex);
            }

        }
coxcoxgo
  • 39
  • 1
  • 5
  • Why you are using `while (true) { Bot.GetUpdates() }`, Use webhook, Or use `Bot.StartReceiving()`. – Muaath Aug 21 '21 at 06:11

1 Answers1

-1

I can see multiple issues with your code:

  1. It is hard to read. While this is a personal preference I strongly advise to write short concise methods that have 1 responsibility. This will make it easier to understand and maintain your code. https://en.wikipedia.org/wiki/Single-responsibility_principle

  2. Everything is static. This makes it very hard to keep track of any state such as language that should be tracked per user.

  3. Using infinite loops and recursion with no escape. I highly doubt this was intended but you could get an infinite chain of calls like this BotOnMessage -> AnonymEN -> BotOnMessage -> AnonymEN. I think you want to exit the AnonymEN function using either a return, break or while(someVar) approach instead of calling the BotOnMessage function.

  4. If two users are sending messages you get mixed responses. Example message flow user1: /start, user1: eng, user2: hello. The bot will now give an english response to user2. I'm sure this is not intended

The code below is a minimal example that addresses the issues I mentioned. It is not perfect code but should help you get started.

private Dictionaty<string, UserSession> userSessions = new ();

async Task BotOnMessage()
{
  try
  {
    while(true)
    {
      var message = await GetMessage(timeout);
      var userSession = GetUserSession(message.user);
      userSession.ProcessMessage(message);
     }
  }
  catch(){}
}

async void GetUserSession(string user)
{
  if(!userSessions.HasKey(user))
  {
    userSessions[user](new Session());
  }
  return userSessions[user];
}

public class UserSession
{
  public async Task ProcessMessage(message)
  {
    // Existing message processing code goes here. 
    // Do not use a loop or recursion.
    // Instead track the state (e.g. languge) using fields.
  }
}
gjhommersom
  • 159
  • 1
  • 7