예제 #1
0
        /// <summary>
        /// Handles a user message
        /// * will keep track of user messages, and rate limit them when appropiate
        /// * will keep track of user cooldowns, and only let through commands if not on cooldown
        /// </summary>
        private async Task MessageReceivedAsync(SocketMessage messageParam)
        {
            try
            {
                if (!(messageParam is SocketUserMessage message) ||
                    message.Author.IsBot ||
                    message.Author.IsWebhook ||
                    message.Channel is SocketDMChannel)
                {
                    return;
                }

                var author = message.Author;
                TrackRateLimit(author.Id, message);

                if (IsRateLimited(author.Id))
                {
                    await message.DeleteAsync(new RequestOptions { AuditLogReason = $"User is rate limited until {RateLimitedUsers[author.Id].ToString()}" });

                    if (NeedsRateLimit(author.Id) && author is SocketGuildUser sgu)
                    {
                        await sgu.KickAsync($"User repeatedly spammed while rate limited");
                    }
                    return;
                }

                bool isAdmin = author.Id == BotOwner.Id;
                SocketTextChannel channel = message.Channel as SocketTextChannel;
                SocketGuild       guild   = channel?.Guild;
                GuildConfig       config  = null;

                if (channel != null)
                {
                    if ((config = ConfigManager.GetManagedConfig(guild.Id)) == null)
                    {
                        return;
                    }

                    if (!isAdmin)
                    {
                        isAdmin = config.Permissions.IsAdmin(message.Author.Id);
                    }
                }

                var context = new SocketCommandContext(_client, message);

                if (!isAdmin)
                {
                    // we're not admin, and we've spammed. we get muted.
                    if (NeedsRateLimit(author.Id))
                    {
                        var startTime = DateTimeOffset.UtcNow;
                        var endTime   = await GiveRateLimit(author.Id, startTime, config);

                        bool notify = true;
                        if (config != null && author is SocketGuildUser gu && config.UserRateLimitCounts[author.Id] > 3)
                        {
                            try
                            {
                                notify = false;
                                var reason = $"User was automatically kicked after being rate limited {config.UserRateLimitCounts[author.Id]} times.";
                                await gu.KickAsync(reason, new RequestOptions { AuditLogReason = reason });
                            }
                            catch (Exception)
                            {
                                // TODO notify no ability to kick. --> mute persists, no worries.
                                // could not kick
                                notify = true;
                            }
                        }

                        if (notify)
                        {
                            await context.Channel.SendMessageAsync($"{author.Mention}, you have been rate limited for {(endTime - startTime).TotalMinutes} minutes.");
                        }

                        // go over messages of spam, delete them
                        foreach (var msg in RateLimits.Select(x => x.Value).SelectMany(x => x.Item1))
                        {
                            await msg.DeleteAsync(new RequestOptions { AuditLogReason = "User was automatically rate limited." });
                        }

                        // clear
                        UntrackRateLimit(author.Id);
                        return;
                    }

                    if (!CooldownReady(message.Author.Id, DateTimeOffset.UtcNow))
                    {
                        return;
                    }
                }

                if (NeedsTrackingClear(author.Id))
                {
                    UntrackRateLimit(author.Id);
                }

                var argPos = 0;
                if (message.Content.EqualsIgnoreCase(".") ||
                    !(message.HasCharPrefix('.', ref argPos)
                      /*|| message.HasMentionPrefix(_client.CurrentUser, ref argPos))*/))
                {
                    return;
                }

                // give command cooldown
                GiveCooldown(message.Author.Id, DateTimeOffset.UtcNow.AddSeconds(3));

                // attempt execute
                var result = await _commands.ExecuteAsync(context, argPos, _services);

                // no success
                if (!result.IsSuccess)
                {
                    // try looking for tags with this key
                    if (channel != null)
                    {
                        var key   = message.Content.Substring(1);
                        var check = Format.Sanitize(key);
                        if (check.Equals(key))
                        {
                            // we dont have this key, try looking for other people's keys
                            if (!config.HasTagKey(author.Id, key))
                            {
                                if (config.AnyKeyName(key))
                                {
                                    var tagstr = message.Content.Substring(1);
                                    // first, check for any global tags.
                                    var globalTags = config.Tags.Values.SelectMany(x => x.Where(y => y.Key.Contains(tagstr) && y.IsGlobal));
                                    if (globalTags.Any())
                                    {
                                        // only one. get it
                                        if (globalTags.Count() == 1)
                                        {
                                            var tag = globalTags.First();
                                            result = await _commands.ExecuteAsync(context, $"tag -g {tag.OwnerId} {tag.Key}", multiMatchHandling : MultiMatchHandling.Exception);

                                            if (result.IsSuccess)
                                            {
                                                return;
                                            }
                                        }
                                        else                                         // multiple, log
                                        {
                                            // todo
                                            result = await _commands.ExecuteAsync(context, $"tag -f tags::global", multiMatchHandling : MultiMatchHandling.Exception);

                                            if (result.IsSuccess)
                                            {
                                                return;
                                            }
                                        }
                                    }

                                    result = await _commands.ExecuteAsync(context, $"tag -f {tagstr}", multiMatchHandling : MultiMatchHandling.Exception);
                                }

                                if (result.IsSuccess)
                                {
                                    return;
                                }
                            }
                            else
                            {
                                // we have this key, get ours
                                //TakeCooldown(message.Author.Id);
                                var tag = config.Tags[author.Id].First(x => x.Key.EqualsIgnoreCase(key));
                                await channel.SendMessageAsync($"{Format.Bold($"Tag: {tag.Key}")}" +
                                                               $"\n{tag.Value}");

                                return;
                            }
                        }
                    }

                    TakeCooldown(author.Id);

                    // send the problem
                    if (!result.ErrorReason.EqualsIgnoreCase("Unknown command."))
                    {
                        await context.Channel.SendMessageAsync(result.ErrorReason);
                    }
                }
            }
            catch (Exception e)
            {
                await Log(new LogMessage(LogSeverity.Info, "self", e.ToString(), e));
            }
        }