Beispiel #1
0
        public async Task ProcessQueue(CancellationToken cancellationToken)
        {
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                if (DateTime.UtcNow >= DateTime.UtcNow.Date.AddHours(7) && dateTime != DateTime.UtcNow.Date)
                {
                    Log.Write("Refreshing queue...", LogType.Queue);
                    List <User> usersCopy = users.ShallowCopy();
                    users.Shuffle();
                    DateTime tmpDate = DateTime.UtcNow;
                    foreach (User user in usersCopy)
                    {
                        if (usersToSkip.Contains(user.Login))
                        {
                            Log.Write($"Skipping user {user.Login}", LogType.Queue);
                            usersToSkip.Remove(user.Login);
                            continue;
                        }
                        tmpDate = tmpDate.AddMinutes(rnd.Next(15, 41)).AddSeconds(rnd.Next(0, 60));
                        usersQueue.Enqueue(new QueueEntry()
                        {
                            User = user, ProcessTime = tmpDate
                        });
                        Log.Write($"Queued user {user.Login} at {tmpDate}", LogType.Queue);
                        await communication.SendMessageAsync(user.UserId, "Your InstaShit session " +
                                                             $"will be started at {tmpDate.AddHours(2).ToString("HH:mm:ss")} Polish time (with max. 1 minute delay). Please don't attempt " +
                                                             "to start Insta.Ling session at this time, even from other InstaShit apps. " +
                                                             "You'll be notified when your session finishes.");
                    }
                    dateTime = DateTime.UtcNow.Date;
                }
                while (usersQueue.Count > 0)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    QueueEntry entry = usersQueue.Peek();
                    if (DateTime.UtcNow >= entry.ProcessTime)
                    {
                        usersQueue.Dequeue();
                        if (!users.Any(u => u.Login == entry.User.Login))
                        {
                            continue;
                        }
                        if (usersToSkip.Contains(entry.User.Login))
                        {
                            Log.Write($"Skipping user {entry.User.Login}", LogType.Queue);
                            usersToSkip.Remove(entry.User.Login);
                            continue;
                        }
                        InstaShit instaShit;
                        try
                        {
                            instaShit = new InstaShit(Path.Combine(assemblyLocation, entry.User.Login));
                        }
                        catch (Exception ex)
                        {
                            Log.Write("Can't create InstaShit object: " + ex, LogType.Queue);
                            await communication.SendMessageAsync(entry.User.UserId, "An internal error occured. " +
                                                                 "It has been reported to the administrator.");

                            continue;
                        }
                        Log.Write($"Starting InstaShit for user {entry.User.Login}", LogType.Queue);
                        await communication.SendMessageAsync(entry.User.UserId, "Starting session.");

                        cancellationToken.ThrowIfCancellationRequested();
                        if (!await instaShit.Process())
                        {
                            await communication.SendMessageAsync(entry.User.UserId, "An error occured " +
                                                                 "while processing your session. Please try to solve session using " +
                                                                 "InstaShit.CLI or InstaShit.Android. Please also check if Insta.Ling website " +
                                                                 "is down. If you think it's InstaShit's fault, create an issue on GitHub: " +
                                                                 "https://github.com/konrad11901/InstaShit.Bot if it applies only to InstaShit.Bot or " +
                                                                 "https://github.com/konrad11901/InstaShitCore if it affects all InstaShit apps.");

                            await communication.SendMessageAsync(entry.User.UserId, $"Detailed information: {instaShit.ErrorMessage}");

                            Log.Write("Can't solve session, moving to next person", LogType.Queue);
                        }
                        else
                        {
                            Log.Write($" Session finished", LogType.Queue);
                            await communication.SendMessageAsync(entry.User.UserId, "Session successfully " +
                                                                 "finished.");

                            var childResults = await instaShit.GetResultsAsync();

                            StringBuilder messageToSend = new StringBuilder();
                            if (childResults.PreviousMark != "NONE")
                            {
                                messageToSend.AppendLine($"Mark from previous week: {childResults.PreviousMark}");
                            }
                            messageToSend.AppendLine($"Days of work in this week: {childResults.DaysOfWork}");
                            messageToSend.AppendLine($"From extracurricular words: +{childResults.ExtraParentWords}");
                            messageToSend.AppendLine($"Teacher's words: {childResults.TeacherWords}");
                            messageToSend.AppendLine($"Extracurricular words in current edition: {childResults.ParentWords}");
                            messageToSend.AppendLine($"Mark as of today at least: {childResults.CurrrentMark}");
                            messageToSend.Append($"Days until the end of this week: {childResults.WeekRemainingDays}");
                            await communication.SendMessageAsync(entry.User.UserId, messageToSend.ToString());
                        }
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    if (usersQueue.Count > 0)
                    {
                        TimeSpan span = usersQueue.Peek().ProcessTime - DateTime.UtcNow;
                        if (span.TotalMilliseconds > 0)
                        {
                            Log.Write("Waiting " + (int)span.TotalMilliseconds + " milliseconds for next person...", LogType.Queue);
                            await Task.Delay((int)span.TotalMilliseconds, cancellationToken);
                        }
                    }
                }
                TimeSpan span2;
                if (DateTime.UtcNow.Hour < 7)
                {
                    span2 = DateTime.UtcNow.Date.AddHours(7) - DateTime.UtcNow;
                }
                else
                {
                    span2 = DateTime.UtcNow.Date.AddDays(1).AddHours(7) - DateTime.UtcNow;
                }
                Log.Write("Waiting " + (int)span2.TotalMilliseconds + " milliseconds for next queue refresh...", LogType.Queue);
                await Task.Delay((int)span2.TotalMilliseconds, cancellationToken);
            }
        }
        private async void BotOnMessageReceived(object sender, MessageEventArgs args)
        {
            Telegram.Bot.Types.Message message = args.Message;
            if (message.Type == MessageType.Document && userStep.ContainsKey(message.From.Id) && userStep[message.From.Id] == 1)
            {
                Telegram.Bot.Types.File file = await Bot.GetFileAsync(message.Document.FileId);

                try
                {
                    string content;
                    using (var client = new WebClient())
                        content = await client.DownloadStringTaskAsync($"https://api.telegram.org/file/bot{token}/{file.FilePath}");
                    InstaShitCore.Settings settings = JsonConvert.DeserializeObject <InstaShitCore.Settings>(content);
                    if (Directory.Exists(Path.Combine(assemblyLocation, settings.Login)))
                    {
                        await SendMessageAsync(message.From.Id, "This user is already registered. " +
                                               "If you have recently unregisted from this bot, you have to wait up to 24 hours " +
                                               "before registering again.");

                        return;
                    }
                    if (settings.MinimumSleepTime < 3000 || settings.MinimumSleepTime > 10000)
                    {
                        await SendMessageAsync(message.Chat.Id, "MinimumSleepTime must be at least " +
                                               "3000 but no more than 10000.");

                        return;
                    }
                    if (settings.MaximumSleepTime < 5000 || settings.MaximumSleepTime > 15000)
                    {
                        await SendMessageAsync(message.Chat.Id, "MaximumSleepTime must be at least " +
                                               "5000 but no more than 15000.");

                        return;
                    }
                    if (settings.MaximumSleepTime - settings.MinimumSleepTime < 2000)
                    {
                        await SendMessageAsync(message.Chat.Id, "The difference between " +
                                               "MaximumSleepTime and MinimumSleepTime must be at least 2000 and " +
                                               "MaximumSleepTime must be greater than MinimumSleepTime.");

                        return;
                    }
                    InstaShit instaShit = new InstaShit(settings);
                    if (!await instaShit.TryLoginAsync())
                    {
                        await SendMessageAsync(message.Chat.Id, "Incorrect login or password.");

                        return;
                    }
                    Directory.CreateDirectory(Path.Combine(assemblyLocation, settings.Login));
                    File.WriteAllText(Path.Combine(assemblyLocation, settings.Login, "settings.json"), JsonConvert.SerializeObject(settings, Formatting.Indented));
                    userStep.Remove(message.From.Id);
                    User user = new User()
                    {
                        Login  = settings.Login,
                        UserId = message.From.Id
                    };
                    users.Add(user);
                    await SendMessageAsync(message.Chat.Id, "User successfully added!\n" +
                                           "You'll be added to queue at the next queue refresh (9:00 Polish time every day).");
                }
                catch
                {
                    await SendMessageAsync(message.Chat.Id, "An error occured while trying to get settings. " +
                                           "Make sure you're sending the right file.");
                }
            }
            if (message.Type == MessageType.Text)
            {
                Log.Write($"Received message from user {message.From.Id}: {message.Text}", LogType.Communication);
                switch (message.Text.ToLower())
                {
                case "/start":
                    await SendMessageAsync(message.Chat.Id, "Hi! I'm InstaShit, a bot " +
                                           "for Insta.Ling which automatically solves daily sessions.\nTo get started, " +
                                           " type /configure. For more information, type /help.");

                    break;

                case "/configure":
                    if (users.Any(u => u.UserId == message.From.Id))
                    {
                        await SendMessageAsync(message.Chat.Id, "Already configured.");

                        return;
                    }
                    if (!userStep.ContainsKey(message.From.Id))
                    {
                        if (useWhitelist)
                        {
                            userStep.Add(message.From.Id, 4);
                            await SendMessageAsync(message.Chat.Id, "This instance of InstaShit.Bot has whitelisting " +
                                                   "enabled. Please enter the unique key received from the server administrator. " +
                                                   "If you don't have it, contact server's owner or use another instance of the " +
                                                   "bot which is publically available.\nTo abort, type /cancel.");
                        }
                        else
                        {
                            userStep.Add(message.From.Id, 1);
                            await SendMessageAsync(message.Chat.Id, "Please attach the InstaShit settings file.\n" +
                                                   "You can use InstaShit.CLI to generate it. You can also " +
                                                   "share settings directly from InstaShit.Android " +
                                                   "(since version 0.5) - just go to \"Edit settings\", \"Advanced mode\" " +
                                                   "and touch \"Share\" button. Ability to create new settings directly " +
                                                   "from bot coming soon!\nType /cancel to abort this action.");
                        }
                    }
                    break;

                case "/dictionary":
                    var user = users.FirstOrDefault(u => u.UserId == message.From.Id);
                    if (user == null)
                    {
                        await SendMessageAsync(message.Chat.Id, "No configuration found.");

                        return;
                    }
                    if (File.Exists(Path.Combine(assemblyLocation, user.Login, "wordsDictionary.json")))
                    {
                        await SendFileAsync(message.Chat.Id, Path.Combine(assemblyLocation, user.Login, "wordsDictionary.json"));
                    }
                    else
                    {
                        await SendMessageAsync(message.Chat.Id, "Dictionary file doesn't exist.");
                    }
                    break;

                case "/cancel":
                    if (userStep.ContainsKey(message.From.Id))
                    {
                        userStep.Remove(message.From.Id);
                        await SendMessageAsync(message.Chat.Id, "Cancelled!");
                    }
                    break;

                case "/remove":
                    if (!users.Any(u => u.UserId == message.From.Id))
                    {
                        await SendMessageAsync(message.Chat.Id, "No configuration found.");

                        return;
                    }
                    if (!userStep.ContainsKey(message.From.Id))
                    {
                        userStep.Add(message.From.Id, 2);
                        await SendMessageAsync(message.Chat.Id, "You can stop automatic InstaShit session " +
                                               "solving if you wish. Please note that this action won't cancel ongoing InstaShit session, " +
                                               "if there's any.\nIf you want to continue, type /remove again. " +
                                               "To cancel, type /cancel.");
                    }
                    else if (userStep[message.From.Id] == 2)
                    {
                        userStep.Remove(message.From.Id);
                        User userToRemove = users.Find(u => u.UserId == message.From.Id);
                        users.Remove(userToRemove);
                        try
                        {
                            Directory.Delete(Path.Combine(assemblyLocation, userToRemove.Login), true);
                            await SendMessageAsync(message.Chat.Id, "Successfully removed.");
                        }
                        catch
                        {
                            await Task.Delay(3000);

                            try
                            {
                                Directory.Delete(Path.Combine(assemblyLocation, userToRemove.Login), true);
                                await SendMessageAsync(message.Chat.Id, "Successfully removed.");
                            }
                            catch (Exception ex)
                            {
                                Log.Write("ERROR: " + ex, LogType.Communication);
                                await SendMessageAsync(message.Chat.Id, "An error occured while trying to remove " +
                                                       "your files. The administrator has been notifies about this issue.");
                            }
                        }
                    }
                    break;

                case "/skip":
                    if (!users.Any(u => u.UserId == message.From.Id))
                    {
                        await SendMessageAsync(message.Chat.Id, "No configuration found.");

                        return;
                    }
                    if (usersToSkip.Contains(users.Find(u => u.UserId == message.From.Id).Login))
                    {
                        await SendMessageAsync(message.Chat.Id, "Already on the skip list.");

                        return;
                    }
                    if (!userStep.ContainsKey(message.From.Id))
                    {
                        userStep.Add(message.From.Id, 3);
                        await SendMessageAsync(message.Chat.Id, "You can skip the next InstaShit session if you wish. " +
                                               " Please note that this action won't cancel ongoing InstaShit session, if there's any." +
                                               "\nIf you want to continue, type /skip again. To cancel, type /cancel.");
                    }
                    else if (userStep[message.From.Id] == 3)
                    {
                        userStep.Remove(message.From.Id);
                        usersToSkip.Add(users.Find(u => u.UserId == message.From.Id).Login);
                        await SendMessageAsync(message.Chat.Id, "Successfully added to skip list.");
                    }
                    break;

                default:
                    if (userStep.ContainsKey(message.From.Id) && userStep[message.From.Id] == 4)
                    {
                        if (whitelist.Any(t => t.Item1 == message.Text))
                        {
                            whitelist.Remove(whitelist.Find(t => t.Item1 == message.Text));
                            userStep[message.From.Id] = 1;
                            await SendMessageAsync(message.Chat.Id, "Success!");
                            await SendMessageAsync(message.Chat.Id, "Please attach the InstaShit settings file.\n" +
                                                   "You can use InstaShit.CLI to generate it. You can also share settings directly " +
                                                   "from InstaShit.Android (since version 0.5) - just go to \"Edit settings\", " +
                                                   "\"Advanced mode\" and touch \"Share\" button. Ability to create new settings " +
                                                   "using the bot coming soon!\nType /cancel to abort this action (you'll need " +
                                                   "a new unique key if you try to configure the bot again in the future).");
                        }
                        else
                        {
                            await SendMessageAsync(message.Chat.Id, "Incorrect key.");
                        }
                        break;
                    }
                    await SendMessageAsync(message.Chat.Id, "Usage:\n" +
                                           "/configure - Configures InstaShit bot\n" +
                                           "/skip - Skips next InstaShit session\n" +
                                           "/remove - Unregisters from the bot\n" +
                                           "/cancel - Cancels any ongoing process (configure/remove/skip)\n" +
                                           "/dictionary - Returns the wordsDictionary.json file");

                    break;
                }
            }
        }