Ratelimiting done, untested
This commit is contained in:
		@@ -5,9 +5,10 @@ using NadekoBot.Attributes;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
//todo rewrite to accept msg/sec (for example 1/5 - 1 message every 5 seconds)
 | 
			
		||||
//todo rewrite
 | 
			
		||||
namespace NadekoBot.Modules.Administration
 | 
			
		||||
{
 | 
			
		||||
    public partial class Administration
 | 
			
		||||
@@ -15,58 +16,101 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class RatelimitCommand
 | 
			
		||||
        {
 | 
			
		||||
            public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>();
 | 
			
		||||
            public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
 | 
			
		||||
 | 
			
		||||
            private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5);
 | 
			
		||||
            private DiscordSocketClient _client { get; }
 | 
			
		||||
 | 
			
		||||
            public class Ratelimiter
 | 
			
		||||
            {
 | 
			
		||||
                public class RatelimitedUser
 | 
			
		||||
                {
 | 
			
		||||
                    public ulong UserId { get; set; }
 | 
			
		||||
                    public int MessageCount { get; set; } = 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                public ulong ChannelId { get; set; }
 | 
			
		||||
 | 
			
		||||
                public int MaxMessages { get; set; }
 | 
			
		||||
                public int PerSeconds { get; set; }
 | 
			
		||||
 | 
			
		||||
                public CancellationTokenSource cancelSource { get; set; }
 | 
			
		||||
                public CancellationToken cancelToken { get; set; }
 | 
			
		||||
 | 
			
		||||
                public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; }
 | 
			
		||||
 | 
			
		||||
                public bool CheckUserRatelimit(ulong id)
 | 
			
		||||
                {
 | 
			
		||||
                    RatelimitedUser usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
 | 
			
		||||
                    if (usr.MessageCount == MaxMessages)
 | 
			
		||||
                    {
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        usr.MessageCount++;
 | 
			
		||||
                        var t = Task.Run(async () => {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await Task.Delay(PerSeconds * 1000, cancelToken);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (OperationCanceledException) { }
 | 
			
		||||
                            usr.MessageCount--;
 | 
			
		||||
                        });
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public RatelimitCommand()
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                this._client = NadekoBot.Client;
 | 
			
		||||
 | 
			
		||||
               _client.MessageReceived += async (umsg) =>
 | 
			
		||||
               _client.MessageReceived += (umsg) =>
 | 
			
		||||
                {
 | 
			
		||||
                    var usrMsg = umsg as IUserMessage;
 | 
			
		||||
                    var channel = usrMsg.Channel as ITextChannel;
 | 
			
		||||
 | 
			
		||||
                    if (channel == null || await usrMsg.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
                    ConcurrentDictionary<ulong, DateTime> userTimePair;
 | 
			
		||||
                    if (!RatelimitingChannels.TryGetValue(channel.Id, out userTimePair)) return;
 | 
			
		||||
                    DateTime lastMessageTime;
 | 
			
		||||
                    if (userTimePair.TryGetValue(usrMsg.Author.Id, out lastMessageTime))
 | 
			
		||||
                    var t = Task.Run(async () =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (DateTime.Now - lastMessageTime < ratelimitTime)
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await usrMsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        var usrMsg = umsg as IUserMessage;
 | 
			
		||||
                        var channel = usrMsg.Channel as ITextChannel;
 | 
			
		||||
 | 
			
		||||
                        if (channel == null || await usrMsg.IsAuthor())
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    userTimePair.AddOrUpdate(usrMsg.Author.Id, id => DateTime.Now, (id, dt) => DateTime.Now);
 | 
			
		||||
                        Ratelimiter limiter;
 | 
			
		||||
                        if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        if (limiter.CheckUserRatelimit(usrMsg.Author.Id))
 | 
			
		||||
                            await usrMsg.DeleteAsync();
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Slowmode(IUserMessage umsg)
 | 
			
		||||
            public async Task Slowmode(IUserMessage umsg, int msg = 1, int perSec = 5)
 | 
			
		||||
            {
 | 
			
		||||
                var channel = (ITextChannel)umsg.Channel;
 | 
			
		||||
 | 
			
		||||
                ConcurrentDictionary<ulong, DateTime> throwaway;
 | 
			
		||||
                Ratelimiter throwaway;
 | 
			
		||||
                if (RatelimitingChannels.TryRemove(channel.Id, out throwaway))
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync("Slow mode disabled.").ConfigureAwait(false);
 | 
			
		||||
                    await channel.SendMessageAsync("`Slow mode disabled.`").ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if (RatelimitingChannels.TryAdd(channel.Id, new ConcurrentDictionary<ulong, DateTime>()))
 | 
			
		||||
 | 
			
		||||
                if (msg < 1 || perSec < 1)
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync("Slow mode initiated. " +
 | 
			
		||||
                                                "Users can't send more than 1 message every 5 seconds.")
 | 
			
		||||
                    await channel.SendMessageAsync("`Invalid parameters.`");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (RatelimitingChannels.TryAdd(channel.Id,throwaway = new Ratelimiter() {
 | 
			
		||||
                    ChannelId = channel.Id
 | 
			
		||||
                }))
 | 
			
		||||
                {
 | 
			
		||||
                    await channel.SendMessageAsync("`Slow mode initiated.` " +
 | 
			
		||||
                                                $"Users can't send more than {throwaway.MaxMessages} message(s) every {throwaway.PerSeconds} second(s).")
 | 
			
		||||
                                                .ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
// todo rewrite
 | 
			
		||||
namespace NadekoBot.Modules.Games.Trivia
 | 
			
		||||
{
 | 
			
		||||
    public class TriviaGame
 | 
			
		||||
 
 | 
			
		||||
@@ -417,7 +417,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            musicPlayer.RemoveSongAt(num - 1);
 | 
			
		||||
            await channel.SendMessageAsync($"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**").ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
        //todo fix
 | 
			
		||||
 | 
			
		||||
        [LocalizedCommand, LocalizedDescription, LocalizedSummary]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public async Task Remove(IUserMessage umsg, string all)
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,6 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                    {
 | 
			
		||||
                        var res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
                        var smallObj = JArray.Parse(res)[0];
 | 
			
		||||
                        //todo check if successfull
 | 
			
		||||
                        var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        return await Task.Run(() => JsonConvert.DeserializeObject<MangaResult>(aniData)).ConfigureAwait(false);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user